Skip to content

Commit 03217eb

Browse files
committed
Merge remote-tracking branch 'origin/MAGETWO-72867' into 2.3-develop-pr3
2 parents 5b53109 + 40c8106 commit 03217eb

File tree

11 files changed

+579
-15
lines changed

11 files changed

+579
-15
lines changed

app/code/Magento/Ui/Controller/Adminhtml/Index/Render.php

Lines changed: 71 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@
1010
use Magento\Framework\View\Element\UiComponentFactory;
1111
use Magento\Framework\View\Element\UiComponentInterface;
1212
use Magento\Ui\Model\UiComponentTypeResolver;
13+
use Psr\Log\LoggerInterface;
14+
use Magento\Framework\Escaper;
15+
use Magento\Framework\Controller\Result\JsonFactory;
1316

1417
class Render extends AbstractAction
1518
{
@@ -18,39 +21,97 @@ class Render extends AbstractAction
1821
*/
1922
private $contentTypeResolver;
2023

24+
/**
25+
* @var JsonFactory
26+
*/
27+
private $resultJsonFactory;
28+
29+
/**
30+
* @var Escaper
31+
*/
32+
private $escaper;
33+
34+
/**
35+
* @var LoggerInterface
36+
*/
37+
private $logger;
38+
2139
/**
2240
* @param Context $context
2341
* @param UiComponentFactory $factory
2442
* @param UiComponentTypeResolver $contentTypeResolver
43+
* @param JsonFactory|null $resultJsonFactory
44+
* @param Escaper|null $escaper
45+
* @param LoggerInterface|null $logger
2546
*/
2647
public function __construct(
2748
Context $context,
2849
UiComponentFactory $factory,
29-
UiComponentTypeResolver $contentTypeResolver
50+
UiComponentTypeResolver $contentTypeResolver,
51+
JsonFactory $resultJsonFactory = null,
52+
Escaper $escaper = null,
53+
LoggerInterface $logger = null
3054
) {
3155
parent::__construct($context, $factory);
3256
$this->contentTypeResolver = $contentTypeResolver;
57+
$this->resultJsonFactory = $resultJsonFactory ?: \Magento\Framework\App\ObjectManager::getInstance()
58+
->get(\Magento\Framework\Controller\Result\JsonFactory::class);
59+
$this->escaper = $escaper ?: \Magento\Framework\App\ObjectManager::getInstance()
60+
->get(\Magento\Framework\Escaper::class);
61+
$this->logger = $logger ?: \Magento\Framework\App\ObjectManager::getInstance()
62+
->get(\Psr\Log\LoggerInterface::class);
3363
}
3464

3565
/**
36-
* Action for AJAX request
37-
*
38-
* @return void
66+
* @inheritdoc
3967
*/
4068
public function execute()
4169
{
4270
if ($this->_request->getParam('namespace') === null) {
4371
$this->_redirect('admin/noroute');
72+
4473
return;
4574
}
4675

47-
$component = $this->factory->create($this->getRequest()->getParam('namespace'));
48-
if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) {
49-
$this->prepareComponent($component);
50-
$this->getResponse()->appendBody((string) $component->render());
76+
try {
77+
$component = $this->factory->create($this->getRequest()->getParam('namespace'));
78+
if ($this->validateAclResource($component->getContext()->getDataProvider()->getConfigData())) {
79+
$this->prepareComponent($component);
80+
$this->getResponse()->appendBody((string)$component->render());
81+
82+
$contentType = $this->contentTypeResolver->resolve($component->getContext());
83+
$this->getResponse()->setHeader('Content-Type', $contentType, true);
84+
}
85+
} catch (\Magento\Framework\Exception\LocalizedException $e) {
86+
$this->logger->critical($e);
87+
$result = [
88+
'error' => $this->escaper->escapeHtml($e->getMessage()),
89+
'errorcode' => $this->escaper->escapeHtml($e->getCode())
90+
];
91+
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
92+
$resultJson = $this->resultJsonFactory->create();
93+
$resultJson->setStatusHeader(
94+
\Zend\Http\Response::STATUS_CODE_400,
95+
\Zend\Http\AbstractMessage::VERSION_11,
96+
'Bad Request'
97+
);
98+
99+
return $resultJson->setData($result);
100+
} catch (\Exception $e) {
101+
$this->logger->critical($e);
102+
$result = [
103+
'error' => _('UI component could not be rendered because of system exception'),
104+
'errorcode' => $this->escaper->escapeHtml($e->getCode())
105+
];
106+
/** @var \Magento\Framework\Controller\Result\Json $resultJson */
107+
$resultJson = $this->resultJsonFactory->create();
108+
$resultJson->setStatusHeader(
109+
\Zend\Http\Response::STATUS_CODE_400,
110+
\Zend\Http\AbstractMessage::VERSION_11,
111+
'Bad Request'
112+
);
51113

52-
$contentType = $this->contentTypeResolver->resolve($component->getContext());
53-
$this->getResponse()->setHeader('Content-Type', $contentType, true);
114+
return $resultJson->setData($result);
54115
}
55116
}
56117

app/code/Magento/Ui/Test/Unit/Controller/Adminhtml/Index/RenderTest.php

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,11 @@
88
use Magento\Ui\Controller\Adminhtml\Index\Render;
99
use Magento\Ui\Model\UiComponentTypeResolver;
1010
use Magento\Framework\View\Element\UiComponent\ContextInterface;
11+
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager as ObjectManagerHelper;
1112

1213
/**
1314
* @SuppressWarnings(PHPMD.CouplingBetweenObjects)
15+
* @SuppressWarnings(PHPMD.TooManyFields)
1416
*/
1517
class RenderTest extends \PHPUnit\Framework\TestCase
1618
{
@@ -19,6 +21,11 @@ class RenderTest extends \PHPUnit\Framework\TestCase
1921
*/
2022
private $render;
2123

24+
/**
25+
* @var ObjectManagerHelper
26+
*/
27+
private $objectManagerHelper;
28+
2229
/**
2330
* @var \PHPUnit_Framework_MockObject_MockObject
2431
*/
@@ -80,6 +87,16 @@ class RenderTest extends \PHPUnit\Framework\TestCase
8087
*/
8188
private $uiComponentTypeResolverMock;
8289

90+
/**
91+
* @var \Magento\Framework\Controller\Result\JsonFactory|\PHPUnit_Framework_MockObject_MockObject
92+
*/
93+
private $resultJsonFactoryMock;
94+
95+
/**
96+
* @var \Psr\Log\LoggerInterface|\PHPUnit_Framework_MockObject_MockObject
97+
*/
98+
private $loggerMock;
99+
83100
protected function setUp()
84101
{
85102
$this->requestMock = $this->getMockBuilder(\Magento\Framework\App\Request\Http::class)
@@ -121,6 +138,14 @@ protected function setUp()
121138
['render']
122139
);
123140

141+
$this->resultJsonFactoryMock = $this->getMockBuilder(
142+
\Magento\Framework\Controller\Result\JsonFactory::class
143+
)
144+
->disableOriginalConstructor()
145+
->getMock();
146+
147+
$this->loggerMock = $this->getMockForAbstractClass(\Psr\Log\LoggerInterface::class);
148+
124149
$this->contextMock->expects($this->any())
125150
->method('getRequest')
126151
->willReturn($this->requestMock);
@@ -146,7 +171,71 @@ protected function setUp()
146171
->disableOriginalConstructor()
147172
->getMock();
148173

149-
$this->render = new Render($this->contextMock, $this->uiFactoryMock, $this->uiComponentTypeResolverMock);
174+
$this->objectManagerHelper = new ObjectManagerHelper($this);
175+
176+
$this->render = $this->objectManagerHelper->getObject(
177+
\Magento\Ui\Controller\Adminhtml\Index\Render::class,
178+
[
179+
'context' => $this->contextMock,
180+
'factory' => $this->uiFactoryMock,
181+
'contentTypeResolver' => $this->uiComponentTypeResolverMock,
182+
'resultJsonFactory' => $this->resultJsonFactoryMock,
183+
'logger' => $this->loggerMock,
184+
]
185+
);
186+
}
187+
188+
public function testExecuteAjaxRequestException()
189+
{
190+
$name = 'test-name';
191+
$renderedData = '<html>data</html>';
192+
193+
$this->requestMock->expects($this->any())
194+
->method('getParam')
195+
->with('namespace')
196+
->willReturn($name);
197+
$this->requestMock->expects($this->any())
198+
->method('getParams')
199+
->willReturn([]);
200+
$this->responseMock->expects($this->once())
201+
->method('appendBody')
202+
->willThrowException(new \Exception('exception'));
203+
204+
$jsonResultMock = $this->getMockBuilder(\Magento\Framework\Controller\Result\Json::class)
205+
->disableOriginalConstructor()
206+
->setMethods(['setData'])
207+
->getMock();
208+
209+
$this->resultJsonFactoryMock->expects($this->once())
210+
->method('create')
211+
->willReturn($jsonResultMock);
212+
213+
$jsonResultMock->expects($this->once())
214+
->method('setData')
215+
->willReturnSelf();
216+
217+
$this->loggerMock->expects($this->once())
218+
->method('critical')
219+
->willReturnSelf();
220+
221+
$this->dataProviderMock->expects($this->once())
222+
->method('getConfigData')
223+
->willReturn([]);
224+
225+
$this->uiComponentMock->expects($this->once())
226+
->method('render')
227+
->willReturn($renderedData);
228+
$this->uiComponentMock->expects($this->once())
229+
->method('getChildComponents')
230+
->willReturn([]);
231+
$this->uiComponentMock->expects($this->once())
232+
->method('getContext')
233+
->willReturn($this->uiComponentContextMock);
234+
$this->uiFactoryMock->expects($this->once())
235+
->method('create')
236+
->willReturn($this->uiComponentMock);
237+
238+
$this->render->executeAjaxRequest();
150239
}
151240

152241
public function testExecuteAjaxRequest()

app/code/Magento/Ui/view/base/web/js/grid/filters/filters.js

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,10 @@ define([
1010
'underscore',
1111
'mageUtils',
1212
'uiLayout',
13-
'uiCollection'
14-
], function (_, utils, layout, Collection) {
13+
'uiCollection',
14+
'mage/translate',
15+
'jquery'
16+
], function (_, utils, layout, Collection, $t, $) {
1517
'use strict';
1618

1719
/**
@@ -48,6 +50,7 @@ define([
4850
stickyTmpl: 'ui/grid/sticky/filters',
4951
_processed: [],
5052
columnsProvider: 'ns = ${ $.ns }, componentType = columns',
53+
bookmarksProvider: 'ns = ${ $.ns }, componentType = bookmark',
5154
applied: {
5255
placeholder: true
5356
},
@@ -102,7 +105,9 @@ define([
102105
applied: '${ $.provider }:params.filters'
103106
},
104107
imports: {
105-
'onColumnsUpdate': '${ $.columnsProvider }:elems'
108+
onColumnsUpdate: '${ $.columnsProvider }:elems',
109+
onBackendError: '${ $.provider }:lastError',
110+
bookmarksActiveIndex: '${ $.bookmarksProvider }:activeIndex'
106111
},
107112
modules: {
108113
columns: '${ $.columnsProvider }',
@@ -371,6 +376,37 @@ define([
371376
*/
372377
onColumnsUpdate: function (columns) {
373378
columns.forEach(this.addFilter, this);
379+
},
380+
381+
/**
382+
* Provider ajax error listener.
383+
*
384+
* @param {bool} isError - Selected index of the filter.
385+
*/
386+
onBackendError: function (isError) {
387+
var defaultMessage = 'Something went wrong with processing the default view and we have restored the ' +
388+
'filter to its original state.',
389+
customMessage = 'Something went wrong with processing current custom view and filters have been ' +
390+
'reset to its original state. Please edit filters then click apply.';
391+
392+
if (isError) {
393+
this.clear();
394+
395+
$('body').notification('clear')
396+
.notification('add', {
397+
error: true,
398+
message: $.mage.__(this.bookmarksActiveIndex !== 'default' ? customMessage : defaultMessage),
399+
400+
/**
401+
* @param {String} message
402+
*/
403+
insertMethod: function (message) {
404+
var $wrapper = $('<div/>').html(message);
405+
406+
$('.page-main-actions').after($wrapper);
407+
}
408+
});
409+
}
374410
}
375411
});
376412
});

