Skip to content

Commit f3abd4a

Browse files
committed
Merge branch 'ACP2E-3504' of https://github.com/adobe-commerce-tier-4/magento2ce into PR-03-17-2025
2 parents 087ccf3 + 7fc65c0 commit f3abd4a

File tree

6 files changed

+232
-10
lines changed

6 files changed

+232
-10
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ConfigurableProduct\Test\Unit\ViewModel;
9+
10+
use Magento\ConfigurableProduct\ViewModel\UploadResizeConfigValue;
11+
use Magento\Backend\Model\Image\UploadResizeConfigInterface;
12+
use PHPUnit\Framework\MockObject\MockObject;
13+
use PHPUnit\Framework\TestCase;
14+
15+
class UploadResizeConfigValueTest extends TestCase
16+
{
17+
/**
18+
* @var UploadResizeConfigInterface|MockObject
19+
*/
20+
private $uploadResizeConfigMock;
21+
22+
/**
23+
* @var UploadResizeConfigValue
24+
*/
25+
private $viewModel;
26+
27+
protected function setUp(): void
28+
{
29+
$this->uploadResizeConfigMock = $this->createMock(UploadResizeConfigInterface::class);
30+
$this->viewModel = new UploadResizeConfigValue($this->uploadResizeConfigMock);
31+
}
32+
33+
public function testGetMaxWidth()
34+
{
35+
$this->uploadResizeConfigMock->method('getMaxWidth')->willReturn(100);
36+
$this->assertEquals(100, $this->viewModel->getMaxWidth());
37+
}
38+
39+
public function testGetMaxHeight()
40+
{
41+
$this->uploadResizeConfigMock->method('getMaxHeight')->willReturn(200);
42+
$this->assertEquals(200, $this->viewModel->getMaxHeight());
43+
}
44+
45+
public function testIsResizeEnabled()
46+
{
47+
$this->uploadResizeConfigMock->method('isResizeEnabled')->willReturn(true);
48+
$this->assertTrue($this->viewModel->isResizeEnabled());
49+
}
50+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\ConfigurableProduct\ViewModel;
9+
10+
use Magento\Backend\Model\Image\UploadResizeConfigInterface;
11+
use Magento\Framework\View\Element\Block\ArgumentInterface;
12+
13+
/**
14+
* Get configuration values for frontend image uploader.
15+
*/
16+
class UploadResizeConfigValue implements ArgumentInterface
17+
{
18+
/**
19+
* @var UploadResizeConfigInterface
20+
*/
21+
private UploadResizeConfigInterface $uploadResizeConfig;
22+
23+
/**
24+
* @param UploadResizeConfigInterface $uploadResizeConfig
25+
*/
26+
public function __construct(
27+
UploadResizeConfigInterface $uploadResizeConfig
28+
) {
29+
$this->uploadResizeConfig = $uploadResizeConfig;
30+
}
31+
32+
/**
33+
* Get maximal width value for resized image
34+
*
35+
* @return int
36+
*/
37+
public function getMaxWidth(): int
38+
{
39+
return $this->uploadResizeConfig->getMaxWidth();
40+
}
41+
42+
/**
43+
* Get maximal height value for resized image
44+
*
45+
* @return int
46+
*/
47+
public function getMaxHeight(): int
48+
{
49+
return $this->uploadResizeConfig->getMaxHeight();
50+
}
51+
52+
/**
53+
* Get config value for frontend resize
54+
*
55+
* @return bool
56+
*/
57+
public function isResizeEnabled(): bool
58+
{
59+
return $this->uploadResizeConfig->isResizeEnabled();
60+
}
61+
}

app/code/Magento/ConfigurableProduct/view/adminhtml/layout/catalog_product_wizard.xml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
<?xml version="1.0"?>
22
<!--
33
/**
4-
* Copyright © Magento, Inc. All rights reserved.
5-
* See COPYING.txt for license details.
4+
* Copyright 2016 Adobe
5+
* All Rights Reserved.
66
*/
77
-->
88
<layout xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:View/Layout/etc/page_layout.xsd">
@@ -58,6 +58,7 @@
5858
<item name="modal" xsi:type="string">configurableModal</item>
5959
<item name="dataScope" xsi:type="string">productFormConfigurable</item>
6060
</argument>
61+
<argument name="view_model" xsi:type="object">Magento\ConfigurableProduct\ViewModel\UploadResizeConfigValue</argument>
6162
</arguments>
6263
</block>
6364
<block class="Magento\ConfigurableProduct\Block\Adminhtml\Product\Steps\Summary" name="step4" template="Magento_ConfigurableProduct::catalog/product/edit/attribute/steps/summary.phtml">

app/code/Magento/ConfigurableProduct/view/adminhtml/templates/catalog/product/edit/attribute/steps/bulk.phtml

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
11
<?php
22
/**
3-
* Copyright © Magento, Inc. All rights reserved.
4-
* See COPYING.txt for license details.
3+
* Copyright 2015 Adobe
4+
* All Rights Reserved.
55
*/
66

77
// phpcs:disable PHPCompatibility.Miscellaneous.RemovedAlternativePHPTags.MaybeASPOpenTagFound
88
/* @var $block \Magento\ConfigurableProduct\Block\Adminhtml\Product\Steps\Bulk */
99
/** @var \Magento\Framework\View\Helper\SecureHtmlRenderer $secureRenderer */
10+
/** @var $viewModel uploadResizeConfigValue */
1011
/** @var \Magento\Framework\Escaper $escaper */
11-
?>
1212

13+
use Magento\ConfigurableProduct\ViewModel\uploadResizeConfigValue;
14+
15+
$viewModel = $block->getViewModel();
16+
?>
1317
<?php
1418
/** @var \Magento\Framework\Json\Helper\Data $jsonHelper */
1519
$jsonHelper = $block->getData('jsonHelper');
@@ -767,7 +771,11 @@ $uploadUrl = $block->getUrl('catalog/product_gallery/upload');
767771
"component": "Magento_ConfigurableProduct/js/variations/steps/bulk",
768772
"appendTo": "<?= /* @noEscape */ $block->getParentComponentName() ?>",
769773
"noImage": "<?= /* @noEscape */ $block->getNoImageUrl() ?>",
770-
"variationsComponent": "<?= /* @noEscape */ $block->getData('config/form')?>.configurableVariations"
774+
"variationsComponent": "<?= /* @noEscape */ $block->getData('config/form')
775+
?>.configurableVariations",
776+
"isResizeEnabled": <?= /* @noEscape */ $viewModel->isResizeEnabled() ?>,
777+
"maxWidth": <?= /* @noEscape */ $viewModel->getMaxWidth() ?>,
778+
"maxHeight": <?= /* @noEscape */ $viewModel->getMaxHeight() ?>
771779
}
772780
}
773781
}

