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
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.
### 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)
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
In one of the versions we've changed the type of the argument from
`I18n<any, any>` to `I18n<unknown, unknown>` and this has caused some
issues with TS resolving the type compatibility in the `formatDate`
utility so it no longer supports `I18nClient`.
This type change happened in
https://github.com/payloadcms/payload/pull/10030
- The `ConfigProvider` was unnecessarily sanitizing the client config
twice on initial render, leading to an unnecessary re-render. Now it
only happens once
- Memoizes the context value to prevent accidental, unnecessary
re-renders of consumers
We've already supported `autoComplete` on admin config for text fields
but it wasn't being threaded through to the text input element so it
couldn't be applied.
Closes https://github.com/payloadcms/payload/issues/12355
TabbedUI doesn't always work as intended and it can be affected by
existing fields or the order of other plugins, this mentions that and
links to the recommended direct use of fields example.
Important: An intentional effort is being made during migration to not
modify runtime behavior. This implies that there will be several
assertions, non-null assertions, and @ts-expect-error. This philosophy
applies only to migrating old code to TypeScript strict, not to writing
new code. For a more detailed justification for this reasoning,
https://github.com/payloadcms/payload/pull/11840#discussion_r2021975897.
In this PR, instead of following the approach of migrating a subset of
files, I'm migrating all files by disabling a specific rule. In this
case, `strictNullChecks`.
`strictNullChecks` is a good rule to start the migration with because
it's easy to silence with non-null assertions or optional chainings.
Additionally, almost all ts strict errors are due to this rule.
This PR improves 200+ files, leaving only 68 remaining to migrate to
strict mode in the payload package.
## 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
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.
This adds a new `tests-e2e-turbo` CI step that runs our e2e test suite
against turbo. This will ensure that we can guarantee full support for
turbopack.
Our CI runners are already at capacity, so the turbo steps will only run
if the `tests-e2e-turbo` label is set on the PR.
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/12653https://github.com/payloadcms/payload/pull/12652
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>
This PR uses the new `useQueue` hook for relationship react-select field
for loading options. This will reduce flakiness in our CI and ensure the
following:
- most recently triggered options loading request will not have its
result overwritten by a previous, delayed request
- reduce unnecessary, parallel requests - outdated requests are
discarded from the queue if a newer request exist
### 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

### After

---------
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
### 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
### 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>
<!--
Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.
Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.
The following items will ensure that your PR is handled as smoothly as
possible:
- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change
### What?
### Why?
### How?
Fixes #
-->
### What?
This PR fixes an issue with `plugin-seo` where the `MetaImageComponent`
would not allow creating a new upload document from the field.
### Why?
To allow users to upload new media documents for use as a meta image.
### How?
Threads `allowCreate` through to the underlying upload input.
Fixes#12616
Before:

After:

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.
When cloning a new project from the examples dir via create-payload-app,
the corresponding `.env` file is not being generated. This is because
the `--example` flag does not prompt for database credentials, which
ultimately skips this step.
For example:
```bash
npx create-payload-app --example live-preview
```
The result will include the provided `.env.example`, but lacks a `.env`.
We were previously writing to the `.env.example` file, which is
unexpected. We should only be writing to the `.env` file itself. To do
this, we only write the `.env.example` to memory as needed, instead of
the file system.
This PR also simplifies the logic needed to set default vars, and
improves the testing coverage overall.
Type inferences broke as a result of migrating to ts strict mode in
#12298. This leads to compile-time errors that may prevent build.
Here is an example:
```ts
export interface Page {
id: string;
slug: string;
title: string;
// ...
}
/**
* Type 'Page' does not satisfy the constraint 'Record<string, unknown>'.
* Index signature for type 'string' is missing in type 'Page'.
*/
const { data } = useLivePreview<Page>({
depth: 2,
initialData: initialPage,
serverURL: PAYLOAD_SERVER_URL,
})
```
The problem is that Payload generated type _interfaces_ do not satisfy
the `Record<string, unknown>` type. This is because interfaces are a
possible target for declaration merging, so their properties are not
fully known. More details on this
[here](https://github.com/microsoft/TypeScript/issues/42825).
This PR also cleans up the JSDocs.
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.

---------
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
🤖 Automated bump of templates for v3.40.0
Triggered by user: @denolfe
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
- I corrected the use of `yarn` instead of `pnpm`
- I corrected the URL for previewing the documentation (it was missing
`/local`).
- I removed the incorrect section about what type of commit falls into
the release notes.
---------
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Exposes a new argument to authentication strategies which allows the
author to determine if this auth strategy has the capability of setting
response headers or not.
This is useful because some auth strategies may want to set headers, but
in Next.js server components (AKA the admin panel), it's not possible to
set headers. It is, however, possible to set headers within API
responses and similar contexts.
So, an author might decide to only run operations that require setting
headers (i.e. refreshing an access token) if the auth strategy is being
executed in contexts where setting headers is possible.
Following up on https://github.com/payloadcms/payload/pull/12515, we
could instead use the same `parseCookies` method that Next.js uses. This
handles a few edge-cases differently:
- correctly strips whitespace
- parses attributes without explicit values
I think it's a good idea to match the behavior of Next.js as close as
possible here. [This](https://github.com/vercel/edge-runtime/pull/374)
is a good example of how the Next.js behavior behaves differently.
## Example
Input: `'my_value=true; Secure; HttpOnly'`
Previous Output:
```
Map(3) {
'my_value' => 'true',
'Secure' => '',
'HttpOnly' => '',
}
```
New Output:
```
Map(3) {
'my_value' => 'true',
'Secure' => 'true',
'HttpOnly' => 'true'
}
```
this has been already reported here:
https://github.com/payloadcms/payload/issues/10591
`parseCookies.ts` tries to decode cookie's values using `decodeURI()`
and throws an Error when it fails
Since it does that on all cookies set on the current domain, there's no
control on which cookie get evaluated; for instance ads networks,
analytics providers, external fonts, etc... all set cookies with
different encodings.
### Taking in consideration:
- HTTP specs doesn't define a standard way for cookie value encoding but
simply provide recommendations:
[RFC6265](https://httpwg.org/specs/rfc6265.html#sane-set-cookie)
> To maximize compatibility with user agents, servers that wish to store
arbitrary data in a cookie-value SHOULD encode that data, for example,
using Base64
- NextJS does a pretty similar parsing and ignore invalid encoded values
https://github.com/vercel/edge-runtime/blob/main/packages/cookies/src/serialize.ts
`function parseCookie(cookie: string)`
```typescript
try {
map.set(key, decodeURIComponent(value ?? 'true'))
} catch {
// ignore invalid encoded values
}
```
### With the current implementation:
- it's impossible to login because `parseCookies.ts` get called and if
fails to parse throws and error
- requests to `/api/users/me` fail for the same reason
### Fix
the pull request address these issues by simply ignoring decoding
errors:
CURRENT:
```typescript
try {
const decodedValue = decodeURI(encodedValue)
list.set(key, decodedValue)
} catch (e) {
throw new APIError(`Error decoding cookie value for key ${key}: ${e.message}`)
}
```
AFTER THIS PULL REQUEST
```typescript
try {
const decodedValue = decodeURI(encodedValue)
list.set(key, decodedValue)
} catch {
// ignore invalid encoded values
}
```
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
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>
To reproduce this bug, insert the following feature into the richtext
editor:
```ts
BlocksFeature({
inlineBlocks: [
{
slug: 'inline-media',
fields: [
{
name: 'media',
type: 'relationship',
relationTo: ['media'],
admin: {
appearance: 'drawer',
},
},
],
},
],
}),
```
Then try opening the relationship field drawer. The inline block drawer
will close.
Note: Interestingly, at least in Chrome, this only happens with DevTools
closed. It worked fine with DevTools open. It probably has to do with
capturing events like focus.
The current solution is a 50ms delay. I couldn't test it with CPU
throttle because it disappears when I close the devtools. If you
encounter this bug, please open an issue so we can increase the delay
or, better yet, find a more elegant solution.
- update SantizeCollection to SanitizedCollection in TypeScript section
- fix new issue link in Multi-Tenant plugin section
- correct You can disabled to disable in Core Features
- fix duplicate section links for MongoDB and Postgres in Migrations
section