diff --git a/src/lib/stores/uploader.ts b/src/lib/stores/uploader.ts index 0c2c3bbc4..efc16f255 100644 --- a/src/lib/stores/uploader.ts +++ b/src/lib/stores/uploader.ts @@ -82,22 +82,29 @@ const createUploader = () => { n.files.unshift(newFile); return n; }); - const uploadedFile = await temporaryStorage(region, projectId).createFile({ - bucketId, - fileId: id ?? ID.unique(), - file, - permissions, - onProgress: (progress) => { - newFile.$id = progress.$id; - newFile.progress = progress.progress; - newFile.status = progress.progress === 100 ? 'success' : 'pending'; - updateFile(progress.$id, newFile); - } - }); - newFile.$id = uploadedFile.$id; - newFile.progress = 100; - newFile.status = 'success'; - updateFile(newFile.$id, newFile); + try { + const uploadedFile = await temporaryStorage(region, projectId).createFile({ + bucketId, + fileId: id ?? ID.unique(), + file, + permissions, + onProgress: (progress) => { + newFile.$id = progress.$id; + newFile.progress = progress.progress; + newFile.status = progress.progress === 100 ? 'success' : 'pending'; + updateFile(progress.$id, newFile); + } + }); + newFile.$id = uploadedFile.$id; + newFile.progress = 100; + newFile.status = 'success'; + updateFile(newFile.$id, newFile); + } catch (e) { + newFile.status = 'failed'; + newFile.error = e?.message ?? 'Upload failed'; + updateFile(newFile.$id, newFile); + throw e; + } }; const uploadFiles = async ( diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte index e17db7799..e0d6f5a45 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/+page.svelte @@ -105,9 +105,30 @@ isDragging = false; if (!event.dataTransfer?.files?.length) return; + const allowedExtensions: string[] = data.bucket.allowedFileExtensions ?? []; const droppedFiles = Array.from(event.dataTransfer.files); - const count = droppedFiles.length; + const validFiles: File[] = []; + const rejectedFiles: File[] = []; + for (const file of droppedFiles) { + const ext = file.name.split('.').pop()?.toLowerCase(); + if (allowedExtensions.length && (!ext || !allowedExtensions.includes(ext))) { + rejectedFiles.push(file); + } else { + validFiles.push(file); + } + } + + if (rejectedFiles.length) { + addNotification({ + type: 'error', + message: `${rejectedFiles.length} file(s) rejected — only ${allowedExtensions.join(', ')} allowed` + }); + } + + if (!validFiles.length) return; + + const count = validFiles.length; addNotification({ type: 'success', message: count === 1 ? 'File upload in progress' : `${count} file uploads in progress` @@ -115,18 +136,25 @@ trackEvent(Submit.FileCreate, { customId: false }); - const filesToUpload = droppedFiles.map((file) => ({ + const filesToUpload = validFiles.map((file) => ({ id: ID.unique(), file })); - await uploader.uploadFiles( + const results = await uploader.uploadFiles( page.params.region, page.params.project, page.params.bucket, filesToUpload, [] ); + const failures = results.filter((r) => r.status === 'rejected'); + if (failures.length) { + addNotification({ + type: 'error', + message: `${failures.length} file(s) failed to upload` + }); + } invalidate(Dependencies.FILES); } diff --git a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte index ae3ac8591..f12bf3926 100644 --- a/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/storage/bucket-[bucket]/create/+page.svelte @@ -69,7 +69,14 @@ trackEvent(Submit.FileCreate, { customId: !!id }); - await promise; + const results = await promise; + const failures = results.filter((r) => r.status === 'rejected'); + if (failures.length) { + addNotification({ + type: 'error', + message: `${failures.length} file(s) failed to upload` + }); + } invalidate(Dependencies.FILES); } catch (e) { addNotification({