Commit Graph

2389 Commits

Author SHA1 Message Date
Alessio Gravili
4e2e4d2aed feat(next): version view overhaul (#12027)
#11769 improved the lexical version view diff component. This PR
improves the rest of the version view.

## What changed

- Column layout when selecting a version:
	- Previously: Selected version on the left, latest version on the left
- Now: Previous version on the left, previous version on the right
(mimics behavior of GitHub)
- Locale selector now displayed in pill selector, rather than
react-select
- Smoother, more reliable locale, modifiedOnly and version selection.
Now uses clean event callbacks rather than useEffects
- React-diff-viewer-continued has been replaced with the html differ we
use in lexical
- Updated Design for all field diffs
- Version columns now have a clearly defined separator line
- Fixed collapsibles showing in version view despite having no modified
fields if modifiedOnly is true
- New, redesigned header
	

## Screenshots

### Before

![CleanShot 2025-04-11 at 20 10
03@2x](https://github.com/user-attachments/assets/a93a500a-3cdd-4cf0-84dd-cf5481aac2b3)

![CleanShot 2025-04-11 at 20 10
28@2x](https://github.com/user-attachments/assets/59bc5885-cbaf-49ea-8d1d-8d145463fd80)

### After

![Screenshot 2025-06-09 at 17 43
49@2x](https://github.com/user-attachments/assets/f6ff0369-76c9-4c1c-9aa7-cbd88806ddc1)

![Screenshot 2025-06-09 at 17 44
50@2x](https://github.com/user-attachments/assets/db93a3db-48d6-4e5d-b080-86a34fff5d22)

![Screenshot 2025-06-09 at 17 45
19@2x](https://github.com/user-attachments/assets/27b6c720-05fe-4957-85af-1305d6b65cfd)

![Screenshot 2025-06-09 at 17 45
34@2x](https://github.com/user-attachments/assets/6d42f458-515a-4611-b27a-f4d6bafbf555)
2025-06-16 07:58:03 -04:00
Sasha
9943b3508d fix: filtering joins in where by ID (#12804)
Fixes https://github.com/payloadcms/payload/issues/12768

Example:
```
const found_1 = await payload.find({
  collection: 'categories',
  where: { 'relatedPosts.id': { equals: post.id } },
})
```
or
```
const found_2 = await payload.find({
  collection: 'categories',
  where: { relatedPosts: { equals: post.id } },
})
```
2025-06-13 14:13:17 -04:00
Kendell Joseph
f2e04222f4 feat: admin upload controls (#11615)
### What?
Adds the ability to add additional components to the file upload
component.

```ts
export const Media: CollectionConfig = {
  slug: 'media',
  upload: {
    admin: {
      components: {
        controls: [
          '/collections/components/Control/index.js#UploadControl',
        ],
      },
    },
  },
  fields: [],
}
```

![image](https://github.com/user-attachments/assets/4706e05b-4e95-4f15-8444-a279c589074e)

### Provider
Use the `useUploadControls` provider to either `setUploadControlFile`
passing a file object, or set the file by url using
`setUploadControlFileUrl`.

```tsx
'use client'
import { Button, useUploadControls } from '@payloadcms/ui'
import React, { useCallback } from 'react'

export const UploadControl = () => {
  const { setUploadControlFile, setUploadControlFileUrl } = useUploadControls()

  const loadFromFile = useCallback(async () => {
    const response = await fetch('https://payloadcms.com/images/universal-truth.jpg')
    const blob = await response.blob()
    const file = new File([blob], 'universal-truth.jpg', { type: 'image/jpeg' })
    setUploadControlFile(file)
  }, [setUploadControlFile])

  const loadFromUrl = useCallback(() => {
    setUploadControlFileUrl('https://payloadcms.com/images/universal-truth.jpg')
  }, [setUploadControlFileUrl])

  return (
    <div>
      <Button id="load-from-file-upload-button" onClick={loadFromFile}>
        Load from File
      </Button>
      <br />
      <Button id="load-from-url-upload-button" onClick={loadFromUrl}>
        Load from URL
      </Button>
    </div>
  )
}
```


### Why?
Add the ability to use a custom component to select a document to
upload.
2025-06-13 12:47:46 -04:00
Sasha
e60db0750a fix(ui): reordering with a join field inside a group (#12803)
Fixes https://github.com/payloadcms/payload/issues/12802
2025-06-13 12:31:07 -04:00
Jessica Rynkar
65309b1d21 feat(next): reorder document view tabs (#12288)
Introduces the ability to customize the order of both default and custom
tabs. This way you can make custom tabs appear before default ones, or
change the order of tabs as you see fit.

To do this, use the new `tab.order` property in your edit view's config:

```ts
import type { CollectionConfig } from 'payload'

export const MyCollectionConfig: CollectionConfig = {
  // ...
  admin: {
    components: {
      views: {
        edit: {
          myCustomView: {
            path: '/my-custom-view',
            Component: '/path/to/component',
            tab: {
              href: '/my-custom-view',
              order: 100, // This will put this tab in the first position
            },
          }
        }
      }
    }
  }
}
```

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-06-13 15:28:29 +01:00
Sasha
245a2dee7e fix(db-mongodb): 4x and more level deep relationships querying (#12800)
Fixes https://github.com/payloadcms/payload/issues/12721
2025-06-13 14:11:13 +00:00
Jacob Fletcher
53835f2620 refactor(next): simplify document tab rendering logic (#12795)
Simplifies the rendering logic around document tabs in the following
ways:

- Merges default tabs with custom tabs in a more predictable way, now
there is only a single array of tabs to iterate over, no more concept of
"custom" tabs vs "default" tabs, there's now just "tabs"
- Deduplicates rendering conditions for all tabs, now any changes to
default tabs would also apply to custom tabs with half the code
- Removes unnecessary `getCustomViews` function, this is a relic of the
past
- Removes unnecessary `getViewConfig` function, this is a relic of the
past
- Removes unused `references`, `relationships`, and `version` key
placeholders, these are relics of the past
- Prevents tab conditions from running twice unnecessarily
- Other misc. cleanup like unnecessarily casting the tab conditions
result to a boolean, etc.
2025-06-13 07:12:28 -04:00
Sasha
df8be92d47 fix(db-postgres): x3 and more nested blocks regression (#12770) 2025-06-12 19:37:07 +03:00
Jarrod Flesch
e7b5884ec2 fix(ui): not showing hyphenated field values in table (#12791) 2025-06-12 12:36:24 -04:00
Kendell Joseph
c04c257712 chore: adds filters (#12622)
Filters URLs to avoid issues with SSRF

Had to use `undici` instead of native `fetch` because it was the only
viable alternative that supported both overriding agent/dispatch and
also implemented `credentials: include`.

[More info
here.](https://blog.doyensec.com/2023/03/16/ssrf-remediation-bypass.html)

---------

Co-authored-by: Elliot DeNolf <denolfe@gmail.com>
2025-06-12 09:46:49 -04:00
Jacob Fletcher
f64a0aec5f fix: remove unsupported path property from default document view configs (#12774)
Customizing the `path` property on default document views is currently
not supported, but the types suggest that it is. You can only provide a
path to custom views. This PR ensures that `path` cannot be set on
default views as expected.

For example:

```ts
import type { CollectionConfig } from 'payload'

export const MyCollectionConfig: CollectionConfig = {
  // ...
  admin: {
    components: {
      views: {
        edit: {
          default: {
            path: '/' // THIS IS NOT ALLOWED!
          },
          myCustomView: {
            path: '/edit', // THIS IS ALLOWED!
            Component: '/collections/CustomViews3/MyEditView.js#MyEditView',
          },
        },
      },
    },
  },
}
```

For background context, this was deeply explored in #12701. This is not
planned, however, due to [performance and maintainability
concerns](https://github.com/payloadcms/payload/pull/12701#issuecomment-2963926925),
plus [there are alternatives to achieve
this](https://github.com/payloadcms/payload/pull/12772).

This PR also fixes and improves various jsdocs, and fixes a typo found
in the docs.
2025-06-12 09:01:20 -04:00
Paul
143aff57ae fix: field inside an unnamed group field erroring when used as a title (#12771)
Fixes https://github.com/payloadcms/payload/issues/12632

Config sanitisation will error without this PR when attempting to
useAsTitle a field inside an unnamed group field.
2025-06-12 05:57:37 -07:00
Alessio Gravili
cf43c5cd08 fix: error when saving global with versioning enabled (#12778)
When saving a global with versioning enabled as draft, and then
publishing it, the following error may appear: `[16:50:35] ERROR: Could
not find createdAt or updatedAt in latestVersion.version`

This is due to an incorrect check to appease typescript strict mode. We
shouldn't throw if `version.updatedAt` doesn't exist - the purpose of
this logic is to add that property if it doesn't exist
2025-06-12 01:39:13 +00:00
Anders Semb Hermansen
018317dfba fix(storage-azure): return error status 404 when file is not found instead of 500 (#11734)
### What?

The azure storage adapter returns a 500 internal server error when a
file is not found.
It's expected that it will return 404 when a file is not found.

### Why?

There is no checking if the blockBlobClient exists before it's used, so
it throws a RestError when used and the blob does not exist.

### How?

Check if exception thrown is of type RestError and have a 404 error from
the Azure API and return a 404 in that case.

An alternative way would be to call the exists() method on the
blockBlobClient, but that will be one more API call for blobs that does
exist. So I chose to check the exception instead.

Also added integration tests for azure storage in the same manner as s3,
as it was missing for azure storage.
2025-06-11 07:49:34 -07:00
Dan Ribbens
37afbe6c04 fix: orderable has incorrect sort results depending on capitalization (#12758)
### What?
The results when querying orderable collections can be incorrect due to
how the underlying database handles sorting when capitalized letters are
introduced.

### Why?
The original fractional indexing logic uses base 62 characters to
maximize the amount of data per character. This optimization saves a few
characters of text in the database but fails to return accurate results
when mixing uppercase and lowercase characters.

### How?
Instead we can use base 36 values instead (0-9,a-z) so that all
databases handle the sort consistently without needing to introduce
collation or other alternate solutions.

Fixes #12397
2025-06-11 09:49:53 -04:00
Patrik
458a04b77c feat: expose data argument in afterChange hook for collections and globals (#12756)
### What

This PR updates the `afterChange` hook for collections and globals to
include the `data` argument.

While the `doc` argument provides the saved version of the document,
having access to the original `data` allows for additional context—such
as detecting omitted fields, raw client input, or conditional logic
based on user-supplied data.

### Changes

- Adds the `data` argument to the `afterChange` hook args.
- Applies to both `collection` and `global` hooks.

### Example

```
afterChange: [
  ({ context, data, doc, operation, previousDoc, req }) => {
    if (data?.customFlag) {
       // Perform logic based on raw input
    }
  },
],
```
2025-06-11 06:23:22 -07:00
Anders Semb Hermansen
a19921d08f fix(storage-s3): return error status 404 when file is not found instead of 500 (#11733)
### What?

The s3 storage adapter returns a 500 internal server error when a file
is not found.
It's expected that it will return 404 when a file is not found.

### Why?

The getObject function from aws s3 sdk does not return undefined when a
blob is not found, but throws a NoSuchKey error:
https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/Package/-aws-sdk-client-s3/Class/NoSuchKey/

### How?

Check if exception thrown is of type NoSuchKey and return a 404 in that
case.

Related discord discussion:

https://discord.com/channels/967097582721572934/1350826594062696539/1350826594062696539
2025-06-11 12:04:25 +00:00
Sasha
860e0b4ff9 fix(db-mongodb): bump mongoose to 8.15.1 (#12755)
Updates the `mongoose` package to the latest version `8.15.1`.
Fixes https://github.com/payloadcms/payload/issues/12708
2025-06-11 06:30:36 +03:00
Dan Ribbens
c4e5831fbb fix(plugin-import-export): export all available fields by default (#12731)
When making an export of a collection, and no fields are selected then
you get am empty CSV. The intended behavior is that all data is exported
by default.

This fixes the issue that from the admin UI, when the fields selector
the resulting CSV has no columns.
2025-06-10 12:03:26 -04:00
Jarrod Flesch
a43d1a685f feat(ui): moves folder rendering from the client to the server (#12710) 2025-06-10 11:56:28 -04:00
Jarrod Flesch
254ffecaea fix(db-sqlite): sqlite unique validation messages (#12740)
Fixes https://github.com/payloadcms/payload/issues/12628

When using sqlite, the error from the db is a bit different than
Postgres.

This PR allows us to extract the fieldName when using sqlite for the
unique constraint error.
2025-06-10 10:08:06 -04:00
Sasha
0a357372e9 feat(db-postgres): support read replicas (#12728)
Adds support for read replicas
https://orm.drizzle.team/docs/read-replicas that can be used to offload
read-heavy traffic.

To use (both `db-postgres` and `db-vercel-postgres` are supported):
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'

database: postgresAdapter({
  pool: {
    connectionString: process.env.POSTGRES_URL,
  },
  readReplicas: [process.env.POSTGRES_REPLICA_URL],
})
```

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2025-06-09 19:09:52 +00:00
Sasha
865a9cd9d1 feat(storage-s3): dynamic presigned URL downloads (#12706)
Previously, if you enabled presigned URL downloads for a collection, all
the files would use them. However, it might be possible that you want to
use presigned URLs only for specific files (like videos), this PR allows
you to pass `shouldUseSignedURL` to control that behavior dynamically.
```ts
s3Storage({
  collections: {
    media: {
      signedDownloads: {
        shouldUseSignedURL: ({ collection, filename, req }) => {
          return req.headers.get('X-Disable-Signed-URL') !== 'false'
        },
      },
    },
  },
})
```
2025-06-09 19:03:06 +00:00
Sasha
9fbc3f6453 fix: proper globals max versions clean up (#12611)
Fixes https://github.com/payloadcms/payload/issues/11879
2025-06-09 14:38:07 -04:00
Dan Ribbens
8f4c4423f3 feat(plugin-import-export): add custom toCSV function on fields (#12533)
This makes it possible to add custom logic into how we map the document
data into the CSV data on a field-by-field basis.

- Allow custom data transformation to be added to
`custom.['plugin-import-export'].toCSV inside the field config
- Add type declaration to FieldCustom to improve types
- Export with `depth: 1`

Example:
```ts
    {
      name: 'customRelationship',
      type: 'relationship',
      relationTo: 'users',
      custom: {
        'plugin-import-export': {
          toCSV: ({ value, columnName, row, siblingDoc, doc }) => {
            row[`${columnName}_id`] = value.id
            row[`${columnName}_email`] = value.email
          },
        },
      },
    },
```
2025-06-09 13:53:30 -04:00
Alessio Gravili
3d177fd935 fix(richtext-lexical): text state css not applied if 2+ text state groups present (#12726)
Fixes #12723 

## Problem

With two or more state groups, a falsy state entry would run
`dom.style.cssText = ''`, wiping all inline styles - including valid
styles just set by earlier groups. This caused earlier groups to lack
css styling.

## Solution

**1. Collect first, apply once**

During the stateMap.forEach loop, gather each active group's styles into
a shared `mergedStyles` object.

Inactive groups still clear their own `data-*` attribute but leave
styles untouched.

**2. Single reset + single write**

After the loop, perform one cssText reset, instead of one cssText in
each iteration. Then apply each state group's css all at once, after the
blank reset

Result: every state group can coexist without overwriting styles from
the others
2025-06-09 15:22:21 +00:00
Alessio Gravili
f80dc5b99e chore: enable turbopack by default in monorepo (#12684)
No issues with turbopack reported so far, let's enable it by default in
our monorepo. The `--turbo` flag for our package.json `dev` and
`test:e2e` scripts has been replaced with an opt-out `--no-turbo` flag
2025-06-05 22:01:55 -03:00
Alessio Gravili
aef4f779b1 perf(richtext-lexical): improve typing performance while toolbars are enabled (#12669)
The lexical fixed and inline toolbars do active / enabled state
calculations for toolbar buttons / dropdowns on every keystroke. This
can incur a performance hit on slow machines.

This PR
- deprioritizes these state calculations using `useDeferredValue` and
`requestIdleCallback`
- introduces additional memoization and replace unnecessary `useEffect`s
to reduce re-rendering

## Before (20x cpu throttling)


https://github.com/user-attachments/assets/dfb6ed79-b5bd-4937-a01d-cd26f9a23831

## After (20x cpu throttling)


https://github.com/user-attachments/assets/d4722fb4-5fd0-48b5-928c-35fcd4f98f78
2025-06-05 16:51:32 +00:00
Alessio Gravili
7c05c775cb docs: improve jobs autorun docs, adds e2e test (#12196)
This clarifies that jobs.autoRun only *runs* already-queued jobs. It does not queue the jobs for you.

Also adds an e2e test as this functionality had no e2e coverage
2025-06-05 09:19:19 -07:00
Jarrod Flesch
9581092995 feat(ui): use document drawers for folder edit/create (#12676)
This PR re-uses the document drawers for editing and creating folders.
This allows us to easily render document fields that are added inside
`collectionOverrides` on the folder config.

Not much changed, the folder drawer UI now resembles what you would
expect when you create a document in payload. It is a bit slimmed back
but generally very similar.
2025-06-04 16:52:49 -04:00
Alessio Gravili
545d870650 chore: fix various e2e test setup issues (#12670)
I noticed a few issues when running e2e tests that will be resolved by
this PR:

- Most important: for some test suites (fields, fields-relationship,
versions, queues, lexical), the database was cleared and seeded
**twice** in between each test run. This is because the onInit function
was running the clear and seed script, when it should only have been
running the seed script. Clearing the database / the snapshot workflow
is being done by the reInit endpoint, which then calls onInit to seed
the actual data.
- The slowest part of `clearAndSeedEverything` is recreating indexes on
mongodb. This PR slightly improves performance here by:
- Skipping this process for the built-in `['payload-migrations',
'payload-preferences', 'payload-locked-documents']` collections
- Previously we were calling both `createIndexes` and `ensureIndexes`.
This was unnecessary - `ensureIndexes` is a deprecated alias of
`createIndexes`. This PR changes it to only call `createIndexes`
- Makes the reinit endpoint accept GET requests instead of POST requests
- this makes it easier to debug right in the browser
- Some typescript fixes
- Adds a `dev:memorydb` script to the package.json. For some reason,
`dev` is super unreliable on mongodb locally when running e2e tests - it
frequently fails during index creation. Using the memorydb fixes this
issue, with the bonus of more closely resembling the CI environment
- Previously, you were unable to run test suites using turbopack +
postgres. This fixes it, by explicitly installing `pg` as devDependency
in our monorepo
- Fixes jest open handles warning
2025-06-04 17:34:37 -03:00
Jarrod Flesch
337f6188da feat: optionally exclude collection documents from appearing in browse-by-folder (#12654)
Adds configurations for browse-by-folder document results. This PR
**does NOT** allow for filtering out folders on a per collection basis.
That will be addressed in a future PR 👍

### Disable browse-by-folder all together
```ts
type RootFoldersConfiguration = {
  /**
   * If true, the browse by folder view will be enabled
   *
   * @default true
   */
  browseByFolder?: boolean
  // ...rest of type
}
```

### Remove document types from appearing in the browse by folder view
```ts
type CollectionFoldersConfiguration =
  | boolean
  | {
      /**
       * If true, the collection documents will be included in the browse by folder view
       *
       * @default true
       */
      browseByFolder?: boolean
    }
```

### Misc
Fixes https://github.com/payloadcms/payload/issues/12631 where adding
folders.collectionOverrides was being set on the client config - it
should be omitted.

Fixes an issue where `baseListFilters` were not being respected.
2025-06-04 13:22:26 -04:00
Said Akhrarov
bd512f1eda fix(db-postgres): ensure deletion of numbers and texts in upsertRow (#11787)
### What?
This PR fixes an issue while using `text` & `number` fields with
`hasMany: true` where the last entry would be unreachable, and thus
undeletable, because the `transformForWrite` function did not track
these rows for deletion. This causes values that should've been deleted
to remain in the edit view form, as well as the db, after a submission.

This PR also properly threads the placeholder value from
`admin.placeholder` to `text` & `number` `hasMany: true` fields.

### Why?
To remove rows from the db when a submission is made where these fields
are empty arrays, and to properly show an appropriate placeholder when
one is set in config.

### How?
Adjusting `transformForWrite` and the `traverseFields` to keep track of
rows for deletion.

Fixes #11781

Before:


[Editing---Post-dbpg-before--Payload.webm](https://github.com/user-attachments/assets/5ba1708a-2672-4b36-ac68-05212f3aa6cb)

After:


[Editing---Post--dbpg-hasmany-after-Payload.webm](https://github.com/user-attachments/assets/1292e998-83ff-49d0-aa86-6199be319937)
2025-06-04 10:13:46 -04:00
Sasha
c08cdff498 fix(db-postgres): in query with null (#12661)
Previously, this was possible in MongoDB but not in Postgres/SQLite
(having `null` in an `in` query)
```
const { docs } = await payload.find({
  collection: 'posts',
  where: { text: { in: ['text-1', 'text-3', null] } },
})
```
This PR fixes that behavior
2025-06-03 20:56:10 -04:00
Alessio Gravili
30bb749e25 ci: skip flaky test on supabase (#12667)
This disables running the "`can reliably run workflows with parallel
tasks`" int test on supabase. For unknown reasons, it fails most of the
time.
2025-06-03 16:24:15 -04:00
Jessica Rynkar
625d8d9319 feat(ui): adds new editMenuItems custom component (#12649)
## What
Adds a new custom component called `editMenuItems` that can be used in
the document view.
This options allows users to inject their own custom components into the
dropdown menu found in the document controls (the 3 dot menu), the
provided component(s) will be added below the default existing actions
(Create New, Duplicate, Delete and so on).

## Why
To increase flexibility and customization for users who wish to add
functionality to this menu. This provides a clean and consistent way to
add additional actions without needing to override or duplicate existing
UI logic.

## How
- Introduced the `editMenuItems` slot in the document controls dropdown
(three-dot menu) - in edit and preview tabs.
- Added documentation and tests to cover this new custom component

#### Testing
Use the `admin` test suite and go to the `edit menu items` collection
2025-06-03 14:57:48 +01:00
Paul
a9ff375cc0 fix(ui): clear miliseconds in date fields unless theyre explicitly provided in the display format (#12650)
Fixes https://github.com/payloadcms/payload/issues/12532

Normally we clear any values when picking a date such that your hour,
minutes and seconds are normalised to 0 unless specified. Equally when
you specify a time we will normalise seconds so that only minutes are
relevant as configured.

Miliseconds were never removed from the actual date value and whatever
milisecond the editor was in was that value that was being added.
There's this [abandoned
issue](https://github.com/Hacker0x01/react-datepicker/issues/1991) from
the UI library `react-datepicker` as it's not something configurable.

This fixes that problem by making sure that miliseconds are always 0
unless the `displayFormat` includes `SSS` as an intention to show and
customise them.

This also caused [issues with scheduled
jobs](https://github.com/payloadcms/payload/issues/12566) if things were
slightly out of order or not being scheduled in the expected time
interval.
2025-06-03 02:44:52 -07:00
Alessio Gravili
319d3355de feat: improve turbopack compatibility (#11376)
This PR introduces a few changes to improve turbopack compatibility and
ensure e2e tests pass with turbopack enabled

## Changes to improve turbopack compatibility
- Use correct sideEffects configuration to fix scss issues
- Import scss directly instead of duplicating our scss rules
- Fix some scss rules that are not supported by turbopack
- Bump Next.js and all other dependencies used to build payload

## Changes to get tests to pass

For an unknown reason, flaky tests flake a lot more often in turbopack.
This PR does the following to get them to pass:
- add more `wait`s
- fix actual flakes by ensuring previous operations are properly awaited

## Blocking turbopack bugs
- [X] https://github.com/vercel/next.js/issues/76464
  - Fix PR: https://github.com/vercel/next.js/pull/76545
  - Once fixed: change `"sideEffectsDisabled":` back to `"sideEffects":`
  
## Non-blocking turbopack bugs
- [ ] https://github.com/vercel/next.js/issues/76956

## Related PRs

https://github.com/payloadcms/payload/pull/12653
https://github.com/payloadcms/payload/pull/12652
2025-06-02 22:01:07 +00:00
Sasha
2b40e0f21f feat: polymorphic join querying by fields that don't exist in every collection (#12648)
This PR makes it possible to do polymorphic join querying by fields that
don't exist in all collections specified in `field.collection`, for
example:
```
const result = await payload.find({
  collection: 'payload-folders',
  joins: {
    documentsAndFolders: {
      where: {
        and: [
          {
            relationTo: {
              in: ['folderPoly1', 'folderPoly2'],
            },
          },
          {
            folderPoly2Title: { // this field exists only in the folderPoly2 collection, before it'd throw a query error.
              equals: 'Poly 2 Title',
            },
          },
        ],
      },
    },
  },
})
```

---------

Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
2025-06-03 00:48:07 +03:00
Jacob
c639c5f278 fix(next): cannot override tab of default views (#11789)
### What?

TypeScript says that it is possible to modify the tab of the default
view however, when you specify the path to the custom component, nothing
happens. I fixed it.

### How?

If a Component for the tab of the default view is defined in the config,
I return that Component instead of DocumentTab

### Example Configuration

config.ts
```ts
export const MenuGlobal: GlobalConfig = {
  slug: menuSlug,
  fields: [
    {
      name: 'globalText',
      type: 'text',
    },
  ],
  admin: {
    components: {
      views: {
        edit: {
          api: {
            tab: {
              Component: './TestComponent.tsx',
            },
          },
        },
      },
    },
  },
}
```
./TestComponent.tsx
```tsx
const TestComponent = () => 'example'

export default TestComponent
```


### Before
![Screenshot 2025-03-20 at 08 42
06](https://github.com/user-attachments/assets/2acc0950-847f-44c5-bedf-660c5c3747a0)

### After
![Screenshot 2025-03-20 at 08 43
06](https://github.com/user-attachments/assets/c3917d02-abfb-4f80-9235-cc1ba784586d)

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-06-02 14:51:33 -04:00
Patrik
05eeddba7c fix: correctly detect glb & gltf mimetypes during upload (#12623)
### What?

The browser was incorrectly setting the mimetype for `.glb` and `.gltf`
files to `application/octet-stream` when uploading when they should be
receiving proper types consistent with `glb` and `gltf`.

This patch adds logic to infer the correct `MIME` type for `.glb` files
(`model/gltf-binary`) & `gltf` files (`model/gltf+json`) based on file
extension during multipart processing, ensuring consistent MIME type
detection regardless of browser behavior.

Fixes #12620
2025-06-02 11:26:26 -07:00
Tobias Odendahl
08a6f88a4b fix(ui): reset columns state throwing errors (#11903)
### What?
Fixes `resetColumnsState` in `useTableColumns` react hook.

### Why?
`resetColumnsState` threw errors when being executed, e.g. `Uncaught (in
promise) TypeError: Cannot read properties of undefined (reading
'findIndex')`

### How?
Removes unnecessary parsing of URL query parameters in
`setActiveColumns` when resetting columns.

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-06-02 14:24:00 -04:00
Germán Jabloñski
89ced5ec6b fix(richtext-lexical): enable select inputs with ctrl+a or cmd+a (#12453)
Fixes #6871

To review this PR, use `pnpm dev lexical` and the auto-created document
in the `lexical fields` collection. Select any input within the blocks
and press `cmd+a`. The selection should contain the entire input.

I made sure that `cmd+a` still works fine inside the editor but outside
of inputs.
2025-05-30 18:28:51 -03:00
Paul
d5611953a7 fix: allow unnamed group fields to not set a label at all (#12580)
Technically you could already set `label: undefined` and it would be
supported by group fields but the types didn't reflect this.

So now you can create an unnamed group field like this:

```ts
{
      type: 'group',
      fields: [
        {
          type: 'text',
          name: 'insideGroupWithNoLabel',
        },
      ],
    },
```

This will remove the label while still visually grouping the fields.

![image](https://github.com/user-attachments/assets/ecb0b364-9cff-4d71-bf9f-86961915aecd)

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2025-05-29 22:03:39 +00:00
Sasha
6888f13f27 fix(db-postgres): properly escape the ' character (#12590)
Fixes the issue when `defaultValue` contains `'` it'd double the amount
of `'` for the `DEFAULT` statement in the generated migration
2025-05-29 15:27:07 -04:00
Alessio Gravili
ca26402377 fix(richtext-lexical): respect disableBlockName (#12597)
Fixes #12588 

Previously, the new `disableBlockName` was not respected for lexical
blocks. This PR adds a new e2e test and does some clean-up of previous
e2e tests
2025-05-28 22:41:05 +00:00
Germán Jabloñski
8a7ac784c4 fix(translations): improve Spanish translations (#12555)
There are still things to improve.

- We're inconsistent with our use of capital letters. There are still
sentences where every word starts with a capital letter, and it looks
ugly (this also happens in English, but to a lesser extent).
- We're inconsistent with the use of punctuation at the end.
- Sentences with variables like {{count}} can result in inconsistencies
if it's 1 and the noun is plural.
- The same thing happens in Spanish, but also with gender. It's
impossible to know without the context in which it's used.

---------

Co-authored-by: Paul Popus <paul@payloadcms.com>
2025-05-28 16:50:47 -03:00
Patrik
20f7017758 feat: show nested fields in named tabs as separate columns in the list view (#12530)
### What

Continuation of #7355 by extending the functionality to named tabs.

Updates `flattenFields` to hoist nested fields inside named tabs to the
top-level field array when `moveSubFieldsToTop` is enabled.

Also fixes an issue where group fields with custom cells were being
flattened out.

Now, group fields with a custom cell components remain available as
top-level columns.

Fixes #12563
2025-05-27 14:15:47 -07:00
Jacob Fletcher
0204f0dcbc feat: filter query preset constraints (#12485)
You can now specify exactly who can change the constraints within a
query preset.

For example, you want to ensure that only "admins" are allowed to set a
preset to "everyone".

To do this, you can use the new `queryPresets.filterConstraints`
property. When a user lacks the permission to change a constraint, the
option will either be hidden from them or disabled if it is already set.

```ts
import { buildConfig } from 'payload'

const config = buildConfig({
  // ...
  queryPresets: {
    // ...
    filterConstraints: ({ req, options }) =>
      !req.user?.roles?.includes('admin')
        ? options.filter(
            (option) =>
              (typeof option === 'string' ? option : option.value) !==
              'everyone',
          )
        : options,
  },
})
```

The `filterConstraints` functions takes the same arguments as
`reduceOptions` property on select fields introduced in #12487.
2025-05-27 16:55:37 -04:00
Jessica Rynkar
feb7e082af chore(ui): finish adding folders e2e tests (#12524) 2025-05-27 13:00:56 -04:00