mirror of https://github.com/abpframework/abp.git
18 changed files with 499 additions and 10 deletions
@ -0,0 +1,26 @@ |
|||
using System.Threading.Tasks; |
|||
using Volo.Abp.Ui.Navigation; |
|||
|
|||
namespace AbpDesk.Web.Mvc.Navigation |
|||
{ |
|||
public class MainMenuContributor : IMenuContributor |
|||
{ |
|||
public Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
if (context.Menu.Name != StandardMenus.Main) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
context.Menu.DisplayName = "Main Menu"; |
|||
|
|||
context.Menu.AddItem( |
|||
new ApplicationMenuItem("TicketManagement", "Ticket Management") |
|||
.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management")) |
|||
.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management")) |
|||
); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,22 @@ |
|||
@using System.Threading.Tasks |
|||
@model Volo.Abp.Ui.Navigation.ApplicationMenu |
|||
<h2>@Model.DisplayName</h2> |
|||
<ul> |
|||
@foreach (var menuItem in Model.Items) |
|||
{ |
|||
<li> |
|||
<a href="@menuItem.Url">@menuItem.DisplayName</a> |
|||
@if (menuItem.Items.Any()) |
|||
{ |
|||
<ul> |
|||
@foreach (var childMenuItem in menuItem.Items) |
|||
{ |
|||
<li> |
|||
<a href="@childMenuItem.Url">@childMenuItem.DisplayName</a> |
|||
</li> |
|||
} |
|||
</ul> |
|||
} |
|||
</li> |
|||
} |
|||
</ul> |
|||
@ -0,0 +1,24 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.AspNetCore.Mvc; |
|||
using Volo.Abp.Ui.Navigation; |
|||
|
|||
namespace AbpDesk.Web.Mvc.Views.Shared.Components.HorizontalMenu |
|||
{ |
|||
public class HorizontalMenuViewComponent : ViewComponent |
|||
{ |
|||
private readonly IMenuManager _menuManager; |
|||
|
|||
public HorizontalMenuViewComponent(IMenuManager menuManager) |
|||
{ |
|||
//TODO: Create a INavigationAppService that can also be used remotely, instead of directly using IMenuManager!
|
|||
|
|||
_menuManager = menuManager; |
|||
} |
|||
|
|||
public async Task<IViewComponentResult> InvokeAsync(string menuName = StandardMenus.Main) |
|||
{ |
|||
var menu = await _menuManager.GetAsync(StandardMenus.Main); |
|||
return View(menu); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,63 @@ |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class ApplicationMenu : IHasMenuItems |
|||
{ |
|||
/// <summary>
|
|||
/// Unique name of the menu in the application.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string Name { get; } |
|||
|
|||
/// <summary>
|
|||
/// Display name of the menu.
|
|||
/// Default value is the <see cref="Name"/>.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string DisplayName |
|||
{ |
|||
get { return _displayName; } |
|||
set |
|||
{ |
|||
Check.NotNullOrWhiteSpace(value, nameof(value)); |
|||
_displayName = value; |
|||
} |
|||
} |
|||
private string _displayName; |
|||
|
|||
/// <inheritdoc cref="IHasMenuItems.Items"/>
|
|||
[NotNull] |
|||
public IList<ApplicationMenuItem> Items { get; } //TODO: Create a specialized collection (that can contain AddAfter for example)
|
|||
|
|||
/// <summary>
|
|||
/// Can be used to store a custom object related to this menu.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public object CustomData { get; set; } |
|||
|
|||
public ApplicationMenu( |
|||
[NotNull] string name, |
|||
string displayName = null) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
|
|||
Name = name; |
|||
DisplayName = displayName ?? Name; |
|||
|
|||
Items = new List<ApplicationMenuItem>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a <see cref="ApplicationMenuItem"/> to <see cref="Items"/>.
|
|||
/// </summary>
|
|||
/// <param name="menuItem"><see cref="ApplicationMenuItem"/> to be added</param>
|
|||
/// <returns>This <see cref="ApplicationMenu"/> object</returns>
|
|||
public ApplicationMenu AddItem([NotNull] ApplicationMenuItem menuItem) |
|||
{ |
|||
Items.Add(menuItem); |
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,108 @@ |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
using Volo.ExtensionMethods.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class ApplicationMenuItem : IHasMenuItems |
|||
{ |
|||
private string _displayName; |
|||
|
|||
/// <summary>
|
|||
/// Default <see cref="Order"/> value of a menu item.
|
|||
/// </summary>
|
|||
public const int DefaultOrder = 1000; |
|||
|
|||
/// <summary>
|
|||
/// Unique name of the menu in the application.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string Name { get; } |
|||
|
|||
/// <summary>
|
|||
/// Display name of the menu item.
|
|||
/// </summary>
|
|||
[NotNull] |
|||
public string DisplayName |
|||
{ |
|||
get { return _displayName; } |
|||
set |
|||
{ |
|||
Check.NotNullOrWhiteSpace(value, nameof(value)); |
|||
_displayName = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The Display order of the menu.
|
|||
/// Default value: 1000.
|
|||
/// </summary>
|
|||
public int Order { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// The URL to navigate when this menu item is selected.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public string Url { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Icon of the menu item if exists.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public string Icon { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Returns true if this menu item has no child <see cref="Items"/>.
|
|||
/// </summary>
|
|||
public bool IsLeaf => Items.IsNullOrEmpty(); |
|||
|
|||
/// <summary>
|
|||
/// Target of the menu item. Can be null, "_blank", "_self", "_parent", "_top" or a frame name for web applications.
|
|||
/// </summary>
|
|||
[CanBeNull] |
|||
public string Target { get; set; } |
|||
|
|||
/// <inheritdoc cref="IHasMenuItems.Items"/>
|
|||
[NotNull] |
|||
public IList<ApplicationMenuItem> Items { get; } |
|||
|
|||
/// <summary>
|
|||
/// Can be used to store a custom object related to this menu item. Optional.
|
|||
/// </summary>
|
|||
public object CustomData { get; set; } |
|||
|
|||
public ApplicationMenuItem( |
|||
[NotNull] string name, |
|||
[NotNull] string displayName, |
|||
string url = null, |
|||
string icon = null, |
|||
int order = DefaultOrder, |
|||
object customData = null, |
|||
string target = null) |
|||
{ |
|||
Check.NotNullOrWhiteSpace(name, nameof(name)); |
|||
Check.NotNullOrWhiteSpace(displayName, nameof(displayName)); |
|||
|
|||
Name = name; |
|||
DisplayName = displayName; |
|||
Url = url; |
|||
Icon = icon; |
|||
Order = order; |
|||
CustomData = customData; |
|||
Target = target; |
|||
|
|||
Items = new List<ApplicationMenuItem>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Adds a <see cref="ApplicationMenuItem"/> to <see cref="Items"/>.
|
|||
/// </summary>
|
|||
/// <param name="menuItem"><see cref="ApplicationMenuItem"/> to be added</param>
|
|||
/// <returns>This <see cref="ApplicationMenuItem"/> object</returns>
|
|||
public ApplicationMenuItem AddItem([NotNull] ApplicationMenuItem menuItem) |
|||
{ |
|||
Items.Add(menuItem); |
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,12 @@ |
|||
using System.Collections.Generic; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public interface IHasMenuItems |
|||
{ |
|||
/// <summary>
|
|||
/// Menu items.
|
|||
/// </summary>
|
|||
IList<ApplicationMenuItem> Items { get; } |
|||
} |
|||
} |
|||
@ -0,0 +1,11 @@ |
|||
using Volo.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public interface IMenuConfigurationContext : IServiceProviderAccessor |
|||
{ |
|||
ApplicationMenu Menu { get; set; } |
|||
|
|||
//TODO: Add Localization, Authorization components since they are most used components on menu creation!
|
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public interface IMenuContributor |
|||
{ |
|||
Task ConfigureMenuAsync(MenuConfigurationContext context); |
|||
} |
|||
} |
|||
@ -0,0 +1,9 @@ |
|||
using System.Threading.Tasks; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public interface IMenuManager |
|||
{ |
|||
Task<ApplicationMenu> GetAsync(string name); |
|||
} |
|||
} |
|||
@ -0,0 +1,17 @@ |
|||
using System; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class MenuConfigurationContext : IMenuConfigurationContext |
|||
{ |
|||
public ApplicationMenu Menu { get; set; } |
|||
|
|||
public IServiceProvider ServiceProvider { get; } |
|||
|
|||
public MenuConfigurationContext(ApplicationMenu menu, IServiceProvider serviceProvider) |
|||
{ |
|||
Menu = menu; |
|||
ServiceProvider = serviceProvider; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,39 @@ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Microsoft.Extensions.Options; |
|||
using Volo.DependencyInjection; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class MenuManager : IMenuManager, ITransientDependency |
|||
{ |
|||
private readonly NavigationOptions _options; |
|||
private readonly IServiceProvider _serviceProvider; |
|||
|
|||
public MenuManager( |
|||
IOptions<NavigationOptions> options, |
|||
IServiceProvider serviceProvider) |
|||
{ |
|||
_serviceProvider = serviceProvider; |
|||
_options = options.Value; |
|||
} |
|||
|
|||
public async Task<ApplicationMenu> GetAsync(string name) |
|||
{ |
|||
var menu = new ApplicationMenu(name); |
|||
|
|||
using (var scope = _serviceProvider.CreateScope()) |
|||
{ |
|||
var context = new MenuConfigurationContext(menu, scope.ServiceProvider); |
|||
|
|||
foreach (var contributor in _options.MenuContributors) |
|||
{ |
|||
await contributor.ConfigureMenuAsync(context); |
|||
} |
|||
} |
|||
|
|||
return menu; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,16 @@ |
|||
using System.Collections.Generic; |
|||
using JetBrains.Annotations; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class NavigationOptions |
|||
{ |
|||
[NotNull] |
|||
public List<IMenuContributor> MenuContributors { get; } |
|||
|
|||
public NavigationOptions() |
|||
{ |
|||
MenuContributors = new List<IMenuContributor>(); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,8 @@ |
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public static class StandardMenus |
|||
{ |
|||
public const string Main = "Main"; |
|||
public const string User = "User"; |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
using System.Threading.Tasks; |
|||
using Microsoft.Extensions.DependencyInjection; |
|||
using Shouldly; |
|||
using Volo.Abp.Modularity; |
|||
using Volo.Abp.TestBase; |
|||
using Volo.ExtensionMethods.Collections.Generic; |
|||
using Xunit; |
|||
|
|||
namespace Volo.Abp.Ui.Navigation |
|||
{ |
|||
public class MenuManager_Tests : AbpIntegratedTest<MenuManager_Tests.TestModule> |
|||
{ |
|||
private readonly IMenuManager _menuManager; |
|||
|
|||
public MenuManager_Tests() |
|||
{ |
|||
_menuManager = ServiceProvider.GetRequiredService<IMenuManager>(); |
|||
} |
|||
|
|||
[Fact] |
|||
public async Task Should_Get_Menu() |
|||
{ |
|||
var mainMenu = await _menuManager.GetAsync(StandardMenus.Main); |
|||
|
|||
mainMenu.Name.ShouldBe(StandardMenus.Main); |
|||
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].Items[0].Name.ShouldBe("Administration.UserManagement"); |
|||
mainMenu.Items[1].Items[1].Name.ShouldBe("Administration.RoleManagement"); |
|||
mainMenu.Items[1].Items[2].Name.ShouldBe("Administration.DashboardSettings"); |
|||
} |
|||
|
|||
public class TestModule : AbpModule |
|||
{ |
|||
public override void ConfigureServices(IServiceCollection services) |
|||
{ |
|||
services.Configure<NavigationOptions>(options => |
|||
{ |
|||
options.MenuContributors.Add(new TestMenuContributer1()); |
|||
options.MenuContributors.Add(new TestMenuContributer2()); |
|||
}); |
|||
} |
|||
} |
|||
|
|||
/* Adds menu items: |
|||
* - Administration |
|||
* - User Management |
|||
* - Role Management |
|||
*/ |
|||
public class TestMenuContributer1 : IMenuContributor |
|||
{ |
|||
public Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
if (context.Menu.Name != StandardMenus.Main) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
context.Menu.DisplayName = "Main Menu"; |
|||
|
|||
var administration = context.Menu.Items.GetOrAdd( |
|||
m => m.Name == "Administration", |
|||
() => new ApplicationMenuItem("Administration", "Administration") |
|||
); |
|||
|
|||
administration.AddItem(new ApplicationMenuItem("Administration.UserManagement", "User Management")); |
|||
administration.AddItem(new ApplicationMenuItem("Administration.RoleManagement", "Role Management")); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
|
|||
/* Adds menu items: |
|||
* - Dashboard |
|||
* - Administration |
|||
* - Dashboard Settings |
|||
*/ |
|||
public class TestMenuContributer2 : IMenuContributor |
|||
{ |
|||
public Task ConfigureMenuAsync(MenuConfigurationContext context) |
|||
{ |
|||
if (context.Menu.Name != StandardMenus.Main) |
|||
{ |
|||
return Task.CompletedTask; |
|||
} |
|||
|
|||
context.Menu.Items.Insert(0, new ApplicationMenuItem("Dashboard", "Dashboard")); |
|||
|
|||
var administration = context.Menu.Items.GetOrAdd( |
|||
m => m.Name == "Administration", |
|||
() => new ApplicationMenuItem("Administration", "Administration") |
|||
); |
|||
|
|||
administration.AddItem(new ApplicationMenuItem("Administration.DashboardSettings", "Dashboard Settings")); |
|||
|
|||
return Task.CompletedTask; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue