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

Allow to search by "Name" on the product attribute page (admin area) #7518

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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 @@ -29,11 +29,12 @@ public partial interface IProductAttributeService
/// </summary>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="name">Filter by name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the product attributes
/// </returns>
Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(int pageIndex = 0, int pageSize = int.MaxValue);
Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(int pageIndex = 0, int pageSize = int.MaxValue, string name = "");

/// <summary>
/// Gets a product attribute
Expand Down
15 changes: 7 additions & 8 deletions src/Libraries/Nop.Services/Catalog/ProductAttributeService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -88,21 +88,20 @@ public virtual async Task DeleteProductAttributesAsync(IList<ProductAttribute> p
/// </summary>
/// <param name="pageIndex">Page index</param>
/// <param name="pageSize">Page size</param>
/// <param name="name">Filter by name</param>
/// <returns>
/// A task that represents the asynchronous operation
/// The task result contains the product attributes
/// </returns>
public virtual async Task<IPagedList<ProductAttribute>> GetAllProductAttributesAsync(int pageIndex = 0,
int pageSize = int.MaxValue)
int pageSize = int.MaxValue, string name = "")
{
var productAttributes = await _productAttributeRepository.GetAllPagedAsync(query =>
{
return from pa in query
orderby pa.Name
select pa;
}, pageIndex, pageSize);
var query = _productAttributeRepository.Table;

if (!string.IsNullOrWhiteSpace(name))
query = query.Where(pa => pa.Name.Contains(name));

return productAttributes;
return await query.OrderBy(x => x.Name).ToPagedListAsync(pageIndex, pageSize);
}

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ public override void Up()
//#7398
["Admin.ConfigurationSteps.Product.Details.Text"] = "Enter the relevant product details in these fields. The screenshot below shows how they will be displayed on the product page with the default nopCommerce theme: <div class=\"row row-cols-1\"><img class=\"img-thumbnail mt-3\" src=\"/js/admintour/images/product-page.jpg\"/></div>",
["Admin.ConfigurationSteps.PaymentPayPal.ApiCredentials.Text"] = "If you already have an app created in your PayPal account, follow these steps.",

//#7515
["Admin.Catalog.Attributes.ProductAttributes.List.SearchProductAttributeName"] = "Product attribute name",
["Admin.Catalog.Attributes.ProductAttributes.List.SearchProductAttributeName.Hint"] = "A Product attribute name.",
}, languageId);

#endregion
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1956,6 +1956,12 @@
<LocaleResource Name="Admin.Catalog.Attributes.ProductAttributes.UsedByProducts.Published">
<Value>Published</Value>
</LocaleResource>
<LocaleResource Name="Admin.Catalog.Attributes.ProductAttributes.List.SearchProductAttributeName">
<Value>Product attribute name</Value>
</LocaleResource>
<LocaleResource Name="Admin.Catalog.Attributes.ProductAttributes.List.SearchProductAttributeName">
<Value>A Product attribute name.</Value>
</LocaleResource>
<LocaleResource Name="Admin.Catalog.Attributes.SpecificationAttributes">
<Value>Specification attributes</Value>
</LocaleResource>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public partial class ProductAttributeController : BaseAdminController
protected readonly IProductAttributeModelFactory _productAttributeModelFactory;
protected readonly IProductAttributeService _productAttributeService;

#endregion Fields
#endregion Fields

#region Ctor

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ public virtual async Task<ProductAttributeListModel> PrepareProductAttributeList

//get product attributes
var productAttributes = await _productAttributeService
.GetAllProductAttributesAsync(pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize);
.GetAllProductAttributesAsync(pageIndex: searchModel.Page - 1, pageSize: searchModel.PageSize, name: searchModel.SearchProductAttributeName);

