Skip to content

Commit 9ded153

Browse files
authored
Mitigate race condition when fetching folder contents storage (supabase#36363)
* Mitigate race condition when fetching folder contents storage * Fix
1 parent 886fca7 commit 9ded153

File tree

6 files changed

+65
-20
lines changed

6 files changed

+65
-20
lines changed

apps/studio/components/to-be-cleaned/Storage/EmptyBucketModal.tsx

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ export const EmptyBucketModal = ({ visible = false, bucket, onClose }: EmptyBuck
1919
const { mutate: emptyBucket, isLoading } = useBucketEmptyMutation({
2020
onSuccess: async () => {
2121
if (bucket === undefined) return
22-
await fetchFolderContents({ folderId: bucket.id, folderName: bucket.name, index: -1 })
22+
await fetchFolderContents({
23+
bucketId: bucket.id,
24+
folderId: bucket.id,
25+
folderName: bucket.name,
26+
index: -1,
27+
})
2328
toast.success(`Successfully deleted bucket ${bucket!.name}`)
2429
onClose()
2530
},

apps/studio/components/to-be-cleaned/Storage/StorageExplorer/FileExplorerRow.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import type { ItemRenderer } from 'components/ui/InfiniteList'
2222
import { useCheckPermissions } from 'hooks/misc/useCheckPermissions'
2323
import { BASE_PATH } from 'lib/constants'
2424
import { formatBytes } from 'lib/helpers'
25+
import { toast } from 'sonner'
2526
import { useStorageExplorerStateSnapshot } from 'state/storage-explorer'
2627
import {
2728
Checkbox,
@@ -50,6 +51,7 @@ import { StorageItem, StorageItemWithColumn } from '../Storage.types'
5051
import FileExplorerRowEditing from './FileExplorerRowEditing'
5152
import { copyPathToFolder, downloadFile } from './StorageExplorer.utils'
5253
import { useCopyUrl } from './useCopyUrl'
54+
import { useSelectedBucket } from './useSelectedBucket'
5355

5456
export const RowIcon = ({
5557
view,
@@ -114,6 +116,7 @@ const FileExplorerRow: ItemRenderer<StorageItem, FileExplorerRowProps> = ({
114116
openedFolders = [],
115117
}) => {
116118
const { ref: projectRef, bucketId } = useParams()
119+
const { bucket } = useSelectedBucket()
117120

118121
const {
119122
selectedBucket,
@@ -152,11 +155,18 @@ const FileExplorerRow: ItemRenderer<StorageItem, FileExplorerRowProps> = ({
152155
}
153156

154157
const onSelectFolder = async (columnIndex: number, folder: StorageItem) => {
158+
if (!bucket) return toast.error('Unable to retrieve bucket details')
159+
155160
setSelectedFilePreview(undefined)
156161
clearSelectedItems(columnIndex + 1)
157162
popOpenedFoldersAtIndex(columnIndex - 1)
158163
pushOpenedFolderAtIndex(folder, columnIndex)
159-
await fetchFolderContents({ folderId: folder.id, folderName: folder.name, index: columnIndex })
164+
await fetchFolderContents({
165+
bucketId: bucket.id,
166+
folderId: folder.id,
167+
folderName: folder.name,
168+
index: columnIndex,
169+
})
160170
}
161171

162172
const onCheckItem = (isShiftKeyHeld: boolean) => {

apps/studio/components/to-be-cleaned/Storage/StorageExplorer/StorageExplorer.tsx

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,15 @@ const StorageExplorer = ({ bucket }: StorageExplorerProps) => {
6767
if (!currentFolder) {
6868
// At root of bucket
6969
await fetchFolderContents({
70+
bucketId: bucket.id,
7071
folderId: bucket.id,
7172
folderName: bucket.name,
7273
index: -1,
7374
searchString: itemSearchString,
7475
})
7576
} else {
7677
await fetchFolderContents({
78+
bucketId: bucket.id,
7779
folderId: currentFolder.id,
7880
folderName: currentFolder.name,
7981
index: currentFolderIdx,
@@ -83,18 +85,33 @@ const StorageExplorer = ({ bucket }: StorageExplorerProps) => {
8385
} else {
8486
if (!currentFolder) {
8587
// At root of bucket
86-
await fetchFolderContents({ folderId: bucket.id, folderName: bucket.name, index: -1 })
88+
await fetchFolderContents({
89+
bucketId: bucket.id,
90+
folderId: bucket.id,
91+
folderName: bucket.name,
92+
index: -1,
93+
})
8794
} else {
8895
await fetchFolderContents({
96+
bucketId: bucket.id,
8997
folderId: currentFolder.id,
9098
folderName: currentFolder.name,
9199
index: currentFolderIdx,
92100
})
93101
}
94102
}
95103
} else if (view === STORAGE_VIEWS.COLUMNS) {
96-
const paths = openedFolders.map((folder) => folder.name)
97-
fetchFoldersByPath({ paths, searchString: itemSearchString, showLoading: true })
104+
if (openedFolders.length > 0) {
105+
const paths = openedFolders.map((folder) => folder.name)
106+
fetchFoldersByPath({ paths, searchString: itemSearchString, showLoading: true })
107+
} else {
108+
await fetchFolderContents({
109+
bucketId: bucket.id,
110+
folderId: bucket.id,
111+
folderName: bucket.name,
112+
index: -1,
113+
})
114+
}
98115
}
99116
}
100117

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { useParams } from 'common'
2+
import { useBucketsQuery } from 'data/storage/buckets-query'
3+
4+
export const useSelectedBucket = () => {
5+
const { ref, bucketId } = useParams()
6+
7+
const { data: buckets = [], isSuccess, isError, error } = useBucketsQuery({ projectRef: ref })
8+
const bucket = buckets.find((b) => b.id === bucketId)
9+
10+
return { bucket, isSuccess, isError, error }
11+
}

apps/studio/pages/project/[ref]/storage/buckets/[bucketId].tsx

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
import { useParams } from 'common'
2-
import { find } from 'lodash'
32

43
import DefaultLayout from 'components/layouts/DefaultLayout'
54
import { useProjectContext } from 'components/layouts/ProjectLayout/ProjectContext'
65
import StorageBucketsError from 'components/layouts/StorageLayout/StorageBucketsError'
76
import StorageLayout from 'components/layouts/StorageLayout/StorageLayout'
87
import { StorageExplorer } from 'components/to-be-cleaned/Storage'
9-
import { useBucketsQuery } from 'data/storage/buckets-query'
8+
import { useSelectedBucket } from 'components/to-be-cleaned/Storage/StorageExplorer/useSelectedBucket'
109
import { useStorageExplorerStateSnapshot } from 'state/storage-explorer'
1110
import type { NextPageWithLayout } from 'types'
1211

1312
const PageLayout: NextPageWithLayout = () => {
14-
const { ref, bucketId } = useParams()
13+
const { bucketId } = useParams()
1514
const { project } = useProjectContext()
1615
const { projectRef } = useStorageExplorerStateSnapshot()
17-
18-
const { data, isSuccess, isError, error } = useBucketsQuery({ projectRef: ref })
19-
const buckets = data ?? []
20-
const bucket = find(buckets, { id: bucketId })
16+
const { bucket, error, isSuccess, isError } = useSelectedBucket()
2117

2218
if (!project || !projectRef) return null
2319

apps/studio/state/storage-explorer.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ import { InlineLink } from 'components/ui/InlineLink'
3434
import { configKeys } from 'data/config/keys'
3535
import { getAPIKeys, useProjectSettingsV2Query } from 'data/config/project-settings-v2-query'
3636
import { ProjectStorageConfigResponse } from 'data/config/project-storage-config-query'
37-
import type { Project } from 'data/projects/project-detail-query'
3837
import { getQueryClient } from 'data/query-client'
3938
import { deleteBucketObject } from 'data/storage/bucket-object-delete-mutation'
4039
import { downloadBucketObject } from 'data/storage/bucket-object-download-mutation'
@@ -208,12 +207,6 @@ function createStorageExplorerState({
208207
localStorage.setItem(localStorageKey, JSON.stringify({ view, sortBy, sortByOrder }))
209208
},
210209

211-
openBucket: async (bucket: Bucket) => {
212-
const { id, name } = bucket
213-
state.setSelectedBucket(bucket)
214-
await state.fetchFolderContents({ folderId: id, folderName: name, index: -1 })
215-
},
216-
217210
// Functions that manage the UI of the Storage Explorer
218211

219212
getLatestColumnIndex: () => {
@@ -226,6 +219,17 @@ function createStorageExplorerState({
226219
})
227220
},
228221

222+
openBucket: async (bucket: Bucket) => {
223+
const { id, name } = bucket
224+
state.setSelectedBucket(bucket)
225+
await state.fetchFolderContents({
226+
bucketId: bucket.id,
227+
folderId: id,
228+
folderName: name,
229+
index: -1,
230+
})
231+
},
232+
229233
// ======== Folders CRUD ========
230234

231235
getPathAlongOpenedFolders: (includeBucket = true) => {
@@ -305,11 +309,13 @@ function createStorageExplorerState({
305309
},
306310

307311
fetchFolderContents: async ({
312+
bucketId,
308313
folderId,
309314
folderName,
310315
index,
311316
searchString,
312317
}: {
318+
bucketId: string
313319
folderId: string | null
314320
folderName: string
315321
index: number
@@ -340,8 +346,8 @@ function createStorageExplorerState({
340346
try {
341347
const data = await listBucketObjects(
342348
{
349+
bucketId,
343350
projectRef: state.projectRef,
344-
bucketId: state.selectedBucket.id,
345351
path: prefix,
346352
options,
347353
},

0 commit comments

Comments
 (0)