app/code/Magento/Ui/view/base/web/js/grid/provider.js

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ define([
2121
return Element.extend({
2222
defaults: {
2323
firstLoad: true,
24+
lastError: false,
2425
storageConfig: {
2526
component: 'Magento_Ui/js/grid/data-storage',
2627
provider: '${ $.storageConfig.name }',
@@ -120,7 +121,7 @@ define([
120121

121122
request
122123
.done(this.onReload)
123-
.fail(this.onError);
124+
.fail(this.onError.bind(this));
124125

125126
return request;
126127
},
@@ -144,6 +145,10 @@ define([
144145
return;
145146
}
146147

148+
this.set('lastError', true);
149+
150+
this.firstLoad = false;
151+
147152
alert({
148153
content: $t('Something went wrong.')
149154
});
@@ -157,6 +162,8 @@ define([
157162
onReload: function (data) {
158163
this.firstLoad = false;
159164

165+
this.set('lastError', false);
166+
160167
this.setData(data)
161168
.trigger('reloaded');
162169
},

dev/tests/functional/tests/app/Magento/Backend/Test/Block/System/Store/StoreGrid.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,18 @@ public function searchAndOpenWebsite(Website $website)
9999
$this->_rootElement->find(sprintf($this->storeName, $websiteName), Locator::SELECTOR_XPATH)->click();
100100
}
101101

102+
/**
103+
* Search and open appropriate Website by name.
104+
*
105+
* @param string $websiteName
106+
* @return void
107+
*/
108+
public function searchAndOpenWebsiteByName($websiteName)
109+
{
110+
$this->search(['website_title' => $websiteName]);
111+
$this->_rootElement->find(sprintf($this->storeName, $websiteName), Locator::SELECTOR_XPATH)->click();
112+
}
113+
102114
/**
103115
* Search and open appropriate Store View.
104116
*

dev/tests/functional/tests/app/Magento/Catalog/Test/Block/Adminhtml/Product/Grid.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ class Grid extends DataGrid
6060
'selector' => '[name="attribute_set_id"]',
6161
'input' => 'select',
6262
],
63+
'store_id' => [
64+
'selector' => '[name="store_id"]',
65+
'input' => 'select',
66+
],
6367
];
6468

6569
/**

0 commit comments

Comments
 (0)