From 2bb17b5510f110842338068de1a818d0038abb21 Mon Sep 17 00:00:00 2001 From: Alex Freska Date: Thu, 12 Dec 2024 16:56:47 -0500 Subject: [PATCH] fix(renterd): first file download no bucket error --- .changeset/late-points-learn.md | 5 + apps/renterd-e2e/src/specs/files.spec.ts | 23 ++++ .../renterd/contexts/config/transform.spec.ts | 1 + .../contexts/filesManager/downloads.tsx | 118 ++++++++++-------- 4 files changed, 93 insertions(+), 54 deletions(-) create mode 100644 .changeset/late-points-learn.md diff --git a/.changeset/late-points-learn.md b/.changeset/late-points-learn.md new file mode 100644 index 000000000..ed8877ec7 --- /dev/null +++ b/.changeset/late-points-learn.md @@ -0,0 +1,5 @@ +--- +'renterd': patch +--- + +Fixed an issue where the first attempt to download a file would show a bucket not found error. diff --git a/apps/renterd-e2e/src/specs/files.spec.ts b/apps/renterd-e2e/src/specs/files.spec.ts index e8d02765a..e20801353 100644 --- a/apps/renterd-e2e/src/specs/files.spec.ts +++ b/apps/renterd-e2e/src/specs/files.spec.ts @@ -111,6 +111,29 @@ test('can upload, rename, and delete files', async ({ page }) => { await deleteBucket(page, bucketName) }) +test('can upload and download a file', async ({ page }) => { + const bucketName = 'files-test' + const fileName = 'sample.txt' + const filePath = `${bucketName}/${fileName}` + + // Create bucket. + await navigateToBuckets({ page }) + await createBucket(page, bucketName) + await openBucket(page, bucketName) + + // Upload. + await dragAndDropFileFromSystem(page, fileName) + await expect(page.getByText('100%')).toBeVisible() + await fileInList(page, filePath) + + // Download. + await openFileContextMenu(page, filePath) + await page.getByRole('menuitem', { name: 'Download file' }).click() + await expect( + page.getByRole('button', { name: 'Active downloads' }) + ).toBeVisible() +}) + test('can rename and delete a directory with contents', async ({ page }) => { test.setTimeout(120_000) const bucketName = 'files-test' diff --git a/apps/renterd/contexts/config/transform.spec.ts b/apps/renterd/contexts/config/transform.spec.ts index d858bf3d8..2887dad36 100644 --- a/apps/renterd/contexts/config/transform.spec.ts +++ b/apps/renterd/contexts/config/transform.spec.ts @@ -464,6 +464,7 @@ describe('tansforms', () => { function buildAllResponses() { return { autopilotState: { + enabled: true, migrating: true, migratingLastStart: new Date().toISOString(), scanning: true, diff --git a/apps/renterd/contexts/filesManager/downloads.tsx b/apps/renterd/contexts/filesManager/downloads.tsx index 314e5e808..2126b00b9 100644 --- a/apps/renterd/contexts/filesManager/downloads.tsx +++ b/apps/renterd/contexts/filesManager/downloads.tsx @@ -85,68 +85,78 @@ export function useDownloads() { download.controller.abort() }, []) - const downloadFiles = async (files: FullPath[]) => { - files.forEach(async (path) => { - let isDone = false - const bucketName = getBucketFromPath(path) - const key = getKeyFromPath(path) - const bucket = buckets.data?.find((b) => b.name === bucketName) - if (!bucket) { - triggerErrorToast({ title: 'Bucket not found', body: bucketName }) - return - } - const name = getFilename(path) - - if (downloadsMap[path]) { - triggerErrorToast({ title: 'Already downloading file', body: path }) - return - } + const downloadFiles = useCallback( + async (files: FullPath[]) => { + files.forEach(async (path) => { + let isDone = false + const bucketName = getBucketFromPath(path) + const key = getKeyFromPath(path) + const bucket = buckets.data?.find((b) => b.name === bucketName) + if (!bucket) { + triggerErrorToast({ title: 'Bucket not found', body: bucketName }) + return + } + const name = getFilename(path) - const controller = new AbortController() - const onDownloadProgress = throttle((e) => { - if (isDone) { + if (downloadsMap[path]) { + triggerErrorToast({ title: 'Already downloading file', body: path }) return } - updateDownloadProgress({ + + const controller = new AbortController() + const onDownloadProgress = throttle((e) => { + if (isDone) { + return + } + updateDownloadProgress({ + path, + loaded: e.loaded, + size: e.total, + }) + }, 2000) + initDownloadProgress({ path, - loaded: e.loaded, - size: e.total, + key, + name, + bucket, + loaded: 0, + size: 1, + controller, }) - }, 2000) - initDownloadProgress({ - path, - key, - name, - bucket, - loaded: 0, - size: 1, - controller, - }) - const response = await download.get(name, { - params: bucketAndKeyParamsFromPath(path), - config: { - axios: { - onDownloadProgress, - signal: controller.signal, + const response = await download.get(name, { + params: bucketAndKeyParamsFromPath(path), + config: { + axios: { + onDownloadProgress, + signal: controller.signal, + }, }, - }, - }) - isDone = true - if (response.error) { - if (response.error === 'canceled') { - triggerToast({ title: 'File download canceled' }) + }) + isDone = true + if (response.error) { + if (response.error === 'canceled') { + triggerToast({ title: 'File download canceled' }) + } else { + triggerErrorToast({ + title: 'Error downloading file', + body: response.error, + }) + } + removeDownload(path) } else { - triggerErrorToast({ - title: 'Error downloading file', - body: response.error, - }) + removeDownload(path) } - removeDownload(path) - } else { - removeDownload(path) - } - }) - } + }) + }, + [ + buckets.data, + download, + downloadsMap, + initDownloadProgress, + removeDownload, + updateDownloadProgress, + ] + ) const downloadsList = useMemo( () => Object.entries(downloadsMap).map((d) => d[1]),