Skip to content

Implemented UrlFilterApplier component #28932

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

Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="AdminProductGridUrlFilterApplierTest">
<annotations>
<features value="Catalog"/>
<stories value="Filter product using GET URL parameter"/>
<title value="Verify that filter is applied on product grid when filters parameter is set on url"/>
<description value="Accessing product grid url with filters parameter"/>
<severity value="MAJOR"/>
<testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4931106"/>
<group value="product"/>
</annotations>
<before>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
<createData entity="simpleProductWithShortNameAndSku" stepKey="createSimpleProduct"/>
</before>
<after>
<actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearGridFilter"/>
<deleteData createDataKey="createSimpleProduct" stepKey="deleteProduct"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/>
</after>
<amOnPage url="{{AdminProductIndexPage.url}}?filters[name]=$$createSimpleProduct.name$$" stepKey="navigateToProductGridWithFilters"/>
<waitForPageLoad stepKey="waitForProductGrid"/>
<see selector="{{AdminProductGridSection.productGridNameProduct($$createSimpleProduct.name$$)}}" userInput="$$createSimpleProduct.name$$" stepKey="seeProduct"/>
<seeElement selector="{{AdminProductGridFilterSection.enabledFilters}}" stepKey="seeEnabledFilters"/>
<see selector="{{AdminProductGridFilterSection.enabledFilters}}" userInput="Name: $$createSimpleProduct.name$$" stepKey="seeProductNameFilter"/>
</test>
</tests>
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
<referenceContainer name="content">
<uiComponent name="product_listing"/>
<block class="Magento\Catalog\Block\Adminhtml\Product" name="products_list"/>
<block class="Magento\Backend\Block\Template" template="Magento_Catalog::product/grid/url_filter_applier.phtml" name="product_list_url_filter_applier" />
</referenceContainer>
</body>
</page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

/** @var $block \Magento\Backend\Block\Template */
?>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/grid/url-filter-applier": {
"listingNamespace": "product_listing"
}
}
}
</script>
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
<element name="idColumn" type="button" selector="//div[contains(@data-role, 'grid-wrapper')]/table/thead/tr/th/span[contains(text(), 'ID')]"/>
<element name="clearAll" type="button" selector="//div[@class='admin__data-grid-header']//button[contains(text(), 'Clear all')]"/>
<element name="activeFilters" type="button" selector="//div[@class='admin__data-grid-header']//span[contains(text(), 'Active filters:')]" />
<element name="activeFilterDiv" type="button" selector="(//div[contains(@class, 'admin__data-grid-filters-current') and contains(@class, '_show')])[1]"/>
<element name="FilterBtn" type="input" selector="//button[text()='Filters']"/>
<element name="URLKey" type="input" selector="//div[@class='admin__form-field-control']/input[@name='identifier']"/>
<element name="ApplyFiltersBtn" type="button" selector="//span[text()='Apply Filters']"/>
<element name="blockGridRowByTitle" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true" timeout="30"/>
</section>
</sections>
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
<element name="edit" type="button" selector="//div[text()='{{var1}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='Edit']" parameterized="true"/>
<element name="preview" type="button" selector="//div[text()='{{var1}}']/parent::td//following-sibling::td[@class='data-grid-actions-cell']//a[text()='View']" parameterized="true"/>
<element name="clearAllButton" type="button" selector="//div[@class='admin__data-grid-header']//button[contains(text(), 'Clear all')]"/>
<element name="clearFilters" type="button" selector=".admin__data-grid-header button[data-action='grid-filter-reset']" timeout="30"/>
<element name="activeFilters" type="button" selector="//div[@class='admin__data-grid-header']//span[contains(text(), 'Active filters:')]" />
<element name="spinner" type="input" selector='//div[@data-component="cms_page_listing.cms_page_listing.cms_page_columns"]'/>
<element name="firstItemSelectButton" type="button" selector=".data-grid .action-select-wrap button.action-select"/>
Expand All @@ -31,5 +32,6 @@
<element name="massActionsButton" type="button" selector="//div[@class='admin__data-grid-header'][(not(ancestor::*[@class='sticky-header']) and not(contains(@style,'visibility: hidden'))) or (ancestor::*[@class='sticky-header' and not(contains(@style,'display: none'))])]//button[contains(@class, 'action-select')]" />
<element name="massActionsOption" type="button" selector="//div[@class='admin__data-grid-header'][(not(ancestor::*[@class='sticky-header']) and not(contains(@style,'visibility: hidden'))) or (ancestor::*[@class='sticky-header' and not(contains(@style,'display: none'))])]//span[contains(@class, 'action-menu-item') and .= '{{action}}']" parameterized="true"/>
<element name="gridDataRow" type="input" selector=".data-row .data-grid-cell-content"/>
<element name="pagesGridRowByTitle" type="input" selector="//tbody//tr//td//div[contains(., '{{var1}}')]" parameterized="true" timeout="30"/>
</section>
</sections>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="AdminCmsBlockGridUrlFilterApplierTest">
<annotations>
<features value="Cms"/>
<stories value="Filter CMS block using GET URL parameter"/>
<title value="Verify that filter is applied on block grid when filters parameter is set on url"/>
<description value="Accessing block grid url with filters parameter"/>
<severity value="MAJOR"/>
<testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4931106"/>
<group value="Cms"/>
</annotations>
<before>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
<createData entity="Sales25offBlock" stepKey="createBlock"/>
</before>
<after>
<actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearGridFilter"/>
<deleteData createDataKey="createBlock" stepKey="deletePage"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/>
</after>
<amOnPage url="{{CmsBlocksPage.url}}?filters[title]=$$createBlock.title$$" stepKey="navigateToBlockGridWithFilters"/>
<waitForPageLoad stepKey="waitForBlockGrid"/>
<see selector="{{BlockPageActionsSection.blockGridRowByTitle($$createBlock.title$$)}}" userInput="$$createBlock.title$$" stepKey="seeBlock"/>
<seeElement selector="{{BlockPageActionsSection.activeFilterDiv}}" stepKey="seeEnabledFilters"/>
<see selector="{{BlockPageActionsSection.activeFilterDiv}}" userInput="Title: $$createBlock.title$$" stepKey="seeBlockTitleFilter"/>
</test>
</tests>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/
-->

