### What?
In the WhereBuilder Condition DefaultFilter component, there is a switch
statement that contains components to return based on the built filter
in the admin ui. Having a filter built out then navigating to another
collection list view causes an error to occur due to InternalField being
undefined but the DefaultFilter tries to access the field on it.
### Why?
To fix unexpected `cannot access property field of undefined` errors.
### How?
Adding a conditional chaining operator.
Odd thing here is that the `Text` component where this error originates
from doesn't actually make use of the passed `InternalField`. Might be
worth it to take a closer look at it.
Fixes#9179
Fixes types for workflows / jobs `input` and `output` when using
`strict: true` or `strictNullChecks: true` by ensuring that all
properties in generates types are requried
The Edit and Live Preview views were duplicately making the same Local
API requests for document data. This is because while the top-level
document view handler makes these requests _before_ rendering the Live
Preview view, it wasn't passing it's data through as props. This has
also led to inconsistencies in the options being passed through the
requests themselves, such as `locale`, `user`, and `overrideAccess:
false`. Everything is now standardized as expected through the existing
`getDocumentData` utility.
If you start a fresh dev server and open payload, the nav will initially
show as closed and then jump to its open state. This is because no
preferences are set, so the server tells the client to initially keep it
closed, despite the default nav state being _open_.
### What?
Custom providers could not be resolved because payload was not
initialized in the Root layout with the importMap passed in from props.
### How?
Pass importMap from props into the getPayload function in the Root
layout.
Fixes https://github.com/payloadcms/payload/issues/9288
### What?
When a block had a subfield named `blocks`, sanitization would throw an
error.
### Why?
An incorrect check for the key of `"fields"` would then attempt to pass
`data.blocks[key].fields` aka `data.blocks.fields.fields` to the next
call of `areAllPermissionsTrue` which would be undefined. Instead if the
key is `fields` it should pass `data.blocks[key]`.
### How?
Remove the second `.fields` property accessor.
Optimizes initial page responses by removing unnecessary inline field
styles that were being sent through the HTML response. The Client Config
contains a large number of duplicates of the string:
`"style\":{\"flex\":\"1 1 auto\"}`, one for every single field within
the entirely of the config. This leads to hundreds or potentially
thousands of instances of this same string, depending on the number of
fields within the config itself. This is regardless of custom field
widths being defined. Instead, we can do this entirely client-side,
preventing this string from ever being transmitted over the network in
the first place.
## Breaking Changes
This only effects those who are importing Payload's field components
into your own Custom Components or front-end application. The `width`
prop no longer exists. It has been consolidated into the existing
`style` prop. To migrate, simply move this prop as follows:
```diff
import { TextInput } from '@payloadcms/ui
export const MyCustomComponent = () => {
return (
<TextInput
- width="60%"
style={{
+ width: "60%,
}}
/>
)
}
```
### What?
Fixes potential errors when passed to `sanitizeRelationships` `ref`
could potentially be a non object (for example `string`) because of
having in the database data in old structure.
```
"Cannot create property 'a' on string 'B'",
```
### Why?
Necessary particularly for the migration script, as it migrates
everything including versions that can have outdated data.
### How?
Ensures passed `ref` is an `object`.
### What?
When a script attempts to load payload using `getPayload()`, it will end
with: `Error: connect ECONNREFUSED 127.0.0.1:3000` etc...
### Why?
Even though there is a try/catch, it still errors because WebSocket
connection failures happen asynchronously after the ws object is
instantiated.
### How?
Added the error handling function cached.ws.onerror to prevent exit.
Custom field description functions were being duplicately called in both
the Client Config and form state. Static field descriptions were also
being rendered in form state unnecessarily. Now, field description
functions are only executed once within form state, and static
descriptions are deferred to the client for rendering.
Supports bi-directional import/export between MDX <=> Lexical. JSX will
be mapped to lexical blocks back and forth.
This will allow editing our mdx docs in payload while keeping mdx as the
source of truth
---------
Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
### What?
Fixes the issue when visiting the create view with the Join Field and
using postgres adapter
```
invalid input syntax for type integer: "NaN"
```
This happens because we don't have an ID yet and we send to the
database:
`WHERE id = NaN`
### How?
Avoids calling `getTableState` inside of `RelationshipTable` if there's
no ID yet, as it will always lead to the same empty result. While we
_could_ avoid error directly in the database adapter, I don't think we
should do that render request
Fixes https://github.com/payloadcms/payload/issues/9193
### What?
Previously, this code led to a validation error because `movie` is an
object and you needed to use `movie.id` instead.
```ts
const movie = await payload.create({ collection: 'movies', data: {} })
const result = await payload.create({
collection: 'object-writes',
data: {
many: [movie],
manyPoly: [{ relationTo: 'movies', value: movie }],
one: movie,
onePoly: {
relationTo: 'movies',
value: movie,
},
},
})
```
While it's simple to modify this example, it's more painful when you
have a data with `depth` > 0 and then you want to update that document.
### Why?
Better DX as less checks needed, and TypeScript says that we can pass an
object.
### How?
Sanitizes the field value in the root `beforeValidate` hook
The field RSC now provides an initial state for all lexical blocks. This
completely obliterates any flashes and lexical block loading states when
loading or saving a document.
Previously, when a document is loaded or saved, every lexical block was
sending a network request in order to fetch their form state. Now, this
is batched and handled in the lexical server component. All lexical
block form states are sent to the client together with the parent
lexical field, and are thus available immediately.
We also do the same with block collapsed preferences. Thus, there are no
loading states or layout shifts/flashes of blocks anymore.
Additionally, when saving a document while your cursor is inside a
lexical field, the cursor position is preserved. Previously, a document
save would kick your cursor out of the lexical field.
## Look at how nice this is:
https://github.com/user-attachments/assets/21d736d4-8f80-4df0-a782-7509edd993da
**BREAKING:**
This removes the `feature.hooks.load` and `feature.hooks.save`
interfaces from custom lexical features, as they weren't used internally
and added unnecessary, additional overhead.
If you have custom features that use those, you can migrate to using
normal payload hooks that run on the server instead of the client.
With this PR, you can now customize the way that `blocks` and
`inlineBlocks` are rendered within Lexical's `BlocksFeature` by passing
your own React components.
This is super helpful when you need to create "previews" or more
accurate UI for your Lexical blocks.
For example, let's say you have a `gallery` block where your admins
select a bunch of images. By default, Lexical would just render a
collapsible with your block's fields in it. But now you can customize
the `admin.components.Block` property on your `block` config by passing
it a custom React component for us to render instead.
So using that, with this `gallery` example, you could make a dynamic
gallery React component that shows the images to your editors - and then
render our built-in `BlockEditButton` to allow your editors to manage
your gallery in a drawer.
Here is an example where the BlockEditButton is added to the default
Block Collapsible/Header:

