diff --git a/apps/studio/state/storage-explorer.tsx b/apps/studio/state/storage-explorer.tsx index 4e98579275d..fa1a9590e69 100644 --- a/apps/studio/state/storage-explorer.tsx +++ b/apps/studio/state/storage-explorer.tsx @@ -62,7 +62,8 @@ type UploadProgress = { const LIMIT = 200 const OFFSET = 0 -const BATCH_SIZE = 2 +const DEFAULT_RETRY_SECONDS = 5 +const RATE_LIMIT_RETRY_SECONDS = 60 const DEFAULT_PREFERENCES = { view: STORAGE_VIEWS.COLUMNS, @@ -660,10 +661,10 @@ function createStorageExplorerState({ const files = await state.getAllItemsAlongFolder(folder) let progress = 0 - let hasErrors = false + let failedFiles = 0 + let retrySeconds = DEFAULT_RETRY_SECONDS - // Make this batched promises into a reusable function for storage, i think this will be super helpful - const promises = files.map((file) => { + for (const file of files) { const fromPath = `${file.prefix}/${file.name}` const pathSegments = fromPath.split('/') const toPath = pathSegments @@ -671,50 +672,86 @@ function createStorageExplorerState({ .concat(newName) .concat(pathSegments.slice(columnIndex + 1)) .join('/') - return () => { - return new Promise(async (resolve) => { - progress = progress + 1 / files.length - try { - await moveStorageObject({ - projectRef: state.projectRef, - bucketId: state.selectedBucket.id, - from: fromPath, - to: toPath, + + let success = false + let isRateLimited = false + + for (let attempt = 0; attempt < 3 && !success; attempt++) { + try { + if (attempt > 0) { + await new Promise((resolve) => { + let seconds = retrySeconds + const interval = setInterval(() => { + toast( + , + { id: toastId, closeButton: false, position: 'top-right', duration: Infinity } + ) + + seconds-- + if (seconds <= 0) { + clearInterval(interval) + resolve() + } + }, 1000) }) - } catch (error) { - hasErrors = true - toast.error(`Failed to move ${fromPath} to the new folder`) } - resolve() - }) + + await moveStorageObject({ + projectRef: state.projectRef, + bucketId: state.selectedBucket.id, + from: fromPath, + to: toPath, + }) + success = true + } catch (error) { + if ((error as ResponseError).code === 429) { + isRateLimited = true + retrySeconds = RATE_LIMIT_RETRY_SECONDS + } else { + isRateLimited = false + retrySeconds = DEFAULT_RETRY_SECONDS + } + + if (attempt === 2) failedFiles += 1 + } } - }) - const batchedPromises = chunk(promises, BATCH_SIZE) - // [Joshen] I realised this can be simplified with just a vanilla for loop, no need for reduce - // Just take note, but if it's working fine, then it's okay - - await batchedPromises.reduce(async (previousPromise, nextBatch) => { - await previousPromise - await Promise.all(nextBatch.map((batch) => batch())) + progress += 1 / files.length toast( - , - { id: toastId, closeButton: false, position: 'top-right' } + , + { id: toastId, closeButton: false, position: 'top-right', duration: Infinity } ) - }, Promise.resolve()) + } - if (!hasErrors) { + if (failedFiles === 0) { toast.success(`Successfully renamed folder to ${newName}`, { id: toastId, closeButton: true, duration: SONNER_DEFAULT_DURATION, }) } else { - toast.error(`Renamed folder to ${newName} with some errors`, { - id: toastId, - closeButton: true, - duration: SONNER_DEFAULT_DURATION, - }) + toast.error( +
+

+ Renamed folder to {newName} with {failedFiles} error{failedFiles > 1 ? 's' : ''} +

+

+ You may try again to rename the folder {originalName} to {newName} +

+
, + { + id: toastId, + closeButton: true, + duration: Infinity, + } + ) } if (state.openedFolders[columnIndex]?.name === folder.name) { diff --git a/packages/ui/src/components/shadcn/ui/sonner-progress.tsx b/packages/ui/src/components/shadcn/ui/sonner-progress.tsx index d349947ac03..643d06f92f9 100644 --- a/packages/ui/src/components/shadcn/ui/sonner-progress.tsx +++ b/packages/ui/src/components/shadcn/ui/sonner-progress.tsx @@ -18,11 +18,13 @@ export const SonnerProgress = ({ progressPrefix, action, message, + description = 'Please do not close the browser', }: { progress: number progressPrefix?: string action?: React.ReactNode message: string + description?: string }) => (
@@ -36,7 +38,7 @@ export const SonnerProgress = ({
- Please do not close the browser + {description} {action}