//prepare list model
var model = new ProductAttributeListModel().PrepareToGrid(searchModel, productAttributes, () =>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using Nop.Web.Framework.Models;
using Nop.Web.Framework.Mvc.ModelBinding;

namespace Nop.Web.Areas.Admin.Models.Catalog;

Expand All @@ -7,4 +8,6 @@ namespace Nop.Web.Areas.Admin.Models.Catalog;
/// </summary>
public partial record ProductAttributeSearchModel : BaseSearchModel
{
[NopResourceDisplayName("Admin.Catalog.Attributes.ProductAttributes.List.SearchProductAttributeName")]
public string SearchProductAttributeName { get; set; }
}
203 changes: 124 additions & 79 deletions src/Presentation/Nop.Web/Areas/Admin/Views/ProductAttribute/List.cshtml
Original file line number Diff line number Diff line change
Expand Up @@ -7,96 +7,141 @@
NopHtml.SetActiveMenuItemSystemName("Product attributes");
}


<div class="content-header clearfix">
<h1 class="float-left">
@T("Admin.Catalog.Attributes.ProductAttributes")
</h1>
<div class="float-right">
<a asp-action="Create" class="btn btn-primary">
<i class="fas fa-square-plus"></i>
@T("Admin.Common.AddNew")
</a>
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.ProductAttributeListButtons, additionalData = Model })
<button type="button" id="delete-selected" class="btn btn-danger">
<i class="far fa-trash-can"></i>
@T("Admin.Common.Delete.Selected")
</button>
<nop-action-confirmation asp-button-id="delete-selected" />
@{
const string hideSearchBlockAttributeName = "ProductAttributeListPage.HideSearchBlock";
var hideSearchBlock = await genericAttributeService.GetAttributeAsync<bool>(await workContext.GetCurrentCustomerAsync(), hideSearchBlockAttributeName);
}
<form asp-controller="ProductAttribute" asp-action="List" method="post">
<div class="content-header clearfix">
<h1 class="float-left">
@T("Admin.Catalog.Attributes.ProductAttributes")
</h1>
<div class="float-right">
<a asp-action="Create" class="btn btn-primary">
<i class="fas fa-square-plus"></i>
@T("Admin.Common.AddNew")
</a>
@await Component.InvokeAsync(typeof(AdminWidgetViewComponent), new { widgetZone = AdminWidgetZones.ProductAttributeListButtons, additionalData = Model })
<button type="button" id="delete-selected" class="btn btn-danger">
<i class="far fa-trash-can"></i>
@T("Admin.Common.Delete.Selected")
</button>
<nop-action-confirmation asp-button-id="delete-selected" />
</div>
</div>
</div>

