fix(ui): use full image url for upload previews instead of thumbnail url (#11435)

This commit is contained in:
Patrik
2025-02-28 12:47:02 -05:00
committed by GitHub
parent 9e97319c6f
commit 96d1d90e78
6 changed files with 149 additions and 46 deletions

View File

@@ -67,14 +67,22 @@ export function UploadComponentHasMany(props: Props) {
> >
{fileDocs.map(({ relationTo, value }, index) => { {fileDocs.map(({ relationTo, value }, index) => {
const id = String(value.id) const id = String(value.id)
const url: string = value.thumbnailURL || value.url
let src: string let src: string
let thumbnailSrc: string
if (url) { if (value.url) {
try { try {
src = new URL(url, serverURL).toString() src = new URL(value.url, serverURL).toString()
} catch { } catch {
src = `${serverURL}${url}` src = `${serverURL}${value.url}`
}
}
if (value.thumbnailURL) {
try {
thumbnailSrc = new URL(value.thumbnailURL, serverURL).toString()
} catch {
thumbnailSrc = `${serverURL}${value.thumbnailURL}`
} }
} }
@@ -118,6 +126,7 @@ export function UploadComponentHasMany(props: Props) {
onRemove={() => removeItem(index)} onRemove={() => removeItem(index)}
reloadDoc={reloadDoc} reloadDoc={reloadDoc}
src={src} src={src}
thumbnailSrc={thumbnailSrc || src}
withMeta={false} withMeta={false}
x={value?.width as number} x={value?.width as number}
y={value?.height as number} y={value?.height as number}

View File

@@ -29,13 +29,23 @@ export function UploadComponentHasOne(props: Props) {
const { relationTo, value } = fileDoc const { relationTo, value } = fileDoc
const id = String(value?.id) const id = String(value?.id)
const url: string = value.thumbnailURL || value.url
let src: string let src: string
let thumbnailSrc: string
if (value.url) {
try { try {
src = new URL(url, serverURL).toString() src = new URL(value.url, serverURL).toString()
} catch { } catch {
src = `${serverURL}${url}` src = `${serverURL}${value.url}`
}
}
if (value.thumbnailURL) {
try {
thumbnailSrc = new URL(value.thumbnailURL, serverURL).toString()
} catch {
thumbnailSrc = `${serverURL}${value.thumbnailURL}`
}
} }
return ( return (
@@ -52,6 +62,7 @@ export function UploadComponentHasOne(props: Props) {
onRemove={onRemove} onRemove={onRemove}
reloadDoc={reloadDoc} reloadDoc={reloadDoc}
src={src} src={src}
thumbnailSrc={thumbnailSrc || src}
x={value?.width as number} x={value?.width as number}
y={value?.height as number} y={value?.height as number}
/> />

View File

@@ -27,6 +27,7 @@ type Props = {
readonly onRemove: () => void readonly onRemove: () => void
readonly reloadDoc: ReloadDoc readonly reloadDoc: ReloadDoc
readonly src: string readonly src: string
readonly thumbnailSrc: string
readonly withMeta?: boolean readonly withMeta?: boolean
readonly x?: number readonly x?: number
readonly y?: number readonly y?: number
@@ -45,6 +46,7 @@ export function RelationshipContent(props: Props) {
onRemove, onRemove,
reloadDoc, reloadDoc,
src, src,
thumbnailSrc,
withMeta = true, withMeta = true,
x, x,
y, y,
@@ -86,7 +88,7 @@ export function RelationshipContent(props: Props) {
alt={alt} alt={alt}
className={`${baseClass}__thumbnail`} className={`${baseClass}__thumbnail`}
filename={filename} filename={filename}
fileSrc={src} fileSrc={thumbnailSrc}
size="small" size="small"
/> />
<div className={`${baseClass}__details`}> <div className={`${baseClass}__details`}>

View File

@@ -41,6 +41,17 @@ export const Uploads1: CollectionConfig = {
}, },
}, },
}, },
{
type: 'upload',
name: 'hasManyThumbnailUpload',
relationTo: 'admin-thumbnail-size',
hasMany: true,
},
{
type: 'upload',
name: 'singleThumbnailUpload',
relationTo: 'admin-thumbnail-size',
},
{ {
type: 'richText', type: 'richText',
name: 'richText', name: 'richText',

View File

@@ -696,6 +696,72 @@ describe('Uploads', () => {
await expect(clientText).toHaveText('This text was rendered on the client') await expect(clientText).toHaveText('This text was rendered on the client')
}) })
test('should show original image url on a single upload card for an upload with adminThumbnail defined', async () => {
await page.goto(uploadsOne.create)
const singleThumbnailButton = page.locator('#field-singleThumbnailUpload button', {
hasText: exactText('Create New'),
})
await singleThumbnailButton.click()
const singleThumbnailModal = page.locator('[id^="doc-drawer_admin-thumbnail-size"]')
await expect(singleThumbnailModal).toBeVisible()
await page.setInputFiles(
'[id^="doc-drawer_admin-thumbnail-size"] input[type="file"]',
path.resolve(dirname, './test-image.png'),
)
const filename = page.locator('[id^="doc-drawer_admin-thumbnail-size"] .file-field__filename')
await expect(filename).toHaveValue('test-image.png')
await page.waitForSelector('[id^="doc-drawer_admin-thumbnail-size"] #action-save')
await page.locator('[id^="doc-drawer_admin-thumbnail-size"] #action-save').click()
await expect(page.locator('.payload-toast-container')).toContainText('successfully')
const href = await page.locator('#field-singleThumbnailUpload a').getAttribute('href')
// Ensure the URL starts correctly
expect(href).toMatch(/^\/api\/admin-thumbnail-size\/file\/test-image(-\d+)?\.png$/i)
// Ensure no "-100x100" or any similar suffix
expect(href).not.toMatch(/-\d+x\d+\.png$/)
})
test('should show original image url on a hasMany upload card for an upload with adminThumbnail defined', async () => {
await page.goto(uploadsOne.create)
const hasManyThumbnailButton = page.locator('#field-hasManyThumbnailUpload button', {
hasText: exactText('Create New'),
})
await hasManyThumbnailButton.click()
const hasManyThumbnailModal = page.locator('#bulk-upload-drawer-slug-1')
await expect(hasManyThumbnailModal).toBeVisible()
await page.setInputFiles('#bulk-upload-drawer-slug-1 .dropzone input[type="file"]', [
path.resolve(dirname, './test-image.png'),
])
const saveButton = page.locator('.bulk-upload--actions-bar__saveButtons button')
await saveButton.click()
await page.waitForSelector('#field-hasManyThumbnailUpload .upload--has-many__dragItem')
const itemCount = await page
.locator('#field-hasManyThumbnailUpload .upload--has-many__dragItem')
.count()
expect(itemCount).toEqual(1)
await page.waitForSelector('#field-hasManyThumbnailUpload .upload--has-many__dragItem a')
const href = await page
.locator('#field-hasManyThumbnailUpload .upload--has-many__dragItem a')
.getAttribute('href')
expect(href).toMatch(/^\/api\/admin-thumbnail-size\/file\/test-image(-\d+)?\.png$/i)
expect(href).not.toMatch(/-\d+x\d+\.png$/)
})
describe('bulk uploads', () => { describe('bulk uploads', () => {
test('should bulk upload multiple files', async () => { test('should bulk upload multiple files', async () => {
// Navigate to the upload creation page // Navigate to the upload creation page

View File

@@ -1002,6 +1002,8 @@ export interface Uploads1 {
id: string; id: string;
hasManyUpload?: (string | Uploads2)[] | null; hasManyUpload?: (string | Uploads2)[] | null;
singleUpload?: (string | null) | Uploads2; singleUpload?: (string | null) | Uploads2;
hasManyThumbnailUpload?: (string | AdminThumbnailSize)[] | null;
singleThumbnailUpload?: (string | null) | AdminThumbnailSize;
richText?: { richText?: {
root: { root: {
type: string; type: string;
@@ -1049,42 +1051,6 @@ export interface Uploads2 {
focalX?: number | null; focalX?: number | null;
focalY?: number | null; focalY?: number | null;
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "admin-thumbnail-function".
*/
export interface AdminThumbnailFunction {
id: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "admin-thumbnail-with-search-queries".
*/
export interface AdminThumbnailWithSearchQuery {
id: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "admin-thumbnail-size". * via the `definition` "admin-thumbnail-size".
@@ -1121,6 +1087,42 @@ export interface AdminThumbnailSize {
}; };
}; };
} }
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "admin-thumbnail-function".
*/
export interface AdminThumbnailFunction {
id: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "admin-thumbnail-with-search-queries".
*/
export interface AdminThumbnailWithSearchQuery {
id: string;
updatedAt: string;
createdAt: string;
url?: string | null;
thumbnailURL?: string | null;
filename?: string | null;
mimeType?: string | null;
filesize?: number | null;
width?: number | null;
height?: number | null;
focalX?: number | null;
focalY?: number | null;
}
/** /**
* This interface was referenced by `Config`'s JSON-Schema * This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "optional-file". * via the `definition` "optional-file".
@@ -2344,6 +2346,8 @@ export interface ExternallyServedMediaSelect<T extends boolean = true> {
export interface Uploads1Select<T extends boolean = true> { export interface Uploads1Select<T extends boolean = true> {
hasManyUpload?: T; hasManyUpload?: T;
singleUpload?: T; singleUpload?: T;
hasManyThumbnailUpload?: T;
singleThumbnailUpload?: T;
richText?: T; richText?: T;
updatedAt?: T; updatedAt?: T;
createdAt?: T; createdAt?: T;