Improves the logging that `routeError` throws.
Logs were sometimes being swallowed if there was a problem with the
incoming request. Now they will surface.
## Description
Allows some fields to be collapsed in the version diff view. The fields
that can be collapsed are the ones which can also be collapsed in the
edit view, or that have visual grouping:
- `collapsible`
- `group`
- `array` (and their rows)
- `blocks` (and their rows)
- `tabs`
It also
- Fixes incorrect indentation of some fields
- Fixes the rendering of localized tabs in the diff view
- Fixes locale labels for the group field
- Adds a field change count to each collapsible diff (could imagine this
being used in other places)
- Brings the indentation gutter back to help visualize multiple nesting
levels
## Future improvements
- Persist collapsed state across page reloads (sessionStorage vs
preferences)
## Screenshots
### Without locales

### With locales

--------------
- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
## Type of change
<!-- Please delete options that are not relevant. -->
- [x] New feature (non-breaking change which adds functionality)
## Checklist:
- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] ~I have made corresponding changes to the documentation~
Fixes https://github.com/payloadcms/payload/issues/10787
This is the first part of the fix for
https://github.com/payloadcms/payload/issues/10787.
The second part is https://github.com/payloadcms/payload/pull/10785
The `packages/plugin-form-builder/src/types.ts` file contains many more
types besides MessageField.message that are unnecessarily `unknown` or
`any`.
In this PR I'm only fixing that one because:
1. It's what's needed to fix the issue.
2. I want to avoid a breaking change (they should be improved in v4
though).
I don't think MessageField.message will cause a breaking change for
anyone, since it's based on a rich text field.
### What?
- Removes the tenant cookie when the user logs out
- Prevents double redirect to globals when no tenant is selected
### Why?
There were a couple scenarios where the cookie and the tenant did not
match, ie if you logged into 1 tenant, and then out and then into
another tenant.
Field validations currently run very often, such as within form state on
type. This can lead to serious performance implications within the admin
panel if those validation functions are async, especially if they
perform expensive database queries. One glaring example of this is how
all relationship and upload fields perform a database lookup in order to
evaluate that the given value(s) satisfy the defined filter options. If
the field is polymorphic, this can happen multiple times over, one for
each collection. Similarly, custom validation functions might also
perform expensive tasks, something that Payload has no control over.
The fix here is two-fold. First, we now provide a new `event` arg to all
`validate` functions that allow you to opt-in to performing expensive
operations _only when documents are submitted_, and fallback to
significantly more performant validations as form state is generated.
This new pattern will be the new default for relationship and upload
fields, however, any custom validation functions will need to be
implemented in this way in order to take advantage of it. Here's what
that might look like:
```
[
// ...
{
name: 'text'
type: 'text',
validate: async (value, { event }) => {
if (event === 'onChange') {
// Do something highly performant here
return true
}
// Do something more expensive here
return true
}
}
]
```
The second part of this is to only run validations _after the form as
been submitted_, and then every change event thereafter. This work is
being done in #10580.
This was a tricky one.
Fixes https://github.com/payloadcms/payload/issues/10700
May potentially fix 9163
This could have also been causing glitchyness related to things like
lexical upload / relationship / link node population.
## Issue and solution explained
The lexical field afterRead hook is responsible for executing afterRead
hooks (this includes relationship population) for all sub-nodes, e.g.
upload or block nodes.
Any field and population promises that were created in the process of
traversing the lexical editor state were added to the parent
`fieldPromises` and `populationPromises` array.
Now this lexical `afterRead` hook, which is responsible for creating and
adding all field and population promises of its sub-nodes to the parent
`fieldPromises` and `populationPromises` arrays, was itself part of the
**same** `fieldPromises` array.
The execution of this lexical `afterRead` hook itself is happening while
the `fieldPromises` array is being awaited. This means that new field
and population promises were being added to this same array DURING the
process of awaiting all promises of this array.
As a result, any promises dynamically added while awaiting the initial
set of fieldPromises were not included in the initial `Promise.all()`
awaiting process, leading to unhandled promises.
This PR resolves the issue by ensuring that promises are repeatedly
awaited until no new promises remain in the arrays. By continuously
awaiting the `fieldPromises` and `populationPromises` until all
dynamically added promises are fully resolved, this PR ensures that any
promises added during the processing of a parent promise are also
properly awaited. This guarantees that no promises are skipped,
preserving the intended behavior of the afterRead hook
- Blocks can now be selected (only inline blocks were possible before).
- Any DecoratorNode that users create will have the necessary logic out
of the box so that they are selected with a click and deleted with
backspace/delete.
- By having the code for selecting and deleting centralized, a lot of
repetitive code was eliminated
- More performant code due to the use of event delegation. There is only
one listener, previously there was one for each decoratorNode.
- Heuristics to exclude scenarios where you don't want to select the
node: if it is inside the DecoratorNode, but is also inside a button,
input, textarea, contentEditable, .react-select, .code-editor or
.no-select-decorator. That last one was added as a means of opt-out.
- Fix#10634
Note: arrow navigation will be introduced in a later PR.
https://github.com/user-attachments/assets/92f91cad-4f70-4f72-a36f-c68afbe33c0d
### What
This PR adds a filtering mechanism to exclude certain reserved fields
from being displayed in the `Edit Many` drawer for bulk uploads. This
ensures that only relevant fields are available for bulk editing.
### Why
Fields like `filename`, `mimeType`, and `filesize` are not intended to
be edited in bulk. Filtering these fields streamlines the interface and
focuses on fields that are meaningful for bulk operations.
### How
- Introduced a `filterOutUploadFields` utility to exclude reserved
fields from the field selection in bulk uploads.
- Applied this filter to the `Edit Many` drawer, ensuring a more
relevant and user-friendly experience.
- Reserved fields include properties like `file`, `mimeType`, `url`,
`width`, `height`, and others that are not applicable for bulk editing.
### What?
This PR introduces the ability to bulk edit multiple uploads
simultaneously within the `Edit all` option for bulk uploads. Users can
now select fields to update across all selected uploads in a single
operation.
### Why?
Managing multiple uploads individually can be time-consuming and
inefficient, especially when updating common fields. This feature
streamlines the process, improving user experience and productivity when
handling bulk uploads.
### How?
* Added an `Edit Many` drawer component specific to bulk uploads that
allows users to select fields for bulk editing.
* Enhanced the FormsManager and related logic to ensure updates are
applied consistently across all selected uploads.

