fix: image previews getting stuck in list view when paginating (#12062)

### What?
In the List View, row data related to images and relationships gets
stuck when you go from one page to another.

### Why?
The `key` we are providing is not unique and not triggering the DOM to
update.

### How?
Uses the `row id` as a unique key prop to each table row to ensure
proper re-rendering of rows during pagination.

#### Testing
Adds e2e test to `upload` test suite. You can recreate the issue using
the `upload` test suite and new `list view preview` collection.
This commit is contained in:
Jessica Chowdhury
2025-04-10 13:18:10 +01:00
committed by GitHub
parent 101f7658f7
commit a0fb3353c6
4 changed files with 78 additions and 1 deletions

View File

@@ -40,7 +40,14 @@ export const Table: React.FC<Props> = ({ appearance, columns, data }) => {
<tbody>
{data &&
data.map((row, rowIndex) => (
<tr className={`row-${rowIndex + 1}`} key={rowIndex}>
<tr
className={`row-${rowIndex + 1}`}
key={
typeof row.id === 'string' || typeof row.id === 'number'
? String(row.id)
: rowIndex
}
>
{activeColumns.map((col, colIndex) => {
const { accessor } = col

View File

@@ -1,3 +1,5 @@
import type { CollectionSlug } from 'payload'
import path from 'path'
import { getFileByPath } from 'payload'
import { fileURLToPath } from 'url'
@@ -18,6 +20,7 @@ import {
enlargeSlug,
focalNoSizesSlug,
hideFileInputOnCreateSlug,
listViewPreviewSlug,
mediaSlug,
mediaWithoutCacheTagsSlug,
mediaWithoutRelationPreviewSlug,
@@ -760,6 +763,26 @@ export default buildConfigWithDefaults({
},
],
},
{
slug: listViewPreviewSlug,
fields: [
{
name: 'title',
type: 'text',
},
{
name: 'imageUpload',
type: 'upload',
relationTo: mediaWithRelationPreviewSlug,
displayPreview: true,
},
{
name: 'imageRelationship',
type: 'relationship',
relationTo: mediaWithRelationPreviewSlug,
},
],
},
],
onInit: async (payload) => {
const uploadsDir = path.resolve(dirname, './media')
@@ -932,6 +955,22 @@ export default buildConfigWithDefaults({
},
file: imageFile,
})
for (let i = 0; i < 20; i++) {
const data = {
title: `List View Preview ${i + 1}`,
imageUpload: uploadedImageWithPreview,
imageRelationship: uploadedImageWithPreview,
}
if (i > 15) {
data.imageUpload = ''
data.imageRelationship = ''
}
await payload.create({
collection: listViewPreviewSlug as CollectionSlug,
data,
})
}
},
serverURL: undefined,
upload: {

View File

@@ -31,6 +31,7 @@ import {
customUploadFieldSlug,
focalOnlySlug,
hideFileInputOnCreateSlug,
listViewPreviewSlug,
mediaSlug,
mediaWithoutCacheTagsSlug,
relationPreviewSlug,
@@ -55,6 +56,7 @@ let relationURL: AdminUrlUtil
let adminThumbnailSizeURL: AdminUrlUtil
let adminThumbnailFunctionURL: AdminUrlUtil
let adminThumbnailWithSearchQueriesURL: AdminUrlUtil
let listViewPreviewURL: AdminUrlUtil
let mediaWithoutCacheTagsSlugURL: AdminUrlUtil
let focalOnlyURL: AdminUrlUtil
let withMetadataURL: AdminUrlUtil
@@ -89,6 +91,7 @@ describe('Uploads', () => {
serverURL,
adminThumbnailWithSearchQueries,
)
listViewPreviewURL = new AdminUrlUtil(serverURL, listViewPreviewSlug)
mediaWithoutCacheTagsSlugURL = new AdminUrlUtil(serverURL, mediaWithoutCacheTagsSlug)
focalOnlyURL = new AdminUrlUtil(serverURL, focalOnlySlug)
withMetadataURL = new AdminUrlUtil(serverURL, withMetadataSlug)
@@ -1400,4 +1403,30 @@ describe('Uploads', () => {
await expect(thumbnail).toHaveAttribute('src', '/api/focal-only/file/small.png')
})
})
test('should show correct image preview or placeholder after paginating', async () => {
await page.goto(listViewPreviewURL.list)
const firstRow = page.locator('.row-1')
const imageUploadCell = firstRow.locator('.cell-imageUpload .relationship-cell')
await expect(imageUploadCell).toHaveText('<No Image Upload>')
const imageRelationshipCell = firstRow.locator('.cell-imageRelationship .relationship-cell')
await expect(imageRelationshipCell).toHaveText('<No Image Relationship>')
const pageTwoButton = page.locator('.paginator__page', { hasText: '2' })
await expect(pageTwoButton).toBeVisible()
await pageTwoButton.click()
const imageUploadImg = imageUploadCell.locator('.thumbnail')
await expect(imageUploadImg).toBeVisible()
await expect(imageRelationshipCell).toHaveText('image-1.png')
const pageOneButton = page.locator('.paginator__page', { hasText: '1' })
await expect(pageOneButton).toBeVisible()
await pageOneButton.click()
await expect(imageUploadCell).toHaveText('<No Image Upload>')
await expect(imageRelationshipCell).toHaveText('<No Image Relationship>')
})
})

View File

@@ -22,3 +22,5 @@ export const withMetadataSlug = 'with-meta-data'
export const withoutMetadataSlug = 'without-meta-data'
export const withOnlyJPEGMetadataSlug = 'with-only-jpeg-meta-data'
export const customFileNameMediaSlug = 'custom-file-name-media'
export const listViewPreviewSlug = 'list-view-preview'