app/code/Magento/ConfigurableProduct/view/adminhtml/web/js/variations/steps/bulk.js

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/**
2-
* Copyright © Magento, Inc. All rights reserved.
3-
* See COPYING.txt for license details.
2+
* Copyright 2015 Adobe
3+
* All Rights Reserved.
44
*/
55

66
/* eslint-disable no-undef */
@@ -35,6 +35,9 @@ define([
3535
notificationMessage: {
3636
text: null,
3737
error: null
38+
},
39+
options: {
40+
isResizeEnabled: ''
3841
}
3942
},
4043

@@ -46,7 +49,7 @@ define([
4649
},
4750

4851
/** @inheritdoc */
49-
initialize: function () {
52+
initialize: function (config) {
5053
var self = this;
5154

5255
this._super();
@@ -72,6 +75,13 @@ define([
7275
}
7376
});
7477

78+
// Retrieve configuration passed from .phtml
79+
if (config) {
80+
this.options.isResizeEnabled = config.isResizeEnabled;
81+
this.options.maxWidth = config.maxWidth;
82+
this.options.maxHeight = config.maxHeight;
83+
}
84+
7585
this.variationsComponent(function (variationsComponent) {
7686
this.sections().price.currencySymbol = variationsComponent.getCurrencySymbol();
7787
}.bind(this));
@@ -166,6 +176,7 @@ define([
166176

167177
this.initCountVariations();
168178
this.bindGalleries();
179+
this.bindGalleries = this.bindGalleries.bind(this);
169180
},
170181

171182
/**
@@ -368,6 +379,8 @@ define([
368379
* Bind galleries.
369380
*/
370381
bindGalleries: function () {
382+
var self = this; // Save the correct context of 'this'
383+
371384
$('[data-role=bulk-step] [data-role=gallery]').each(function (index, element) {
372385
var gallery = $(element),
373386
uploadInput = $(gallery.find('.uploader'))[0],
@@ -385,6 +398,8 @@ define([
385398
let targetElement = uploadInput,
386399
fileId = null,
387400
arrayFromObj = Array.from,
401+
allowedExt = ['jpeg', 'jpg', 'png', 'gif'],
402+
allowedResize = false,
388403
options = {
389404
proudlyDisplayPoweredByUppy: false,
390405
target: targetElement,
@@ -425,6 +440,8 @@ define([
425440
id: fileId
426441
}
427442
});
443+
// check if file is allowed to upload and resize
444+
allowedResize = $.inArray(currentFile.extension?.toLowerCase(), allowedExt) !== -1;
428445

429446
// code to allow duplicate files from same folder
430447
const modifiedFile = {
@@ -444,6 +461,21 @@ define([
444461

445462
// initialize Uppy upload
446463
uppy.use(Uppy.Dashboard, options);
464+
// Use 'self.options' to access component options
465+
self.options = self.options || {};
466+
467+
if (self.options.isResizeEnabled ?? false) {
468+
uppy.use(Uppy.Compressor, {
469+
maxWidth: self.options.maxWidth,
470+
maxHeight: self.options.maxHeight,
471+
quality: 0.92,
472+
beforeDraw() {
473+
if (!allowedResize) {
474+
this.abort();
475+
}
476+
}
477+
});
478+
}
447479

448480
// drop area for file upload
449481
uppy.use(Uppy.DropTarget, {
@@ -462,7 +494,6 @@ define([
462494
endpoint: uploadUrl,
463495
fieldName: 'image'
464496
});
465-
466497
uppy.on('upload-success', (file, response) => {
467498
if (response.body && !response.body.error) {
468499
gallery.trigger('addItem', response.body);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* Copyright 2025 Adobe
3+
* All Rights Reserved.
4+
*/
5+
6+
/* eslint-disable max-nested-callbacks */
7+
define([
8+
'Magento_ConfigurableProduct/js/variations/steps/bulk',
9+
'jquery',
10+
'ko',
11+
'underscore',
12+
'mage/template',
13+
'Magento_Ui/js/modal/alert',
14+
'Magento_Catalog/js/product-gallery',
15+
'jquery/uppy-core',
16+
'mage/translate'
17+
], function (Bulk, $) {
18+
'use strict';
19+
20+
describe('Magento_ConfigurableProduct/js/variations/steps/bulk', function () {
21+
let bulkInstance, config;
22+
23+
beforeEach(function () {
24+
config = {
25+
isResizeEnabled: true,
26+
maxWidth: 800,
27+
maxHeight: 600
28+
};
29+
bulkInstance = new Bulk(config);
30+
31+
window.FORM_KEY = 'mocked_form_key';
32+
});
33+
34+
describe('bindGalleries', function () {
35+
beforeEach(function () {
36+
spyOn($.fn, 'mage').and.returnValue({
37+
productGallery: jasmine.createSpy('productGallery')
38+
});
39+
spyOn($.fn, 'trigger');
40+
spyOn($.fn, 'data').and.returnValue(false);
41+
spyOn($.fn, 'find').and.returnValue($('<div></div>'));
42+
spyOn($.fn, 'on');
43+
spyOn($.fn, 'each').and.callFake(function (callback) {
44+
callback.call(this, 0, $('<div></div>'));
45+
});
46+
47+
window.Uppy = {
48+
Uppy: jasmine.createSpy('Uppy').and.returnValue({
49+
use: jasmine.createSpy('use'),
50+
on: jasmine.createSpy('on')
51+
}),
52+
Dashboard: jasmine.createSpy('Dashboard'),
53+
Compressor: jasmine.createSpy('Compressor'),
54+
DropTarget: jasmine.createSpy('DropTarget'),
55+
XHRUpload: jasmine.createSpy('XHRUpload')
56+
};
57+
});
58+
59+
it('should initialize galleries and Uppy', function () {
60+
bulkInstance.bindGalleries();
61+
62+
expect($.fn.mage).toHaveBeenCalledWith('productGallery', jasmine.any(Object));
63+
expect(window.Uppy.Uppy).toHaveBeenCalled();
64+
expect(window.Uppy.Uppy().use).toHaveBeenCalledWith(window.Uppy.Dashboard, jasmine.any(Object));
65+
expect(window.Uppy.Uppy().use).toHaveBeenCalledWith(window.Uppy.Compressor, jasmine.any(Object));
66+
expect(window.Uppy.Uppy().use).toHaveBeenCalledWith(window.Uppy.DropTarget, jasmine.any(Object));
67+
expect(window.Uppy.Uppy().use).toHaveBeenCalledWith(window.Uppy.XHRUpload, jasmine.any(Object));
68+
});
69+
});
70+
});
71+
});

0 commit comments

Comments
 (0)