@@ -39,6 +39,11 @@ import { exportFile } from "@/lib/export-file"
3939import { getContentType } from "@/lib/mime-types"
4040import { formatBytes } from "@/lib/functions"
4141import { buildBucketPath } from "@/lib/bucket-path"
42+ import {
43+ createObjectListScope ,
44+ shouldApplyObjectListResponse ,
45+ shouldResetObjectListPagination ,
46+ } from "@/lib/object-list-state"
4247import {
4348 resolveBucketVersioningState ,
4449 shouldForceDeleteObjects ,
@@ -104,14 +109,34 @@ export function ObjectList({
104109 const [ deleteAllVersions , setDeleteAllVersions ] = React . useState ( false )
105110
106111 const prefix = decodeURIComponent ( path )
112+ const listScope = React . useMemo (
113+ ( ) =>
114+ createObjectListScope ( {
115+ bucket,
116+ prefix,
117+ pageSize,
118+ showDeleted,
119+ } ) ,
120+ [ bucket , prefix , pageSize , showDeleted ] ,
121+ )
107122 const canBulkDelete = canCapability ( "objects.bulkDelete" , { bucket, prefix } )
108123 const canBulkDownload = canCapability ( "objects.download" , { bucket, prefix } )
109124
110125 const bucketPath = React . useCallback ( ( p ?: string | string [ ] ) => buildBucketPath ( bucket , p ) , [ bucket ] )
126+ const requestIdRef = React . useRef ( 0 )
127+ const activeScopeRef = React . useRef ( listScope )
128+ const previousScopeRef = React . useRef ( listScope )
129+
130+ React . useEffect ( ( ) => {
131+ activeScopeRef . current = listScope
132+ } , [ listScope ] )
111133
112134 const fetchObjects = React . useCallback (
113- async ( tokenOverride ?: string ) => {
114- const token = tokenOverride !== undefined ? tokenOverride : continuationToken
135+ async ( options ?: { token ?: string ; resetPagination ?: boolean } ) => {
136+ const token = options ?. resetPagination ? undefined : ( options ?. token ?? continuationToken )
137+ const requestId = requestIdRef . current + 1
138+ requestIdRef . current = requestId
139+ const requestScope = activeScopeRef . current
115140 setLoading ( true )
116141 try {
117142 const response = await listObject ( bucket , prefix || undefined , pageSize , token , {
@@ -124,6 +149,17 @@ export function ObjectList({
124149 NextContinuationToken ?: string
125150 }
126151
152+ if (
153+ ! shouldApplyObjectListResponse ( {
154+ requestId,
155+ activeRequestId : requestIdRef . current ,
156+ requestScope,
157+ activeScope : activeScopeRef . current ,
158+ } )
159+ ) {
160+ return
161+ }
162+
127163 setNextToken ( r . NextContinuationToken )
128164
129165 const prefixItems : ObjectRow [ ] = ( r . CommonPrefixes ?? [ ] ) . map ( ( item ) => ( {
@@ -142,7 +178,18 @@ export function ObjectList({
142178
143179 setData ( [ ...prefixItems , ...objectItems ] )
144180 } finally {
145- setTimeout ( ( ) => setLoading ( false ) , 200 )
181+ window . setTimeout ( ( ) => {
182+ if (
183+ shouldApplyObjectListResponse ( {
184+ requestId,
185+ activeRequestId : requestIdRef . current ,
186+ requestScope,
187+ activeScope : activeScopeRef . current ,
188+ } )
189+ ) {
190+ setLoading ( false )
191+ }
192+ } , 200 )
146193 }
147194 } ,
148195 [ bucket , prefix , pageSize , continuationToken , showDeleted , listObject ] ,
@@ -151,17 +198,19 @@ export function ObjectList({
151198 const prevRefreshTriggerRef = React . useRef ( refreshTrigger )
152199
153200 React . useEffect ( ( ) => {
201+ const shouldResetPagination = shouldResetObjectListPagination ( previousScopeRef . current , listScope )
202+ previousScopeRef . current = listScope
154203 const isRefresh = prevRefreshTriggerRef . current !== refreshTrigger
155204 prevRefreshTriggerRef . current = refreshTrigger
156205
157- if ( isRefresh ) {
206+ if ( isRefresh || shouldResetPagination ) {
158207 setContinuationToken ( undefined )
159208 setTokenHistory ( [ ] )
160- void fetchObjects ( undefined )
209+ void fetchObjects ( { resetPagination : true } )
161210 } else {
162211 void fetchObjects ( )
163212 }
164- } , [ bucket , prefix , pageSize , continuationToken , showDeleted , refreshTrigger , fetchObjects ] )
213+ } , [ listScope , bucket , prefix , pageSize , continuationToken , showDeleted , refreshTrigger , fetchObjects ] )
165214
166215 const prevDeleteTaskIdsRef = React . useRef < Set < string > > ( new Set ( ) )
167216
@@ -175,7 +224,7 @@ export function ObjectList({
175224 const anyActive = currentDeleteTasks . some ( ( t ) => [ "pending" , "running" ] . includes ( t . status ) )
176225 if ( ! anyActive ) {
177226 // No more active delete tasks, refresh the list
178- void fetchObjects ( )
227+ void fetchObjects ( { resetPagination : true } )
179228 }
180229 }
181230
@@ -576,7 +625,7 @@ export function ObjectList({
576625 ) : null }
577626 </ >
578627 ) : null }
579- < Button variant = "outline" onClick = { ( ) => ( onRefresh ?? fetchObjects ) ( ) } >
628+ < Button variant = "outline" onClick = { ( ) => ( onRefresh ? onRefresh ( ) : void fetchObjects ( { resetPagination : true } ) ) } >
580629 < RiRefreshLine className = "size-4" />
581630 < span > { t ( "Refresh" ) } </ span >
582631 </ Button >
0 commit comments