### What?
Previously, the `admin.group` property on `collection` / `global`
configs allowed for a custom group and the `admin.hidden` property would
not only hide the entity from the nav sidebar / dashboard but also
disable its routes.
### Why?
There was not a simple way to hide an entity from the nav sidebar /
dashboard but still keep the entities routes.
### How?
Now - we've added the `false` type to the `admin.group` field to account
for this.
Passing `false` to `admin.group` will hide the entity from the sidebar
nav and dashboard but keep the routes available to navigate.
I.e
```
admin: {
group: false,
},
```
Previously, Autosave could trigger 2 parallel fetches where the second
could outpace the first, leading to inconsistent results.
Now, we use a simple queue-based system where we can push multiple
autosave events into a queue, and only the latest autosave will be
performed.
This also prevents multiple autosaves from ever running in parallel.
Continuation of #9846 and partial fix for #9774. When setting
`admin.disableListFilter` retroactively, it remains active within the
list filter controls. Same for when the URL search query contains one of
these fields, except this will actually display the _wrong_ field,
falling back to the _first_ field from the config. The fix is to
properly disable the condition for this field if it's an active filter,
while still preventing it from ever rendering as an option within the
field selector itself.
Partial fix for #9774. When `admin.disableListColumn` is set
retroactively, it continues to appear in column state, but shouldn't.
This was because the table column context was not refreshing after HMR
runs, and would instead hold onto these stale columns until the page
itself refreshes. Similarly, this was also a problem when the user had
saved any of these columns to their list preferences, where those prefs
would take precedence despite these properties being set on the
underlying fields. The fix is to filter these columns from all requests
that send them, and ensure local component state properly refreshes
itself.
### What?
It became possible for fields to reset to a defined `defaultValue` when
bulk editing from the `edit-many` drawer.
### Why?
The form-state of all fields were being considered during a bulk edit -
this also meant using their initial states - this meant any fields with
default values or nested fields (`arrays`) would be overwritten with
their initial states
I.e. empty values or default values.
### How?
Now - we only send through the form data of the fields specifically
being edited in the edit-many drawer and ignore all other fields.
Leaving all other fields stay their current values.
Fixes#9590
---------
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
### What?
Previously, `initCollapsed: true` `array` fields would auto collapse
when typing in their respective inputs while in the create new view.
### Why?
This was due to the fact that we were only checking if `preferences`
existed in `form state` to handle the current state of the array row and
then falling back on the `initCollapsed` prop if `preferences` didn't
exist.
This was a problem because during create - `preferences` do not exist
yet. As a result, the state of the array row would keep falling back to
collapsed if `initCollapsed` was set to `true`.
### How?
To fix this, we now check the actual form state first before falling
back to preferences and then falling back to the initCollapsed prop
value.
Fixes#9775
The join field was not respecting the defaultSort or defaultLimit of the
field configuration.
### Why?
This was never implemented.
### How?
This fix applies these correct limit and sort properties to the query,
first based on the field config and as a fallback, the collection
configuration.
### What?
Fixes issue with stale locale from searchParams
### Why?
Bad use of useEffect/useState inside our useSearchParams provider.
### How?
Memoize the locale instead of relying on the useEffect which was causing
unnecessary renders with stale values.
### What?
The `<header>` dom node was rendering even if empty for group fields.
Causing extra margin to be added even if no label/description were
provided.
### Why?
If the field had no label, description or errors it would still render.
### How?
Wraps the header node in an additional condition that checks for label,
description or errors before rendering the node.
- [fix: join field shows loading when creating a
document](9f7a2e7936)
- [fix: join field
descriptions](90e8cdb464)
- [feat(ui): adds before & after inputs to join
field](19d43329ad)
---------
Co-authored-by: Patrik <patrik@payloadcms.com>
### What?

