Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/files/FilesPage.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ const FilesPage = ({
failedPins: failedPins || [],
filesPathInfo,
selected,
modalOpen: modals.show !== null,
onSelect: (name, isSelected) => {
if (Array.isArray(name)) {
if (isSelected) {
Expand Down
11 changes: 8 additions & 3 deletions src/files/files-grid/files-grid.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,12 @@ interface FilesGridPropsConnected extends FilesGridProps {
onSelect: (fileName: string | string[], isSelected: boolean) => void
filesIsFetching: boolean
selected: string[]
modalOpen: boolean
}

const FilesGrid = ({
files, pins = [], remotePins = [], pendingPins = [], failedPins = [], filesPathInfo, t, onRemove, onRename, onNavigate, onAddFiles,
onMove, handleContextMenuClick, filesIsFetching, onSetPinning, onDismissFailedPin, selected = [], onSelect
onMove, handleContextMenuClick, filesIsFetching, onSetPinning, onDismissFailedPin, selected = [], onSelect, modalOpen = false
}: FilesGridPropsConnected) => {
const [focused, setFocused] = useState<string | null>(null)
const filesRefs = useRef<Record<string, HTMLDivElement>>({})
Expand Down Expand Up @@ -67,6 +68,11 @@ const FilesGrid = ({
}, [onSelect])

const keyHandler = useCallback((e: KeyboardEvent) => {
// Don't handle keyboard events when a modal is open
if (modalOpen) {
return
}

const focusedFile = focused == null ? null : files.find(el => el.name === focused)

gridRef.current?.focus?.()
Expand Down Expand Up @@ -148,8 +154,7 @@ const FilesGrid = ({
}
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [files, focused])
}, [files, focused, selected, onSelect, onRename, onRemove, onNavigate, handleSelect, modalOpen])

useEffect(() => {
if (filesIsFetching) return
Expand Down
21 changes: 18 additions & 3 deletions test/e2e/grid-view.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -126,25 +126,40 @@ test.describe('Files grid view', () => {
const folder = page.locator('.grid-file[title$="/"], .grid-file[data-type="directory"]').first()
const folderName = await folder.getAttribute('title')

// Press ArrowRight to focus the first item
await page.keyboard.press('ArrowRight')
// Wait for the focused element to appear using proper Playwright waiting
await page.locator('.grid-file.focused').waitFor({ state: 'visible', timeout: 5000 })

// Navigate to the folder (may need multiple presses)
for (let i = 0; i < 5; i++) {
const focusedItem = page.locator('.grid-file.focused')
await focusedItem.waitFor({ state: 'visible', timeout: 5000 })

const focusedTitle = await focusedItem.getAttribute('title') || ''

if (focusedTitle === folderName || focusedTitle.endsWith('/')) {
break
}
await page.keyboard.press('ArrowRight')
// Small wait for focus to update
await page.waitForTimeout(100)
}

// Store current URL to detect navigation
const currentUrl = page.url()

// Press Enter to open folder
await page.keyboard.press('Enter')

// Verify we're inside a folder (wait for navigation)
await page.waitForTimeout(1000)
// Wait for navigation using proper Playwright methods
await page.waitForFunction(
(url) => window.location.href !== url,
currentUrl,
{ timeout: 5000 }
)

// Verify navigation happened (URL changed or breadcrumb updated)
await expect(page.locator('.joyride-files-breadcrumbs')).toContainText(`Files/${folderName}`)
await expect(page.locator('.joyride-files-breadcrumbs')).toContainText(`Files/${folderName}`, { timeout: 5000 })
})
})
15 changes: 14 additions & 1 deletion test/e2e/settings.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,29 @@ async function checkClassWithTimeout (page, element, className, maxWaitTime = 16
* @param {string} expectedClass - The expected class after submission.
*/
async function submitGatewayAndCheck (page, inputElement, submitButton, gatewayURL, expectedClass) {
// Clear the input first to ensure a clean state
await inputElement.click({ clickCount: 3 }) // Select all text
await inputElement.fill(gatewayURL)

// Give time for async validation to complete
await page.waitForTimeout(500)

// Check if the submit button is not null, and click it only if it's available
if (submitButton) {
const buttonId = await submitButton.evaluate(el => el.id)
// Use locator API which handles re-renders automatically
const submitBtn = page.locator(`#${buttonId}`)
// Wait for button to be enabled after input validation

// Wait for button to be visible first
await submitBtn.waitFor({ state: 'visible', timeout: 10000 })

// Wait for the button to become enabled (validation must complete)
await expect(submitBtn).toBeEnabled({ timeout: 10000 })

// Now click the enabled button
await submitBtn.click()
}

const hasExpectedClass = await checkClassWithTimeout(page, inputElement, expectedClass)
expect(hasExpectedClass).toBe(true)
}
Expand Down
2 changes: 1 addition & 1 deletion test/helpers/grid.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ const selectViewMode = async (page, mode) => {
const navigateToFilesPage = async (page) => {
await page.goto(webuiUrl + '#/files')
await waitForIpfsStats()
await page.waitForSelector('.files-grid, .FilesList')
await page.waitForSelector('.files-grid, .FilesList', { timeout: 60000 })
}

/**
Expand Down