- Fixes collection and tab descriptions not having a bottom padding:
- Deprecates `description` on tabs config in favour of
`admin.description` but supports both
- Adds test to make sure `admin.description` renders with static string
and function too for tabs
Fixes an issue where pasting text over a selection will automatically
add it as a link instead of replacing the text. This is caused by poor
regex matching in the case of relative URLs.
Added tests and strengthened both absolute and relative URL matchers
### What?
When switching tenants from within a document and then navigating back
out to the list view, the tenant would not be set correctly.
### Why?
This was because we handle the tenant selector selection differently
when viewing a document.
### How?
Now when you navigate out, the page will refresh the cookie.
Also adds test suite config that shows how the dom can be used to
manipulate styles per tenant.
Running `pnpm add @payloadcms/plugin-multi-tenant@beta` will install
`v.0.0.1` which is outdated:
https://www.npmjs.com/package/@payloadcms/plugin-multi-tenant?activeTab=versions
I suspect the intention was to remove `@beta` from the plugin install
instructions with yesterday's Payload `v3.18.0` release which also
bumped `plugin-multi-tenant` to `v3.18.0`, but this might have been
missed.
### What?
Fixes issue where the provider would throw an error and prevent the
login screen from loading if there was no user.
### Why?
Missing try/catch around tenant find for the provider. (Missed because
test suites have autoLogin: true)
### How?
Adds try/catch around find query.
### What?
Currently it is not possible to override the upload component.
### Why?
The ability to override the upload component is missing from
`renderDocumentSlots`.
### How?
Adding a check to include the custom upload component if it is
available.
This issue is holding me back from releasing a payload plugin.
Fixes#9591
Previously, we were unnecessarily passing the `ClientCollectionConfig`
down from the Table to the Client, even though the client cell
components could simply access it via the `useConfig` hook. This
resulted in redundant data being sent to the client for every single
table cell. Additionally, we were performing a deep copy of the
`ClientCollectionConfig`, which wasted both memory and CPU resources on
the server.
---------
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Custom block row labels defined on `admin.components.Label` were not
rendering despite existing in the config. Instead, if a custom label
component was defined on the _top-level_ blocks field itself, it was
incorrectly replacing each blocks label _in addition_ to the field's
label. Now, custom labels defined at the field-level now only replace
the field's label as expected, and custom labels defined at the
block-level are now supported as the types suggest.
Previously, the beforeValidate hook was deepCopying input data. This
indirectly ensured that the passed input data was not mutated.
E.g., if you run the `payload.create` local API, you do not want that to
mutate the `data` object that is passed as an argument. This will create
issues if you attempt to use it multiple times.
This PR moves the deepCopy logic from the beforeValidate hook to the
start of the local API operation. This ensures that
- Input data is intentionally copied at the beginning which makes more
sense. Comment was added to explain why
- GraphQL and Rest operations are now faster, as we don't need to ensure
that the input data is not mutated for those => deepCopy only runs for
local API
Following https://github.com/payloadcms/payload/pull/10551, I found and
fixed a handful more bugs:
- When writing to the input, the results that were already there were
not cleaned, causing incorrect results to appear.
- the scroll was causing an infinite loop that showed repeated elements
- optimization: only the required field is selected (not required)
- refs are set to the initial value to avoid a state where nothing can
be searched
https://github.com/payloadcms/payload/pull/9962 could be considered a
breaking change - this PR restores compatibility by allowing unknown
collection slugs, while still providing type suggestions.
Bumps the following dependencies:
- next
- typescript
- http-status
- nodemailer
- Payload & next versions in all templates
- Monorepo only: playwright and dotenv
Removes unused dependencies:
- ts-jest
- jest-environment-jsdom
- resend (we don't use their sdk, we only use their rest API)