Files
payloadcms/packages/payload/src/uploads/getBaseFields.ts
Patrik e1ea07441e feat: adds disableListColumn and disableListFilter to imageSize admin props (#13699)
### What?

Added support for `disableListColumn` and `disableListFilter` admin
properties on imageSize configurations that automatically apply to all
fields within the corresponding size group.

### Why?

Upload collections with multiple image sizes can clutter the admin list
view with many size-specific columns and filters. This feature allows
developers to selectively hide size fields from list views while keeping
them accessible in the document edit view.

### How?

Modified `getBaseFields.ts` to inherit admin properties from imageSize
configuration and apply them to all nested fields (url, width, height,
mimeType, filesize, filename) within each size group. The implementation
uses conditional spread operators to only apply these properties when
explicitly set to `true`, maintaining backward compatibility.
2025-09-09 11:56:57 -04:00

281 lines
7.2 KiB
TypeScript

import type { CollectionConfig } from '../collections/config/types.js'
import type { Config } from '../config/types.js'
import type { Field } from '../fields/config/types.js'
import type { UploadConfig } from './types.js'
import { mimeTypeValidator } from './mimeTypeValidator.js'
type GenerateURLArgs = {
collectionSlug: string
config: Config
filename?: string
}
const generateURL = ({ collectionSlug, config, filename }: GenerateURLArgs) => {
if (filename) {
return `${config.serverURL || ''}${config.routes?.api || ''}/${collectionSlug}/file/${encodeURIComponent(filename)}`
}
return undefined
}
type Options = {
collection: CollectionConfig
config: Config
}
export const getBaseUploadFields = ({ collection, config }: Options): Field[] => {
const uploadOptions: UploadConfig = typeof collection.upload === 'object' ? collection.upload : {}
const mimeType: Field = {
name: 'mimeType',
type: 'text',
admin: {
hidden: true,
readOnly: true,
},
label: 'MIME Type',
}
const thumbnailURL: Field = {
name: 'thumbnailURL',
type: 'text',
admin: {
hidden: true,
readOnly: true,
},
hooks: {
afterRead: [
({ originalDoc }) => {
const adminThumbnail =
typeof collection.upload !== 'boolean' ? collection.upload?.adminThumbnail : undefined
if (typeof adminThumbnail === 'function') {
return adminThumbnail({ doc: originalDoc })
}
if (
typeof adminThumbnail === 'string' &&
'sizes' in originalDoc &&
originalDoc.sizes?.[adminThumbnail]?.filename
) {
return generateURL({
collectionSlug: collection.slug,
config,
filename: originalDoc.sizes?.[adminThumbnail].filename as string,
})
}
return null
},
],
},
label: 'Thumbnail URL',
}
const width: Field = {
name: 'width',
type: 'number',
admin: {
hidden: true,
readOnly: true,
},
label: ({ t }) => t('upload:width'),
}
const height: Field = {
name: 'height',
type: 'number',
admin: {
hidden: true,
readOnly: true,
},
label: ({ t }) => t('upload:height'),
}
const filesize: Field = {
name: 'filesize',
type: 'number',
admin: {
hidden: true,
readOnly: true,
},
label: ({ t }) => t('upload:fileSize'),
}
const filename: Field = {
name: 'filename',
type: 'text',
admin: {
disableBulkEdit: true,
hidden: true,
readOnly: true,
},
index: true,
label: ({ t }) => t('upload:fileName'),
}
// Only set unique: true if the collection does not have a compound index
if (
collection.upload === true ||
(typeof collection.upload === 'object' && !collection.upload.filenameCompoundIndex)
) {
filename.unique = true
}
const url: Field = {
name: 'url',
type: 'text',
admin: {
hidden: true,
readOnly: true,
},
label: 'URL',
}
let uploadFields: Field[] = [
{
...url,
hooks: {
afterRead: [
({ data, value }) => {
if (value && !data?.filename) {
return value
}
return generateURL({
collectionSlug: collection.slug,
config,
filename: data?.filename,
})
},
],
},
},
thumbnailURL,
filename,
mimeType,
filesize,
width,
height,
]
// Add focal point fields if not disabled
if (
uploadOptions.focalPoint !== false ||
uploadOptions.imageSizes ||
uploadOptions.resizeOptions
) {
uploadFields = uploadFields.concat(
['focalX', 'focalY'].map((name) => {
return {
name,
type: 'number',
admin: {
disableListColumn: true,
disableListFilter: true,
hidden: true,
},
}
}),
)
}
if (uploadOptions.mimeTypes) {
mimeType.validate = mimeTypeValidator(uploadOptions.mimeTypes)
}
// In Payload v4, image size subfields (`url`, `width`, `height`, etc.) should
// default to `disableListColumn: true` and `disableListFilter: true`
// to avoid cluttering the collection list view and filters by default.
if (uploadOptions.imageSizes) {
uploadFields = uploadFields.concat([
{
name: 'sizes',
type: 'group',
admin: {
hidden: true,
},
fields: uploadOptions.imageSizes.map((size) => ({
name: size.name,
type: 'group',
admin: {
hidden: true,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
fields: [
{
...url,
admin: {
...url.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
hooks: {
afterRead: [
({ data, value }) => {
if (value && size.height && size.width && !data?.filename) {
return value
}
const sizeFilename = data?.sizes?.[size.name]?.filename
if (sizeFilename) {
return `${config.serverURL}${config.routes?.api}/${collection.slug}/file/${sizeFilename}`
}
return null
},
],
},
},
{
...width,
admin: {
...width.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
},
{
...height,
admin: {
...height.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
},
{
...mimeType,
admin: {
...mimeType.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
},
{
...filesize,
admin: {
...filesize.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
},
{
...filename,
admin: {
...filename.admin,
...(size.admin?.disableListColumn && { disableListColumn: true }),
...(size.admin?.disableListFilter && { disableListFilter: true }),
},
unique: false,
},
],
label: size.name,
})),
label: ({ t }) => t('upload:sizes'),
},
])
}
return uploadFields
}