Skip to content

Commit 6270d73

Browse files
authored
perf: download only images and optimize image selection for upload list view, prioritize best-fit size (#11696)
### What? This PR optimizes how images are selected for display in the upload list view. It ensures that only image files are processed and selects the most appropriate size to minimize unnecessary downloads and improve performance. #### Previously: - Non-image files were being processed unnecessarily, despite not generating thumbnails. - Images without a `thumbnailURL` defaulted to their original full size, even when smaller, optimized versions were available. #### Now: - **Only images** are processed for thumbnails, avoiding redundant requests for non-images. - **The smallest available image within a target range** (`40px - 180px`) is prioritized for display. - **If no images fit within this range**, the logic selects: - The next smallest larger image (if available). - The **original** image if it is smaller than the next available larger size. - The largest **smaller** image if no better fit exists. ### Why? Prevents unnecessary downloads of non-image files, reduces bandwidth usage by selecting more efficient image sizes and improves load times and performance in the list view. ### How? - **Filters out non-image files** when determining which assets to display. - Uses a more precise selection algorithm to find the best-fit image size: - Prefers the smallest image within `40px - 180px`. - Falls back to the closest match above or below the range if no in-range image exists. - Ensures the original image is only used when it provides a better fit. Fixes #11690 Before (4.7mb transfer): ![chrome_2025-03-14_02-39-16](https://github.com/user-attachments/assets/4d87b0ae-164e-47c5-a426-43bd2083b725) After (129kb transfer): ![chrome_2025-03-14_01-01-19](https://github.com/user-attachments/assets/1cdab4ec-f3ad-40ae-9099-c8b789588ac7)
1 parent 427a5f1 commit 6270d73

File tree

2 files changed

+51
-4
lines changed

2 files changed

+51
-4
lines changed

packages/ui/src/elements/Table/DefaultCell/fields/File/index.tsx

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ import './index.scss'
1313

1414
const baseClass = 'file'
1515

16+
const targetThumbnailSizeMin = 40
17+
const targetThumbnailSizeMax = 180
18+
1619
export interface FileCellProps
1720
extends DefaultCellComponentProps<TextFieldClient | UploadFieldClient> {
1821
readonly collectionConfig: ClientCollectionConfig
@@ -28,6 +31,50 @@ export const FileCell: React.FC<FileCellProps> = ({
2831
const previewAllowed = fieldPreviewAllowed ?? collectionConfig.upload?.displayPreview ?? true
2932

3033
if (previewAllowed) {
34+
let fileSrc: string | undefined = rowData?.thumbnailURL ?? rowData?.url
35+
36+
if (
37+
rowData?.url &&
38+
!rowData?.thumbnailURL &&
39+
typeof rowData?.mimeType === 'string' &&
40+
rowData?.mimeType.startsWith('image') &&
41+
rowData?.sizes
42+
) {
43+
const sizes = Object.values<{ url?: string; width?: number }>(rowData.sizes)
44+
45+
const bestFit = sizes.reduce(
46+
(closest, current) => {
47+
if (!current.width || current.width < targetThumbnailSizeMin) {
48+
return closest
49+
}
50+
51+
if (current.width >= targetThumbnailSizeMin && current.width <= targetThumbnailSizeMax) {
52+
return !closest.width ||
53+
current.width < closest.width ||
54+
closest.width < targetThumbnailSizeMin ||
55+
closest.width > targetThumbnailSizeMax
56+
? current
57+
: closest
58+
}
59+
60+
if (
61+
!closest.width ||
62+
(!closest.original &&
63+
closest.width < targetThumbnailSizeMin &&
64+
current.width > closest.width) ||
65+
(closest.width > targetThumbnailSizeMax && current.width < closest.width)
66+
) {
67+
return current
68+
}
69+
70+
return closest
71+
},
72+
{ original: true, url: rowData?.url, width: rowData?.width },
73+
)
74+
75+
fileSrc = bestFit.url || fileSrc
76+
}
77+
3178
return (
3279
<div className={baseClass}>
3380
<Thumbnail
@@ -37,7 +84,7 @@ export const FileCell: React.FC<FileCellProps> = ({
3784
...rowData,
3885
filename,
3986
}}
40-
fileSrc={rowData?.thumbnailURL || rowData?.url}
87+
fileSrc={fileSrc}
4188
size="small"
4289
uploadConfig={collectionConfig?.upload}
4390
/>

packages/ui/src/elements/Thumbnail/index.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@ export type ThumbnailProps = {
2121
}
2222

2323
export const Thumbnail: React.FC<ThumbnailProps> = (props) => {
24-
const { className = '', doc: { filename } = {}, fileSrc, imageCacheTag, size } = props
24+
const { className = '', doc: { filename, mimeType } = {}, fileSrc, imageCacheTag, size } = props
2525
const [fileExists, setFileExists] = React.useState(undefined)
2626

2727
const classNames = [baseClass, `${baseClass}--size-${size || 'medium'}`, className].join(' ')
2828

2929
React.useEffect(() => {
30-
if (!fileSrc) {
30+
if (!fileSrc || (typeof mimeType === 'string' && !mimeType.startsWith('image'))) {
3131
setFileExists(false)
3232
return
3333
}
@@ -41,7 +41,7 @@ export const Thumbnail: React.FC<ThumbnailProps> = (props) => {
4141
img.onerror = () => {
4242
setFileExists(false)
4343
}
44-
}, [fileSrc])
44+
}, [fileSrc, mimeType])
4545

4646
let src: string = ''
4747

0 commit comments

Comments
 (0)