<tests xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="urn:magento:mftf:Test/etc/testSchema.xsd">
<test name="AdminCmsPageGridUrlFilterApplierTest">
<annotations>
<features value="CmsPage"/>
<stories value="Filter CMS page using GET URL parameter"/>
<title value="Verify that filter is applied on page grid when filters parameter is set on url"/>
<description value="Accessing page grid url with filters parameter"/>
<severity value="MAJOR"/>
<testCaseId value="https://studio.cucumber.io/projects/131313/test-plan/folders/1320712/scenarios/4931106"/>
<group value="Cms"/>
</annotations>
<before>
<actionGroup ref="AdminLoginActionGroup" stepKey="loginAsAdmin"/>
<createData entity="_defaultCmsPage" stepKey="createPage"/>
</before>
<after>
<actionGroup ref="ClearFiltersAdminDataGridActionGroup" stepKey="clearGridFilter"/>
<deleteData createDataKey="createPage" stepKey="deletePage"/>
<actionGroup ref="AdminLogoutActionGroup" stepKey="logoutOfAdmin"/>
</after>
<amOnPage url="{{CmsPagesPage.url}}?filters[title]=$$createPage.title$$" stepKey="navigateToPageGridWithFilters"/>
<waitForPageLoad stepKey="waitForPageGrid"/>
<see selector="{{CmsPagesPageActionsSection.pagesGridRowByTitle($$createPage.title$$)}}" userInput="$$createPage.title$$" stepKey="seePage"/>
<seeElement selector="{{CmsPagesPageActionsSection.activeFilter}}" stepKey="seeEnabledFilters"/>
<see selector="{{CmsPagesPageActionsSection.activeFilter}}" userInput="Title: $$createPage.title$$" stepKey="seePageTitleFilter"/>
</test>
</tests>
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@
<body>
<referenceContainer name="content">
<uiComponent name="cms_block_listing"/>
<block class="Magento\Backend\Block\Template" template="Magento_Cms::url_filter_applier.phtml" name="block_list_url_filter_applier">
<arguments>
<argument name="listing_namespace" xsi:type="string">cms_block_listing</argument>
</arguments>
</block>
</referenceContainer>
<referenceContainer name="admin.scope.col.wrap" htmlClass="admin__old" /> <!-- ToDo UI: remove this wrapper with old styles removal. The class name "admin__old" is for tests only, we shouldn't use it in any way -->
</body>
Expand Down
5 changes: 5 additions & 0 deletions app/code/Magento/Cms/view/adminhtml/layout/cms_page_index.xml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
<body>
<referenceContainer name="content">
<uiComponent name="cms_page_listing"/>
<block class="Magento\Backend\Block\Template" template="Magento_Cms::url_filter_applier.phtml" name="page_list_url_filter_applier">
<arguments>
<argument name="listing_namespace" xsi:type="string">cms_page_listing</argument>
</arguments>
</block>
</referenceContainer>
</body>
</page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