### Why?
`user.id` was being used as a dependency is callbacks and when the user
was logged out due to inactivity the above error would throw.
### How?
Added optional chaining to the dependency.
Fixes https://github.com/payloadcms/payload/issues/9701
### What?
Previously, when defining `localization.locales` like this:
```ts
localization: {
defaultLocale: 'en',
locales: [{ label: { en: 'ESLocale' }, code: 'es' },{ label: { en: 'ESLocale' }, code: 'en' }],
},
```
The title in "copy to locale" modal was displayed incorrectly
```
Copy to locale: Copying from [object Object] to [object Object]
```
### How?
Uses the `getTranslation` function to handle this behavior properly
### What?
Write conflict errors can arise when collections have hooks.
### Why?
The copyDataFromLocale local API calls to update were not passsing req
so changes could be made on different transcations.
### How?
Fixed the error by passing `req` and also introduced some perf
optimizations using `depth` and disabling `joins` since that data isn't
needed for this operation.
Adds configuration options to `auth.disableLocalStrategy` to allow
customization of how payload treats an auth enabled collection.
Two new properties have been added to `disableLocalStrategy`:
- `enableFields` Include auth fields on the collection even though the
local strategy is disabled. Useful when you do not want the database or
types to vary depending on the auth configuration used.
- `optionalPassword`: makes the password field not required
As described in #9576, the `SearchParamsProvider` can become stale when
navigating routes and relying on search params during initial render.
This is because this context, along with the `ParamsProvider`, is
duplicative to the internal lifecycle of `useSearchParams` and
`useParams` from `next/navigation`– but always one render behind.
Instead, we need to use the hooks directly from `next/navigation` as
described in the jsdocs. This will also remove any abstraction over top
the web standard for `URLSearchParams`.
For this reason, these providers and their corresponding hooks have been
marked with the deprecated flag and will continue to behave as they do
now, but will be removed in the next major release. This PR replaces all
internal reliance on these hooks with `next/navigation` as suggested,
except for the `useParams` hook, which was never used in the first
place.
```diff
'use client'
- import { useSearchParams } from '@payloadcms/ui'
+ import { useSearchParams } from 'next/navigation'
+ import { parseSearchParams } from '@payloadcms/ui'
export function MyClientComponent() {
- const { searchParams } = useSearchParams()
+ const searchParams = useSearchParams()
+ const parsedParams = parseSearchParams(searchParams)
// ...
}
```
_MyClientComponent.tsx_
Fixes https://github.com/payloadcms/payload/issues/9567. When using the
`AnimateHeight` component on a patched browser such as Webkit,
components with dynamically rendered children are not properly animating
in, such as blocks with rich text. This is because the height of that
content is unable to be calculated before it's rendered, preventing the
component from acquiring a target height to animate toward. This change
was originally introduced in #9456 in effort to remove unnecessary
dependencies.
The fix is to setup a ResizeObserver during animation to watch for
changes to the content's height. This way, as components dynamically
render in based on the "open" state, the hook will simply increment the
target height accordingly.
This PR updates all react and next-related packages to the latest
version in our test directory and in our templates, while still allowing
older versions to be used.
Additionally, this ensures that the "scheduler" package version we
install matches the version installed by react-dom
### What?
When the document is saved the formState was not being reset from the
server.
### Why?
getFormState was not being called onSuccess of the form submission
### How?
The `Form` onSuccess function now allows for an optional return type of
`FormState` if the functions returns formState then we check to see if
that differs from the current formState on the client. If it does then
we dispatch the `REPLACE_STATE` action with the newState.
Fixes https://github.com/payloadcms/payload/issues/9423
Closes#9132. When query params are present in the URL, such as after
searching or filtering in the list view, they are not being retained
after navigating back to that view via `history.back()` (i.e. the back
button). This makes it difficult to quickly navigate in and out of
documents from the list view when an underlying search exists. This was
because the `SearchParamsProvider` is stale when the new view renders,
which then replaces the URL with these stale params. The fix here is to
_not_ use the `SearchParamsProvider` at all, and instead use
`next/navigation` directly. Ultimately, this provider should likely be
marked deprecated and then removed in the next major release for this
very reason.
When using the `admin.hidden: true` property on a collection, it
rightfully removes all navigation and routing for that particular
collection. However, this also affects the expected behavior of hidden
entities when they are rendered within a drawer, such as the document
drawer or list drawer. For example, when creating a new _admin.hidden_
document through the relationship or join field, the drawer should still
render the view, despite the underlying route for that view being
disabled. This change was a result of the introduction of on-demand
server components in #8364, where we now make a server roundtrip to
render the view in its entirety, which include the logic that redirects
these hidden entities.
Now, we pass a new `overrideEntityVisibility` argument through the
server function that, when true, skips this step. This way documents can
continue to respect `admin.hidden` while also having the ability to
override on a case-by-case basis throughout the UI.