---------
Co-authored-by: James <james@trbl.design>
Deprecates `getPayloadHMR` and simplifies this pattern into a single
`import { getPayload } from 'payload'`.
We will still retain the exported `getPayloadHMR` but it now will throw
a deprecation warning with instructions for how to migrate.
Custom `account` and `dashboard` views now defined as lowercase in the
config. This is to maintain consistency with all other custom views
throughout the config. The underlying reason for this change is that
previously, you could define React Components directly on these
properties. Now, these are strictly _view configuration objects_, and
the property names have been adjusted in order to semantically reflect
that. These two views in particular, however, were never updated
accordingly.
## Breaking Changes
```diff
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: {
components: {
// ...
views: {
// ...
- Account: ...
- Dashboard: ...
+ account: ...
+ dashboard: ...
},
},
},
})
```
Fixes#9246. Custom default root views (account and dashboard) were not
being properly thread to the custom component renderer. Custom account
views were also improperly _stacking_ instead of _replacing_ the default
view.
Tests for this are incoming. To properly test this we need to wrap our
default root views with custom ones, so that out existing `admin` test
suite can continue to work alongside tests specifically for this issue.
This PR fixes cases where you may have a field called `id` within a
group or a named tab, which would have incorrectly been treated as a
custom ID field for the collection.
However, custom IDs need to be defined at the root level - and now
Payload only respects custom IDs defined at the root level.
Protects the `/api/access` endpoint behind authentication and sanitizes
the result, making it more secure and significantly smaller. To do this:
1. The `permission` keyword is completely omitted from the result
2. Only _truthy_ access results are returned
3. All nested permissions are consolidated when possible
---------
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
**BREAKING:**
Improves type-safety of collection / global slugs by using `CollectionSlug` / `UploadCollectionSlug` and `GlobalSlug` types instead of `string` in these places:
Adds `UploadCollectionSlug` and `TypedUploadCollection` utility types
This also changes how we suggest to add an upload collection to a cloud-storage adapter:
Before:
```ts
azureStorage({
collections: {
[Media.slug]: true,
},
})
```
After:
```ts
azureStorage({
collections: {
media: true,
},
})
```
The collection list columns are stored as user preferences to the
payload-preferences collection. Normally one user should never have
duplicate documents with the same key. This is controlled by using an
upsert normally. The collection list does not have a good way to call
upsert and was creating preferences documents every time. This change
makes it so that existing preferences are updated rather than created
with each column change.
### What?
Upgrades mongoose from 6 to latest `v8.8.1`
Fixes https://github.com/payloadcms/payload/issues/9171
### Why?
Compatibilty with Mongodb Atlas
### How?
- Updates deps
- Changed ObjectId from bson-objectid to use `new Type.ObjectId` from
mongoose for compatibility (only inside of db-mongodb)
- Internal type adjustments
https://github.com/payloadcms/payload/discussions/9088
BREAKING CHANGES:
All projects with existing data having versions enabled, or relationship or upload fields will want to create the predefined migration that converts all strings to ObjectIDs where needed. This can be created using `payload migrate:create --file @payloadcms/mongodb/relationships-v2-v3`.
For projects making use of the exposed Models from mongoose, review the
upgrade guides from [v6 to
v7](https://mongoosejs.com/docs/7.x/docs/migrating_to_7.html) and [v7 to
v8](https://mongoosejs.com/docs/migrating_to_8.html) and make
adjustments as needed.
---------
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
The mongodb adapter `updateOne` method accepts an `options` argument
that allows query options to be passed to mongoose. This parameter was
added in https://github.com/payloadcms/payload/pull/8397 to support the
`upsert` operation.
This `options` parameter can also be useful when using the database
adaptor directly without going through the local api. It is true that
the Mongoose models could be used directly in such situations, but the
adapter methods include a lot of useful functionality, like for instance
the sanitization of document and relationship ids, so it is desirable to
be able to use the adapter functions while still being able to provide
mongoose query options (e.g. `{timestamps: false}`).
This PR adds the same options parameter to the other update methods of
the mongodb adapter.
### What?
Aligns types for HiddenField and the WatchCondition component with the
rest of the fields. Since path is required when rendering a Field
component, there is no need to keep it optional in the WatchCondition
component.
### Why?
Hidden fields were requiring the `field` property to be passed, but the
only reason it needed it was to allow the path to fallback to name if
path was not passed. But path is required so there is no need for this
anymore.
This makes using the HiddenField simpler now.
### How?
Adjusts type on the HiddenField and the WatchCondition component.
Similar to https://github.com/payloadcms/payload/pull/9195 but
specifically removing `i18n.supportedLanguages` from the client config.
This is a potentially large object that does not need to be sent through
the network when making RSC requests.
### What?
Changes the order of the `DefaultCellComponentProps` generic type,
allowing us to infer the type of cellData when a ClientField type is
passed as the first generic argument. You can override the cellData type
by passing the second generic.
Previously:
```ts
type DefaultCellComponentProps<TCellData = any, TField extends ClientField = ClientField>
```
New:
```ts
type DefaultCellComponentProps<TField extends ClientField = ClientField, TCellData = undefined>
```
### Why?
Changing the ClientField type to be the first argument allows us to
infer the cellData value type based on the type of field.
I could have kept the same signature but the usage would look like:
```ts
// Not very DX friendly
const MyCellComponent<DefaultCellComponentProps<,ClientField>> = () => null
```
### How?
The changes made
[here](https://github.com/payloadcms/payload/compare/chore/beta/simplify-DefaultCellComponentProps?expand=1#diff-24f3c92e546c2be3fed0bab305236bba83001309a7239c20a3e3dbd6f5f71dc6R29-R73)
allow this. You can override the type by passing in the second argument
to the generic.