diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs index fce412c22f..a40c67cdf6 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenu.cs @@ -1,5 +1,5 @@ -using System.Collections.Generic; using JetBrains.Annotations; +using Volo.Abp.Ui.Navigation; namespace Volo.Abp.UI.Navigation { @@ -29,11 +29,11 @@ namespace Volo.Abp.UI.Navigation /// [NotNull] - public IList Items { get; } //TODO: Create a specialized collection (that can contain AddAfter for example) + public ApplicationMenuItemList Items { get; } /// /// Can be used to store a custom object related to this menu. - /// TODO: Conver to dictionary! + /// TODO: Convert to dictionary! /// [CanBeNull] public object CustomData { get; set; } @@ -47,7 +47,7 @@ namespace Volo.Abp.UI.Navigation Name = name; DisplayName = displayName ?? Name; - Items = new List(); + Items = new ApplicationMenuItemList(); } /// @@ -60,5 +60,10 @@ namespace Volo.Abp.UI.Navigation Items.Add(menuItem); return this; } + + public override string ToString() + { + return $"[ApplicationMenu] Name = {Name}"; + } } } \ No newline at end of file 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 index 4c24027a1e..e69471e15d 100644 --- 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 @@ -1,5 +1,5 @@ -using System.Linq; using JetBrains.Annotations; +using System.Linq; using Volo.Abp.Ui.Navigation; namespace Volo.Abp.UI.Navigation @@ -7,13 +7,18 @@ namespace Volo.Abp.UI.Navigation public static class ApplicationMenuExtensions { [NotNull] - public static ApplicationMenuItem GetAdministration(this ApplicationMenu applicationMenu) + public static ApplicationMenuItem GetAdministration( + [NotNull] this ApplicationMenu applicationMenu) { - return applicationMenu.GetMenuItem(DefaultMenuNames.Application.Main.Administration); + return applicationMenu.GetMenuItem( + DefaultMenuNames.Application.Main.Administration + ); } [NotNull] - public static ApplicationMenuItem GetMenuItem(this IHasMenuItems menuWithItems, string menuItemName) + public static ApplicationMenuItem GetMenuItem( + [NotNull] this IHasMenuItems menuWithItems, + string menuItemName) { var menuItem = menuWithItems.GetMenuItemOrNull(menuItemName); if (menuItem == null) @@ -26,10 +31,29 @@ namespace Volo.Abp.UI.Navigation [CanBeNull] public static ApplicationMenuItem GetMenuItemOrNull( - this IHasMenuItems menuWithItems, + [NotNull] this IHasMenuItems menuWithItems, string menuItemName) { + Check.NotNull(menuWithItems, nameof(menuWithItems)); + return menuWithItems.Items.FirstOrDefault(mi => mi.Name == menuItemName); } + + [NotNull] + public static IHasMenuItems SetSubItemOrder( + [NotNull] this IHasMenuItems menuWithItems, + string menuItemName, + int order) + { + Check.NotNull(menuWithItems, nameof(menuWithItems)); + + var menuItem = menuWithItems.GetMenuItemOrNull(menuItemName); + if (menuItem != null) + { + menuItem.Order = order; + } + + return menuWithItems; + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs index de19f6db7b..e09c065b00 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItem.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using JetBrains.Annotations; +using Volo.Abp.Ui.Navigation; namespace Volo.Abp.UI.Navigation { @@ -68,7 +69,7 @@ namespace Volo.Abp.UI.Navigation /// [NotNull] - public IList Items { get; } + public ApplicationMenuItemList Items { get; } /// /// Can be used to store a custom object related to this menu item. Optional. @@ -109,7 +110,7 @@ namespace Volo.Abp.UI.Navigation ElementId = elementId ?? GetDefaultElementId(); CssClass = cssClass; - Items = new List(); + Items = new ApplicationMenuItemList(); } /// @@ -127,5 +128,10 @@ namespace Volo.Abp.UI.Navigation { return "MenuItem_" + Name; } + + public override string ToString() + { + return $"[ApplicationMenuItem] Name = {Name}"; + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItemList.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItemList.cs new file mode 100644 index 0000000000..0e9c845664 --- /dev/null +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/ApplicationMenuItemList.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Volo.Abp.UI.Navigation; + +namespace Volo.Abp.Ui.Navigation +{ + public class ApplicationMenuItemList : List + { + public ApplicationMenuItemList() + { + + } + + public ApplicationMenuItemList(int capacity) + : base(capacity) + { + + } + + public ApplicationMenuItemList(IEnumerable collection) + : base(collection) + { + + } + + public void Normalize() + { + RemoveEmptyItems(); + Order(); + } + + private void RemoveEmptyItems() + { + RemoveAll(item => item.IsLeaf && item.Url.IsNullOrEmpty()); + } + + private void Order() + { + //TODO: Is there any way that is more performant? + var orderedItems = this.OrderBy(item => item.Order).ToArray(); + Clear(); + AddRange(orderedItems); + } + } +} diff --git a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuItems.cs b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuItems.cs index adfa8f2f40..f33ddcd4c2 100644 --- a/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuItems.cs +++ b/framework/src/Volo.Abp.UI.Navigation/Volo/Abp/Ui/Navigation/IHasMenuItems.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using Volo.Abp.Ui.Navigation; namespace Volo.Abp.UI.Navigation { @@ -7,6 +7,6 @@ namespace Volo.Abp.UI.Navigation /// /// Menu items. /// - IList Items { get; } + ApplicationMenuItemList Items { get; } } } \ 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 ada287ff87..9c96006b02 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,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; using Microsoft.Extensions.Options; using Volo.Abp.DependencyInjection; @@ -38,10 +39,14 @@ namespace Volo.Abp.UI.Navigation return menu; } - protected virtual void NormalizeMenu(ApplicationMenu menu) + protected virtual void NormalizeMenu(IHasMenuItems menuWithItems) { - //TODO: Should also consider sub menus, recursively, bottom to top! - menu.Items.RemoveAll(item => item.IsLeaf && item.Url.IsNullOrEmpty()); + foreach (var menuItem in menuWithItems.Items) + { + NormalizeMenu(menuItem); + } + + menuWithItems.Items.Normalize(); } } } \ No newline at end of file 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 0b2d5db4a0..77203962ae 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 @@ -29,6 +29,9 @@ namespace Volo.Abp.UI.Navigation 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"); + mainMenu.Items[1].Items[3].Name.ShouldBe("Administration.SubMenu1"); + mainMenu.Items[1].Items[3].Items[0].Name.ShouldBe("Administration.SubMenu1.1"); + mainMenu.Items[1].Items[3].Items[1].Name.ShouldBe("Administration.SubMenu1.2"); } [DependsOn(typeof(AbpUiNavigationModule))] @@ -89,6 +92,12 @@ namespace Volo.Abp.UI.Navigation administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings", url: "/admin/settings/dashboard")); + administration.AddItem( + new ApplicationMenuItem("Administration.SubMenu1", "Sub menu 1") + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.1", "Sub menu 1.1", url: "/submenu1/submenu1_1")) + .AddItem(new ApplicationMenuItem("Administration.SubMenu1.2", "Sub menu 1.2", url: "/submenu1/submenu1_2")) + ); + return Task.CompletedTask; } } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs index c6ff751d57..1fbd519bfd 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMainMenuContributor.cs @@ -25,7 +25,16 @@ namespace Volo.Abp.SettingManagement.Web.Navigation //TODO: Localize //var l = context.ServiceProvider.GetRequiredService>(); - context.Menu.AddItem(new ApplicationMenuItem(SettingManagementMenuNames.GroupName, "Settings", "/SettingManagement", icon: "fa fa-cog", order: int.MaxValue - 1000)); + context.Menu + .GetAdministration() + .AddItem( + new ApplicationMenuItem( + SettingManagementMenuNames.GroupName, + "Settings", + "/SettingManagement", + icon: "fa fa-cog" + ) + ); return Task.CompletedTask; } diff --git a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMenuNames.cs b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMenuNames.cs index 67678f5b9e..4c5af73abe 100644 --- a/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMenuNames.cs +++ b/modules/setting-management/src/Volo.Abp.SettingManagement.Web/Navigation/SettingManagementMenuNames.cs @@ -1,14 +1,7 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace Volo.Abp.SettingManagement.Web.Navigation +namespace Volo.Abp.SettingManagement.Web.Navigation { public class SettingManagementMenuNames { public const string GroupName = "SettingManagement"; - - public const string Settings = GroupName + ".Settings"; } }