Skip to content

Commit

Permalink
Added the ability to manage menus in the admin panel.
Browse files Browse the repository at this point in the history
  • Loading branch information
support committed Sep 30, 2023
1 parent e2b6494 commit 35bd274
Show file tree
Hide file tree
Showing 23 changed files with 1,031 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,9 @@ namespace Grand.Business.Core.Interfaces.System.Admin
public interface IAdminSiteMapService
{
Task<IList<AdminSiteMap>> GetSiteMap();
Task InsertSiteMap(AdminSiteMap entity);
Task UpdateSiteMap(AdminSiteMap entity);
Task DeleteSiteMap(AdminSiteMap entity);

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -697,12 +697,21 @@ public static class StandardAdminSiteMap
DisplayOrder = 6,
IconClass = "fa fa-dot-circle-o"
},
new () {
SystemName = "Admin menu",
ResourceName = "Admin.Configuration.Menu",
PermissionNames = new List<string> { PermissionSystemName.Maintenance },
ControllerName = "Menu",
ActionName = "Index",
DisplayOrder = 7,
IconClass = "fa fa-dot-circle-o"
},
new () {
SystemName = "Payment",
ResourceName = "Admin.Configuration.Payment",
PermissionNames = new List<string> { PermissionSystemName.PaymentMethods },
IconClass = "fa fa-arrow-circle-o-right",
DisplayOrder = 7,
DisplayOrder = 8,
ChildNodes = new List<AdminSiteMap> {
new () {
SystemName = "Payment methods",
Expand Down Expand Up @@ -738,7 +747,7 @@ public static class StandardAdminSiteMap
ResourceName = "Admin.Configuration.Shipping",
PermissionNames = new List<string> { PermissionSystemName.ShippingSettings },
IconClass = "fa fa-arrow-circle-o-right",
DisplayOrder = 8,
DisplayOrder = 9,
ChildNodes = new List<AdminSiteMap> {
new () {
SystemName = "Shipping providers",
Expand Down Expand Up @@ -812,7 +821,7 @@ public static class StandardAdminSiteMap
ResourceName = "Admin.Configuration.Tax",
PermissionNames = new List<string> { PermissionSystemName.TaxSettings },
IconClass = "fa fa-arrow-circle-o-right",
DisplayOrder = 9,
DisplayOrder = 10,
ChildNodes = new List<AdminSiteMap> {
new () {
SystemName = "Tax providers",
Expand Down Expand Up @@ -845,7 +854,7 @@ public static class StandardAdminSiteMap
ResourceName = "Admin.Configuration.Layouts",
PermissionNames = new List<string> { PermissionSystemName.Maintenance },
IconClass = "fa fa-arrow-circle-o-right",
DisplayOrder = 10,
DisplayOrder = 11,
ChildNodes = new List<AdminSiteMap> {
new () {
SystemName = "Category layouts",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,37 +1,82 @@
using Grand.Business.Core.Interfaces.System.Admin;
using Grand.Business.Core.Utilities.System;
using Grand.Infrastructure.Caching;
using Grand.Domain.Admin;
using Grand.Domain.Data;
using Grand.Infrastructure.Caching.Constants;
using Grand.Infrastructure.Extensions;
using MediatR;

namespace Grand.Business.System.Services.Admin
{
public class AdminSiteMapService : IAdminSiteMapService
{
private readonly IRepository<AdminSiteMap> _adminSiteMapRepository;
private readonly ICacheBase _cacheBase;
private readonly IMediator _mediator;

public AdminSiteMapService(
IRepository<AdminSiteMap> adminSiteMapRepository,
ICacheBase cacheBase)
ICacheBase cacheBase,
IMediator mediator)
{
_adminSiteMapRepository = adminSiteMapRepository;
_cacheBase = cacheBase;
_mediator = mediator;
}

public virtual async Task<IList<AdminSiteMap>> GetSiteMap()
{
return await _cacheBase.GetAsync("ADMIN_SITEMAP", async () =>
return await _cacheBase.GetAsync(CacheKey.ADMIN_SITEMAP_KEY, () =>
{
var query = from c in _adminSiteMapRepository.Table
orderby c.DisplayOrder
select c;
var list = query.ToList();
if (list.Any())
return list;
return await Task.FromResult(StandardAdminSiteMap.SiteMap.OrderBy(x=>x.DisplayOrder).ToList());
return Task.FromResult(query.ToList());
});
}

public virtual async Task InsertSiteMap(AdminSiteMap entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));

await _adminSiteMapRepository.InsertAsync(entity);

//clear cache
await _cacheBase.RemoveByPrefix(CacheKey.ADMIN_SITEMAP_PATTERN_KEY);

//event notification
await _mediator.EntityInserted(entity);

}

public virtual async Task UpdateSiteMap(AdminSiteMap entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));

await _adminSiteMapRepository.UpdateAsync(entity);

//clear cache
await _cacheBase.RemoveByPrefix(CacheKey.ADMIN_SITEMAP_PATTERN_KEY);

//event notification
await _mediator.EntityUpdated(entity);
}

public virtual async Task DeleteSiteMap(AdminSiteMap entity)
{
if (entity == null)
throw new ArgumentNullException(nameof(entity));

await _adminSiteMapRepository.DeleteAsync(entity);

//clear cache
await _cacheBase.RemoveByPrefix(CacheKey.ADMIN_SITEMAP_PATTERN_KEY);

//event notification
await _mediator.EntityDeleted(entity);
}
}
}
16 changes: 16 additions & 0 deletions src/Core/Grand.Infrastructure/Caching/Constants/SiteMapCacheKey.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace Grand.Infrastructure.Caching.Constants
{
public static partial class CacheKey
{
/// <summary>
/// Key for caching
/// </summary>
public static string ADMIN_SITEMAP_KEY => "Grand.admin-sitemap.all";

/// <summary>
/// Key pattern to clear cache
/// </summary>
public static string ADMIN_SITEMAP_PATTERN_KEY => "Grand.admin-sitemap.";

}
}
30 changes: 30 additions & 0 deletions src/Web/Grand.Web.Admin/Areas/Admin/Views/Menu/Create.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
@model MenuModel
@{
//page title
ViewBag.Title = Loc["Admin.Configuration.Menu.AddNew"];
}
<form asp-area="@Constants.AreaAdmin" asp-controller="Menu" asp-action="Create" method="post" asp-route-parentId="@Context.Request.Query["parentId"]">
<div class="row">
<div class="col-md-12">
<div class="x_panel light form-fit">
<div class="x_title">
<div class="caption">
<i class="fa fa-sitemap"></i>
@Loc["Admin.Configuration.Menu.AddNew"]
<small><i class="fa fa-arrow-circle-left"></i>@Html.ActionLink(Loc["Admin.Configuration.Menu.BackToList"], "Index")</small>
</div>
<div class="actions">
<div class="btn-group btn-group-devided">
<button class="btn btn-success" type="submit" name="save"><i class="fa fa-check"></i> @Loc["Admin.Common.Save"] </button>
<button class="btn btn-success" type="submit" name="save-continue"><i class="fa fa-check-circle"></i> @Loc["Admin.Common.SaveContinue"] </button>
</div>
</div>
</div>
<vc:admin-widget widget-zone="menu_details_buttons" additional-data="null" />
<div class="x_content form">
<partial name="Partials/CreateOrUpdate" model="Model" />
</div>
</div>
</div>
</div>
</form>
47 changes: 47 additions & 0 deletions src/Web/Grand.Web.Admin/Areas/Admin/Views/Menu/Edit.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
@using Microsoft.AspNetCore.Mvc.TagHelpers
@using Grand.Web.Admin.Components
@using Grand.Web.Admin.Interfaces
@using Grand.Web.Common.TagHelpers.Admin
@model MenuModel
@inject IMenuViewModelService MenuViewModelService
@{
//page title
ViewBag.Title = Loc["Admin.Configuration.Menu.Edit"];
var parent = await MenuViewModelService.FindParentNodeById(Model.Id);
}

<form asp-area="@Constants.AreaAdmin" asp-controller="Menu" asp-action="Edit" method="post" id="menu-edit">

<div class="row">
<div class="col-md-12">
<div class="x_panel light form-fit">
<div class="x_title">
<div class="caption">
<i class="fa fa-sitemap"></i>
@Loc["Admin.Configuration.Menu.Edit"] - @Model.SystemName
@if (parent != null && parent.Id != Model.Id)
{
<small><i class="fa fa-arrow-circle-left"></i>@Html.ActionLink(Loc[parent.ResourceName], "Edit", new { Id = parent.Id, area = @Constants.AreaAdmin })</small>
}
else
{
<small><i class="fa fa-arrow-circle-left"></i>@Html.ActionLink(Loc["Admin.Configuration.Menu.BackToList"], "Index")</small>
}
</div>
<div class="actions">
<div class="btn-group btn-group-devided">
<button class="btn btn-success" type="submit" name="save"><i class="fa fa-check"></i> @Loc["Admin.Common.Save"] </button>
<button class="btn btn-success" type="submit" name="save-continue"><i class="fa fa-check-circle"></i> @Loc["Admin.Common.SaveContinue"] </button>
<span id="menu-delete" class="btn red"><i class="fa fa-trash-o"></i> @Loc["Admin.Common.Delete"]</span>
</div>
</div>
</div>
<vc:admin-widget widget-zone="menu_details_buttons" additional-data="Model" />
<div class="x_content form">
<partial name="Partials/CreateOrUpdate" model="Model" />
</div>
</div>
</div>
</div>
</form>
<admin-delete-confirmation button-id="menu-delete"/>
76 changes: 76 additions & 0 deletions src/Web/Grand.Web.Admin/Areas/Admin/Views/Menu/List.cshtml
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
@{
//page title
ViewBag.Title = Loc["Admin.Configuration.Menu"];
}

<div class="row">
<div class="col-md-12">
<div class="x_panel light form-fit">
<div class="x_title">
<div class="caption">
<i class="fa fa-sitemap"></i>
@Loc["Admin.Configuration.Menu"]
</div>
<div class="actions btn-group btn-group-devided">
<a href="@Url.Action("Create", new { area = Constants.AreaAdmin })" class="btn green"><i class="fa fa-plus"></i><span class="d-none d-sm-inline"> @Loc["Admin.Common.AddNew"] </span></a>
</div>
</div>
<div class="x_content form">
<div class="form-horizontal">
<div class="form-body">
<div class="x_content">
<div id="menu-grid"></div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

<script>
$(document).ready(function () {
$("#menu-grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "@Html.Raw(Url.Action("ListItem", "Menu", new { area = Constants.AreaAdmin }))",
type: "POST",
dataType: "json",
data: addAntiForgeryToken
}
},
schema: {
data: "Data",
total: "Total",
errors: "Errors"
},
error: function(e) {
display_kendoui_grid_error(e);
// Cancel the changes
this.cancelChanges();
},
serverPaging: false,
serverFiltering: true,
},
editable: {
confirmation: false,
mode: "inline"
},
scrollable: false,
columns: [{
field: "SystemName",
title: "@Loc["Admin.Configuration.Menu.Fields.SystemName"]",
width: 400,
template: '<a class="k-link" href="Edit/#=Id#">#=kendo.htmlEncode(SystemName)#</a>',
},
{
field: "DisplayOrder",
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" },
title: "@Loc["Admin.Configuration.Menu.Fields.DisplayOrder"]",
width: 125
}]
});
});
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
@model MenuModel

@if (!string.IsNullOrEmpty(Model.Id))
{
<div class="panel panel-default">
<vc:admin-widget widget-zone="menu_details_documents_top" additional-data="Model" />
<div class="panel-body">
<div id="menu-grid"></div>
</div>
<div class="panel-footer">
<button type="button" class="k-button" onclick="location.href='@Url.Action("Create", "Menu", new { parentId = Model.Id, area = Constants.AreaAdmin })'"><i class="fa fa-plus"></i>&nbsp;@Loc["Admin.Common.AddNew"]</button>
</div>
<vc:admin-widget widget-zone="menu_details_documents_bottom" additional-data="Model" />
</div>
<script>
$(document).ready(function () {
$("#menu-grid").kendoGrid({
dataSource: {
transport: {
read: {
url: "@Html.Raw(Url.Action("ChildItem", "Menu", new { ParentId = Model.Id, area = Constants.AreaAdmin }))",
type: "POST",
dataType: "json",
data: addAntiForgeryToken
}
},
schema: {
data: "Data",
total: "Total",
errors: "Errors"
},
error: function(e) {
display_kendoui_grid_error(e);
// Cancel the changes
this.cancelChanges();
},
serverPaging: false,
serverFiltering: true,
},
editable: {
confirmation: false,
mode: "inline"
},
scrollable: false,
columns: [{
field: "SystemName",
title: "@Loc["Admin.Configuration.Menu.Fields.SystemName"]",
width: 400,
template: '<a class="k-link" href="../Edit/#=Id#">#=kendo.htmlEncode(SystemName)#</a>',
},
{
field: "DisplayOrder",
headerAttributes: { style: "text-align:center" },
attributes: { style: "text-align:center" },
title: "@Loc["Admin.Configuration.Menu.Fields.DisplayOrder"]",
width: 125
}]
});
});
</script>

}
else
{
<div class="note note-info">
@Loc["Admin.Catalog.SaveBeforeEdit"]
</div>
}
Loading

0 comments on commit 35bd274

Please sign in to comment.