<section class="content">
<div class="container-fluid">
<div class="cards-group">
<div class="card card-default">
<div class="card-body">
<p>
@T("Admin.Catalog.Attributes.ProductAttributes.Description")
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.ProductAttributes", Docs.ProductAttributes + Utm.OnAdmin)" asp-add-wrapper="false"/>
</p>
@await Html.PartialAsync("Table", new DataTablesModel
{
Name = "products-grid",
UrlRead = new DataUrl("List", "ProductAttribute", null),
Length = Model.PageSize,
LengthMenu = Model.AvailablePageSizes,
ColumnCollection = new List<ColumnProperty>
{
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
<section class="content">
<div class="container-fluid">
<div class="form-horizontal">
<div class="cards-group">
<div class="card card-default card-search">
<div class="card-body">
<div class="row search-row @(!hideSearchBlock ? "opened" : "")" data-hideAttribute="@hideSearchBlockAttributeName">
<div class="search-text">@T("Admin.Common.Search")</div>
<div class="icon-search"><i class="fas fa-magnifying-glass" aria-hidden="true"></i></div>
<div class="icon-collapse"><i class="far fa-angle-@(!hideSearchBlock ? "up" : "down")" aria-hidden="true"></i></div>
</div>

<div class="search-body @(hideSearchBlock ? "closed" : "")">
<div class="row">
<div class="col-md-6">
<div class="form-group row">
<div class="col-md-4">
<nop-label asp-for="SearchProductAttributeName" />
</div>
<div class="col-md-8">
<nop-editor asp-for="SearchProductAttributeName" />
</div>
</div>
</div>
</div>
<div class="row">
<div class="text-center col-12">
<button type="button" id="search-productattributes" class="btn btn-primary btn-search">
<i class="fas fa-magnifying-glass"></i>
@T("Admin.Common.Search")
</button>
</div>
</div>
</div>
</div>
</div>

<div class="card card-default">
<div class="card-body">
<p>
@T("Admin.Catalog.Attributes.ProductAttributes.Description")
<nop-doc-reference asp-string-resource="@T("Admin.Documentation.Reference.ProductAttributes", Docs.ProductAttributes + Utm.OnAdmin)" asp-add-wrapper="false" />
</p>
@await Html.PartialAsync("Table", new DataTablesModel
{
Name = "products-grid",
UrlRead = new DataUrl("List", "ProductAttribute", null),
SearchButtonId = "search-productattributes",
Length = Model.PageSize,
LengthMenu = Model.AvailablePageSizes,
Filters = new List<FilterParameter>
{
new FilterParameter(nameof(Model.SearchProductAttributeName))
},
ColumnCollection = new List<ColumnProperty>
{
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
IsMasterCheckBox = true,
Render = new RenderCheckBox("checkbox_productattributes"),
ClassName = NopColumnClassDefaults.CenterAll,
Width = "50"
},
new ColumnProperty(nameof(ProductAttributeModel.Name))
{
},
new ColumnProperty(nameof(ProductAttributeModel.Name))
{
Title = T("Admin.Catalog.Attributes.ProductAttributes.Fields.Name").Text
},
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
},
new ColumnProperty(nameof(ProductAttributeModel.Id))
{
Title = T("Admin.Common.Edit").Text,
Width = "100",
ClassName = NopColumnClassDefaults.Button,
Render = new RenderButtonEdit(new DataUrl("~/Admin/ProductAttribute/Edit"))
}
}
})
}
}
})

<script>
$(function() {
$('#delete-selected-action-confirmation-submit-button').bind('click', function () {
var postData = {
selectedIds: selectedIds
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@(Url.Action("DeleteSelected", "ProductAttribute"))",
data: postData,
error: function (jqXHR, textStatus, errorThrown) {
showAlert('deleteSelectedFailed', errorThrown);
},
complete: function (jqXHR, textStatus) {
if (jqXHR.status === 204)
{
showAlert('nothingSelectedAlert', '@T("Admin.Common.Alert.NothingSelected")');
return;
}
updateTable('#products-grid');
}
});
$('#delete-selected-action-confirmation').modal('toggle');
return false;
});
});
</script>
<nop-alert asp-alert-id="deleteSelectedFailed" />
<nop-alert asp-alert-id="nothingSelectedAlert" />
<script>
$(function() {
$('#delete-selected-action-confirmation-submit-button').bind('click', function () {
var postData = {
selectedIds: selectedIds
};
addAntiForgeryToken(postData);
$.ajax({
cache: false,
type: "POST",
url: "@(Url.Action("DeleteSelected", "ProductAttribute"))",
data: postData,
error: function (jqXHR, textStatus, errorThrown) {
showAlert('deleteSelectedFailed', errorThrown);
},
complete: function (jqXHR, textStatus) {
if (jqXHR.status === 204)
{
showAlert('nothingSelectedAlert', '@T("Admin.Common.Alert.NothingSelected")');
return;
}
updateTable('#products-grid');
}
});
$('#delete-selected-action-confirmation').modal('toggle');
return false;
});
});
</script>
<nop-alert asp-alert-id="deleteSelectedFailed" />
<nop-alert asp-alert-id="nothingSelectedAlert" />
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</section>
</form>