Fixed bread crumbs.

This commit is contained in:
retoor 2025-11-10 17:59:40 +01:00
parent 4c36a9ea41
commit 2325661df4

View File

@ -5,6 +5,7 @@ export class FileUploadView extends HTMLElement {
super(); super();
this.folderId = null; this.folderId = null;
this.handleEscape = this.handleEscape.bind(this); this.handleEscape = this.handleEscape.bind(this);
this.uploadItems = new Map();
} }
connectedCallback() { connectedCallback() {
@ -94,6 +95,8 @@ export class FileUploadView extends HTMLElement {
const uploadList = this.querySelector('#upload-list'); const uploadList = this.querySelector('#upload-list');
if (!uploadList) return; if (!uploadList) return;
const uploadPromises = [];
for (const file of files) { for (const file of files) {
const itemId = `upload-${Date.now()}-${Math.random()}`; const itemId = `upload-${Date.now()}-${Math.random()}`;
const item = document.createElement('div'); const item = document.createElement('div');
@ -113,22 +116,31 @@ export class FileUploadView extends HTMLElement {
`; `;
uploadList.appendChild(item); uploadList.appendChild(item);
try { this.uploadItems.set(itemId, {
await this.uploadFile(file, itemId); element: item,
const statusEl = item.querySelector('.upload-item-status'); progress: 0
if (statusEl) { });
statusEl.textContent = 'Complete';
statusEl.classList.add('success'); const promise = this.uploadFile(file, itemId)
} .then(() => {
} catch (error) { setTimeout(() => {
const statusEl = item.querySelector('.upload-item-status'); this.uploadItems.delete(itemId);
if (statusEl) { item.remove();
statusEl.textContent = 'Failed: ' + error.message; }, 500);
statusEl.classList.add('error'); })
} .catch(error => {
} const statusEl = item.querySelector('.upload-item-status');
if (statusEl) {
statusEl.textContent = 'Failed: ' + error.message;
statusEl.classList.add('error');
}
});
uploadPromises.push(promise);
} }
await Promise.all(uploadPromises);
this.dispatchEvent(new CustomEvent('upload-complete', { bubbles: true })); this.dispatchEvent(new CustomEvent('upload-complete', { bubbles: true }));
setTimeout(() => { setTimeout(() => {
@ -136,6 +148,19 @@ export class FileUploadView extends HTMLElement {
}, 1500); }, 1500);
} }
sortUploadList() {
const uploadList = this.querySelector('#upload-list');
if (!uploadList) return;
const items = Array.from(this.uploadItems.entries())
.sort((a, b) => b[1].progress - a[1].progress);
uploadList.innerHTML = '';
items.forEach(([itemId, data]) => {
uploadList.appendChild(data.element);
});
}
async uploadFile(file, itemId) { async uploadFile(file, itemId) {
const formData = new FormData(); const formData = new FormData();
formData.append('file', file); formData.append('file', file);
@ -149,18 +174,34 @@ export class FileUploadView extends HTMLElement {
xhr.upload.addEventListener('progress', (e) => { xhr.upload.addEventListener('progress', (e) => {
if (e.lengthComputable) { if (e.lengthComputable) {
const percentComplete = (e.loaded / e.total) * 100; const percentComplete = (e.loaded / e.total) * 100;
const item = this.querySelector(`#${itemId}`); const itemData = this.uploadItems.get(itemId);
if (item) { if (itemData) {
const progressFill = item.querySelector('.progress-fill'); itemData.progress = percentComplete;
const progressFill = itemData.element.querySelector('.progress-fill');
if (progressFill) { if (progressFill) {
progressFill.style.width = percentComplete + '%'; progressFill.style.width = percentComplete + '%';
} }
this.sortUploadList();
} }
} }
}); });
xhr.addEventListener('load', () => { xhr.addEventListener('load', () => {
if (xhr.status >= 200 && xhr.status < 300) { if (xhr.status >= 200 && xhr.status < 300) {
const itemData = this.uploadItems.get(itemId);
if (itemData) {
itemData.progress = 100;
const progressFill = itemData.element.querySelector('.progress-fill');
const statusEl = itemData.element.querySelector('.upload-item-status');
if (progressFill) {
progressFill.style.width = '100%';
}
if (statusEl) {
statusEl.textContent = 'Complete';
statusEl.classList.add('success');
}
this.sortUploadList(); // Sort after completion to move completed items to top
}
resolve(JSON.parse(xhr.responseText)); resolve(JSON.parse(xhr.responseText));
} else { } else {
reject(new Error(xhr.statusText)); reject(new Error(xhr.statusText));