Fixes https://github.com/payloadcms/payload/issues/13565
The logout operation was running twice and causing a race condition on
user updates. This change ensures the logout operation only runs 1 time.
Really this view should have 1 purpose and that is to show the
inactivity view. Currently it has 2 purposes which is why it needs the
useEffect — the root of this issue. Instead we should just call the
`logOut` function from the logout button instead of it linking to a
logout page.
### What?
Ensure the Rich Text field is read-only when viewing a locked document.
### Why?
When opening a locked doc in read-only mode, the Rich Text field could
still appear editable. This is inconsistent with other fields and allows
users to try typing into a locked document.
### How?
- Pass `readOnly={isTrashedDoc || isLocked}` into `buildFormState` in
the edit view renderer.
Fixes#13527.
When upgrading to [Next.js 15.5](https://nextjs.org/blog/next-15-5) with
Payload, you might experience a runtime or build error similar to this:
```ts
Type error: Type 'typeof import("/src/app/(payload)/api/graphql/route")' does not satisfy the expected type 'RouteHandlerConfig<"/api/graphql">'.
Types of property 'OPTIONS' are incompatible.
Type '(request: Request, args: { params: Promise<{ slug: string[]; }>; }) => Promise<Response>' is not assignable to type '(request: NextRequest, context: { params: Promise<{}>; }) => void | Promise<void> | Response | Promise<Response>'.
Types of parameters 'args' and 'context' are incompatible.
Type '{ params: Promise<{}>; }' is not assignable to type '{ params: Promise<{ slug: string[]; }>; }'.
Types of property 'params' are incompatible.
Type 'Promise<{}>' is not assignable to type 'Promise<{ slug: string[]; }>'.
Property 'slug' is missing in type '{}' but required in type '{ slug: string[]; }'.
```
This is because Next.js route types are now _stricter_. Our REST handler
is nested within a catch-all `/api/[...slug]` route, so the slug param
_will_ exist in the handler—but the _same_ handler is re-used for the
`/api/graphql` OPTIONS route, which **_is not_** nested within the
`slug` param and so it **_will not_** exist as the types suggest.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1211115021865680
---------
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Adjustment to https://github.com/payloadcms/payload/pull/13526
Prefer to thread ID through arguments instead of relying on routeParams
which would mean that ID is always a string - would not work for PG dbs
or non-text based ID's.
### What?
Make the document `id` available to server-rendered admin components
that expect it—specifically `EditMenuItems` and
`BeforeDocumentControls`—so `props.id` matches the official docs.
### Why?
The docs show examples using `props.id`, but the runtime `serverProps`
and TS types didn’t include it. This led to `undefined` at render time.
### How?
- Add id to ServerProps and set it in renderDocumentSlots from
req.routeParams.id.
Fixes#13420
This PR fixes some incorrect field paths handling (=> should not pass
path and schema paths that contain index paths down to sub-fields
outside of the indexPath property) when building the version fields.
Fixes https://github.com/payloadcms/payload/issues/12376
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210932060696925
<!--
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 translates the block and item label in the version view, as well
as the version label in the step nav.
### Why?
To appropriately translate labels in the version views.
### How?
By using the TFunction from useTranslation as well as existing
translation keys.
Fixes#13193Fixes#13194
### What?
Fixes an issue where using a function as the `label` for a `tabs` field
causes the versions UI to break.
### Why?
The versions UI was not properly resolving function labels on `tab`
fields, leading to a crash when trying to render them.
### How?
Tweaked the logic so that if the label is a function, it gets called
before rendering.
Fixes#13375
## What
Before this PR, an internal link in the Lexical editor could reference a
document from a different tenant than the active one.
Reproduction:
1. `pnpm dev plugin-multi-tenant`
2. Log in with `dev@payloadcms.com` and password `test`
3. Go to `http://localhost:3000/admin/collections/food-items` and switch
between the `Blue Dog` and `Steel Cat` tenants to see which food items
each tenant has.
4. Go to http://localhost:3000/admin/collections/food-items/create, and
in the new richtext field enter an internal link
5. In the relationship select menu, you will see the 6 food items at
once (3 of each of those tenants). In the relationship select menu, you
would previously see all 6 food items at once (3 from each of those
tenants). Now, you'll only see the 3 from the active tenant.
The new test verifies that this is fixed.
## How
`baseListFilter` is used, but now it's called `baseFilter` for obvious
reasons: it doesn't just filter the List View. Having two different
properties where the same function was supposed to be placed wasn't
feasible. `baseListFilter` is still supported for backwards
compatibility. It's used as a fallback if `baseFilter` isn't defined,
and it's documented as deprecated.
`baseFilter` is injected into `filterOptions` of the internal link field
in the Lexical Editor.
When grouping by a checkbox field, boolean values are not translated,
causing labels to render incorrectly, and falsey values to render
without a heading.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210979856538211
When grouping by a date field and its value is null, the list view
crashes.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210979856538208
Field-level permissions were not handled correctly at all. If you had a
field set with access control, this would mean that nested fields would
incorrectly be omitted from the version view.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210932060696919
### What?
Fixes an issue where document links in the trash view were incorrectly
generated when group-by was enabled for a collection. Previously, links
in grouped tables would omit the `/trash` segment, causing navigation to
crash while trying to route to the default edit view instead of the
trashed document view.
### Why?
When viewing a collection in group-by mode, document rows are rendered
in grouped tables via the `handleGroupBy` logic. However, these tables
were unaware of whether the view was operating in trash mode, so the
generated row links did not include the necessary `/trash` segment. This
broke navigation when trying to view or edit trashed documents.
### How?
- Threaded the `viewType` prop through `renderListView` into the
`handleGroupBy` utility.
- Passed `viewType` into each `renderTable` call within `handleGroupBy`,
ensuring proper link generation.
- `renderTable` already supports `viewType` and appends `/trash` to edit
links when it's set to 'trash'.
### What?
- Updated `TrashView` to pass `trash: true` as a dedicated prop instead
of embedding it in the `query` object.
- Modified `renderListView` to correctly merge `trash` and `where`
queries by using both `queryFromArgs` and `queryFromReq`.
- Ensured filtering (via `where`) works correctly in the trash view.
### Why?
Previously, the `trash: true` flag was injected into the `query` object,
and `renderListView` only used `queryFromArgs`.
This caused the `where` clause from filters (added by the
`WhereBuilder`) to be overridden, breaking filtering in the trash view.
### How?
- Introduced an explicit `trash` prop in `renderListView` arguments.
- Updated `TrashView` to pass `trash: true` separately.
- Updated `renderListView` to apply the `trash` filter in addition to
any `where` conditions.
When grouping by a relationship field and it's value is `null`, the list
view crashes.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210916642997992
Fixes#12975.
When editing autosave-enabled documents through the join field, the
document drawer closes unexpectedly on every autosave interval, making
it nearly impossible to use.
This is because as of #12842, the underlying relationship table
re-renders on every autosave event, remounting the drawer each time. The
fix is to lift the drawer out of table's rendering tree and into the
join field itself. This way all rows share the same drawer, whose
rendering lifecycle has been completely decoupled from the table's
state.
Note: this is very similar to how relationship fields achieve similar
functionality.
This PR also adds jsdocs to the `useDocumentDrawer` hook and strengthens
its types.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210906078627353
Catches list filter errors and prevents the list view from crashing when
attempting to search on fields the user does not have access to. Instead
just shows the default "no results found" message.
Custom document tab components (server components) do not receive the
`user` prop, as the types suggest. This makes it difficult to wire up
conditional rendering based on the user. This is because tab conditions
don't receive a user argument either, forcing you to render the default
tab component yourself—but a custom component should not be needed for
this in the first place.
Now they both receive `req` alongside `user`, which is more closely
aligned with custom field components.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210906078627357
### What?
- Fixed an issue where group-by enabled collections with `trash: true`
were not showing trashed documents in the collection’s trash view.
- Ensured that the `trash` query argument is properly passed to the
`findDistinct` call within `handleGroupBy`, allowing trashed documents
to be included in grouped list views.
### Why?
Previously, when viewing the trash view of a collection with both
**group-by** and **trash** enabled, trashed documents would not appear.
This was caused by the `trash` argument not being forwarded to
`findDistinct` in `handleGroupBy`, which resulted in empty or incorrect
group-by results.
### How?
- Passed the `trash` flag through all relevant `findDistinct` and `find`
calls in `handleGroupBy`.
- bumps next.js from 15.3.2 to 15.4.4 in monorepo and templates. It's
important to run our tests against the latest Next.js version to
guarantee full compatibility.
- bumps playwright because of peer dependency conflict with next 15.4.4
- bumps react types because why not
https://nextjs.org/blog/next-15-4
As part of this upgrade, the functionality added by
https://github.com/payloadcms/payload/pull/11658 broke. This PR fixes it
by creating a wrapper around `React.isValidElemen`t that works for
Next.js 15.4.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210803039809808
### What?
This PR introduces complete trash (soft-delete) support. When a
collection is configured with `trash: true`, documents can now be
soft-deleted and restored via both the API and the admin panel.
```
import type { CollectionConfig } from 'payload'
const Posts: CollectionConfig = {
slug: 'posts',
trash: true, // <-- New collection config prop @default false
fields: [
{
name: 'title',
type: 'text',
},
// other fields...
],
}
```
### Why
Soft deletes allow developers and admins to safely remove documents
without losing data immediately. This enables workflows like reversible
deletions, trash views, and auditing—while preserving compatibility with
drafts, autosave, and version history.
### How?
#### Backend
- Adds new `trash: true` config option to collections.
- When enabled:
- A `deletedAt` timestamp is conditionally injected into the schema.
- Soft deletion is performed by setting `deletedAt` instead of removing
the document from the database.
- Extends all relevant API operations (`find`, `findByID`, `update`,
`delete`, `versions`, etc.) to support a new `trash` param:
- `trash: false` → excludes trashed documents (default)
- `trash: true` → includes both trashed and non-trashed documents
- To query **only trashed** documents: use `trash: true` with a `where`
clause like `{ deletedAt: { exists: true } }`
- Enforces delete access control before allowing a soft delete via
update or updateByID.
- Disables version restoring on trashed documents (must be restored
first).
#### Admin Panel
- Adds a dedicated **Trash view**: `/collections/:collectionSlug/trash`
- Default delete action now soft-deletes documents when `trash: true` is
set.
- **Delete confirmation modal** includes a checkbox to permanently
delete instead.
- Trashed documents:
- Displays UI banner for better clarity of trashed document edit view vs
non-trashed document edit view
- Render in a read-only edit view
- Still allow access to **Preview**, **API**, and **Versions** tabs
- Updated Status component:
- Displays “Previously published” or “Previously a draft” for trashed
documents.
- Disables status-changing actions when documents are in trash.
- Adds new **Restore** bulk action to clear the `deletedAt` timestamp.
- New `Restore` and `Permanently Delete` buttons for
single-trashed-document restore and permanent deletion.
- **Restore confirmation modal** includes a checkbox to restore as
`published`, defaults to `draft`.
- Adds **Empty Trash** and **Delete permanently** bulk actions.
#### Notes
- This feature is completely opt-in. Collections without trash: true
behave exactly as before.
https://github.com/user-attachments/assets/00b83f8a-0442-441e-a89e-d5dc1f49dd37
Supports grouping documents by specific fields within the list view.
For example, imagine having a "posts" collection with a "categories"
field. To report on each specific category, you'd traditionally filter
for each category, one at a time. This can be quite inefficient,
especially with large datasets.
Now, you can interact with all categories simultaneously, grouped by
distinct values.
Here is a simple demonstration:
https://github.com/user-attachments/assets/0dcd19d2-e983-47e6-9ea2-cfdd2424d8b5
Enable on any collection by setting the `admin.groupBy` property:
```ts
import type { CollectionConfig } from 'payload'
const MyCollection: CollectionConfig = {
// ...
admin: {
groupBy: true
}
}
```
This is currently marked as beta to gather feedback while we reach full
stability, and to leave room for API changes and other modifications.
Use at your own risk.
Note: when using `groupBy`, bulk editing is done group-by-group. In the
future we may support cross-group bulk editing.
Dependent on #13102 (merged).
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210774523852467
---------
Co-authored-by: Paul Popus <paul@payloadcms.com>
### What?
Refactors the `LeaveWithoutSaving` modal to be generic and delegates
document unlock logic back to the `DefaultEditView` component via a
callback.
### Why?
Previously, `unlockDocument` was triggered in a cleanup `useEffect` in
the edit view. When logging out from the edit view, the unlock request
would often fail due to the session ending — leaving the document in a
locked state.
### How?
- Introduced `onConfirm` and `onPrevent` props for `LeaveWithoutSaving`.
- Moved all document lock/unlock logic into `DefaultEditView`’s
`handleLeaveConfirm`.
- Captures the next navigation target via `onPrevent` and evaluates
whether to unlock based on:
- Locking being enabled.
- Current user owning the lock.
- Navigation not targeting internal admin views (`/preview`, `/api`,
`/versions`).
---------
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
Prevents base list filters from being injected into the URL.
This is a problem with the multi-tenant plugin, for example, where
changing the tenant adds a `baseListFilter` to the query, but should
never be exposed to the end user.
Introduced in #13200.
### What?
This PR ensures that when a document is created using the `Publish in
__` button, it is saved to the correct locale.
### Why?
During document creation, the buttons `Publish` or `Publish in [locale]`
have the same effect. As a result, we overlooked the case where a user
may specifically click `Publish in [locale]` for the first save. In this
scenario, the create operation does not respect the
`publishSpecificLocale` value, so the document was always saved in the
default locale regardless of the intended one.
### How?
Passes the `publishSpecificLocale` value to the create operation,
ensuring the document and version is saved to the correct locale.
**Fixes:** #13117
Some search params within the list view do not properly sync to user
preferences, and visa versa.
For example, when selecting a query preset, the `?preset=123` param is
injected into the URL and saved to preferences, but when reloading the
page without the param, that preset is not reactivated as expected.
### Problem
The reason this wasn't working before is that omitting this param would
also reset prefs. It was designed this way in order to support
client-side resets, e.g. clicking the query presets "x" button.
This pattern would never work, however, because this means that every
time the user navigates to the list view directly, their preference is
cleared, as no param would exist in the query.
Note: this is not an issue with _all_ params, as not all are handled in
the same way.
### Solution
The fix is to use empty values instead, e.g. `?preset=`. When the server
receives this, it knows to clear the pref. If it doesn't exist at all,
it knows to load from prefs. And if it has a value, it saves to prefs.
On the client, we sanitize those empty values back out so they don't
appear in the URL in the end.
This PR also refactors much of the list query context and its respective
provider to be significantly more predictable and easier to work with,
namely:
- The `ListQuery` type now fully aligns with what Payload APIs expect,
e.g. `page` is a number, not a string
- The provider now receives a single `query` prop which matches the
underlying context 1:1
- Propagating the query from the server to the URL is significantly more
predictable
- Any new props that may be supported in the future will automatically
work
- No more reconciling `columns` and `listPreferences.columns`, its just
`query.columns`
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210827129744922
As discussed in [this
RFC](https://github.com/payloadcms/payload/discussions/12729), this PR
supports collection-scoped folders. You can scope folders to multiple
collection types or just one.
This unlocks the possibility to have folders on a per collection instead
of always being shared on every collection. You can combine this feature
with the `browseByFolder: false` to completely isolate a collection from
other collections.
Things left to do:
- [x] ~~Create a custom react component for the selecting of
collectionSlugs to filter out available options based on the current
folders parameters~~
https://github.com/user-attachments/assets/14cb1f09-8d70-4cb9-b1e2-09da89302995
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210564397815557
Previously, we were always initializing cronjobs when calling
`getPayload` or `payload.init`.
This is undesired in bin scripts - we don't want cron jobs to start
triggering db calls while we're running an initial migration using
`payload migrate` for example. This has previously led to a race
condition, triggering the following, occasional error, if job autoruns
were enabled:
```ts
DrizzleQueryError: Failed query: select "payload_jobs"."id", "payload_jobs"."input", "payload_jobs"."completed_at", "payload_jobs"."total_tried", "payload_jobs"."has_error", "payload_jobs"."error", "payload_jobs"."workflow_slug", "payload_jobs"."task_slug", "payload_jobs"."queue", "payload_jobs"."wait_until", "payload_jobs"."processing", "payload_jobs"."updated_at", "payload_jobs"."created_at", "payload_jobs_log"."data" as "log" from "payload_jobs" "payload_jobs" left join lateral (select coalesce(json_agg(json_build_array("payload_jobs_log"."_order", "payload_jobs_log"."id", "payload_jobs_log"."executed_at", "payload_jobs_log"."completed_at", "payload_jobs_log"."task_slug", "payload_jobs_log"."task_i_d", "payload_jobs_log"."input", "payload_jobs_log"."output", "payload_jobs_log"."state", "payload_jobs_log"."error") order by "payload_jobs_log"."_order" asc), '[]'::json) as "data" from (select * from "payload_jobs_log" "payload_jobs_log" where "payload_jobs_log"."_parent_id" = "payload_jobs"."id" order by "payload_jobs_log"."_order" asc) "payload_jobs_log") "payload_jobs_log" on true where ("payload_jobs"."completed_at" is null and ("payload_jobs"."has_error" is null or "payload_jobs"."has_error" <> $1) and "payload_jobs"."processing" = $2 and ("payload_jobs"."wait_until" is null or "payload_jobs"."wait_until" < $3) and "payload_jobs"."queue" = $4) order by "payload_jobs"."created_at" asc limit $5
params: true,false,2025-07-10T21:25:03.002Z,autorunSecond,100
at NodePgPreparedQuery.queryWithCache (/Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/drizzle-orm@0.44.2_@libsql+client@0.14.0_bufferutil@4.0.8_utf-8-validate@6.0.5__@opentelemetr_asjmtflojkxlnxrshoh4fj5f6u/node_modules/src/pg-core/session.ts:74:11)
at processTicksAndRejections (node:internal/process/task_queues:105:5)
at /Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/drizzle-orm@0.44.2_@libsql+client@0.14.0_bufferutil@4.0.8_utf-8-validate@6.0.5__@opentelemetr_asjmtflojkxlnxrshoh4fj5f6u/node_modules/src/node-postgres/session.ts:154:19
... 6 lines matching cause stack trace ...
at N._trigger (/Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/croner@9.0.0/node_modules/croner/dist/croner.cjs:1:16806) {
query: `select "payload_jobs"."id", "payload_jobs"."input", "payload_jobs"."completed_at", "payload_jobs"."total_tried", "payload_jobs"."has_error", "payload_jobs"."error", "payload_jobs"."workflow_slug", "payload_jobs"."task_slug", "payload_jobs"."queue", "payload_jobs"."wait_until", "payload_jobs"."processing", "payload_jobs"."updated_at", "payload_jobs"."created_at", "payload_jobs_log"."data" as "log" from "payload_jobs" "payload_jobs" left join lateral (select coalesce(json_agg(json_build_array("payload_jobs_log"."_order", "payload_jobs_log"."id", "payload_jobs_log"."executed_at", "payload_jobs_log"."completed_at", "payload_jobs_log"."task_slug", "payload_jobs_log"."task_i_d", "payload_jobs_log"."input", "payload_jobs_log"."output", "payload_jobs_log"."state", "payload_jobs_log"."error") order by "payload_jobs_log"."_order" asc), '[]'::json) as "data" from (select * from "payload_jobs_log" "payload_jobs_log" where "payload_jobs_log"."_parent_id" = "payload_jobs"."id" order by "payload_jobs_log"."_order" asc) "payload_jobs_log") "payload_jobs_log" on true where ("payload_jobs"."completed_at" is null and ("payload_jobs"."has_error" is null or "payload_jobs"."has_error" <> $1) and "payload_jobs"."processing" = $2 and ("payload_jobs"."wait_until" is null or "payload_jobs"."wait_until" < $3) and "payload_jobs"."queue" = $4) order by "payload_jobs"."created_at" asc limit $5`,
params: [ true, false, '2025-07-10T21:25:03.002Z', 'autorunSecond', 100 ],
cause: error: relation "payload_jobs" does not exist
at /Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/pg@8.16.3/node_modules/pg/lib/client.js:545:17
at processTicksAndRejections (node:internal/process/task_queues:105:5)
at /Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/drizzle-orm@0.44.2_@libsql+client@0.14.0_bufferutil@4.0.8_utf-8-validate@6.0.5__@opentelemetr_asjmtflojkxlnxrshoh4fj5f6u/node_modules/src/node-postgres/session.ts:161:13
at NodePgPreparedQuery.queryWithCache (/Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/drizzle-orm@0.44.2_@libsql+client@0.14.0_bufferutil@4.0.8_utf-8-validate@6.0.5__@opentelemetr_asjmtflojkxlnxrshoh4fj5f6u/node_modules/src/pg-core/session.ts:72:12)
at /Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/drizzle-orm@0.44.2_@libsql+client@0.14.0_bufferutil@4.0.8_utf-8-validate@6.0.5__@opentelemetr_asjmtflojkxlnxrshoh4fj5f6u/node_modules/src/node-postgres/session.ts:154:19
at find (/Users/alessio/Documents/GitHub/payload2/packages/drizzle/src/find/findMany.ts:162:19)
at Object.updateMany (/Users/alessio/Documents/GitHub/payload2/packages/drizzle/src/updateJobs.ts:26:16)
at updateJobs (/Users/alessio/Documents/GitHub/payload2/packages/payload/src/queues/utilities/updateJob.ts:102:37)
at runJobs (/Users/alessio/Documents/GitHub/payload2/packages/payload/src/queues/operations/runJobs/index.ts:181:25)
at Object.run (/Users/alessio/Documents/GitHub/payload2/packages/payload/src/queues/localAPI.ts:137:12)
at N.fn (/Users/alessio/Documents/GitHub/payload2/packages/payload/src/index.ts:866:13)
at N._trigger (/Users/alessio/Documents/GitHub/payload2/node_modules/.pnpm/croner@9.0.0/node_modules/croner/dist/croner.cjs:1:16806) {
length: 112,
severity: 'ERROR',
code: '42P01',
detail: undefined,
hint: undefined,
position: '406',
internalPosition: undefined,
internalQuery: undefined,
where: undefined,
schema: undefined,
table: undefined,
column: undefined,
dataType: undefined,
constraint: undefined,
file: 'parse_relation.c',
line: '1449',
routine: 'parserOpenTable'
}
}
```
This PR makes running crons opt-in using a new `cron` flag. By default,
no cron jobs will be created.
Currently, when a nonexistent document is accessed via the URL, a
`NotFound` page is displayed with a button to return to the dashboard.
In most cases, the next step the user will take is to navigate to the
list of documents in that collection. If we automatically redirect users
to the list view and display the error in a banner, we can save them a
couple of redirects.
This is a very common scenario when writing tests or restarting the
local environment.
## Before

## After

Occasionally, I find myself on a URL like
`https://domain.com/admin/collections/myCollection/docId` and I modify
the URL with the intention of going to the admin panel, but I shorten it
in the wrong place: `https://domain.com/admin/collections`.
The confusion arises because the admin panel basically displays the
collections.
I think this redirect is a subtle but nice touch, since `/collections`
is a URL that doesn't exist.
EDIT: now I'm doing also the same thing for `/globals`
Ensures Live Preview url functions aren't fired during create or on
collections that do not have Live Preview enabled.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210743577153852
This adds a new `analyze` step to our CI that analyzes the bundle size
for our `payload`, `@payloadcms/ui`, `@payloadcms/next` and
`@payloadcms/richtext-lexical` packages.
It does so using a new `build:bundle-for-analysis` script that packages
can add if the normal build step does not output an esbuild-bundled
version suitable for analyzing. For example, `ui` already runs esbuild,
but we run it again using `build:bundle-for-analysis` because we do not
want to split the bundle.
---
- To see the specific tasks where the Asana app for GitHub is being
used, see below:
- https://app.asana.com/0/0/1210692087147570
### What?
Adds `token` into the `initialState` for the reset password form to
ensure `token` does not get passed through as `undefined`.
### Why?
Currently the reset password UI is broken because `token` is not getting
passed to the form state.
### How?
Adds `token` to `initialState`
Fixes#13040