Skip to content

Commit

Permalink
fix: renterd files mode navigation
Browse files Browse the repository at this point in the history
  • Loading branch information
alexfreska committed Mar 1, 2024
1 parent e7a887b commit ca00b44
Show file tree
Hide file tree
Showing 6 changed files with 107 additions and 68 deletions.
5 changes: 5 additions & 0 deletions .changeset/tough-shrimps-protect.md
@@ -0,0 +1,5 @@
---
'renterd': patch
---

Fixed an issue navigating back to the active explorer mode from the uploads list.
11 changes: 7 additions & 4 deletions apps/renterd/components/Files/FilesExplorerModeContextMenu.tsx
Expand Up @@ -6,12 +6,15 @@ import {
} from '@siafoundation/design-system'
import { CloudUpload16, Earth16, Folder16 } from '@siafoundation/react-icons'
import { useFilesManager } from '../../contexts/filesManager'
import { useUploads } from '../../contexts/uploads'

export function FilesExplorerModeContextMenu() {
const { activeExplorerMode, setExplorerModeDirectory, setExplorerModeFlat } =
useFilesManager()
const { isViewingUploads, navigateToUploads } = useUploads()
const {
activeExplorerMode,
setExplorerModeDirectory,
setExplorerModeFlat,
isViewingUploads,
navigateToUploads,
} = useFilesManager()

return (
<DropdownMenu
Expand Down
9 changes: 3 additions & 6 deletions apps/renterd/components/TransfersBar.tsx
Expand Up @@ -8,12 +8,9 @@ import { useUploads } from '../contexts/uploads'

export function TransfersBar() {
const { isUnlockedAndAuthedRoute } = useAppSettings()
const { downloadsList, downloadCancel } = useFilesManager()
const {
pageCount: uploadsPageCount,
navigateToUploads,
isViewingUploads,
} = useUploads()
const { downloadsList, downloadCancel, isViewingUploads, navigateToUploads } =
useFilesManager()
const { pageCount: uploadsPageCount } = useUploads()
const [maximized, setMaximized] = useState<boolean>(true)

const isActiveUploads = !!uploadsPageCount
Expand Down
101 changes: 68 additions & 33 deletions apps/renterd/contexts/filesManager/index.spec.tsx
@@ -1,4 +1,4 @@
import { render, act, waitFor } from '@testing-library/react'
import { render, act } from '@testing-library/react'
import { setupServer } from 'msw/node'
import { NextAppCsr } from '@siafoundation/design-system'
import { FilesManagerProvider, useFilesManager, FilesManagerState } from '.'
Expand All @@ -9,15 +9,14 @@ import {
mockMatchMedia,
} from '../../mock/mock'
// eslint-disable-next-line @typescript-eslint/no-var-requires
const { usePathname, useAppRouter } = require('@siafoundation/next')
const { usePathname, useAppRouter, useParams } = require('@siafoundation/next')

// NOTE: Update to use a functional test router after migrating to vitest.
jest.mock('@siafoundation/next', () => {
const push = jest.fn()
return {
useAppRouter: jest.fn().mockReturnValue({
query: {},
push,
push: jest.fn(),
}),
useParams: jest.fn().mockReturnValue({ path: [] }),
usePathname: jest.fn().mockReturnValue('/files'),
Expand All @@ -33,6 +32,7 @@ beforeAll(() => {
server.listen()
})
beforeEach(() => {
jest.clearAllMocks()
localStorage.clear()
})
afterEach(() => server.resetHandlers())
Expand All @@ -41,58 +41,88 @@ afterAll(() => server.close())
describe('filesManager', () => {
it('directory mode navigates to directory with file filter', async () => {
useAppRouter.mockClear()
usePathname.mockReturnValue('/files/default/foo/bar/baz')
useParams.mockReturnValue({
bucket: 'default',
path: ['foo', 'bar', 'baz'],
})
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
const context = mountProvider()
const {
activeExplorerMode,
fileNamePrefixFilter,
navigateToModeSpecificFiltering,
} = context.state
expect(activeExplorerMode).toBe('directory')
expect(context.state.activeExplorerMode).toBe('directory')
act(() => {
navigateToModeSpecificFiltering('/default/photos/cats')
})
waitFor(() => {
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/files/default/photos')
expect(fileNamePrefixFilter).toBe('cats')
context.state.navigateToModeSpecificFiltering('/default/photos/cats')
})
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/buckets/default/files/photos')
expect(context.state.fileNamePrefixFilter).toBe('cats')
})
it('toggling to flat explorer mode applies the active directory as a filter', async () => {
useAppRouter.mockClear()
usePathname.mockReturnValue('/files/default/foo/bar/baz')
useParams.mockReturnValue({
bucket: 'default',
path: ['foo', 'bar', 'baz'],
})
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
const context = mountProvider()
expect(context.state.activeExplorerMode).toBe('directory')
act(() => {
context.state.setExplorerModeFlat()
})
waitFor(() => {
expect(context.state.activeExplorerMode).toBe('flat')
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/files/default')
expect(context.state.fileNamePrefixFilter).toBe('/foo/bar/baz')
})
expect(context.state.activeExplorerMode).toBe('flat')
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
expect(context.state.fileNamePrefixFilter).toBe('foo/bar/baz/')
})
it('toggling from flat mode to directory clears the file filter', async () => {
useAppRouter.mockClear()
usePathname.mockReturnValue('/files/foo/bar/baz')
useParams.mockReturnValue({
bucket: 'default',
path: ['foo', 'bar', 'baz'],
})
usePathname.mockReturnValue('/buckets/default/files/foo/bar/baz')
const context = mountProvider()
act(() => {
context.state.setExplorerModeFlat()
})
waitFor(() => {
expect(context.state.activeExplorerMode).toBe('flat')
expect(context.state.fileNamePrefixFilter).toBe('/foo/bar/baz')
expect(context.state.activeExplorerMode).toBe('flat')
expect(context.state.fileNamePrefixFilter).toBe('foo/bar/baz/')
act(() => {
context.state.setExplorerModeDirectory()
})
expect(context.state.activeExplorerMode).toBe('directory')
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
expect(context.state.fileNamePrefixFilter).toBe('')
})
it('does not routes if mode already active', async () => {
useAppRouter.mockClear()
useParams.mockReturnValue({
bucket: 'default',
path: [],
})
usePathname.mockReturnValue('/buckets/default/files')
const context = mountProvider()
act(() => {
context.state.setExplorerModeDirectory()
})
waitFor(() => {
expect(context.state.activeExplorerMode).toBe('directory')
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/files/default')
expect(context.state.fileNamePrefixFilter).toBe('cats')
expect(context.state.activeExplorerMode).toBe('directory')
const pushCount = getRouterPushCallCount()
expect(pushCount).toBe(0)
expect(context.state.fileNamePrefixFilter).toBe('')
})
it('routes to active mode if viewing uploads', async () => {
useAppRouter.mockClear()
useParams.mockReturnValue({
bucket: 'default',
})
usePathname.mockReturnValue('/buckets/default/uploads')
const context = mountProvider()
act(() => {
context.state.setExplorerModeDirectory()
})
expect(context.state.activeExplorerMode).toBe('directory')
const lastPushCallParams = getLastRouterPushCallParams()
expect(lastPushCallParams[0]).toBe('/buckets/default/files/')
expect(context.state.fileNamePrefixFilter).toBe('')
})
})

Expand Down Expand Up @@ -125,6 +155,11 @@ function mountProvider() {
return context
}

function getRouterPushCallCount() {
const mockPush = useAppRouter.mock.results.slice(-1)[0]
return mockPush?.value.push.mock.calls.length
}

function getLastRouterPushCallParams() {
const mockPush = useAppRouter.mock.results.slice(-1)[0]
const lastPushCallParams = mockPush?.value.push.mock.calls.slice(-1)[0]
Expand Down
25 changes: 22 additions & 3 deletions apps/renterd/contexts/filesManager/index.tsx
@@ -1,7 +1,7 @@
'use client'

import { useServerFilters, useTableState } from '@siafoundation/design-system'
import { useParams, useAppRouter } from '@siafoundation/next'
import { useParams, useAppRouter, usePathname } from '@siafoundation/next'
import { createContext, useCallback, useContext, useMemo } from 'react'
import { columns } from '../filesDirectory/columns'
import {
Expand Down Expand Up @@ -155,21 +155,37 @@ function useFilesManagerMain() {
]
)

const uploadsRoute = routes.buckets.uploads.replace(
'[bucket]',
activeBucketName
)

const navigateToUploads = useCallback(() => {
if (!activeBucket) {
return
}
router.push(uploadsRoute)
}, [activeBucket, uploadsRoute, router])

const pathname = usePathname()
const isViewingUploads = activeBucketName && pathname.startsWith(uploadsRoute)

const setExplorerModeDirectory = useCallback(async () => {
if (activeExplorerMode === 'directory') {
if (!isViewingUploads && activeExplorerMode === 'directory') {
return
}
setActiveDirectoryAndFileNamePrefix([activeBucketName], undefined)
setActiveExplorerMode('directory')
}, [
isViewingUploads,
activeExplorerMode,
activeBucketName,
setActiveExplorerMode,
setActiveDirectoryAndFileNamePrefix,
])

const setExplorerModeFlat = useCallback(async () => {
if (activeExplorerMode === 'flat') {
if (!isViewingUploads && activeExplorerMode === 'flat') {
return
}
setActiveDirectoryAndFileNamePrefix(
Expand All @@ -178,6 +194,7 @@ function useFilesManagerMain() {
)
setActiveExplorerMode('flat')
}, [
isViewingUploads,
activeExplorerMode,
activeBucketName,
activeDirectoryPath,
Expand All @@ -189,10 +206,12 @@ function useFilesManagerMain() {
isViewingBuckets,
isViewingABucket,
isViewingRootOfABucket,
isViewingUploads,
buckets,
activeBucket,
activeBucketName,
activeDirectory,
navigateToUploads,
setActiveDirectory,
setActiveDirectoryAndFileNamePrefix,
activeDirectoryPath,
Expand Down
24 changes: 2 additions & 22 deletions apps/renterd/contexts/uploads/index.tsx
Expand Up @@ -3,24 +3,22 @@ import {
useDatasetEmptyState,
useServerFilters,
} from '@siafoundation/design-system'
import { useAppRouter, usePathname, useSearchParams } from '@siafoundation/next'
import { useSearchParams } from '@siafoundation/next'
import {
useMultipartUploadAbort,
useMultipartUploadListUploads,
} from '@siafoundation/react-renterd'
import { createContext, useCallback, useContext, useMemo } from 'react'
import { createContext, useContext, useMemo } from 'react'
import { columnsDefaultVisible, defaultSortField, sortOptions } from './types'
import { columns } from './columns'
import { join, getFilename } from '../../lib/paths'
import { useFilesManager } from '../filesManager'
import { ObjectUploadData } from '../filesManager/types'
import { routes } from '../../config/routes'

const defaultLimit = 50

function useUploadsMain() {
const { uploadsMap, activeBucket } = useFilesManager()
const router = useAppRouter()
const params = useSearchParams()
const limit = Number(params.get('limit') || defaultLimit)
const marker = params.get('marker')
Expand Down Expand Up @@ -111,27 +109,9 @@ function useUploadsMain() {
filters
)

const uploadsRoute = routes.buckets.uploads.replace(
'[bucket]',
activeBucket?.name
)

const pathname = usePathname()
const isViewingUploads = activeBucket && pathname.startsWith(uploadsRoute)

const navigateToUploads = useCallback(() => {
if (!activeBucket) {
return
}
router.push(uploadsRoute)
}, [activeBucket, uploadsRoute, router])

return {
navigateToUploads,
isViewingUploads,
dataState,
limit,
marker,
nextMarker: response.data?.nextUploadIDMarker,
hasMore: response.data?.hasMore,
isLoading: response.isLoading,
Expand Down

0 comments on commit ca00b44

Please sign in to comment.