Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Auto add Admin prefix only for Admin nodes. #13944

Merged
merged 11 commits into from
Jul 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
using System.Threading.Tasks;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using OrchardCore.Admin;
using OrchardCore.AdminMenu.Services;
using OrchardCore.Navigation;

Expand All @@ -13,11 +15,16 @@ public class LinkAdminNodeNavigationBuilder : IAdminNodeNavigationBuilder
{
private readonly ILogger _logger;
private readonly IAdminMenuPermissionService _adminMenuPermissionService;
private readonly AdminOptions _adminOptions;


public LinkAdminNodeNavigationBuilder(IAdminMenuPermissionService adminMenuPermissionService, ILogger<LinkAdminNodeNavigationBuilder> logger)
public LinkAdminNodeNavigationBuilder(
IAdminMenuPermissionService adminMenuPermissionService,
IOptions<AdminOptions> adminOptions,
ILogger<LinkAdminNodeNavigationBuilder> logger)
{
_adminMenuPermissionService = adminMenuPermissionService;
_adminOptions = adminOptions.Value;
_logger = logger;
}

Expand All @@ -26,22 +33,39 @@ public LinkAdminNodeNavigationBuilder(IAdminMenuPermissionService adminMenuPermi
public Task BuildNavigationAsync(MenuItem menuItem, NavigationBuilder builder, IEnumerable<IAdminNodeNavigationBuilder> treeNodeBuilders)
{
var node = menuItem as LinkAdminNode;

if (node == null || String.IsNullOrEmpty(node.LinkText) || !node.Enabled)
{
return Task.CompletedTask;
}

return builder.AddAsync(new LocalizedString(node.LinkText, node.LinkText), async itemBuilder =>
{
// Add the actual link
itemBuilder.Url(node.LinkUrl);
var nodeLinkUrl = node.LinkUrl;
if (!String.IsNullOrEmpty(nodeLinkUrl) && nodeLinkUrl[0] != '/' && !nodeLinkUrl.Contains("://"))
{
if (nodeLinkUrl.StartsWith("~/", StringComparison.Ordinal))
{
nodeLinkUrl = nodeLinkUrl[2..];
}

// Check if the first segment of 'nodeLinkUrl' is not equal to the admin prefix.
if (!nodeLinkUrl.StartsWith($"{_adminOptions.AdminUrlPrefix}", StringComparison.OrdinalIgnoreCase) ||
(nodeLinkUrl.Length != _adminOptions.AdminUrlPrefix.Length
&& nodeLinkUrl[_adminOptions.AdminUrlPrefix.Length] != '/'))
{
nodeLinkUrl = $"{_adminOptions.AdminUrlPrefix}/{nodeLinkUrl}";
}
}

// Add the actual link.
itemBuilder.Url(nodeLinkUrl);
itemBuilder.Priority(node.Priority);
itemBuilder.Position(node.Position);

if (node.PermissionNames.Any())
{
var permissions = await _adminMenuPermissionService.GetPermissionsAsync();

// Find the actual permissions and apply them to the menu.
var selectedPermissions = permissions.Where(p => node.PermissionNames.Contains(p.Name));
itemBuilder.Permissions(selectedPermissions);
Expand All @@ -51,8 +75,8 @@ public Task BuildNavigationAsync(MenuItem menuItem, NavigationBuilder builder, I
// Add them with a prefix so that later the shape template can extract them to use them on a <i> tag.
node.IconClass?.Split(' ').ToList().ForEach(c => itemBuilder.AddClass("icon-class-" + c));

// Let children build themselves inside this MenuItem
// todo: this logic can be shared by all TreeNodeNavigationBuilders
// Let children build themselves inside this MenuItem.
// Todo: This logic can be shared by all TreeNodeNavigationBuilders.
foreach (var childTreeNode in menuItem.Items)
{
try
Expand All @@ -67,20 +91,5 @@ public Task BuildNavigationAsync(MenuItem menuItem, NavigationBuilder builder, I
}
});
}

// Add adminNode's IconClass property values to menuItem.Classes.
// Add them with a prefix so that later the shape template can extract them to use them on a <i> tag.
private void AddIconPickerClassToLink(string iconClass, NavigationItemBuilder itemBuilder)
Piedone marked this conversation as resolved.
Show resolved Hide resolved
{
if (String.IsNullOrEmpty(iconClass))
{
return;
}

foreach (var c in iconClass.Split(' '))
{
itemBuilder.AddClass("icon-class-" + c);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public class ListsAdminNodeNavigationBuilder : IAdminNodeNavigationBuilder
private ListsAdminNode _node;
private ContentTypeDefinition _contentType;

private const int MaxItemsInNode = 100; // security check
// Security check.
private const int MaxItemsInNode = 100;

public ListsAdminNodeNavigationBuilder(
IContentDefinitionManager contentDefinitionManager,
Expand Down Expand Up @@ -72,7 +73,7 @@ await builder.AddAsync(new LocalizedString(_contentType.DisplayName, _contentTyp
await AddContentItemsAsync(builder);
}

// Add external children
// Add external children.
foreach (var childNode in _node.Items)
{
try
Expand All @@ -89,7 +90,7 @@ await builder.AddAsync(new LocalizedString(_contentType.DisplayName, _contentTyp

private async Task AddContentItemsAsync(NavigationBuilder listTypeMenu)
{
foreach (var ci in await getContentItemsAsync())
foreach (var ci in await GetContentItemsAsync())
{
var cim = await _contentManager.PopulateAspectAsync<ContentItemMetadata>(ci);

Expand All @@ -111,7 +112,7 @@ private async Task AddContentItemsAsync(NavigationBuilder listTypeMenu)
}
}

private async Task<List<ContentItem>> getContentItemsAsync()
private async Task<List<ContentItem>> GetContentItemsAsync()
{
return (await _session.Query<ContentItem, ContentItemIndex>()
.With<ContentItemIndex>(x => x.Latest && x.ContentType == _node.ContentType)
Expand All @@ -121,12 +122,12 @@ private async Task<List<ContentItem>> getContentItemsAsync()
.ToList();
}

private List<string> AddPrefixToClasses(string unprefixed)
private static List<string> AddPrefixToClasses(string unprefixed)
{
return unprefixed?.Split(' ')
.ToList()
.Select(c => "icon-class-" + c)
.ToList<string>()
.ToList()
?? new List<string>();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,47 +16,47 @@ public AdminNode GetMenuItemById(string id)

while (tempStack.Any())
{
// evaluate first node
AdminNode item = tempStack.Pop();
// Evaluate first node.
var item = tempStack.Pop();
if (item.UniqueId.Equals(id, StringComparison.OrdinalIgnoreCase))
{
return item;
}

// not that one; continue with the rest.
// Not that one, continue with the rest.
foreach (var i in item.Items)
{
tempStack.Push((AdminNode)i);
}
}

//not found
// Not found.
return null;
}

// return boolean so that caller can check for success
// Return boolean so that caller can check for success.
public bool RemoveMenuItem(AdminNode nodeToRemove)
{
var tempStack = new Stack<AdminNode>(new AdminNode[] { this });

while (tempStack.Any())
{
// evaluate first
MenuItem item = tempStack.Pop();
// Evaluate first.
var item = tempStack.Pop();
if (item.Items.Contains(nodeToRemove))
{
item.Items.Remove(nodeToRemove);
return true; //success
return true; // Success.
}

// not that one. continue
// Not that one, continue.
foreach (var i in item.Items)
{
tempStack.Push((AdminNode)i);
}
}

// failure
// Failure.
return false;
}

Expand All @@ -65,22 +65,22 @@ public bool InsertMenuItem(AdminNode nodeToInsert, MenuItem destinationNode, int
var tempStack = new Stack<AdminNode>(new AdminNode[] { this });
while (tempStack.Any())
{
// evaluate first
MenuItem node = tempStack.Pop();
// Evaluate first.
var node = tempStack.Pop();
if (node.Equals(destinationNode))
{
node.Items.Insert(position, nodeToInsert);
return true; // success
return true; // Success.
}

// not that one. continue
// Not that one, continue.
foreach (var n in node.Items)
{
tempStack.Push((AdminNode)n);
}
}

// failure
// Failure.
return false;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace OrchardCore.AdminMenu.Services
public interface IAdminNodeNavigationBuilder
{
// This Name will be used to determine if the node passed has to be handled.
// The builder will handle only the nodes whose typeName equals this name.
// The builder will handle only the nodes whose type name equals this name.
string Name { get; }

Task BuildNavigationAsync(MenuItem treeNode, NavigationBuilder builder, IEnumerable<IAdminNodeNavigationBuilder> treeNodeBuilders);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -152,12 +152,21 @@ public NavigationItemBuilder Action(string actionName, string controllerName, st
public NavigationItemBuilder Action(string actionName, string controllerName, string areaName, RouteValueDictionary values)
{
_item.RouteValues = new RouteValueDictionary(values);
if (!string.IsNullOrEmpty(actionName))
if (!String.IsNullOrEmpty(actionName))
{
_item.RouteValues["action"] = actionName;
if (!string.IsNullOrEmpty(controllerName))
}

if (!String.IsNullOrEmpty(controllerName))
{
_item.RouteValues["controller"] = controllerName;
if (!string.IsNullOrEmpty(areaName))
}

if (!String.IsNullOrEmpty(areaName))
{
_item.RouteValues["area"] = areaName;
}

return this;
}
}
Expand Down
Loading