diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Controllers/AdminController.cs b/src/OrchardCore.Modules/OrchardCore.Placements/Controllers/AdminController.cs index dcb45757e25..e49253ae455 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Controllers/AdminController.cs +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Controllers/AdminController.cs @@ -5,14 +5,20 @@ using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc.Localization; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Routing; using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; using Newtonsoft.Json; using Newtonsoft.Json.Linq; +using OrchardCore.DisplayManagement; using OrchardCore.DisplayManagement.Descriptors.ShapePlacementStrategy; using OrchardCore.DisplayManagement.Notify; +using OrchardCore.Navigation; using OrchardCore.Placements.Services; using OrchardCore.Placements.ViewModels; +using OrchardCore.Routing; +using OrchardCore.Settings; namespace OrchardCore.Placements.Controllers { @@ -24,6 +30,8 @@ public class AdminController : Controller private readonly IHtmlLocalizer H; private readonly IStringLocalizer S; private readonly INotifier _notifier; + private readonly ISiteService _siteService; + private readonly dynamic New; public AdminController( ILogger logger, @@ -31,32 +39,71 @@ public AdminController( PlacementsManager placementsManager, IHtmlLocalizer htmlLocalizer, IStringLocalizer stringLocalizer, - INotifier notifier) + INotifier notifier, + ISiteService siteService, + IShapeFactory shapeFactory) { _logger = logger; _authorizationService = authorizationService; _placementsManager = placementsManager; _notifier = notifier; + _siteService = siteService; + New = shapeFactory; H = htmlLocalizer; S = stringLocalizer; } - public async Task Index() + public async Task Index(ContentOptions options, PagerParameters pagerParameters) { if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements)) { return Forbid(); } + var siteSettings = await _siteService.GetSiteSettingsAsync(); + var pager = new Pager(pagerParameters, siteSettings.PageSize); + var shapeTypes = await _placementsManager.ListShapePlacementsAsync(); - return View(new ListShapePlacementsViewModel + var shapeList = shapeTypes.Select(entry => new ShapePlacementViewModel { - ShapePlacements = shapeTypes.Select(entry => new ShapePlacementViewModel - { - ShapeType = entry.Key - }) + ShapeType = entry.Key + }).ToList(); + + if (!string.IsNullOrWhiteSpace(options.Search)) + { + shapeList = shapeList.Where(x => x.ShapeType.Contains(options.Search, StringComparison.OrdinalIgnoreCase)).ToList(); + } + + var count = shapeList.Count(); + + shapeList = shapeList.OrderBy(x => x.ShapeType) + .Skip(pager.GetStartIndex()) + .Take(pager.PageSize).ToList(); + + var pagerShape = (await New.Pager(pager)).TotalItemCount(count); + + var model = new ListShapePlacementsViewModel + { + ShapePlacements = shapeList, + Pager = pagerShape, + Options = options, + }; + + model.Options.ContentsBulkAction = new List() { + new SelectListItem() { Text = S["Delete"], Value = nameof(ContentsBulkAction.Remove) } + }; + + return View("Index", model); + } + + [HttpPost, ActionName("Index")] + [FormValueRequired("submit.Filter")] + public ActionResult IndexFilterPOST(ListShapePlacementsViewModel model) + { + return RedirectToAction("Index", new RouteValueDictionary { + { "Options.Search", model.Options.Search } }); } @@ -196,6 +243,36 @@ public async Task Delete(string shapeType, string returnUrl = nul return RedirectToReturnUrlOrIndex(returnUrl); } + [HttpPost, ActionName("Index")] + [FormValueRequired("submit.BulkAction")] + public async Task IndexPost(ViewModels.ContentOptions options, IEnumerable itemIds) + { + if (!await _authorizationService.AuthorizeAsync(User, Permissions.ManagePlacements)) + { + return Forbid(); + } + + if (itemIds?.Count() > 0) + { + switch (options.BulkAction) + { + case ContentsBulkAction.None: + break; + case ContentsBulkAction.Remove: + foreach (var item in itemIds) + { + await _placementsManager.RemoveShapePlacementsAsync(item); + } + _notifier.Success(H["Placements successfully removed."]); + break; + default: + throw new ArgumentOutOfRangeException(); + } + } + + return RedirectToAction("Index"); + } + private IActionResult RedirectToReturnUrlOrIndex(string returnUrl) { if ((String.IsNullOrEmpty(returnUrl) == false) && (Url.IsLocalUrl(returnUrl))) @@ -232,6 +309,7 @@ private static bool IsEmpty(PlacementNode node) && (node.Wrappers == null || node.Wrappers.Length == 0); } + private static bool FilterEquals(JToken token, string value) { if (token is JArray) diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartDefinitionDriver.cs b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartDefinitionDriver.cs index ca8f044e0a4..f75624e1bf9 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartDefinitionDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartDefinitionDriver.cs @@ -44,6 +44,14 @@ public override IDisplayResult Edit(ContentPartDefinition contentPartDefinition) DisplayType = "Summary", Description = S["Placement for a {0} part in summary views", displayName] }); + + model.ContentSettingsEntries.Add( + new ContentSettingsEntry + { + ShapeType = $"{contentPartDefinition.Name}_Edit", + Description = S["Placement in admin editor for a {0} part", displayName] + }); + }).Location("Shortcuts"); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartFieldDefinitionDisplayDriver.cs b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartFieldDefinitionDisplayDriver.cs index 89e2932d10a..169dff85c0c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartFieldDefinitionDisplayDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentPartFieldDefinitionDisplayDriver.cs @@ -49,6 +49,15 @@ public override IDisplayResult Edit(ContentPartFieldDefinition contentPartFieldD DisplayType = "Summary", Description = S["Placement for the {0} field in a {1} in summary views", displayName, partName] }); + + model.ContentSettingsEntries.Add( + new ContentSettingsEntry + { + ShapeType = $"{shapeType}_Edit", + Differentiator = differentiator, + Description = S["Placement in admin editor for the {0} field in a {1}", displayName, partName] + }); + }).Location("Shortcuts"); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentTypePartDefinitionDriver.cs b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentTypePartDefinitionDriver.cs index 214350d9a47..276452b3fdb 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentTypePartDefinitionDriver.cs +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Settings/PlacementContentTypePartDefinitionDriver.cs @@ -48,6 +48,15 @@ public override IDisplayResult Edit(ContentTypePartDefinition contentTypePartDef DisplayType = "Summary", Description = S["Placement for the {0} part in a {1} type in summary views", partName, displayName] }); + + model.ContentSettingsEntries.Add( + new ContentSettingsEntry + { + ShapeType = $"{partName}_Edit", + ContentType = contentType, + Description = S["Placement in admin editor for the {0} part in a {1} type", partName, displayName] + }); + }).Location("Shortcuts"); } } diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/ViewModels/ListShapePlacementsViewModel.cs b/src/OrchardCore.Modules/OrchardCore.Placements/ViewModels/ListShapePlacementsViewModel.cs index fab8c08d747..aa3709a78a3 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/ViewModels/ListShapePlacementsViewModel.cs +++ b/src/OrchardCore.Modules/OrchardCore.Placements/ViewModels/ListShapePlacementsViewModel.cs @@ -1,9 +1,32 @@ using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc.ModelBinding; +using Microsoft.AspNetCore.Mvc.Rendering; namespace OrchardCore.Placements.ViewModels { public class ListShapePlacementsViewModel { - public IEnumerable ShapePlacements { get; set; } + public IList ShapePlacements { get; set; } + public dynamic Pager { get; set; } + public ContentOptions Options { get; set; } = new ContentOptions(); + } + + public class ContentOptions + { + public string Search { get; set; } + public ContentsBulkAction BulkAction { get; set; } + + #region Lists to populate + + [BindNever] + public List ContentsBulkAction { get; set; } + + #endregion Lists to populate + } + + public enum ContentsBulkAction + { + None, + Remove } } diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Edit.cshtml b/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Edit.cshtml index 8bdf90f8822..f467e0105ea 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Edit.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Edit.cshtml @@ -46,10 +46,7 @@ @T["Delete"] } - @if (Url.IsLocalUrl(returnUrl)) - { - @T["Cancel"] - } + @T["Cancel"] diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Index.cshtml b/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Index.cshtml index e2b01c0ff1e..3a50bcaaf14 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Index.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Views/Admin/Index.cshtml @@ -1,72 +1,142 @@ @model ListShapePlacementsViewModel + +@{ + int startIndex = (Model.Pager.Page - 1) * (Model.Pager.Page) + 1; + int endIndex = startIndex + Model.ShapePlacements.Count - 1; +}

@RenderTitleSegments(T["Placements"])

-
-
- -
    - @foreach (var shapeType in Model.ShapePlacements) - { -
  • - @Html.DisplayFor(m => shapeType) +
      +
    • +
      +
      +
      + + + + +
      +
      + +
    • - } -
    - + @if (Model.ShapePlacements.Any()) + { + @foreach (var entry in Model.ShapePlacements) + { +
  • +
    + + +
    + +
  • + } + } + else + { +
  • + +
  • + } +
+ - diff --git a/src/OrchardCore.Modules/OrchardCore.Placements/Views/_ViewImports.cshtml b/src/OrchardCore.Modules/OrchardCore.Placements/Views/_ViewImports.cshtml index 1553256c8ef..16f5bb9730c 100644 --- a/src/OrchardCore.Modules/OrchardCore.Placements/Views/_ViewImports.cshtml +++ b/src/OrchardCore.Modules/OrchardCore.Placements/Views/_ViewImports.cshtml @@ -7,4 +7,6 @@ @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @addTagHelper *, OrchardCore.DisplayManagement @addTagHelper *, OrchardCore.ResourceManagement +@using Microsoft.Extensions.Localization +@using Microsoft.AspNetCore.Mvc.Localization @using OrchardCore.Placements.ViewModels