chore(ui): simplifies adminThumbnail functionality (#5615)
This commit is contained in:
16
test/admin/collections/Upload.ts
Normal file
16
test/admin/collections/Upload.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import { uploadCollectionSlug } from '../slugs.js'
|
||||
|
||||
export const UploadCollection: CollectionConfig = {
|
||||
slug: uploadCollectionSlug,
|
||||
upload: {
|
||||
adminThumbnail: () => 'https://payloadcms.com/images/universal-truth.jpg',
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
@@ -11,6 +11,7 @@ import { CollectionGroup2B } from './collections/Group2B.js'
|
||||
import { CollectionHidden } from './collections/Hidden.js'
|
||||
import { CollectionNoApiView } from './collections/NoApiView.js'
|
||||
import { Posts } from './collections/Posts.js'
|
||||
import { UploadCollection } from './collections/Upload.js'
|
||||
import { Users } from './collections/Users.js'
|
||||
import { AdminButton } from './components/AdminButton/index.js'
|
||||
import { AfterDashboard } from './components/AfterDashboard/index.js'
|
||||
@@ -74,6 +75,7 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
},
|
||||
collections: [
|
||||
UploadCollection,
|
||||
Posts,
|
||||
Users,
|
||||
CollectionHidden,
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
export const usersCollectionSlug = 'users' as const
|
||||
export const customViews1CollectionSlug = 'custom-views-one' as const
|
||||
export const customViews2CollectionSlug = 'custom-views-two' as const
|
||||
export const geoCollectionSlug = 'geo' as const
|
||||
export const postsCollectionSlug = 'posts' as const
|
||||
export const group1Collection1Slug = 'group-one-collection-ones' as const
|
||||
export const group1Collection2Slug = 'group-one-collection-twos' as const
|
||||
export const group2Collection1Slug = 'group-two-collection-ones' as const
|
||||
export const group2Collection2Slug = 'group-two-collection-twos' as const
|
||||
export const hiddenCollectionSlug = 'hidden-collection' as const
|
||||
export const noApiViewCollectionSlug = 'collection-no-api-view' as const
|
||||
export const usersCollectionSlug = 'users'
|
||||
export const customViews1CollectionSlug = 'custom-views-one'
|
||||
export const customViews2CollectionSlug = 'custom-views-two'
|
||||
export const geoCollectionSlug = 'geo'
|
||||
export const postsCollectionSlug = 'posts'
|
||||
export const group1Collection1Slug = 'group-one-collection-ones'
|
||||
export const group1Collection2Slug = 'group-one-collection-twos'
|
||||
export const group2Collection1Slug = 'group-two-collection-ones'
|
||||
export const group2Collection2Slug = 'group-two-collection-twos'
|
||||
export const hiddenCollectionSlug = 'hidden-collection'
|
||||
export const noApiViewCollectionSlug = 'collection-no-api-view'
|
||||
export const uploadCollectionSlug = 'uploads'
|
||||
export const collectionSlugs = [
|
||||
usersCollectionSlug,
|
||||
customViews1CollectionSlug,
|
||||
@@ -23,12 +24,12 @@ export const collectionSlugs = [
|
||||
noApiViewCollectionSlug,
|
||||
]
|
||||
|
||||
export const customGlobalViews1GlobalSlug = 'custom-global-views-one' as const
|
||||
export const customGlobalViews2GlobalSlug = 'custom-global-views-two' as const
|
||||
export const globalSlug = 'global' as const
|
||||
export const group1GlobalSlug = 'group-globals-one' as const
|
||||
export const group2GlobalSlug = 'group-globals-two' as const
|
||||
export const hiddenGlobalSlug = 'hidden-global' as const
|
||||
export const customGlobalViews1GlobalSlug = 'custom-global-views-one'
|
||||
export const customGlobalViews2GlobalSlug = 'custom-global-views-two'
|
||||
export const globalSlug = 'global'
|
||||
export const group1GlobalSlug = 'group-globals-one'
|
||||
export const group2GlobalSlug = 'group-globals-two'
|
||||
export const hiddenGlobalSlug = 'hidden-global'
|
||||
export const noApiViewGlobalSlug = 'global-no-api-view'
|
||||
export const globalSlugs = [
|
||||
customGlobalViews1GlobalSlug,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { getPayloadHMR } from '@payloadcms/next/utilities'
|
||||
import { createServer } from 'http'
|
||||
import nextImport from 'next'
|
||||
import path from 'path'
|
||||
import { type Payload } from 'payload'
|
||||
import { type Payload } from 'payload/types'
|
||||
import { wait } from 'payload/utilities'
|
||||
import { parse } from 'url'
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@
|
||||
"@payloadcms/ui/templates/*": ["./packages/ui/src/templates/*/index.tsx"],
|
||||
"@payloadcms/ui/utilities/*": ["./packages/ui/src/utilities/*.ts"],
|
||||
"@payloadcms/ui/scss": ["./packages/ui/src/scss.scss"],
|
||||
"@payloadcms/ui/scss/app.scss": ["./packages/ui/src/scss/app.scss"]
|
||||
"@payloadcms/ui/scss/app.scss": ["./packages/ui/src/scss/app.scss"],
|
||||
"payload/types": ["./packages/payload/src/exports/types/index.ts"],
|
||||
}
|
||||
},
|
||||
"exclude": ["dist", "build", "node_modules", ".eslintrc.js", "dist/**/*.js", "**/dist/**/*.js"],
|
||||
|
||||
17
test/uploads/collections/AdminThumbnailFunction/index.ts
Normal file
17
test/uploads/collections/AdminThumbnailFunction/index.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import { adminThumbnailFunctionSlug } from '../../shared.js'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
export const AdminThumbnailFunction: CollectionConfig = {
|
||||
slug: adminThumbnailFunctionSlug,
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, 'test/uploads/media'),
|
||||
adminThumbnail: () => 'https://payloadcms.com/images/universal-truth.jpg',
|
||||
},
|
||||
fields: [],
|
||||
}
|
||||
29
test/uploads/collections/AdminThumbnailSize/index.ts
Normal file
29
test/uploads/collections/AdminThumbnailSize/index.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import path from 'path'
|
||||
import { fileURLToPath } from 'url'
|
||||
|
||||
import { adminThumbnailSizeSlug } from '../../shared.js'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
export const AdminThumbnailSize: CollectionConfig = {
|
||||
slug: adminThumbnailSizeSlug,
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, 'test/uploads/media'),
|
||||
adminThumbnail: 'small',
|
||||
imageSizes: [
|
||||
{
|
||||
name: 'small',
|
||||
width: 100,
|
||||
height: 100,
|
||||
},
|
||||
{
|
||||
name: 'medium',
|
||||
width: 200,
|
||||
height: 200,
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [],
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
'use client'
|
||||
import type React from 'react'
|
||||
|
||||
import { useAdminThumbnail } from '@payloadcms/ui/hooks/useAdminThumbnail'
|
||||
|
||||
type TypeWithFile = {
|
||||
filename: string
|
||||
filesize: number
|
||||
mimeType: string
|
||||
} & Record<string, unknown>
|
||||
|
||||
function docHasFilename(doc: Record<string, unknown>): doc is TypeWithFile {
|
||||
if (typeof doc === 'object' && 'filename' in doc) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
export const adminThumbnailSrc = '/media/image-640x480.png'
|
||||
|
||||
function getThumbnailSrc({ doc }) {
|
||||
if (docHasFilename(doc)) {
|
||||
if (doc.mimeType.startsWith('image/')) {
|
||||
return null // Fallback to default admin thumbnail if image
|
||||
}
|
||||
return adminThumbnailSrc // Use custom thumbnail if not image
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
export const RegisterAdminThumbnailFn: React.FC = () => {
|
||||
void useAdminThumbnail(getThumbnailSrc)
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
import type { CollectionConfig } from 'payload/types'
|
||||
|
||||
import { fileURLToPath } from 'node:url'
|
||||
import path from 'path'
|
||||
|
||||
import { RegisterAdminThumbnailFn } from './RegisterThumbnailFn.js'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
export const AdminThumbnailCol: CollectionConfig = {
|
||||
slug: 'admin-thumbnail',
|
||||
upload: {
|
||||
staticDir: path.resolve(dirname, '../../media'),
|
||||
adminThumbnail: RegisterAdminThumbnailFn,
|
||||
},
|
||||
fields: [],
|
||||
}
|
||||
@@ -5,9 +5,10 @@ import { fileURLToPath } from 'url'
|
||||
import { buildConfigWithDefaults } from '../buildConfigWithDefaults.js'
|
||||
import { devUser } from '../credentials.js'
|
||||
import removeFiles from '../helpers/removeFiles.js'
|
||||
import { AdminThumbnailFunction } from './collections/AdminThumbnailFunction/index.js'
|
||||
import { AdminThumbnailSize } from './collections/AdminThumbnailSize/index.js'
|
||||
import { Uploads1 } from './collections/Upload1/index.js'
|
||||
import { Uploads2 } from './collections/Upload2/index.js'
|
||||
import { AdminThumbnailCol } from './collections/admin-thumbnail/index.js'
|
||||
import {
|
||||
audioSlug,
|
||||
enlargeSlug,
|
||||
@@ -416,7 +417,8 @@ export default buildConfigWithDefaults({
|
||||
},
|
||||
Uploads1,
|
||||
Uploads2,
|
||||
AdminThumbnailCol,
|
||||
AdminThumbnailFunction,
|
||||
AdminThumbnailSize,
|
||||
{
|
||||
slug: 'optional-file',
|
||||
fields: [],
|
||||
@@ -508,7 +510,7 @@ export default buildConfigWithDefaults({
|
||||
|
||||
// Create admin thumbnail media
|
||||
await payload.create({
|
||||
collection: AdminThumbnailCol.slug,
|
||||
collection: AdminThumbnailSize.slug,
|
||||
data: {},
|
||||
file: {
|
||||
...audioFile,
|
||||
@@ -517,12 +519,21 @@ export default buildConfigWithDefaults({
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: AdminThumbnailCol.slug,
|
||||
collection: AdminThumbnailSize.slug,
|
||||
data: {},
|
||||
file: {
|
||||
...imageFile,
|
||||
name: `thumb-${imageFile.name}`,
|
||||
},
|
||||
})
|
||||
|
||||
await payload.create({
|
||||
collection: AdminThumbnailFunction.slug,
|
||||
data: {},
|
||||
file: {
|
||||
...imageFile,
|
||||
name: `function-image-${imageFile.name}`,
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
|
||||
@@ -12,7 +12,13 @@ import { initPageConsoleErrorCatch, saveDocAndAssert } from '../helpers.js'
|
||||
import { AdminUrlUtil } from '../helpers/adminUrlUtil.js'
|
||||
import { initPayloadE2E } from '../helpers/initPayloadE2E.js'
|
||||
import { RESTClient } from '../helpers/rest.js'
|
||||
import { adminThumbnailSlug, audioSlug, mediaSlug, relationSlug } from './shared.js'
|
||||
import {
|
||||
adminThumbnailFunctionSlug,
|
||||
adminThumbnailSizeSlug,
|
||||
audioSlug,
|
||||
mediaSlug,
|
||||
relationSlug,
|
||||
} from './shared.js'
|
||||
const filename = fileURLToPath(import.meta.url)
|
||||
const dirname = path.dirname(filename)
|
||||
|
||||
@@ -24,7 +30,8 @@ let serverURL: string
|
||||
let mediaURL: AdminUrlUtil
|
||||
let audioURL: AdminUrlUtil
|
||||
let relationURL: AdminUrlUtil
|
||||
let adminThumbnailURL: AdminUrlUtil
|
||||
let adminThumbnailSizeURL: AdminUrlUtil
|
||||
let adminThumbnailFunctionURL: AdminUrlUtil
|
||||
|
||||
describe('uploads', () => {
|
||||
let page: Page
|
||||
@@ -39,7 +46,8 @@ describe('uploads', () => {
|
||||
mediaURL = new AdminUrlUtil(serverURL, mediaSlug)
|
||||
audioURL = new AdminUrlUtil(serverURL, audioSlug)
|
||||
relationURL = new AdminUrlUtil(serverURL, relationSlug)
|
||||
adminThumbnailURL = new AdminUrlUtil(serverURL, adminThumbnailSlug)
|
||||
adminThumbnailSizeURL = new AdminUrlUtil(serverURL, adminThumbnailSizeSlug)
|
||||
adminThumbnailFunctionURL = new AdminUrlUtil(serverURL, adminThumbnailFunctionSlug)
|
||||
|
||||
const context = await browser.newContext()
|
||||
page = await context.newPage()
|
||||
@@ -196,6 +204,7 @@ describe('uploads', () => {
|
||||
|
||||
test('should restrict mimetype based on filterOptions', async () => {
|
||||
await page.goto(audioURL.edit(audioDoc.id))
|
||||
await page.waitForURL(audioURL.edit(audioDoc.id))
|
||||
|
||||
// remove the selection and open the list drawer
|
||||
await page.locator('.file-details__remove').click()
|
||||
@@ -210,16 +219,31 @@ describe('uploads', () => {
|
||||
.locator('[id^=doc-drawer_media_2_] .file-field__upload input[type="file"]')
|
||||
.setInputFiles(path.resolve(dirname, './image.png'))
|
||||
await page.locator('[id^=doc-drawer_media_2_] button#action-save').click()
|
||||
await expect(page.locator('.Toastify')).toContainText('successfully')
|
||||
await expect(page.locator('.Toastify .Toastify__toast--success')).toContainText('successfully')
|
||||
await page.locator('.Toastify .Toastify__toast--success .Toastify__close-button').click()
|
||||
|
||||
// save the document and expect an error
|
||||
await page.locator('button#action-save').click()
|
||||
await expect(page.locator('.Toastify')).toContainText('Please correct invalid fields.')
|
||||
await expect(page.locator('.Toastify .Toastify__toast--error')).toContainText(
|
||||
'Please correct invalid fields.',
|
||||
)
|
||||
})
|
||||
|
||||
test('Should execute adminThumbnail and provide thumbnail when set', async () => {
|
||||
await page.goto(adminThumbnailURL.list)
|
||||
await page.waitForURL(adminThumbnailURL.list)
|
||||
test('Should render adminThumbnail when using a function', async () => {
|
||||
await page.goto(adminThumbnailFunctionURL.list)
|
||||
await page.waitForURL(adminThumbnailFunctionURL.list)
|
||||
|
||||
// Ensure sure false or null shows generic file svg
|
||||
const genericUploadImage = page.locator('tr.row-1 .thumbnail img')
|
||||
await expect(genericUploadImage).toHaveAttribute(
|
||||
'src',
|
||||
'https://payloadcms.com/images/universal-truth.jpg',
|
||||
)
|
||||
})
|
||||
|
||||
test('Should render adminThumbnail when using a specific size', async () => {
|
||||
await page.goto(adminThumbnailSizeURL.list)
|
||||
await page.waitForURL(adminThumbnailSizeURL.list)
|
||||
|
||||
// Ensure sure false or null shows generic file svg
|
||||
const genericUploadImage = page.locator('tr.row-1 .thumbnail img')
|
||||
|
||||
@@ -10,7 +10,9 @@ export const enlargeSlug = 'enlarge'
|
||||
|
||||
export const reduceSlug = 'reduce'
|
||||
|
||||
export const adminThumbnailSlug = 'admin-thumbnail'
|
||||
export const adminThumbnailFunctionSlug = 'admin-thumbnail-function'
|
||||
|
||||
export const adminThumbnailSizeSlug = 'admin-thumbnail-size'
|
||||
|
||||
export const unstoredMediaSlug = 'unstored-media'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user