diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs index 44a00808f8..d038d64789 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/AbpAspNetCoreMvcUiBootstrapModule.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.Modularity; +using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs index 57a03d0d75..fb8619b60a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/AbpAspNetCoreMvcUiThemeSharedModule.cs @@ -1,5 +1,4 @@ -using Microsoft.Extensions.DependencyInjection; -using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap; using Volo.Abp.AspNetCore.Mvc.UI.Bundling; using Volo.Abp.AspNetCore.Mvc.UI.Packages; using Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared.Bundling; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/ILayoutManager.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/IPageLayout.cs similarity index 100% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/ILayoutManager.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/Layout/IPageLayout.cs diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo.Abp.UI.Navigation.csproj b/framework/src/Volo.Abp.UI.Navigation/Volo.Abp.UI.Navigation.csproj index 79955d3241..c218698017 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo.Abp.UI.Navigation.csproj +++ b/framework/src/Volo.Abp.UI.Navigation/Volo.Abp.UI.Navigation.csproj @@ -1,4 +1,4 @@ - + @@ -13,6 +13,11 @@ + + + + + diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/AbpUiNavigationModule.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/AbpUiNavigationModule.cs index c0934e0a4a..8f4be85af2 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/AbpUiNavigationModule.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/AbpUiNavigationModule.cs @@ -1,10 +1,32 @@ -using Volo.Abp.Modularity; +using Volo.Abp.Localization; +using Volo.Abp.Modularity; +using Volo.Abp.Ui.Navigation; +using Volo.Abp.Ui.Navigation.Localization.Resource; +using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.UI.Navigation { [DependsOn(typeof(AbpUiModule))] public class AbpUiNavigationModule : AbpModule { + public override void ConfigureServices(ServiceConfigurationContext context) + { + Configure(options => + { + options.FileSets.AddEmbedded(); + }); + Configure(options => + { + options.Resources + .Add("en") + .AddVirtualJson("/Volo/Abp/Ui/Navigation/Localization/Resource"); + }); + + Configure(options => + { + options.MenuContributors.Add(new DefaultMenuContributor()); + }); + } } } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs new file mode 100644 index 0000000000..4c24027a1e --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuExtensions.cs @@ -0,0 +1,35 @@ +using System.Linq; +using JetBrains.Annotations; +using Volo.Abp.Ui.Navigation; + +namespace Volo.Abp.UI.Navigation +{ + public static class ApplicationMenuExtensions + { + [NotNull] + public static ApplicationMenuItem GetAdministration(this ApplicationMenu applicationMenu) + { + return applicationMenu.GetMenuItem(DefaultMenuNames.Application.Main.Administration); + } + + [NotNull] + public static ApplicationMenuItem GetMenuItem(this IHasMenuItems menuWithItems, string menuItemName) + { + var menuItem = menuWithItems.GetMenuItemOrNull(menuItemName); + if (menuItem == null) + { + throw new AbpException($"Could not find a menu item with given name: {menuItemName}"); + } + + return menuItem; + } + + [CanBeNull] + public static ApplicationMenuItem GetMenuItemOrNull( + this IHasMenuItems menuWithItems, + string menuItemName) + { + return menuWithItems.Items.FirstOrDefault(mi => mi.Name == menuItemName); + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuContributor.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuContributor.cs new file mode 100644 index 0000000000..c1f035e292 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuContributor.cs @@ -0,0 +1,34 @@ +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using System.Threading.Tasks; +using Volo.Abp.Ui.Navigation.Localization.Resource; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.Ui.Navigation +{ + public class DefaultMenuContributor : IMenuContributor + { + public virtual Task ConfigureMenuAsync(MenuConfigurationContext context) + { + Configure(context); + return Task.CompletedTask; + } + + protected virtual void Configure(MenuConfigurationContext context) + { + var l = context.ServiceProvider + .GetRequiredService>(); + + if (context.Menu.Name == StandardMenus.Main) + { + context.Menu.AddItem( + new ApplicationMenuItem( + DefaultMenuNames.Application.Main.Administration, + l["Menu:Administration"], + icon: "fa fa-wrench" + ) + ); + } + } + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuNames.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuNames.cs new file mode 100644 index 0000000000..96032f48fa --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/DefaultMenuNames.cs @@ -0,0 +1,13 @@ +namespace Volo.Abp.Ui.Navigation +{ + public static class DefaultMenuNames + { + public static class Application + { + public static class Main + { + public const string Administration = "Abp.Application.Main.Administration"; + } + } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/AbpUiNavigationResource.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/AbpUiNavigationResource.cs new file mode 100644 index 0000000000..96d09e9507 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/AbpUiNavigationResource.cs @@ -0,0 +1,10 @@ +using Volo.Abp.Localization; + +namespace Volo.Abp.Ui.Navigation.Localization.Resource +{ + [LocalizationResourceName("AbpUiNavigation")] + public class AbpUiNavigationResource + { + + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json new file mode 100644 index 0000000000..96ca0c5603 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/en.json @@ -0,0 +1,6 @@ +{ + "culture": "en", + "texts": { + "Menu:Administration": "Administration" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/tr.json b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/tr.json new file mode 100644 index 0000000000..67c6da0197 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/Localization/Resource/tr.json @@ -0,0 +1,6 @@ +{ + "culture": "tr", + "texts": { + "Menu:Administration": "Yönetim" + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs index 93b206a2b4..ada287ff87 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/MenuManager.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; -using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -9,26 +8,26 @@ namespace Volo.Abp.UI.Navigation { public class MenuManager : IMenuManager, ITransientDependency { - private readonly NavigationOptions _options; - private readonly IServiceProvider _serviceProvider; + protected NavigationOptions Options { get; } + protected IHybridServiceScopeFactory ServiceScopeFactory { get; } public MenuManager( IOptions options, - IServiceProvider serviceProvider) + IHybridServiceScopeFactory serviceScopeFactory) { - _serviceProvider = serviceProvider; - _options = options.Value; + ServiceScopeFactory = serviceScopeFactory; + Options = options.Value; } public async Task GetAsync(string name) { var menu = new ApplicationMenu(name); - using (var scope = _serviceProvider.CreateScope()) + using (var scope = ServiceScopeFactory.CreateScope()) { var context = new MenuConfigurationContext(menu, scope.ServiceProvider); - foreach (var contributor in _options.MenuContributors) + foreach (var contributor in Options.MenuContributors) { await contributor.ConfigureMenuAsync(context); } @@ -41,6 +40,7 @@ namespace Volo.Abp.UI.Navigation protected virtual void NormalizeMenu(ApplicationMenu menu) { + //TODO: Should also consider sub menus, recursively, bottom to top! menu.Items.RemoveAll(item => item.IsLeaf && item.Url.IsNullOrEmpty()); } } diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/StandardMenus.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/StandardMenus.cs index b8d63a104d..57a8d7ee41 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/StandardMenus.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/StandardMenus.cs @@ -2,6 +2,12 @@ namespace Volo.Abp.UI.Navigation { public static class StandardMenus { + /* TODO: Consider to create nested class like + * StandardMenus.Application.Main + * StandardMenus.Application.User + * StandardMenus.Application.Shortcut + */ + public const string Main = "Main"; public const string User = "User"; public const string Shortcut = "Shortcut"; diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs index 9eb90832e5..fb4600be6e 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs @@ -2,6 +2,7 @@ namespace Localization.Resources.AbpUi { + //TODO: Move to the Volo.Abp.UI.Localization.Resource folder [LocalizationResourceName("AbpUi")] public class AbpUiResource { diff --git a/framework/src/Volo.Abp.UI/Volo.Abp.UI.csproj b/framework/src/Volo.Abp.UI/Volo.Abp.UI.csproj index 1a7ab915c9..8716d7a210 100644 --- a/framework/src/Volo.Abp.UI/Volo.Abp.UI.csproj +++ b/framework/src/Volo.Abp.UI/Volo.Abp.UI.csproj @@ -1,4 +1,4 @@ - + @@ -15,6 +15,7 @@ + diff --git a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs index fb173ee882..0a9206c309 100644 --- a/framework/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs +++ b/framework/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs @@ -20,7 +20,9 @@ namespace Volo.Abp.UI Configure(options => { - options.Resources.Add("en").AddVirtualJson("/Localization/Resources/AbpUi"); + options.Resources + .Add("en") + .AddVirtualJson("/Localization/Resources/AbpUi"); }); } } diff --git a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs index c7f2093e83..0b2d5db4a0 100644 --- a/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs +++ b/framework/test/Volo.Abp.UI.Navigation.Tests/Volo/Abp/Ui/Navigation/MenuManager_Tests.cs @@ -2,7 +2,7 @@ using Microsoft.Extensions.DependencyInjection; using Shouldly; using Volo.Abp.Modularity; -using System.Collections.Generic; +using Volo.Abp.Ui.Navigation; using Xunit; namespace Volo.Abp.UI.Navigation @@ -25,7 +25,7 @@ namespace Volo.Abp.UI.Navigation mainMenu.DisplayName.ShouldBe("Main Menu"); mainMenu.Items.Count.ShouldBe(2); mainMenu.Items[0].Name.ShouldBe("Dashboard"); - mainMenu.Items[1].Name.ShouldBe("Administration"); + mainMenu.Items[1].Name.ShouldBe(DefaultMenuNames.Application.Main.Administration); mainMenu.Items[1].Items[0].Name.ShouldBe("Administration.UserManagement"); mainMenu.Items[1].Items[1].Name.ShouldBe("Administration.RoleManagement"); mainMenu.Items[1].Items[2].Name.ShouldBe("Administration.DashboardSettings"); @@ -60,10 +60,7 @@ namespace Volo.Abp.UI.Navigation context.Menu.DisplayName = "Main Menu"; - var administration = context.Menu.Items.GetOrAdd( - m => m.Name == "Administration", - () => new ApplicationMenuItem("Administration", "Administration") - ); + var administration = context.Menu.GetAdministration(); administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management", url: "/admin/users")); administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management", url: "/admin/roles")); @@ -88,10 +85,7 @@ namespace Volo.Abp.UI.Navigation context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard", url: "/dashboard")); - var administration = context.Menu.Items.GetOrAdd( - m => m.Name == "Administration", - () => new ApplicationMenuItem("Administration", "Administration") - ); + var administration = context.Menu.GetAdministration(); administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard"));