diff --git a/resources/views/filament/server/pages/file-upload.blade.php b/resources/views/filament/server/pages/file-upload.blade.php
index 920a0ea5d..6d18300e2 100644
--- a/resources/views/filament/server/pages/file-upload.blade.php
+++ b/resources/views/filament/server/pages/file-upload.blade.php
@@ -1,279 +1,308 @@
+ xhr.open('POST', url.toString());
+ xhr.send(formData);
+ });
+ } catch (err) {
+ fileData.status = 'error';
+ fileData.error = 'Failed to get upload token';
+ throw err;
+ }
+ },
+
+ formatBytes(bytes) {
+ if (bytes === 0) return '0.00 B';
+ const k = 1024;
+ 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];
+ },
+ formatSpeed(bytesPerSecond) {
+ return this.formatBytes(bytesPerSecond) + '/s';
+ },
+ handleEscapeKey(e) {
+ if (e.key === 'Escape' && this.isUploading) {
+ this.isUploading = false;
+ this.uploadQueue = [];
+ }
+ },
+ async handleFileSelect(e) {
+ 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">
diff --git a/resources/views/filament/server/pages/list-files.blade.php b/resources/views/filament/server/pages/list-files.blade.php
index e864d0ee9..0ff5dfcb7 100644
--- a/resources/views/filament/server/pages/list-files.blade.php
+++ b/resources/views/filament/server/pages/list-files.blade.php
@@ -44,7 +44,10 @@
}
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) {
@@ -53,67 +56,67 @@
},
async extractFilesFromItems(items) {
- const filesWithPaths = [];
- const traversePromises = [];
+ const filesWithPaths = [];
+ const traversePromises = [];
- for (let i = 0; i < items.length; i++) {
- const entry = items[i].webkitGetAsEntry?.();
+ for (let i = 0; i < items.length; i++) {
+ const entry = items[i].webkitGetAsEntry?.();
- if (entry) {
- traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
- } else if (items[i].kind === 'file') {
- const file = items[i].getAsFile();
- if (file) {
- filesWithPaths.push({
- file: file,
- path: '',
- });
+ if (entry) {
+ traversePromises.push(this.traverseFileTree(entry, '', filesWithPaths));
+ } else if (items[i].kind === 'file') {
+ const file = items[i].getAsFile();
+ if (file) {
+ filesWithPaths.push({
+ file: file,
+ path: '',
+ });
+ }
}
}
- }
- await Promise.all(traversePromises);
+ await Promise.all(traversePromises);
- return filesWithPaths;
+ return filesWithPaths;
},
- async traverseFileTree(entry, path, filesWithPaths) {
- return new Promise((resolve) => {
- if (entry.isFile) {
- entry.file((file) => {
- filesWithPaths.push({
- file: file,
- path: path,
+ async traverseFileTree(entry, path, filesWithPaths) {
+ return new Promise((resolve) => {
+ if (entry.isFile) {
+ entry.file((file) => {
+ filesWithPaths.push({
+ file: file,
+ 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();
- });
- } 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) {
this.isUploading = true;
this.uploadQueue = [];
@@ -124,7 +127,10 @@
try {
const uploadSizeLimit = await $wire.getUploadSizeLimit();
- for (const { file } of filesWithPaths) {
+ for (const {
+ file
+ }
+ of filesWithPaths) {
if (file.size > uploadSizeLimit) {
new window.FilamentNotification()
.title(`File ${file.name} exceeds the upload limit.`)
@@ -136,7 +142,10 @@
}
const folderPaths = new Set();
- for (const { path } of filesWithPaths) {
+ for (const {
+ path
+ }
+ of filesWithPaths) {
if (path) {
const parts = path.split('/').filter(Boolean);
let currentPath = '';
@@ -175,12 +184,17 @@
for (let i = 0; i < this.uploadQueue.length; i++) {
const uploadPromise = this.uploadFile(i)
- .then(() => { completedCount++; this.currentFileIndex = completedCount;
+ .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; });
+ .catch(() => {
+ completedCount++;
+ this.currentFileIndex = completedCount;
+ });
activeUploads.push(uploadPromise);
@@ -196,19 +210,32 @@
await $wire.$refresh();
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) {
- 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 {
- 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) {
this.$nextTick(() => {
- try {
- @this.call('logUploadedFiles', uploadedFiles);
- } catch (e) {
+ if (typeof $wire !== 'undefined' && $wire && typeof $wire.call === 'function') {
$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.isUploading = false;
this.uploadQueue = [];
- },1000);
+ }, 1000);
} catch (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;
}
},