Skip to content
Open
Show file tree
Hide file tree
Changes from all 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 @@ -144,6 +144,9 @@ define([
fileId = null,
arrayFromObj = Array.from,
fileObj = [],
filePositions = {},
uploadedFiles = {},
totalFilesToUpload = 0,
uploaderContainer = this.element.find('input[type="file"]').closest('.image-placeholder'),
options = {
proudlyDisplayPoweredByUppy: false,
Expand Down Expand Up @@ -192,7 +195,12 @@ define([
};

uploaderContainer.addClass('loading');

// Track file selection order for maintaining upload order
const filePosition = fileObj.length;
filePositions[modifiedFile.id] = filePosition;
fileObj.push(currentFile);

return modifiedFile;
},

Expand Down Expand Up @@ -230,6 +238,15 @@ define([
$dropPlaceholder.find('.progress-bar').addClass('in-progress').text(progressWidth + '%');
});

uppy.on('files-added', (files) => {
totalFilesToUpload = files.length;
uploadedFiles = {};

// Reset file tracking arrays
fileObj = [];
filePositions = {};
});

uppy.on('upload-success', (file, response) => {
$dropPlaceholder.find('.progress-bar').text('').removeClass('in-progress');

Expand All @@ -238,17 +255,66 @@ define([
}

if (!response.body.error) {
$galleryContainer.trigger('addItem', response.body);
// Store upload result with position info
const position = filePositions[file.id];
uploadedFiles[position] = response.body;

// Check if all files have been uploaded
if (Object.keys(uploadedFiles).length === totalFilesToUpload) {
// Add images in correct order (by position)
const sortedPositions = Object.keys(uploadedFiles).sort((a, b) => parseInt(a) - parseInt(b));

sortedPositions.forEach(position => {
$galleryContainer.trigger('addItem', uploadedFiles[position]);
});

// Reset for next batch
uploadedFiles = {};
totalFilesToUpload = 0;
}
} else {
alert({
content: $.mage.__('We don\'t recognize or support this file extension type.')
});
}
});

uppy.on('upload-error', (file, error, response) => {
$dropPlaceholder.find('.progress-bar').text('').removeClass('in-progress');

// Reduce total count since this file failed
totalFilesToUpload--;

// Check if remaining successful uploads should be processed
if (Object.keys(uploadedFiles).length === totalFilesToUpload && totalFilesToUpload > 0) {
const sortedPositions = Object.keys(uploadedFiles).sort((a, b) => parseInt(a) - parseInt(b));

sortedPositions.forEach(position => {
$galleryContainer.trigger('addItem', uploadedFiles[position]);
});

// Reset for next batch
uploadedFiles = {};
totalFilesToUpload = 0;
}
});

uppy.on('complete', () => {
uploaderContainer.removeClass('loading');
Array.from = arrayFromObj;

// Handle any remaining uploaded files if some uploads failed
if (Object.keys(uploadedFiles).length > 0 && Object.keys(uploadedFiles).length < totalFilesToUpload) {
const sortedPositions = Object.keys(uploadedFiles).sort((a, b) => parseInt(a) - parseInt(b));

sortedPositions.forEach(position => {
$galleryContainer.trigger('addItem', uploadedFiles[position]);
});

// Reset for next batch
uploadedFiles = {};
totalFilesToUpload = 0;
}
});
}
});
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/**
* Copyright 2024 Adobe
* All Rights Reserved.
*/

/*eslint-disable max-nested-callbacks*/
/*jscs:disable jsDoc*/
define([
'jquery',
'Magento_Catalog/catalog/base-image-uploader'
], function ($) {
'use strict';

describe('Base Image Uploader', function () {
var uploaderEl,
defaultConfig = {
maxImageUploadCount: 10
};

beforeEach(function () {
uploaderEl = $(
'<div data-max-file-size="2048000">' +
'<input type="file" multiple />' +
'<div class="image-placeholder">' +
'<div class="progress-bar"></div>' +
'</div>' +
'</div>'
);

uploaderEl.appendTo('body');
});

afterEach(function () {
uploaderEl.remove();
});

it('should preserve file selection order during upload', function () {
var uploader = uploaderEl.baseImage(defaultConfig),
filePositions,
uploadedFiles;

// Simulate the internal tracking variables
filePositions = {};
uploadedFiles = {};

// Test file order tracking
var testFiles = [
{ id: 'file1', name: 'first.jpg' },
{ id: 'file2', name: 'second.jpg' },
{ id: 'file3', name: 'third.jpg' }
];

// Simulate onBeforeFileAdded behavior
testFiles.forEach(function (file, index) {
filePositions[file.id] = index;
});

// Simulate upload success in random order
var uploadOrder = [1, 0, 2]; // files complete in different order
var mockResponses = [
{ body: { file: 'first.jpg', position: 0 } },
{ body: { file: 'second.jpg', position: 1 } },
{ body: { file: 'third.jpg', position: 2 } }
];

// Store results as they would complete
uploadOrder.forEach(function (fileIndex) {
var file = testFiles[fileIndex];
var position = filePositions[file.id];
uploadedFiles[position] = mockResponses[fileIndex];
});

// Verify ordering logic
var sortedPositions = Object.keys(uploadedFiles).sort(function (a, b) {
return parseInt(a, 10) - parseInt(b, 10);
});

var expectedOrder = ['0', '1', '2'];
expect(sortedPositions).toEqual(expectedOrder);

// Verify the files would be added in correct order
var actualFiles = sortedPositions.map(function (position) {
return uploadedFiles[position].file;
});

expect(actualFiles).toEqual(['first.jpg', 'second.jpg', 'third.jpg']);
});

it('should handle partial upload failures while maintaining order', function () {
var filePositions = { 'file1': 0, 'file2': 1, 'file3': 2 };
var uploadedFiles = {
'0': { file: 'first.jpg' },
'2': { file: 'third.jpg' }
// file2 failed to upload
};

var totalFilesToUpload = 2; // reduced after file2 failed

var sortedPositions = Object.keys(uploadedFiles).sort(function (a, b) {
return parseInt(a, 10) - parseInt(b, 10);
});

var actualFiles = sortedPositions.map(function (position) {
return uploadedFiles[position].file;
});

// Should maintain order of successful uploads
expect(actualFiles).toEqual(['first.jpg', 'third.jpg']);
expect(Object.keys(uploadedFiles).length).toBe(totalFilesToUpload);
});
});
});