Skip to content

Commit ca00b44

Browse files
committed
fix: renterd files mode navigation
1 parent e7a887b commit ca00b44

File tree

6 files changed

+107
-68
lines changed

6 files changed

+107
-68
lines changed

.changeset/tough-shrimps-protect.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'renterd': patch
3+
---
4+
5+
Fixed an issue navigating back to the active explorer mode from the uploads list.

apps/renterd/components/Files/FilesExplorerModeContextMenu.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,15 @@ import {
66
} from '@siafoundation/design-system'
77
import { CloudUpload16, Earth16, Folder16 } from '@siafoundation/react-icons'
88
import { useFilesManager } from '../../contexts/filesManager'
9-
import { useUploads } from '../../contexts/uploads'
109

1110
export function FilesExplorerModeContextMenu() {
12-
const { activeExplorerMode, setExplorerModeDirectory, setExplorerModeFlat } =
13-
useFilesManager()
14-
const { isViewingUploads, navigateToUploads } = useUploads()
11+
const {
12+
activeExplorerMode,
13+
setExplorerModeDirectory,
14+
setExplorerModeFlat,
15+
isViewingUploads,
16+
navigateToUploads,
17+
} = useFilesManager()
1518

1619
return (
1720
<DropdownMenu

apps/renterd/components/TransfersBar.tsx

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,9 @@ import { useUploads } from '../contexts/uploads'
88

99
export function TransfersBar() {
1010
const { isUnlockedAndAuthedRoute } = useAppSettings()
11-
const { downloadsList, downloadCancel } = useFilesManager()
12-
const {
13-
pageCount: uploadsPageCount,
14-
navigateToUploads,
15-
isViewingUploads,
16-
} = useUploads()
11+
const { downloadsList, downloadCancel, isViewingUploads, navigateToUploads } =
12+
useFilesManager()
13+
const { pageCount: uploadsPageCount } = useUploads()
1714
const [maximized, setMaximized] = useState<boolean>(true)
1815

1916
const isActiveUploads = !!uploadsPageCount

apps/renterd/contexts/filesManager/index.spec.tsx

Lines changed: 68 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { render, act, waitFor } from '@testing-library/react'
1+
import { render, act } from '@testing-library/react'
22
import { setupServer } from 'msw/node'
33
import { NextAppCsr } from '@siafoundation/design-system'
44
import { FilesManagerProvider, useFilesManager, FilesManagerState } from '.'
@@ -9,15 +9,14 @@ import {
99
mockMatchMedia,
1010
} from '../../mock/mock'
1111
// eslint-disable-next-line @typescript-eslint/no-var-requires
12-
const { usePathname, useAppRouter } = require('@siafoundation/next')
12+
const { usePathname, useAppRouter, useParams } = require('@siafoundation/next')
1313

1414
// NOTE: Update to use a functional test router after migrating to vitest.
1515
jest.mock('@siafoundation/next', () => {
16-
const push = jest.fn()
1716
return {
1817
useAppRouter: jest.fn().mockReturnValue({
1918
query: {},
20-
push,
19+
push: jest.fn(),
2120
}),
2221
useParams: jest.fn().mockReturnValue({ path: [] }),
2322
usePathname: jest.fn().mockReturnValue('/files'),
@@ -33,6 +32,7 @@ beforeAll(() => {
3332
server.listen()
3433
})
3534
beforeEach(() => {
35+
jest.clearAllMocks()
3636
localStorage.clear()
3737
})
3838
afterEach(() => server.resetHandlers())
@@ -41,58 +41,88 @@ afterAll(() => server.close())
4141
describe('filesManager', () => {
4242
it('directory mode navigates to directory with file filter', async () => {
4343
useAppRouter.mockClear()
44-
usePathname.mockReturnValue('/files/default/foo/bar/baz')
44+
useParams.mockReturnValue({
45+
bucket: 'default',
46+
path: ['foo', 'bar', 'baz'],
47+
})
48+
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
4549
const context = mountProvider()
46-
const {
47-
activeExplorerMode,
48-
fileNamePrefixFilter,
49-
navigateToModeSpecificFiltering,
50-
} = context.state
51-
expect(activeExplorerMode).toBe('directory')
50+
expect(context.state.activeExplorerMode).toBe('directory')
5251
act(() => {
53-
navigateToModeSpecificFiltering('/default/photos/cats')
54-
})
55-
waitFor(() => {
56-
const lastPushCallParams = getLastRouterPushCallParams()
57-
expect(lastPushCallParams[0]).toBe('/files/default/photos')
58-
expect(fileNamePrefixFilter).toBe('cats')
52+
context.state.navigateToModeSpecificFiltering('/default/photos/cats')
5953
})
54+
const lastPushCallParams = getLastRouterPushCallParams()
55+
expect(lastPushCallParams[0]).toBe('/buckets/default/files/photos')
56+
expect(context.state.fileNamePrefixFilter).toBe('cats')
6057
})
6158
it('toggling to flat explorer mode applies the active directory as a filter', async () => {
6259
useAppRouter.mockClear()
63-
usePathname.mockReturnValue('/files/default/foo/bar/baz')
60+
useParams.mockReturnValue({
61+
bucket: 'default',
62+
path: ['foo', 'bar', 'baz'],
63+
})
64+
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
6465
const context = mountProvider()
6566
expect(context.state.activeExplorerMode).toBe('directory')
6667
act(() => {
6768
context.state.setExplorerModeFlat()
6869
})
69-
waitFor(() => {
70-
expect(context.state.activeExplorerMode).toBe('flat')
71-
const lastPushCallParams = getLastRouterPushCallParams()
72-
expect(lastPushCallParams[0]).toBe('/files/default')
73-
expect(context.state.fileNamePrefixFilter).toBe('/foo/bar/baz')
74-
})
70+
expect(context.state.activeExplorerMode).toBe('flat')
71+
const lastPushCallParams = getLastRouterPushCallParams()
72+
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
73+
expect(context.state.fileNamePrefixFilter).toBe('foo/bar/baz/')
7574
})
7675
it('toggling from flat mode to directory clears the file filter', async () => {
7776
useAppRouter.mockClear()
78-
usePathname.mockReturnValue('/files/foo/bar/baz')
77+
useParams.mockReturnValue({
78+
bucket: 'default',
79+
path: ['foo', 'bar', 'baz'],
80+
})
81+
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
7982
const context = mountProvider()
8083
act(() => {
8184
context.state.setExplorerModeFlat()
8285
})
83-
waitFor(() => {
84-
expect(context.state.activeExplorerMode).toBe('flat')
85-
expect(context.state.fileNamePrefixFilter).toBe('/foo/bar/baz')
86+
expect(context.state.activeExplorerMode).toBe('flat')
87+
expect(context.state.fileNamePrefixFilter).toBe('foo/bar/baz/')
88+
act(() => {
89+
context.state.setExplorerModeDirectory()
90+
})
91+
expect(context.state.activeExplorerMode).toBe('directory')
92+
const lastPushCallParams = getLastRouterPushCallParams()
93+
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
94+
expect(context.state.fileNamePrefixFilter).toBe('')
95+
})
96+
it('does not routes if mode already active', async () => {
97+
useAppRouter.mockClear()
98+
useParams.mockReturnValue({
99+
bucket: 'default',
100+
path: [],
86101
})
102+
usePathname.mockReturnValue('/buckets/default/files')
103+
const context = mountProvider()
87104
act(() => {
88105
context.state.setExplorerModeDirectory()
89106
})
90-
waitFor(() => {
91-
expect(context.state.activeExplorerMode).toBe('directory')
92-
const lastPushCallParams = getLastRouterPushCallParams()
93-
expect(lastPushCallParams[0]).toBe('/files/default')
94-
expect(context.state.fileNamePrefixFilter).toBe('cats')
107+
expect(context.state.activeExplorerMode).toBe('directory')
108+
const pushCount = getRouterPushCallCount()
109+
expect(pushCount).toBe(0)
110+
expect(context.state.fileNamePrefixFilter).toBe('')
111+
})
112+
it('routes to active mode if viewing uploads', async () => {
113+
useAppRouter.mockClear()
114+
useParams.mockReturnValue({
115+
bucket: 'default',
116+
})
117+
usePathname.mockReturnValue('/buckets/default/uploads')
118+
const context = mountProvider()
119+
act(() => {
120+
context.state.setExplorerModeDirectory()
95121
})
122+
expect(context.state.activeExplorerMode).toBe('directory')
123+
const lastPushCallParams = getLastRouterPushCallParams()
124+
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
125+
expect(context.state.fileNamePrefixFilter).toBe('')
96126
})
97127
})
98128

@@ -125,6 +155,11 @@ function mountProvider() {
125155
return context
126156
}
127157

158+
function getRouterPushCallCount() {
159+
const mockPush = useAppRouter.mock.results.slice(-1)[0]
160+
return mockPush?.value.push.mock.calls.length
161+
}
162+
128163
function getLastRouterPushCallParams() {
129164
const mockPush = useAppRouter.mock.results.slice(-1)[0]
130165
const lastPushCallParams = mockPush?.value.push.mock.calls.slice(-1)[0]

apps/renterd/contexts/filesManager/index.tsx

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
'use client'
22

33
import { useServerFilters, useTableState } from '@siafoundation/design-system'
4-
import { useParams, useAppRouter } from '@siafoundation/next'
4+
import { useParams, useAppRouter, usePathname } from '@siafoundation/next'
55
import { createContext, useCallback, useContext, useMemo } from 'react'
66
import { columns } from '../filesDirectory/columns'
77
import {
@@ -155,21 +155,37 @@ function useFilesManagerMain() {
155155
]
156156
)
157157

158+
const uploadsRoute = routes.buckets.uploads.replace(
159+
'[bucket]',
160+
activeBucketName
161+
)
162+
163+
const navigateToUploads = useCallback(() => {
164+
if (!activeBucket) {
165+
return
166+
}
167+
router.push(uploadsRoute)
168+
}, [activeBucket, uploadsRoute, router])
169+
170+
const pathname = usePathname()
171+
const isViewingUploads = activeBucketName && pathname.startsWith(uploadsRoute)
172+
158173
const setExplorerModeDirectory = useCallback(async () => {
159-
if (activeExplorerMode === 'directory') {
174+
if (!isViewingUploads && activeExplorerMode === 'directory') {
160175
return
161176
}
162177
setActiveDirectoryAndFileNamePrefix([activeBucketName], undefined)
163178
setActiveExplorerMode('directory')
164179
}, [
180+
isViewingUploads,
165181
activeExplorerMode,
166182
activeBucketName,
167183
setActiveExplorerMode,
168184
setActiveDirectoryAndFileNamePrefix,
169185
])
170186

171187
const setExplorerModeFlat = useCallback(async () => {
172-
if (activeExplorerMode === 'flat') {
188+
if (!isViewingUploads && activeExplorerMode === 'flat') {
173189
return
174190
}
175191
setActiveDirectoryAndFileNamePrefix(
@@ -178,6 +194,7 @@ function useFilesManagerMain() {
178194
)
179195
setActiveExplorerMode('flat')
180196
}, [
197+
isViewingUploads,
181198
activeExplorerMode,
182199
activeBucketName,
183200
activeDirectoryPath,
@@ -189,10 +206,12 @@ function useFilesManagerMain() {
189206
isViewingBuckets,
190207
isViewingABucket,
191208
isViewingRootOfABucket,
209+
isViewingUploads,
192210
buckets,
193211
activeBucket,
194212
activeBucketName,
195213
activeDirectory,
214+
navigateToUploads,
196215
setActiveDirectory,
197216
setActiveDirectoryAndFileNamePrefix,
198217
activeDirectoryPath,

apps/renterd/contexts/uploads/index.tsx

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,22 @@ import {
33
useDatasetEmptyState,
44
useServerFilters,
55
} from '@siafoundation/design-system'
6-
import { useAppRouter, usePathname, useSearchParams } from '@siafoundation/next'
6+
import { useSearchParams } from '@siafoundation/next'
77
import {
88
useMultipartUploadAbort,
99
useMultipartUploadListUploads,
1010
} from '@siafoundation/react-renterd'
11-
import { createContext, useCallback, useContext, useMemo } from 'react'
11+
import { createContext, useContext, useMemo } from 'react'
1212
import { columnsDefaultVisible, defaultSortField, sortOptions } from './types'
1313
import { columns } from './columns'
1414
import { join, getFilename } from '../../lib/paths'
1515
import { useFilesManager } from '../filesManager'
1616
import { ObjectUploadData } from '../filesManager/types'
17-
import { routes } from '../../config/routes'
1817

1918
const defaultLimit = 50
2019

2120
function useUploadsMain() {
2221
const { uploadsMap, activeBucket } = useFilesManager()
23-
const router = useAppRouter()
2422
const params = useSearchParams()
2523
const limit = Number(params.get('limit') || defaultLimit)
2624
const marker = params.get('marker')
@@ -111,27 +109,9 @@ function useUploadsMain() {
111109
filters
112110
)
113111

114-
const uploadsRoute = routes.buckets.uploads.replace(
115-
'[bucket]',
116-
activeBucket?.name
117-
)
118-
119-
const pathname = usePathname()
120-
const isViewingUploads = activeBucket && pathname.startsWith(uploadsRoute)
121-
122-
const navigateToUploads = useCallback(() => {
123-
if (!activeBucket) {
124-
return
125-
}
126-
router.push(uploadsRoute)
127-
}, [activeBucket, uploadsRoute, router])
128-
129112
return {
130-
navigateToUploads,
131-
isViewingUploads,
132113
dataState,
133114
limit,
134-
marker,
135115
nextMarker: response.data?.nextUploadIDMarker,
136116
hasMore: response.data?.hasMore,
137117
isLoading: response.isLoading,

0 commit comments

Comments
 (0)