From 87efe7bf19e578d0058ded75731d78ea4d87b19d Mon Sep 17 00:00:00 2001 From: EngincanV Date: Tue, 19 Aug 2025 16:36:43 +0300 Subject: [PATCH] CMS: Fix dynamic menu ordering --- .../Admin/Menus/IMenuItemAdminAppService.cs | 2 + .../Admin/Menus/MenuItemAdminAppService.cs | 8 ++- .../MenuItemAdminClientProxy.Generated.cs | 8 +++ .../cms-kit-admin-generate-proxy.json | 54 +++++++++++++++++++ .../Admin/Menus/MenuItemAdminController.cs | 9 +++- .../Menus/MenuItems/CreateModal.cshtml.cs | 2 + .../Pages/CmsKit/Menus/MenuItems/index.js | 20 +++++-- .../client-proxies/cms-kit-admin-proxy.js | 29 ++++++++++ .../Volo/CmsKit/Menus/IMenuItemRepository.cs | 6 +++ .../CmsKit/Menus/EfCoreMenuItemRepository.cs | 22 ++++++++ .../MongoDB/Menus/MongoMenuItemRepository.cs | 22 +++++++- .../Public/Menus/MenuItemPublicAppService.cs | 2 +- 12 files changed, 175 insertions(+), 9 deletions(-) diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs index f97fc69ee1..82e953132a 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application.Contracts/Volo/CmsKit/Admin/Menus/IMenuItemAdminAppService.cs @@ -23,4 +23,6 @@ public interface IMenuItemAdminAppService : IApplicationService Task> GetPageLookupAsync(PageLookupInputDto input); Task> GetPermissionLookupAsync(PermissionLookupInputDto inputDto); + + Task GetAvailableMenuOrderAsync(Guid? parentId = null); } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs index 13abdf9607..5fbaf3c802 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Application/Volo/CmsKit/Admin/Menus/MenuItemAdminAppService.cs @@ -41,7 +41,7 @@ public class MenuItemAdminAppService : CmsKitAdminAppServiceBase, IMenuItemAdmin public virtual async Task> GetListAsync() { - var menuItems = await MenuItemRepository.GetListAsync(); + var menuItems = await MenuItemRepository.GetOrderedListAsync(); return new ListResultDto( ObjectMapper.Map, List>(menuItems) @@ -162,4 +162,10 @@ public class MenuItemAdminAppService : CmsKitAdminAppServiceBase, IMenuItemAdmin permissionLookupDtos ); } + + public async Task GetAvailableMenuOrderAsync(Guid? parentId = null) + { + var highestOrder = await MenuItemRepository.GetHighestMenuOrderAsync(parentId); + return highestOrder + 1; + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/Volo/CmsKit/Admin/Menus/MenuItemAdminClientProxy.Generated.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/Volo/CmsKit/Admin/Menus/MenuItemAdminClientProxy.Generated.cs index c707d6ad64..7f530db931 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/Volo/CmsKit/Admin/Menus/MenuItemAdminClientProxy.Generated.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/Volo/CmsKit/Admin/Menus/MenuItemAdminClientProxy.Generated.cs @@ -80,4 +80,12 @@ public partial class MenuItemAdminClientProxy : ClientProxyBase GetAvailableMenuOrderAsync(Guid? parentId) + { + return await RequestAsync(nameof(GetAvailableMenuOrderAsync), new ClientProxyRequestTypeValue + { + { typeof(Guid?), parentId } + }); + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json index 9e5f9a843e..0b3a4ffb71 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi.Client/ClientProxies/cms-kit-admin-generate-proxy.json @@ -2184,6 +2184,23 @@ "type": "Volo.Abp.Application.Dtos.ListResultDto", "typeSimple": "Volo.Abp.Application.Dtos.ListResultDto" } + }, + { + "name": "GetAvailableMenuOrderAsync", + "parametersOnMethod": [ + { + "name": "parentId", + "typeAsString": "System.Nullable`1[[System.Guid, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib", + "type": "System.Guid?", + "typeSimple": "string?", + "isOptional": true, + "defaultValue": null + } + ], + "returnValue": { + "type": "System.Int32", + "typeSimple": "number" + } } ] } @@ -2538,6 +2555,43 @@ }, "allowAnonymous": false, "implementFrom": "Volo.CmsKit.Admin.Menus.IMenuItemAdminAppService" + }, + "GetAvailableMenuOrderAsyncByParentId": { + "uniqueName": "GetAvailableMenuOrderAsyncByParentId", + "name": "GetAvailableMenuOrderAsync", + "httpMethod": "GET", + "url": "api/cms-kit-admin/menu-items/available-order", + "supportedVersions": [], + "parametersOnMethod": [ + { + "name": "parentId", + "typeAsString": "System.Nullable`1[[System.Guid, System.Private.CoreLib, Version=9.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]], System.Private.CoreLib", + "type": "System.Guid?", + "typeSimple": "string?", + "isOptional": true, + "defaultValue": null + } + ], + "parameters": [ + { + "nameOnMethod": "parentId", + "name": "parentId", + "jsonName": null, + "type": "System.Guid?", + "typeSimple": "string?", + "isOptional": false, + "defaultValue": null, + "constraintTypes": null, + "bindingSourceId": "ModelBinding", + "descriptorName": "" + } + ], + "returnValue": { + "type": "System.Int32", + "typeSimple": "number" + }, + "allowAnonymous": false, + "implementFrom": "Volo.CmsKit.Admin.Menus.IMenuItemAdminAppService" } } }, diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs index e3cac24f54..08aacac405 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.HttpApi/Volo/CmsKit/Admin/Menus/MenuItemAdminController.cs @@ -81,8 +81,15 @@ public class MenuItemAdminController : CmsKitAdminController, IMenuItemAdminAppS [HttpGet] [Route("lookup/permissions")] - public Task> GetPermissionLookupAsync(PermissionLookupInputDto inputDto) + public virtual Task> GetPermissionLookupAsync(PermissionLookupInputDto inputDto) { return MenuItemAdminAppService.GetPermissionLookupAsync(inputDto); } + + [HttpGet] + [Route("available-order")] + public virtual Task GetAvailableMenuOrderAsync(Guid? parentId = null) + { + return MenuItemAdminAppService.GetAvailableMenuOrderAsync(parentId); + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/CreateModal.cshtml.cs b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/CreateModal.cshtml.cs index 49a1354b43..f0730d08a7 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/CreateModal.cshtml.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/CreateModal.cshtml.cs @@ -39,6 +39,8 @@ public class CreateModalModel : CmsKitAdminPageModel public virtual async Task OnPostAsync() { + ViewModel.Order = await MenuAdminAppService.GetAvailableMenuOrderAsync(ViewModel.ParentId); + var input = ObjectMapper.Map(ViewModel); var dto = await MenuAdminAppService.CreateAsync(input); diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/index.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/index.js index 42932c5973..6133788cfe 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/index.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/Pages/CmsKit/Menus/MenuItems/index.js @@ -263,11 +263,21 @@ $(function () { }, sort: function (node1, node2) { - if (this.get_node(node2).original.order < this.get_node(node1).original.order) { - return 1; - } - - return -1; + const node1Data = this.get_node(node1).original; + const node2Data = this.get_node(node2).original; + if (node1Data.parentId === null && node2Data.parentId !== null) { + return -1; + } + if (node1Data.parentId !== null && node2Data.parentId === null) { + return 1; + } + if (node1Data.order < node2Data.order) { + return -1; + } + if (node1Data.order > node2Data.order) { + return 1; + } + return 0; }, plugins: [ diff --git a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js index 08dc7bf2c0..928d7c11b9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js +++ b/modules/cms-kit/src/Volo.CmsKit.Admin.Web/wwwroot/client-proxies/cms-kit-admin-proxy.js @@ -49,6 +49,21 @@ }, ajaxParams)); }; + volo.cmsKit.admin.blogs.blogAdmin.getAllList = function(ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-admin/blogs/all', + type: 'GET' + }, ajaxParams)); + }; + + volo.cmsKit.admin.blogs.blogAdmin.moveAllBlogPosts = function(blogId, assignToBlogId, id, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-admin/blogs/' + id + '/move-all-blog-posts' + abp.utils.buildQueryString([{ name: 'blogId', value: blogId }, { name: 'assignToBlogId', value: assignToBlogId }]) + '', + type: 'PUT', + dataType: null + }, ajaxParams)); + }; + })(); // controller volo.cmsKit.admin.blogs.blogFeatureAdmin @@ -330,6 +345,20 @@ }, ajaxParams)); }; + volo.cmsKit.admin.menus.menuItemAdmin.getPermissionLookup = function(inputDto, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-admin/menu-items/lookup/permissions' + abp.utils.buildQueryString([{ name: 'filter', value: inputDto.filter }]) + '', + type: 'GET' + }, ajaxParams)); + }; + + volo.cmsKit.admin.menus.menuItemAdmin.getAvailableMenuOrder = function(parentId, ajaxParams) { + return abp.ajax($.extend(true, { + url: abp.appPath + 'api/cms-kit-admin/menu-items/available-order' + abp.utils.buildQueryString([{ name: 'parentId', value: parentId }]) + '', + type: 'GET' + }, ajaxParams)); + }; + })(); // controller volo.cmsKit.admin.pages.pageAdmin diff --git a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Menus/IMenuItemRepository.cs b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Menus/IMenuItemRepository.cs index afee164e06..8fb0e486f6 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Menus/IMenuItemRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Domain/Volo/CmsKit/Menus/IMenuItemRepository.cs @@ -1,8 +1,14 @@ using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; using Volo.Abp.Domain.Repositories; namespace Volo.CmsKit.Menus; public interface IMenuItemRepository : IBasicRepository { + Task> GetOrderedListAsync(bool includeDetails = false, CancellationToken cancellationToken = default); + + Task GetHighestMenuOrderAsync(Guid? parentId = null, CancellationToken cancellationToken = default); } diff --git a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Menus/EfCoreMenuItemRepository.cs b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Menus/EfCoreMenuItemRepository.cs index 81595c9267..03deb7dfc1 100644 --- a/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Menus/EfCoreMenuItemRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.EntityFrameworkCore/Volo/CmsKit/Menus/EfCoreMenuItemRepository.cs @@ -1,4 +1,9 @@ using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.EntityFrameworkCore; using Volo.Abp.Domain.Repositories.EntityFrameworkCore; using Volo.Abp.EntityFrameworkCore; using Volo.CmsKit.EntityFrameworkCore; @@ -10,4 +15,21 @@ public class EfCoreMenuItemRepository : EfCoreRepository dbContextProvider) : base(dbContextProvider) { } + + public virtual async Task GetHighestMenuOrderAsync(Guid? parentId = null, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .WhereIf(parentId.HasValue, x => x.ParentId == parentId) + .OrderByDescending(x => x.Order) + .Select(x => x.Order) + .FirstOrDefaultAsync(GetCancellationToken(cancellationToken)); + } + + public virtual async Task> GetOrderedListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + { + return await (await GetDbSetAsync()) + .OrderBy(x => x.Order) + .ThenBy(x => x.CreationTime) + .ToListAsync(GetCancellationToken(cancellationToken)); + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Menus/MongoMenuItemRepository.cs b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Menus/MongoMenuItemRepository.cs index 259ac9c92a..6525747ea9 100644 --- a/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Menus/MongoMenuItemRepository.cs +++ b/modules/cms-kit/src/Volo.CmsKit.MongoDB/Volo/CmsKit/MongoDB/Menus/MongoMenuItemRepository.cs @@ -1,7 +1,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using MongoDB.Driver; @@ -17,4 +16,25 @@ public class MongoMenuItemRepository : MongoDbRepository dbContextProvider) : base(dbContextProvider) { } + + public virtual async Task GetHighestMenuOrderAsync(Guid? parentId = null, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + + return await (await GetQueryableAsync(cancellationToken)) + .WhereIf(parentId.HasValue, x => x.ParentId == parentId) + .OrderByDescending(x => x.Order) + .Select(x => x.Order) + .FirstOrDefaultAsync(cancellationToken); + } + + public virtual async Task> GetOrderedListAsync(bool includeDetails = false, CancellationToken cancellationToken = default) + { + cancellationToken = GetCancellationToken(cancellationToken); + + return await (await GetQueryableAsync(cancellationToken)) + .OrderBy(x => x.Order) + .ThenBy(x => x.CreationTime) + .ToListAsync(cancellationToken); + } } diff --git a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs index 571ed7749d..81a88ee955 100644 --- a/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs +++ b/modules/cms-kit/src/Volo.CmsKit.Public.Application/Volo/CmsKit/Public/Menus/MenuItemPublicAppService.cs @@ -30,7 +30,7 @@ public class MenuItemPublicAppService : CmsKitPublicAppServiceBase, IMenuItemPub MenuApplicationConsts.MainMenuCacheKey, async () => { - var menuItems = await MenuItemRepository.GetListAsync(); + var menuItems = await MenuItemRepository.GetOrderedListAsync(); if (menuItems == null) {