/** @var $block \Magento\Backend\Block\Template */
/** @var \Magento\Framework\Escaper $escaper */
?>
<script type="text/x-magento-init">
{
"*": {
"Magento_Ui/js/grid/url-filter-applier": {
"listingNamespace": "<?= $escaper->escapeJs($block->getListingNamespace()) ?>"
}
}
}
</script>
80 changes: 80 additions & 0 deletions app/code/Magento/Ui/view/base/web/js/grid/url-filter-applier.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

define([
'uiComponent',
'underscore'
], function (Component, _) {
'use strict';

return Component.extend({
defaults: {
listingNamespace: null,
filterProvider: 'componentType = filters, ns = ${ $.listingNamespace }',
filterKey: 'filters',
searchString: location.search,
modules: {
filterComponent: '${ $.filterProvider }'
}
},

/**
* Init component
*
* @return {exports}
*/
initialize: function () {
this._super();
this.apply();

return this;
},

/**
* Apply filter
*/
apply: function () {
var urlFilter = this.getFilterParam(this.searchString);

if (_.isUndefined(this.filterComponent())) {
setTimeout(function () {
this.apply();
}.bind(this), 100);

return;
}

if (Object.keys(urlFilter).length) {
this.filterComponent().setData(urlFilter, false);
this.filterComponent().apply();
}
},

/**
* Get filter param from url
*
* @returns {Object}
*/
getFilterParam: function (url) {
var searchString = decodeURI(url),
itemArray;

return _.chain(searchString.slice(1).split('&'))
.map(function (item) {
if (item && item.search(this.filterKey) !== -1) {
itemArray = item.split('=');

itemArray[0] = itemArray[0].replace(this.filterKey, '')
.replace(/[\[\]]/g, '');

return itemArray;
}
}.bind(this))
.compact()
.object()
.value();
}
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/**
* Copyright © Magento, Inc. All rights reserved.
* See COPYING.txt for license details.
*/

/*eslint max-nested-callbacks: 0*/
define([
'Magento_Ui/js/grid/url-filter-applier'
], function (UrlFilterApplier) {
'use strict';

describe('Magento_Ui/js/grid/url-filter-applier', function () {
var urlFilterApplierObj,
filterComponentMock = {
setData: jasmine.createSpy(),
apply: jasmine.createSpy()
};

beforeEach(function () {
urlFilterApplierObj = new UrlFilterApplier({});
urlFilterApplierObj.filterComponent = jasmine.createSpy().and.returnValue(filterComponentMock);
});

describe('"getFilterParam" method', function () {
it('return object from url with a simple filters parameter', function () {
var urlSearch = '?filters[name]=test';

expect(urlFilterApplierObj.getFilterParam(urlSearch)).toEqual({
'name': 'test'
});
});
it('return object from url with multiple filters parameter', function () {
var urlSearch = '?filters[name]=test&filters[qty]=1';

expect(urlFilterApplierObj.getFilterParam(urlSearch)).toEqual({
'name': 'test',
'qty': '1'
});
});
it('return object from url with multiple filters parameter and another parameter', function () {
var urlSearch = '?filters[name]=test&filters[qty]=1&anotherparam=1';

expect(urlFilterApplierObj.getFilterParam(urlSearch)).toEqual({
'name': 'test',
'qty': '1'
});
});
it('return object from url with another parameter', function () {
var urlSearch = '?anotherparam=1';

expect(urlFilterApplierObj.getFilterParam(urlSearch)).toEqual({});
});
});

describe('"apply" method', function () {
it('applies url filter on filter component', function () {
urlFilterApplierObj.searchString = '?filters[name]=test&filters[qty]=1';
urlFilterApplierObj.apply();
expect(urlFilterApplierObj.filterComponent().setData).toHaveBeenCalledWith({
'name': 'test',
'qty': '1'
}, false);
expect(urlFilterApplierObj.filterComponent().apply).toHaveBeenCalled();
});
});
});
});