mirror of
https://github.com/pelican-dev/panel.git
synced 2025-11-09 20:19:26 +01:00
should fix our issues?
This commit is contained in:
parent
339efc754d
commit
227521b7bb
@ -1,279 +1,308 @@
|
|||||||
<div
|
<div
|
||||||
x-data="{
|
x-data="{
|
||||||
isUploading: false,
|
isUploading: false,
|
||||||
uploadQueue: [],
|
uploadQueue: [],
|
||||||
currentFileIndex: 0,
|
currentFileIndex: 0,
|
||||||
totalFiles: 0,
|
totalFiles: 0,
|
||||||
autoCloseTimer: 1000,
|
autoCloseTimer: 1000,
|
||||||
|
|
||||||
async extractFilesFromItems(items) {
|
async extractFilesFromItems(items) {
|
||||||
const filesWithPaths = [];
|
const filesWithPaths = [];
|
||||||
const traversePromises = [];
|
const traversePromises = [];
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
const entry = items[i].webkitGetAsEntry?.();
|
const entry = items[i].webkitGetAsEntry?.();
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
|
traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
|
||||||
} else if (items[i].kind === 'file') {
|
} else if (items[i].kind === 'file') {
|
||||||
const file = items[i].getAsFile();
|
const file = items[i].getAsFile();
|
||||||
if (file) {
|
if (file) {
|
||||||
filesWithPaths.push({
|
filesWithPaths.push({
|
||||||
file: file,
|
file: file,
|
||||||
path: '',
|
path: '',
|
||||||
});
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
await Promise.all(traversePromises);
|
await Promise.all(traversePromises);
|
||||||
return filesWithPaths;
|
return filesWithPaths;
|
||||||
},
|
},
|
||||||
|
|
||||||
async traverseFileTree(entry, path, filesWithPaths) {
|
async traverseFileTree(entry, path, filesWithPaths) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
entry.file((file) => {
|
entry.file((file) => {
|
||||||
filesWithPaths.push({
|
filesWithPaths.push({
|
||||||
file: file,
|
file: file,
|
||||||
path: path,
|
path: path,
|
||||||
});
|
});
|
||||||
resolve();
|
resolve();
|
||||||
});
|
|
||||||
} else if (entry.isDirectory) {
|
|
||||||
const reader = entry.createReader();
|
|
||||||
const readEntries = () => {
|
|
||||||
reader.readEntries(async (entries) => {
|
|
||||||
if (entries.length === 0) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subPromises = entries.map((e) =>
|
|
||||||
this.traverseFileTree(
|
|
||||||
e,
|
|
||||||
path ? `${path}/${entry.name}` : entry.name,
|
|
||||||
filesWithPaths
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(subPromises);
|
|
||||||
readEntries();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
readEntries();
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
} else if (entry.isDirectory) {
|
||||||
|
const reader = entry.createReader();
|
||||||
async uploadFilesWithFolders(filesWithPaths) {
|
const readEntries = () => {
|
||||||
this.isUploading = true;
|
reader.readEntries(async (entries) => {
|
||||||
this.uploadQueue = [];
|
if (entries.length === 0) {
|
||||||
this.totalFiles = filesWithPaths.length;
|
resolve();
|
||||||
this.currentFileIndex = 0;
|
|
||||||
const uploadedFiles = [];
|
|
||||||
|
|
||||||
try {
|
|
||||||
const uploadSizeLimit = await $wire.getUploadSizeLimit();
|
|
||||||
|
|
||||||
for (const { file } of filesWithPaths) {
|
|
||||||
if (file.size > uploadSizeLimit) {
|
|
||||||
new window.FilamentNotification()
|
|
||||||
.title(`File ${file.name} exceeds the upload size limit of ${this.formatBytes(uploadSizeLimit)}`)
|
|
||||||
.danger()
|
|
||||||
.send();
|
|
||||||
this.isUploading = false;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const subPromises = entries.map((e) =>
|
||||||
|
this.traverseFileTree(
|
||||||
|
e,
|
||||||
|
path ? `${path}/${entry.name}` : entry.name,
|
||||||
|
filesWithPaths
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(subPromises);
|
||||||
|
readEntries();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
readEntries();
|
||||||
|
} else {
|
||||||
|
resolve();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
async uploadFilesWithFolders(filesWithPaths) {
|
||||||
|
this.isUploading = true;
|
||||||
|
this.uploadQueue = [];
|
||||||
|
this.totalFiles = filesWithPaths.length;
|
||||||
|
this.currentFileIndex = 0;
|
||||||
|
const uploadedFiles = [];
|
||||||
|
|
||||||
|
try {
|
||||||
|
const uploadSizeLimit = await $wire.getUploadSizeLimit();
|
||||||
|
|
||||||
|
for (const {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
of filesWithPaths) {
|
||||||
|
if (file.size > uploadSizeLimit) {
|
||||||
|
new window.FilamentNotification()
|
||||||
|
.title(`File ${file.name} exceeds the upload size limit of ${this.formatBytes(uploadSizeLimit)}`)
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
|
this.isUploading = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const folderPaths = new Set();
|
||||||
|
for (const {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
of filesWithPaths) {
|
||||||
|
if (path) {
|
||||||
|
const parts = path.split('/').filter(Boolean);
|
||||||
|
let currentPath = '';
|
||||||
|
for (const part of parts) {
|
||||||
|
currentPath += part + '/';
|
||||||
|
folderPaths.add(currentPath);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const folderPaths = new Set();
|
for (const folderPath of folderPaths) {
|
||||||
for (const { path } of filesWithPaths) {
|
try {
|
||||||
if (path) {
|
await $wire.createFolder(folderPath.slice(0, -1));
|
||||||
const parts = path.split('/').filter(Boolean);
|
} catch (error) {
|
||||||
let currentPath = '';
|
console.warn(`Folder ${folderPath} already exists or failed to create.`);
|
||||||
for (const part of parts) {
|
}
|
||||||
currentPath += part + '/';
|
}
|
||||||
folderPaths.add(currentPath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const folderPath of folderPaths) {
|
for (const f of filesWithPaths) {
|
||||||
try {
|
this.uploadQueue.push({
|
||||||
await $wire.createFolder(folderPath.slice(0, -1));
|
file: f.file,
|
||||||
} catch (error) {
|
name: f.file.name,
|
||||||
console.warn(`Folder ${folderPath} already exists or failed to create.`);
|
path: f.path,
|
||||||
}
|
size: f.file.size,
|
||||||
}
|
progress: 0,
|
||||||
|
speed: 0,
|
||||||
|
uploadedBytes: 0,
|
||||||
|
status: 'pending',
|
||||||
|
error: null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
for (const f of filesWithPaths) {
|
const maxConcurrent = 3;
|
||||||
this.uploadQueue.push({
|
let activeUploads = [];
|
||||||
file: f.file,
|
let completedCount = 0;
|
||||||
name: f.file.name,
|
|
||||||
path: f.path,
|
|
||||||
size: f.file.size,
|
|
||||||
progress: 0,
|
|
||||||
speed: 0,
|
|
||||||
uploadedBytes: 0,
|
|
||||||
status: 'pending',
|
|
||||||
error: null
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const maxConcurrent = 3;
|
for (let i = 0; i < this.uploadQueue.length; i++) {
|
||||||
let activeUploads = [];
|
const uploadPromise = this.uploadFile(i)
|
||||||
let completedCount = 0;
|
.then(() => {
|
||||||
|
completedCount++;
|
||||||
|
this.currentFileIndex = completedCount;
|
||||||
|
const item = this.uploadQueue[i];
|
||||||
|
const relativePath = (item.path ? item.path.replace(/^\/+/, '') + '/' : '') + item.name;
|
||||||
|
uploadedFiles.push(relativePath);
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
completedCount++;
|
||||||
|
this.currentFileIndex = completedCount;
|
||||||
|
});
|
||||||
|
|
||||||
for (let i = 0; i < this.uploadQueue.length; i++) {
|
activeUploads.push(uploadPromise);
|
||||||
const uploadPromise = this.uploadFile(i)
|
|
||||||
.then(() => { completedCount++; this.currentFileIndex = completedCount;
|
|
||||||
const item = this.uploadQueue[i];
|
|
||||||
const relativePath = (item.path ? item.path.replace(/^\/+/, '') + '/' : '') + item.name;
|
|
||||||
uploadedFiles.push(relativePath);
|
|
||||||
})
|
|
||||||
.catch(() => { completedCount++; this.currentFileIndex = completedCount; });
|
|
||||||
|
|
||||||
activeUploads.push(uploadPromise);
|
if (activeUploads.length >= maxConcurrent) {
|
||||||
|
await Promise.race(activeUploads);
|
||||||
|
activeUploads = activeUploads.filter(p => p.status !== 'fulfilled' && p.status !== 'rejected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (activeUploads.length >= maxConcurrent) {
|
await Promise.allSettled(activeUploads);
|
||||||
await Promise.race(activeUploads);
|
|
||||||
activeUploads = activeUploads.filter(p => p.status !== 'fulfilled' && p.status !== 'rejected');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.allSettled(activeUploads);
|
const failed = this.uploadQueue.filter(f => f.status === 'error');
|
||||||
|
await $wire.$refresh();
|
||||||
const failed = this.uploadQueue.filter(f => f.status === 'error');
|
|
||||||
await $wire.$refresh();
|
|
||||||
|
|
||||||
if (failed.length === 0) {
|
if (failed.length === 0) {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.success') }}').success().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.success') }}')
|
||||||
|
.success()
|
||||||
|
.send();
|
||||||
} else if (failed.length === this.totalFiles) {
|
} else if (failed.length === this.totalFiles) {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.error_all') }}').danger().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.failed') }}')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
} else {
|
} else {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.error_partial') }}').warning().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.failed') }}')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uploadedFiles.length > 0) {
|
if (uploadedFiles.length > 0) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
try {
|
if (typeof $wire !== 'undefined' && $wire && typeof $wire.call === 'function') {
|
||||||
@this.call('logUploadedFiles', uploadedFiles);
|
$wire.call('logUploadedFiles', uploadedFiles);
|
||||||
} catch (e) {
|
} else if (typeof window.livewire !== 'undefined' && typeof window.livewire.call === 'function') {
|
||||||
$wire.call('logUploadedFiles', uploadedFiles);
|
window.livewire.call('logUploadedFiles', uploadedFiles);
|
||||||
}
|
} else if (typeof Livewire !== 'undefined' && typeof Livewire.call === 'function') {
|
||||||
});
|
Livewire.call('logUploadedFiles', uploadedFiles);
|
||||||
|
} else {
|
||||||
|
console.warn('Could not call Livewire method logUploadedFiles; Livewire not found.');
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (this.autoCloseTimer) clearTimeout(this.autoCloseTimer);
|
if (this.autoCloseTimer) clearTimeout(this.autoCloseTimer);
|
||||||
this.autoCloseTimer = setTimeout(() => {
|
this.autoCloseTimer = setTimeout(() => {
|
||||||
this.isUploading = false;
|
this.isUploading = false;
|
||||||
this.uploadQueue = [];
|
this.uploadQueue = [];
|
||||||
},1000);
|
}, 1000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Upload error:', error);
|
console.error('Upload error:', error);
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.error') }}').danger().send();
|
new window.FilamentNotification()
|
||||||
this.isUploading = false;
|
.title('{{ trans('server/file.actions.upload.error') }}')
|
||||||
}
|
.danger()
|
||||||
},
|
.send();
|
||||||
|
this.isUploading = false;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
async uploadFile(index) {
|
async uploadFile(index) {
|
||||||
const fileData = this.uploadQueue[index];
|
const fileData = this.uploadQueue[index];
|
||||||
fileData.status = 'uploading';
|
fileData.status = 'uploading';
|
||||||
try {
|
try {
|
||||||
const uploadUrl = await $wire.getUploadUrl();
|
const uploadUrl = await $wire.getUploadUrl();
|
||||||
const url = new URL(uploadUrl);
|
const url = new URL(uploadUrl);
|
||||||
let basePath = @js($this->path);
|
let basePath = @js($this->path);
|
||||||
|
|
||||||
if (fileData.path && fileData.path.trim() !== '') {
|
if (fileData.path && fileData.path.trim() !== '') {
|
||||||
basePath = basePath.replace(/\/+$/, '') + '/' + fileData.path.replace(/^\/+/, '');
|
basePath = basePath.replace(/\/+$/, '') + '/' + fileData.path.replace(/^\/+/, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
url.searchParams.append('directory', basePath);
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
const xhr = new XMLHttpRequest();
|
||||||
|
const formData = new FormData();
|
||||||
|
formData.append('files', fileData.file);
|
||||||
|
|
||||||
|
let lastLoaded = 0;
|
||||||
|
let lastTime = Date.now();
|
||||||
|
|
||||||
|
xhr.upload.addEventListener('progress', (e) => {
|
||||||
|
if (e.lengthComputable) {
|
||||||
|
fileData.uploadedBytes = e.loaded;
|
||||||
|
fileData.progress = Math.round((e.loaded / e.total) * 100);
|
||||||
|
|
||||||
|
const now = Date.now();
|
||||||
|
const timeDiff = (now - lastTime) / 1000;
|
||||||
|
if (timeDiff > 0.1) {
|
||||||
|
const bytesDiff = e.loaded - lastLoaded;
|
||||||
|
fileData.speed = bytesDiff / timeDiff;
|
||||||
|
lastTime = now;
|
||||||
|
lastLoaded = e.loaded;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
url.searchParams.append('directory', basePath);
|
xhr.onload = () => {
|
||||||
|
if (xhr.status >= 200 && xhr.status < 300) {
|
||||||
|
fileData.status = 'complete';
|
||||||
|
fileData.progress = 100;
|
||||||
|
resolve();
|
||||||
|
} else {
|
||||||
|
fileData.status = 'error';
|
||||||
|
fileData.error = `Upload failed (${xhr.status})`;
|
||||||
|
reject(new Error(fileData.error));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return new Promise((resolve, reject) => {
|
xhr.onerror = () => {
|
||||||
const xhr = new XMLHttpRequest();
|
|
||||||
const formData = new FormData();
|
|
||||||
formData.append('files', fileData.file);
|
|
||||||
|
|
||||||
let lastLoaded = 0;
|
|
||||||
let lastTime = Date.now();
|
|
||||||
|
|
||||||
xhr.upload.addEventListener('progress', (e) => {
|
|
||||||
if (e.lengthComputable) {
|
|
||||||
fileData.uploadedBytes = e.loaded;
|
|
||||||
fileData.progress = Math.round((e.loaded / e.total) * 100);
|
|
||||||
|
|
||||||
const now = Date.now();
|
|
||||||
const timeDiff = (now - lastTime) / 1000;
|
|
||||||
if (timeDiff > 0.1) {
|
|
||||||
const bytesDiff = e.loaded - lastLoaded;
|
|
||||||
fileData.speed = bytesDiff / timeDiff;
|
|
||||||
lastTime = now;
|
|
||||||
lastLoaded = e.loaded;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
xhr.onload = () => {
|
|
||||||
if (xhr.status >= 200 && xhr.status < 300) {
|
|
||||||
fileData.status = 'complete';
|
|
||||||
fileData.progress = 100;
|
|
||||||
resolve();
|
|
||||||
} else {
|
|
||||||
fileData.status = 'error';
|
|
||||||
fileData.error = `Upload failed (${xhr.status})`;
|
|
||||||
reject(new Error(fileData.error));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.onerror = () => {
|
|
||||||
fileData.status = 'error';
|
|
||||||
fileData.error = 'Network error';
|
|
||||||
reject(new Error('Network error'));
|
|
||||||
};
|
|
||||||
|
|
||||||
xhr.open('POST', url.toString());
|
|
||||||
xhr.send(formData);
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
fileData.status = 'error';
|
fileData.status = 'error';
|
||||||
fileData.error = 'Failed to get upload token';
|
fileData.error = 'Network error';
|
||||||
throw err;
|
reject(new Error('Network error'));
|
||||||
}
|
};
|
||||||
},
|
|
||||||
|
|
||||||
formatBytes(bytes) {
|
xhr.open('POST', url.toString());
|
||||||
if (bytes === 0) return '0.00 B';
|
xhr.send(formData);
|
||||||
const k = 1024;
|
});
|
||||||
const sizes = ['B', 'KB', 'MB', 'GB'];
|
} catch (err) {
|
||||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
fileData.status = 'error';
|
||||||
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
|
fileData.error = 'Failed to get upload token';
|
||||||
},
|
throw err;
|
||||||
formatSpeed(bytesPerSecond) {
|
}
|
||||||
return this.formatBytes(bytesPerSecond) + '/s';
|
},
|
||||||
},
|
|
||||||
handleEscapeKey(e) {
|
formatBytes(bytes) {
|
||||||
if (e.key === 'Escape' && this.isUploading) {
|
if (bytes === 0) return '0.00 B';
|
||||||
this.isUploading = false;
|
const k = 1024;
|
||||||
this.uploadQueue = [];
|
const sizes = ['B', 'KB', 'MB', 'GB'];
|
||||||
}
|
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||||
},
|
return (bytes / Math.pow(k, i)).toFixed(2) + ' ' + sizes[i];
|
||||||
async handleFileSelect(e) {
|
},
|
||||||
const files = Array.from(e.target.files);
|
formatSpeed(bytesPerSecond) {
|
||||||
if (files.length > 0) {
|
return this.formatBytes(bytesPerSecond) + '/s';
|
||||||
const filesWithPaths = files.map(f => ({ file: f, path: '' }));
|
},
|
||||||
await this.uploadFilesWithFolders(filesWithPaths);
|
handleEscapeKey(e) {
|
||||||
}
|
if (e.key === 'Escape' && this.isUploading) {
|
||||||
},
|
this.isUploading = false;
|
||||||
triggerBrowse() {
|
this.uploadQueue = [];
|
||||||
this.$refs.fileInput.click();
|
}
|
||||||
},
|
},
|
||||||
}"
|
async handleFileSelect(e) {
|
||||||
class="relative"
|
const files = Array.from(e.target.files);
|
||||||
>
|
if (files.length > 0) {
|
||||||
|
const filesWithPaths = files.map(f => ({
|
||||||
|
file: f,
|
||||||
|
path: ''
|
||||||
|
}));
|
||||||
|
await this.uploadFilesWithFolders(filesWithPaths);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
triggerBrowse() {
|
||||||
|
this.$refs.fileInput.click();
|
||||||
|
},
|
||||||
|
}"
|
||||||
|
class="relative">
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<input type="file" x-ref="fileInput" class="hidden" multiple @change="handleFileSelect">
|
<input type="file" x-ref="fileInput" class="hidden" multiple @change="handleFileSelect">
|
||||||
|
|
||||||
|
|||||||
@ -44,7 +44,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (files && files.length > 0 && filesWithPaths.length === 0) {
|
if (files && files.length > 0 && filesWithPaths.length === 0) {
|
||||||
filesWithPaths = Array.from(files).map(f => ({ file: f, path: '' }));
|
filesWithPaths = Array.from(files).map(f => ({
|
||||||
|
file: f,
|
||||||
|
path: ''
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filesWithPaths.length > 0) {
|
if (filesWithPaths.length > 0) {
|
||||||
@ -53,67 +56,67 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
async extractFilesFromItems(items) {
|
async extractFilesFromItems(items) {
|
||||||
const filesWithPaths = [];
|
const filesWithPaths = [];
|
||||||
const traversePromises = [];
|
const traversePromises = [];
|
||||||
|
|
||||||
for (let i = 0; i < items.length; i++) {
|
for (let i = 0; i < items.length; i++) {
|
||||||
const entry = items[i].webkitGetAsEntry?.();
|
const entry = items[i].webkitGetAsEntry?.();
|
||||||
|
|
||||||
if (entry) {
|
if (entry) {
|
||||||
traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
|
traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
|
||||||
} else if (items[i].kind === 'file') {
|
} else if (items[i].kind === 'file') {
|
||||||
const file = items[i].getAsFile();
|
const file = items[i].getAsFile();
|
||||||
if (file) {
|
if (file) {
|
||||||
filesWithPaths.push({
|
filesWithPaths.push({
|
||||||
file: file,
|
file: file,
|
||||||
path: '',
|
path: '',
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
await Promise.all(traversePromises);
|
await Promise.all(traversePromises);
|
||||||
|
|
||||||
return filesWithPaths;
|
return filesWithPaths;
|
||||||
},
|
},
|
||||||
|
|
||||||
async traverseFileTree(entry, path, filesWithPaths) {
|
async traverseFileTree(entry, path, filesWithPaths) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
if (entry.isFile) {
|
if (entry.isFile) {
|
||||||
entry.file((file) => {
|
entry.file((file) => {
|
||||||
filesWithPaths.push({
|
filesWithPaths.push({
|
||||||
file: file,
|
file: file,
|
||||||
path: path,
|
path: path,
|
||||||
|
});
|
||||||
|
resolve();
|
||||||
});
|
});
|
||||||
|
} else if (entry.isDirectory) {
|
||||||
|
const reader = entry.createReader();
|
||||||
|
const readEntries = () => {
|
||||||
|
reader.readEntries(async (entries) => {
|
||||||
|
if (entries.length === 0) {
|
||||||
|
resolve();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const subPromises = entries.map((e) =>
|
||||||
|
this.traverseFileTree(
|
||||||
|
e,
|
||||||
|
path ? `${path}/${entry.name}` : entry.name,
|
||||||
|
filesWithPaths
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
await Promise.all(subPromises);
|
||||||
|
readEntries();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
readEntries();
|
||||||
|
} else {
|
||||||
resolve();
|
resolve();
|
||||||
});
|
}
|
||||||
} else if (entry.isDirectory) {
|
});
|
||||||
const reader = entry.createReader();
|
},
|
||||||
const readEntries = () => {
|
|
||||||
reader.readEntries(async (entries) => {
|
|
||||||
if (entries.length === 0) {
|
|
||||||
resolve();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const subPromises = entries.map((e) =>
|
|
||||||
this.traverseFileTree(
|
|
||||||
e,
|
|
||||||
path ? `${path}/${entry.name}` : entry.name,
|
|
||||||
filesWithPaths
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
await Promise.all(subPromises);
|
|
||||||
readEntries();
|
|
||||||
});
|
|
||||||
};
|
|
||||||
readEntries();
|
|
||||||
} else {
|
|
||||||
resolve();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
async uploadFilesWithFolders(filesWithPaths) {
|
async uploadFilesWithFolders(filesWithPaths) {
|
||||||
this.isUploading = true;
|
this.isUploading = true;
|
||||||
this.uploadQueue = [];
|
this.uploadQueue = [];
|
||||||
@ -124,7 +127,10 @@
|
|||||||
try {
|
try {
|
||||||
const uploadSizeLimit = await $wire.getUploadSizeLimit();
|
const uploadSizeLimit = await $wire.getUploadSizeLimit();
|
||||||
|
|
||||||
for (const { file } of filesWithPaths) {
|
for (const {
|
||||||
|
file
|
||||||
|
}
|
||||||
|
of filesWithPaths) {
|
||||||
if (file.size > uploadSizeLimit) {
|
if (file.size > uploadSizeLimit) {
|
||||||
new window.FilamentNotification()
|
new window.FilamentNotification()
|
||||||
.title(`File ${file.name} exceeds the upload limit.`)
|
.title(`File ${file.name} exceeds the upload limit.`)
|
||||||
@ -136,7 +142,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
const folderPaths = new Set();
|
const folderPaths = new Set();
|
||||||
for (const { path } of filesWithPaths) {
|
for (const {
|
||||||
|
path
|
||||||
|
}
|
||||||
|
of filesWithPaths) {
|
||||||
if (path) {
|
if (path) {
|
||||||
const parts = path.split('/').filter(Boolean);
|
const parts = path.split('/').filter(Boolean);
|
||||||
let currentPath = '';
|
let currentPath = '';
|
||||||
@ -175,12 +184,17 @@
|
|||||||
|
|
||||||
for (let i = 0; i < this.uploadQueue.length; i++) {
|
for (let i = 0; i < this.uploadQueue.length; i++) {
|
||||||
const uploadPromise = this.uploadFile(i)
|
const uploadPromise = this.uploadFile(i)
|
||||||
.then(() => { completedCount++; this.currentFileIndex = completedCount;
|
.then(() => {
|
||||||
|
completedCount++;
|
||||||
|
this.currentFileIndex = completedCount;
|
||||||
const item = this.uploadQueue[i];
|
const item = this.uploadQueue[i];
|
||||||
const relativePath = (item.path ? item.path.replace(/^\/+/, '') + '/' : '') + item.name;
|
const relativePath = (item.path ? item.path.replace(/^\/+/, '') + '/' : '') + item.name;
|
||||||
uploadedFiles.push(relativePath);
|
uploadedFiles.push(relativePath);
|
||||||
})
|
})
|
||||||
.catch(() => { completedCount++; this.currentFileIndex = completedCount; });
|
.catch(() => {
|
||||||
|
completedCount++;
|
||||||
|
this.currentFileIndex = completedCount;
|
||||||
|
});
|
||||||
|
|
||||||
activeUploads.push(uploadPromise);
|
activeUploads.push(uploadPromise);
|
||||||
|
|
||||||
@ -196,19 +210,32 @@
|
|||||||
await $wire.$refresh();
|
await $wire.$refresh();
|
||||||
|
|
||||||
if (failed.length === 0) {
|
if (failed.length === 0) {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.success') }}').success().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.success') }}')
|
||||||
|
.success()
|
||||||
|
.send();
|
||||||
} else if (failed.length === this.totalFiles) {
|
} else if (failed.length === this.totalFiles) {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.failed') }}').danger().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.failed') }}')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
} else {
|
} else {
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.failed') }}').danger().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.failed') }}')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uploadedFiles.length > 0) {
|
if (uploadedFiles.length > 0) {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
try {
|
if (typeof $wire !== 'undefined' && $wire && typeof $wire.call === 'function') {
|
||||||
@this.call('logUploadedFiles', uploadedFiles);
|
|
||||||
} catch (e) {
|
|
||||||
$wire.call('logUploadedFiles', uploadedFiles);
|
$wire.call('logUploadedFiles', uploadedFiles);
|
||||||
|
} else if (typeof window.livewire !== 'undefined' && typeof window.livewire.call === 'function') {
|
||||||
|
window.livewire.call('logUploadedFiles', uploadedFiles);
|
||||||
|
} else if (typeof Livewire !== 'undefined' && typeof Livewire.call === 'function') {
|
||||||
|
Livewire.call('logUploadedFiles', uploadedFiles);
|
||||||
|
} else {
|
||||||
|
console.warn('Could not call Livewire method logUploadedFiles; Livewire not found.');
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -217,10 +244,13 @@
|
|||||||
this.autoCloseTimer = setTimeout(() => {
|
this.autoCloseTimer = setTimeout(() => {
|
||||||
this.isUploading = false;
|
this.isUploading = false;
|
||||||
this.uploadQueue = [];
|
this.uploadQueue = [];
|
||||||
},1000);
|
}, 1000);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Upload error:', error);
|
console.error('Upload error:', error);
|
||||||
new window.FilamentNotification().title('{{ trans('server/file.actions.upload.error') }}').danger().send();
|
new window.FilamentNotification()
|
||||||
|
.title('{{ trans('server/file.actions.upload.error') }}')
|
||||||
|
.danger()
|
||||||
|
.send();
|
||||||
this.isUploading = false;
|
this.isUploading = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user