Updated README asset URL
<!--
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?
Update README asset URL for hero
### Why?
Reflect latest Payload branding
### How?
URL change for correct asset
-->
### What?
Adds full support for the point field to Postgres and Vercel Postgres
adapters through the Postgis extension. Fully the same API as with
MongoDB, including support for `near`, `within` and `intersects`
operators.
Additionally, exposes to adapter args:
*
`tablesFilter`https://orm.drizzle.team/docs/drizzle-kit-push#including-tables-schemas-and-extensions.
* `extensions` list of extensions to create, for example `['vector',
'pg_search']`, `postgis` is created automatically if there's any point
field
### Why?
It's essential to support that field type, especially if the postgres
adapter should be out of beta on 3.0 stable.
### How?
* Bumps `drizzle-orm` to `0.36.1` and `drizzle-kit` to `0.28.0` as we
need this change https://github.com/drizzle-team/drizzle-orm/pull/3141
* Uses its functions to achieve querying functionality, for example the
`near` operator works through `ST_DWithin` or `intersects` through
`ST_Intersects`.
* Removes MongoDB condition from all point field tests, but keeps for
SQLite
Resolves these discussions:
https://github.com/payloadcms/payload/discussions/8996https://github.com/payloadcms/payload/discussions/8644
fix: migrateRefresh migrates without previously ran migrations
chore: adds tests for database migrate:fresh and migrate:refresh
---------
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
### What?
Moved the logic for copying the data.id to data._id to the mongoose
adapter.
### Why?
If you have any hooks that need to set the `id`, the value does not get
sent to mongodb as you would expect since it was copied before the
beforeValidate hooks.
### How?
Now data._id is assigned only in the mongodb adapter's `create`
function.
BREAKING CHANGES:
When using custom ID fields, if you have any collection hooks for
beforeValidate, beforeChange then `data._id` will no longer be assigned
as this happens now in the database adapter. Use `data.id` instead.
Closes#9000
When you update a relationship document via the document drawer, the
initial document is registering `modified: true`. We should only set
modified to true on the initial document if the relationship id has
changed.
### What?
Fixes issue with incorrect `totalDocs` value when an aggregation is used
for `find`.
Previously, `limit: 5` for example always returned `totalDocs: 5`.
### Why?
`totalDocs` must be returned correctly.
### How?
Removes `$limit` from the pipeline, as `Model.aggregatePaginate` handles
it by itself.
### What?
Because of my error, we didn't pass `populate` to `findOperation` from
the Local API.
### Why?
`populate` must work for every operation that has `depth`.
### How?
Passes `populate` in `operations/local/find.ts`, ensures it works with
the test, checked that other operations pass it.
### What?
Updated the Bulgarian translations for improved accuracy.
- Fixed translations that were not in Bulgarian. (Czech and Russian)
- Fixed translations that contained typos.
- Improved some translations to use more accurate wording.
Co-authored-by: Teodora Yaneva <theodorayaneva@gmail.com>
## Description
Corrected `emailOrPasswordIncorrect` translation for Danish (da)
- [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
- [x] fix (non-breaking change)
### What?
Fixes a formatting issue that prevents
payloadcms.com/docs/beta/jobs-queue/overview from displaying properly.
There were a couple `<strong>` tags in the `jobs-queue/overview` docs
that did not have proper closing `</strong>` tags.
Using the headless editor was very glitchy. If the server encounters any error anywhere, then any consecutive visit of the list view, where the headless editor will run, will throw a lexical error about no active editor being found when "parseEditorState" is run, despite parseEditorState initializing a new active editor. This is cached in module scope, and server-side errors in Next.js seem to break that behavior for some reason
`create-payload-app` will now use git tags when cloning down the
templates instead of using latest from a branch.
The mechanism is cpa will read its own package.json version and use that
as a git tag prefixed w/ `v`
### What?
- Makes `jobs.workflows` optional
- Dynamically include the `workflowSlugs` select field in the jobs
collection as needed
### Why?
When configuring jobs, it should be possible to define `job` with just
some simple tasks and not be forced to define workflows.
### How?
Workflows type was made optional and optional chaining is added where
needed. The workflowSlugs field is added to the jobs collection if
workflows are defined.
Fixes #
When using postgres, the workflowSlugs being an empty enum cause an
error when drizzle fails to detect the enum already exists. This results
in the error `"enum_payload_jobs_workflow_slug" already exists`. Drizzle
tries to make the enum as: `enum_payload_jobs_workflow_slug as enum();`
and the check for existing enums only works when it has values.
## Problem
When `PayloadRequest` objects are logged using `console.log`, it creates
unstructured, multiline entries in logging services like DataDog and
Sentry. This circumvents the structured logging approach used throughout
the rest of the codebase.
## Solution
Replace `console.x` calls with the structured logging system when
logging `payload.logger.x` objects. This ensures consistent log
formatting and better integration with monitoring tools.
## Changes
- Replaced instances of `console.log` with structured logging methods
only in `@payloadcms/next`
- Maintains logging consistency across the codebase
- Improves log readability in DataDog, Sentry, and other monitoring
services
## First
<img width="914" alt="Screenshot 2024-11-06 at 09 53 44"
src="https://github.com/user-attachments/assets/019b6f4b-40ed-4e54-a92a-8d1b50baa303">
## Then
<img width="933" alt="Screenshot 2024-11-06 at 00 50 29"
src="https://github.com/user-attachments/assets/0a339db4-d706-4ff9-ba8c-80445bbef5d0">
### What?
Generates types for `joins` property.
Example from our `joins` test, keys are type-safe:
<img width="708" alt="image"
src="https://github.com/user-attachments/assets/f1fbbb9d-7c39-49a2-8aa2-a4793ae4ad7e">
Output in `payload-types.ts`:
```ts
collectionsJoins: {
categories: {
relatedPosts: 'posts';
hasManyPosts: 'posts';
hasManyPostsLocalized: 'posts';
'group.relatedPosts': 'posts';
'group.camelCasePosts': 'posts';
filtered: 'posts';
singulars: 'singular';
};
};
```
Additionally, we include type information about on which collection the
join is, it will help when we have types generation for `where` and
`sort`.
### Why?
It provides a better DX as you don't need to memoize your keys.
### How?
Modifies `configToJSONSchema` to generate the json schema for
`collectionsJoins`, uses that type within `JoinQuery`
### What?
Adds `populate` property to Local API and REST API operations that can
be used to specify `select` for a specific collection when it's
populated
```ts
const result = await payload.findByID({
populate: {
// type safe if you have generated types
posts: {
text: true,
},
},
collection: 'pages',
depth: 1,
id: aboutPage.id,
})
result.relatedPost // only has text and id properties
```
```ts
fetch('https://localhost:3000/api/pages?populate[posts][text]=true') // highlight-line
.then((res) => res.json())
.then((data) => console.log(data))
```
It also overrides
[`defaultPopulate`](https://github.com/payloadcms/payload/pull/8934)
Ensures `defaultPopulate` doesn't affect GraphQL.
### How?
Implements the property for all operations that have the `depth`
argument.
### What?
Handles database name with special characters. For example: `-` -
`my-awesome-app`.
### Why?
Previously, `my-awesome-app` led to this error:
```
Error: failed to create database my-awesome-app.
Details: syntax error at or near "-"
```
This can reproduced for example with `create-payload-app`, as the
generated db name is based on project's name.
### How?
Wraps the query variable to quotes, `create database "my-awesome-app"`
instead of `create database my-awesome-app`.
### What?
Uses sequential pattern for Bulk Upload instead of `Promise.all`.
### Why?
* Concurrent uploads led to filename conflicts for example when you have
`upload.png` and `upload(1).png` already and you try to upload
`upload.png`
* Potentially expensive for resources, especially with high amount of
files / sizes
### How?
Replaces `Promise.all` with `for` loop, adds indicator "Uploaded 2/20"
to the loading overlay.
---------
Co-authored-by: James <james@trbl.design>
Setting a custom `id` field within unnamed fields causes duplicative ID
fields to be appear in the client config. When a top-level `id` field is
detected in your config, Payload uses that instead of injecting its
default field. But when nested within unnamed fields, such as an unnamed
tab, these custom `id` fields were not being found, causing the default
field to be duplicately rendered into tables columns, etc.
### What?
Makes it possible to filter join documents using a `where` added
directly in the config.
### Why?
It makes the join field more powerful for adding contextual meaning to
the documents being returned. For example, maybe you have a
`requiresAction` field that you set and you can have a join that
automatically filters the documents to those that need attention.
### How?
In the database adapter, we merge the requested `where` to the `where`
defined on the field.
On the frontend the results are filtered using the `filterOptions`
property in the component.
Fixes
https://github.com/payloadcms/payload/discussions/8936https://github.com/payloadcms/payload/discussions/8937
---------
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
This happened through Slate => Upload Node Component => Swap (opens list drawer) => Select lexical error => Error here. This error is caused by a new initialization of an UploadNode
### What?
Fixes support for custom endpoints with `method: 'put'`.
Previously, this didn't work:
```ts
export default buildConfigWithDefaults({
collections: [ ],
endpoints: [
{
method: 'put',
handler: () => new Response(),
path: '/put',
},
],
})
```
### Why?
We supported this in 2.0 and docs are saying that we can use `'put'` as
`method`
https://payloadcms.com/docs/beta/rest-api/overview#custom-endpoints
### How?
Implements the `REST_PUT` export for `@payloadcms/next/routes`, updates
all templates. Additionally, adds tests to ensure root/collection level
custom endpoints with all necessary methods execute properly.
Fixes https://github.com/payloadcms/payload/issues/8807
-->
### What?
Makes this to actually work
```ts
import type { RequestContext as OriginalRequestContext } from 'payload'
declare module 'payload' {
// Create a new interface that merges your additional fields with the original one
export interface RequestContext extends OriginalRequestContext {
myObject?: string
// ...
}
}
```
<img width="502" alt="image"
src="https://github.com/user-attachments/assets/38570d3c-e8a8-48aa-a57d-6d11e79394f5">
### Why?
This is described in our docs
https://payloadcms.com/docs/beta/hooks/context#typescript therefore it
should work.
### How?
In order to get the declaration work, we need to reuse the type from the
root file `payload/src/index.js`. Additionally, removes `RequestContext`
type duplication in both `payload/src/types/index.js` and
`payload/src/index.js`.
Fixes https://github.com/payloadcms/payload/issues/8851
### What?
Any changes inside edit popup for the field with type `upload` and the
`relationTo` collection does nothing in context of the field, it has
affect only to collection.
I.e. when you make an edit to an uploads field in the edit drawer -
after saving and existing the drawer, your new changes are not present
until a refresh of the page.
### Why?
Previously, we were not performing a reload of the document fetch upon
saving of the doc in the edit drawer.
### How?
Now, we perform a reload (fetch) for updated docs on save within the
edit drawer.
Fixes#8837
### What?
If you have a custom field that sets the value of the field using the
`useField` hook on entry into a document - the `updatedAt` field would
be updated even when a non-owner tries to enter a locked document.
### Why?
When a field is updated in the edit view - we perform an update in
`form-state` to keep the doc in `payload-locked-documents` up to date
with the current editing status. The above scenario would hit this
update operation even on non-owner users because it was previously only
checking for `updateLastEdited` (which would get hit by the `setValue`
in the `useField` hook) so we also need to check to make sure the
current user entering a locked doc is also the owner of the document.
### How?
When performing an update to `payload-locked-documents` in
`buildFormState` - only perform the update if the current user is also
the owner of the locked document otherwise skip the `update` operation.
Fixes#8781
Adds the `x-powered-by` header to include Payload alongside Next.js
End result looks like this
```
x-powered-by:
Next.js, Payload
```
It also respects the nextConfig `poweredBy: false` to completely disable
it
Potentially fixes#9012 by disabling prefetch for all Next.js `Link`
component usage.
With prefetch left as the default and _on_, there were cases where the
prefetch could fetch stale data for Edit routes. Then, when navigating
to the Edit route, the data could be stale.
In addition, I think there is some strangeness happening on the Next.js
side where prefetched data might still come from the router cache even
though router cache is disabled.
This fix should be done regardless, but I suspect it will solve for a
lot of stale data issues.
GraphQL currently doesn't pass CORS checks as we don't expose an OPTIONS
endpoint which is used for browser preflights.
Should also fix situations like this
https://github.com/payloadcms/payload/issues/8974
### What?
Fixes type for the `select` property when having `strictNullChecks:
true` or `strict: true` in tsconfig.
### Why?
`select` should provide autocompletion for users, at this point it
doesn't work with this condtiion
### How?
Makes `collectionsSelect` and `globalsSelect` properties required in
`configToJSONSchema.ts`.
Fixes
https://github.com/payloadcms/payload/pull/8550#issuecomment-2452669237
### What?
Fixes the issue with querying by `id` from REST / `overrideAccess:
false`.
For example, this didn't work:
`/api/loans?where[book.bibliography.id][equals]=67224d74257b3f2acddc75f4`
```
QueryError: The following path cannot be queried: id
```
### Why?
We support this syntax within the Local API.
### How?
Now, for simplicity we sanitize everything like
`relation.otherRelation.id` to `relation.otherRelation`
Fixes https://github.com/payloadcms/payload/issues/9008
### What?
Includes `hasMany`, `minRows`, and `maxRows` in Upload field config
options table.
### Why?
To be inline with the type definitions.
### How?
Changes to `docs/fields/upload.mdx`
### What?
Fixes `select` handling for properties inside of unnamed tabs using the
mongodb adapter.
Additionally, refactors `traverseFields` in drizzle to reuse logic from
groups / collapsible or rows if unnamed.
### Why?
`select` must work for any fields.
### How?
Fixes the `'tab'` case in `buildProjectionFromSelect` to handle when the
field is an unnamed tab.
Adds extra tests for named tabs / unnamed.
### What?
When read access is restricted on the `users` collection - restricted
users would not have access to other users complete user data object
only their IDs when accessing `user.value`.
### Why?
This is problematic when determining the lock status of a document from
a restricted users perspective as `user.id` would not exist - the user
data would not be an object in this case but instead a `string` or
`number` value for user ID
### How?
This PR properly handles both cases now and checks if the incoming user
data is an object or just a `string` / `number`.
## The SEO plugin now takes in a function to override or add in new
fields
- `fieldOverrides` has been removed
- `fields` is now a function that takes in `defaultFields` and expects
an array of fields in return
This makes it a lot easier for end users to override and extend existing
fields and add new ones. This change also brings this plugin inline with
the pattern that we use in our other plugins.
```ts
// before
seoPlugin({
fieldOverrides: {
title: {
required: true,
},
},
fields: [
{
name: 'customField',
type: 'text',
}
]
})
// after
seoPlugin({
fields: ({ defaultFields }) => {
const modifiedFields = defaultFields.map((field) => {
// Override existing fields
if ('name' in field && field.name === 'title') {
return {
...field,
required: true,
}
}
return field
})
return [
...modifiedFields,
// Add a new field
{
name: 'ogTitle',
type: 'text',
label: 'og:title',
},
]
},
})
```
## Also fixes
- Localization labels not showing up on default fields
- The inability to add before and after inputs to default fields
https://github.com/payloadcms/payload/issues/8893
<!--
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?
`auth` enabled collections show "Password" fields whenever a GraphQL
query is performed or the GraphQL playground is opened (see #8032)
You can reproduce this behavior by spinning up the `admin` test with
PostgreSQL:
```bash
pnpm dev:postgres admin
```
Open the admin UI and navigate to the `dev@payloadcms.com` document in
the `Users` collection (see screenshot below)
<img width="915" alt="image"
src="https://github.com/user-attachments/assets/40624a8f-80b7-412b-b851-5e3643ffcae1">
Open the [GraphQL
playground](http://localhost:3000/api/graphql-playground)
Open the admin UI and select the user again. The password field appears
multiple times.
Subsequent GraphQL playground page refreshes lead to even more password
fields in the admin UI.
<img width="1086" alt="image"
src="https://github.com/user-attachments/assets/009264bd-b153-4bf7-8fc9-8e465fc27247">
The current behavior has an impact during development and even on
production. Since the password field is added to the collection, payload
tries to add this field to the database as well (at least I could
observe at in my own project)
### Why?
In the `packages/graphql/src/schema/initCollections.ts` file, the
`initCollections` function mutates the config object by adding the
password field for the GraphQL schema (line 128). This mutation adds the
field multiple times, depending how often you open the playground. In
addition, this added field is also shown in the UI since the config
object is shared (see screenshot above).
### How?
By creating a deep copy of the object, the mutation of the configuration
does not leak additional fields to the UI or other parts of the code.
Fixes an issue where using wildcards in upload-enabled collection
mimeType restrictions would prevent files from being selected in the
bulk upload file selector.
Adds a jobs queue to Payload.
- [x] Docs, w/ examples for Vercel Cron, additional services
- [x] Type the `job` using GeneratedTypes in `JobRunnerArgs`
(@AlessioGr)
- [x] Write the `runJobs` function
- [x] Allow for some type of `payload.runTask`
- [x] Open up a new bin script for running jobs
- [x] Determine strategy for runner endpoint to either await jobs
successfully or return early and stay open until job work completes
(serverless ramifications here)
- [x] Allow for job runner to accept how many jobs to run in one
invocation
- [x] Make a Payload local API method for creating a new job easily
(payload.createJob) or similar which is strongly typed (@AlessioGr)
- [x] Make `payload.runJobs` or similar (@AlessioGr)
- [x] Write tests for retrying up to max retries for a given step
- [x] Write tests for dynamic import of a runner
The shape of the config should permit the definition of steps separate
from the job workflows themselves.
```js
const config = {
// Not sure if we need this property anymore
queues: {
},
// A job is an instance of a workflow, stored in DB
// and triggered by something at some point
jobs: {
// Be able to override the jobs collection
collectionOverrides: () => {},
// Workflows are groups of tasks that handle
// the flow from task to task.
// When defined on the config, they are considered as predefined workflows
// BUT - in the future, we'll allow for UI-based workflow definition as well.
workflows: [
{
slug: 'job-name',
// Temporary name for this
// should be able to pass function
// or path to it for Node to dynamically import
controlFlowInJS: '/my-runner.js',
// Temporary name as well
// should be able to eventually define workflows
// in UI (meaning they need to be serialized in JSON)
// Should not be able to define both control flows
controlFlowInJSON: [
{
task: 'myTask',
next: {
// etc
}
}
],
// Workflows take input
// which are a group of fields
input: [
{
name: 'post',
type: 'relationship',
relationTo: 'posts',
maxDepth: 0,
required: true,
},
{
name: 'message',
type: 'text',
required: true,
},
],
},
],
// Tasks are defined separately as isolated functions
// that can be retried on fail
tasks: [
{
slug: 'myTask',
retries: 2,
// Each task takes input
// Used to auto-type the task func args
input: [
{
name: 'post',
type: 'relationship',
relationTo: 'posts',
maxDepth: 0,
required: true,
},
{
name: 'message',
type: 'text',
required: true,
},
],
// Each task takes output
// Used to auto-type the function signature
output: [
{
name: 'success',
type: 'checkbox',
}
],
onSuccess: () => {},
onFail: () => {},
run: myRunner,
},
]
}
}
```
### `payload.createJob`
This function should allow for the creation of jobs based on either a
workflow (group of tasks) or an individual task.
To create a job using a workflow:
```js
const job = await payload.createJob({
// Accept the `name` of a workflow so we can match to either a
// code-based workflow OR a workflow defined in the DB
// Should auto-type the input
workflowName: 'myWorkflow',
input: {
// typed to the args of the workflow by name
}
})
```
To create a job using a task:
```js
const job = await payload.createJob({
// Accept the `name` of a task
task: 'myTask',
input: {
// typed to the args of the task by name
}
})
```
---------
Co-authored-by: Alessio Gravili <alessio@gravili.de>
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
### What?
I noticed a spelling error in the banner of the beta docs and decided I
could save everyone some time by *running the entirety of the beta docs*
through a spellchecker.
### Why?
To fix many spelling and formatting mistakes at once.
### How?
By enabling `edit mode` in my browser and letting the built-in
spellchecker perform its magic (and changing _only_ where it made
sense).
~~Ironically, the original spelling mistake that inspired me to do this
remains unchanged as that is a part of the website repo. [PR for that is
here](https://github.com/payloadcms/website/pull/388).~~
### What?
Since the join field, we do store relationship fields values in
`ObjectID`. This wasn't true if the field is nested to an array /
blocks.
### Why?
All relationship fields values should be stored in `ObjectID`.
### How?
Fixes arrays / blocks handling in the `traverseFields.ts` function.
Before it didn't run for them.
### What?
Adds `defaultPopulate` property to collection config that allows to
specify which fields to select when the collection is populated from
another document.
```ts
import type { CollectionConfig } from 'payload'
// The TSlug generic can be passed to have type safety for `defaultPopulate`.
// If avoided, the `defaultPopulate` type resolves to `SelectType`.
export const Pages: CollectionConfig<'pages'> = {
slug: 'pages',
// I need only slug, NOT the WHOLE CONTENT!
defaultPopulate: {
slug: true,
},
fields: [
{
name: 'slug',
type: 'text',
required: true,
},
],
}
```
### Why?
This is essential for example in case of links. You don't need the whole
document, which can contain large data but only the `slug`.
### How?
Implements `defaultPopulate` when populating relationships, including
inside of lexical / slate rich text fields.
This PR aims to fix a few issues with the notFound page and custom views
so it matches v2 behaviour:
- Non authorised users should always be redirected to the login page
regardless if not found or valid URL
- Previously notFound would render for non users too potentially
exposing valid but protected routes and creating a confusing workflow as
the UI was being rendered as well
- Custom views are now public by default
- in our `admin` test suite, the `/admin/public-custom-view` is
accessible to non users but
`/admin/public-custom-view/protected-nested-view` is not unless the
checkbox is true in the Settings global, there's e2e coverage for this
- Fixes https://github.com/payloadcms/payload/issues/8716
Documentation updated to match current implementation.
Original Doc:
```ts
import { payloadCloud } from '@payloadcms/payload-cloud'
```
Current:
```ts
import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
```
---
References in docs have been updated.
### What?
Properly specifies `$lookup.from` when the collection name is singular.
### Why?
MongoDB can pluralize the collection name and so can be different for
singular ones.
### How?
Uses the collection name from the driver directly
`adapter.collections[slug].collection.name` instead of just `slug`.
The search plugin was incorrectly retrieving all locales, when it should
just be retrieving the locale of the parent document that was actively
being updated.
## BREAKING CHANGES:
If you have a localized Payload config, and you are using the `plugin-search`, we will now automatically localize the `title` field that is injected by the search plugin and this may lead to data loss. To opt out of this new behavior, you can pass `localize: false` to the plugin options.
Adds `select` which is used to specify the field projection for local
and rest API calls. This is available as an optimization to reduce the
payload's of requests and make the database queries more efficient.
Includes:
- [x] generate types for the `select` property
- [x] infer the return type by `select` with 2 modes - include (`field:
true`) and exclude (`field: false`)
- [x] lots of integration tests, including deep fields / localization
etc
- [x] implement the property in db adapters
- [x] implement the property in the local api for most operations
- [x] implement the property in the rest api
- [x] docs
---------
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
### What?
Adds a way to prevent creating new documents from the admin UI in a join
field.
### Why?
There are two reasons:
1. You want to disable this any time as a feature of your admin user
experience
2. When creating a new document it is not yet possible to create the
relationship, preventing create is necessary for the workflow to make
sense.
### How?
join field has a new admin property called `allowCreate`, can be set to
false. By default the UI will never allow create when the current
document being edited does not yet have an `id`.
Fixes #
#8892
### Before
Even though the document doesn't have an ID yet, the create buttons are
shown which doesn't actually work.

### After
Initial document creation:

Prevented using `allowCreate: false`

Corrects package import paths for live preview test.
- This would cause a import glitch when trying to run the live-preview
test due to incorrect file paths.
### What?
Fixes the issue with passing a string `limit` value from user
preferences to the mongodb `.aggregate` function.
To reproduce:
- click the list view for a collection that has a join field
- set "show per page" to 100
- reload, see this:
<img width="1001" alt="image"
src="https://github.com/user-attachments/assets/86c644d1-d183-48e6-bf34-0ccac23cb114">
### Why?
When using `.aggregate`, MongoDB doesn't cast a value for the `$limit`
stage to a number automatically as it's not handled by Mongoose. It's
also more convenient to store this value as a number.
### How?
Stores `limit` inside of preferences in number.
### What?
This PR aims to fix an issue in the form-builder plugin page - in the
`number` field table, where an issue with one of the columns makes the
whole table unformatted. [See issue
here](https://payloadcms.com/docs/beta/plugins/form-builder#number).
### Why?
As it stands, the whole table is being rendered without any formatting,
making understanding it very difficult.
### How?
Changes to `docs/plugins/form-builder.mdx`
`Issue`:
Previously, documents that were locked but expired would still show in
the list view / render the `DocumentLocked` modal upon other users
entering the document.
The expected outcome should be having expired locked documents seen as
unlocked to other users.
I.e:
- Removing the lock icon from expired locks in the list view.
- Prevent the `DocumentLocked` modal from appearing for other users -
requiring a take over.
`Fix`:
- Only query for locked documents that are not expired, aka their
`updatedAt` dates are greater than the the current time minus the lock
duration.
- Performs a `deleteMany` on expired documents when any user edits any
other document in the same collection.
Fixes#8778
`TODO`: Add tests
### What?
Fixes the issue with `in` querying when the collection has a join field.
### Why?
When using `.aggregate`, MongoDB doesn't cast a comma delimited value
for the `$in` operator to an array automatically as it's not handled by
Mongoose.
### How?
Sanitizes the incoming value to an array if it should.
Fixes https://github.com/payloadcms/payload/issues/8901
### What?
Allow specifying the defaultSort and defaultLimit to use for populating
a join field
### Why?
It is much easier to set defaults rather than be forced to always call
the join query using the query pattern ("?joins[categories][limit]=0").
### How?
See docs and type changes
<!--
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?
Updates the examples in the
[admin/metadata#root-metadata](https://payloadcms.com/docs/beta/admin/metadata#root-metadata)
and
[admin/metadata#icons](https://payloadcms.com/docs/beta/admin/metadata#icons)
sections from using `href` to `url` and fixes the way that the `images`
Type excludes the description due to `|` being parsed as column
separator
### Why?
As of right now, the examples are incorrect and the `images` type bleeds
into the description and omits it entirely
See image of table issue at `images`:

### How?
Changes to `metadata.mdx`
Fixes#8887
Credit to @thgh for the `href` to `url` find
While following the "Adding to an existing app" instructions for the
**beta** docs, I noticed that the pnpm installation commands for the
database adapters were missing the `@beta` tag, which will result in
errors in the project.
Fixes a potential race condition where versions could lose `latest:
true` and potentially also introduce a conflict with the `parent` field.
We now explicitly define these as we update versions in the
`saveVersion` function.
Previously, when opening e.g. a link drawer, clicking within the drawer,
and then closing it, the cursor / selection of the lexical editor will
reset to the beginning of the editor.
Now, we have dedicated logic to storing, preserving and restoring the
lexical selection when working with drawers.
This will work with all drawers. Links, uploads, relationships etc.
https://github.com/user-attachments/assets/ab3858b1-0f52-4ee5-813f-02b848355998
BREAKING CHANGE: Rename `@payloadcms/plugin-cloud` to
`@payloadcms/payload-cloud`. Anyone using the existing plugin will need
to switch to using the new package.
## Why?
Since v3 will be using _fixed versioning_, all versions of `^3` must be
available. Unfortunately, the `@payloadcms/plugin-cloud` version has
already breached that version number. Renaming will allow it to be on
the same version as other monorepo packages.
Additionally, the name `plugin-cloud` is quite ambiguous and sometimes
is confused with `plugin-cloud-storage`, so using `payload-cloud` feels
like a good move to make this more evident.
Fixes an annoying instance where on the /account page if you change your
theme then navigate away the Leaving without save popup is triggered
even though you don't need to submit a form or trigger a save in order
to change your admin theme.
This change adds support for sort with multiple fields in local API and
REST API. Related discussion #2089
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
### What?
Fixes https://github.com/payloadcms/payload/issues/5152 issue related to
sorting by a localized field with SQLite / Postgres database adapters.
### Why?
It was an incorrect behaviour.
### How?
Modifies the `getTableColumnFromPath` file to have correct join
conditions. Previously if you had this structure in the _locales table
_locale title parent
en A 1
es B 1
we sorted by everything that's here, but we need to sort only by the
passed locale.
Additionally fixes a typescript error in `dev.ts` that I added here
https://github.com/payloadcms/payload/pull/8834
Also, removes the condition with `joins.length` in `countDistinct`. It
was there as for this issue
https://github.com/payloadcms/payload/issues/4889 because sorting by a
localized property caused duplication. This can simnifically improve
performance for `.find` with nested querying/sorting on large data sets,
because `count(*)` is faster than `count(DISTINCT id)`
I'm extending the Slate editor with a custom component and everything
works great, except I have to import `useElement()` like this:
```tsx
import { useElement } from 'node_modules/.pnpm/@payloadcms+richtext-slate@3.0.0-beta.113_monaco-editor@0.51.0_next@15.0.0-canary.191_@babel+_qmdxs6s5hpzjhuopohgawpvl6i/node_modules/@payloadcms/richtext-slate/dist/field/providers/ElementProvider.js'
export function Element() {
const { attributes, children } = useElement()
return (
<p {...attributes} className="rich-text-preheading">
{children}
</p>
)
}
```
That's because it's not in the `@payloadcms/richtext-slate/client`
module. This PR fixes this and would allow me to do:
```tsx
import { useElement } from '@payloadcms/richtext-slate/client'
```
Apparently, `nextDev` seems to run in a different process and has its
own env variables, we can run the dev server the same way we run it for
E2Es instead via `createServer`.
Example:
```sh
pnpm add @payloadcms/plugin-sentry
```
to:
```sh
pnpm add @payloadcms/plugin-sentry@beta
```
Because of this, people can be confused with the wrong installed
version. We'll change it back on stable
Adjust drizzle init for changes in drizzle 0.35.0
https://github.com/drizzle-team/drizzle-orm/releases/tag/0.35.0
The pool/connection should now be passed as the `client` arg when
initializing drizzle.
```ts
this.drizzle = drizzle({
client: this.poolOptions ? new VercelPool(this.poolOptions) : sql,
logger,
schema: this.schema,
})
```
This was causing an issue where running `payload migrate` on Vercel was
causing drizzle to attempt to `127.0.0.1:5432` instead of the specified
environment variable in the adapter 🤔
1
`import type { Field } from 'payload/types'`
to
`import type { Field } from 'payload'`
2
`import { buildConfig } from 'payload/config'`
to
`import { buildConfig } from 'payload'`
3
```
import { SelectInput, useField } from 'payload/components/forms';
import { useAuth } from 'payload/components/utilities';
```
to
`import { SelectInput, useAuth, useField } from '@payloadcms/ui'`
4
uses `import type` for `import type { CollectionConfig } from 'payload'`
Fixes a missing import in field prop example in
docs/beta/admin/fields.mdx.
<!--
For external contributors, please include:
- A summary of the pull request and any related issues it fixes.
- Reasoning for the changes made or any additional context that may be
useful.
Ensure you have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
-->
See comments in code for proper explanation. In some cases, where 2
richtext `editor`s referencing the same `editor` are used, the admin
panel will hang. That's because the server will send their client props
that have the same object reference down to the client twice.
Next.js sometimes does not like this and, ever since one of the v15
canaries, started to hang
## Description
The goal is to reduce CLS on collapsed/expanded state of Lexical blocks.
That state is stored as "preferences" and is different for each user.
As Payload has been working so far, if the state of a Lexical block was
"collapsed", it was rendered expanded, and when the correct state was
obtained from the server, it was collapsed producing a CLS with a poor
UX.
My original idea was to get the correct state on the first render.
Talking to @AlessioGr and @jmikrut, we saw that this can be a bit
difficult or challenging, since the feature on the server does not have
access to the Payload object, nor to the user who is making the request.
I was instructed to mimic the behavior of blocks not in Lexial
(`\ui\src\fields\Collapsible\index.tsx`). There the blocks are rendered
after the collapse/expand state is obtained in a useEffect.
In the following video, the case where the first block is collapsed is
shown, rendering everything with a "fast 4G" connection throttle.
https://github.com/user-attachments/assets/078e37c7-6540-4183-a266-bd751cc9d78e
Yes, it's a slight improvement over current behavior. But it could be
much better. There are request waterfalls several levels deep, and
plenty of CLS still.
Unless there is some very big tradeoff that I'm not aware of, I think
it's worth exposing the Payload object and the user to the server in
order to get the correct state on the first render.
And if that's not possible and the request has to be made on the client,
I think initializing the state as collapsed and then expanding it is
better than not showing it at all.
Another observation that is evident from the video, is that there are
several sources or causes of CLS besides the expanded/collapsed state of
the blocks.
- [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
- [x] Bug fix (non-breaking change which fixes an issue)
## 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
- [x] I have made corresponding changes to the documentation
Currently in the `beta` docs at the bottom of [Local API Overview Import
It
section](https://payloadcms.com/docs/beta/local-api/overview#importing-it)
there is a link for _Outside Nextjs_ which incorrectly sends you to
`/docs/beta/beta/local-api/outside-nextjs` instead of
`docs/beta/local-api/outside-nextjs`.
Interestingly enough, a `Not Found` component/message is not rendered
and instead you see a blank screen.
---------
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
Fixes https://github.com/payloadcms/payload/issues/8752
Previously, trying to define a config like this:
```ts
{
type: 'text',
name: 'someText',
index: true,
},
{
type: 'array',
name: 'some',
index: true,
fields: [
{
type: 'text',
name: 'text',
index: true,
},
],
}
```
Lead to the error:
```
Warning We've found duplicated index name across public schema. Please rename your index in either the demonstration table or the table with the duplicated index name
```
Now, if we encounter duplicates, we increment the name like this:
`collection_some_text_idx`
`collection_some_text_1_idx`
---------
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
Fixes https://github.com/payloadcms/payload/issues/8224
Fixes an issue with PG `where` filters not being respected when
generating doc policies/permissions by utilizing the combineQueries
function in getEntityPolicies function.
Fixes#8589
### Issue:
There were problems with updating documents in
`payload-locked-documents` collection i.e when "taking over" a document
- a `patch` request is sent to `payload-locked-documents` to update the
user (owner).
However, as a result, this `update` operation would lock that
corresponding doc in `payload-locked-documents` and therefore error on
the `patch` request.
### Fix:
Disable document locking entirely from `payload-locked-documents` &
`preferences` & `migrations` collections
Fixes#8673
This PR restricts inputs with `type="file"` to only those mimetypes
specified in collection upload configs. This also works for the input in
`bulkUpload` and drag-and-drop capabilities by omitting dropped files if
they do not conform to the upload config mimetypes. This PR also assumes
that an upload config with an empty mimetype array should accept all
files since the negation of that statement makes an upload collection
redundant.
Inheriting all the fixes from drizzle moving to latest versions
## BREAKING CHANGES
If you have a prior version of @libsql/client installed in your project,
you must upgrade to 0.14.0
commit 7a0609ab57
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 10:00:34 2024 -0400
wires abort controller into server fn provider
commit 633aaa721d
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 09:50:12 2024 -0400
adjust err handling
commit 860b6cf2bf
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 09:26:01 2024 -0400
safely accesses signal
commit 463e05d7b9
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 09:13:39 2024 -0400
adds additional ac check prior to firing action
commit 231c4b3d1f
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 09:00:45 2024 -0400
cleanup
commit 494c970b0a
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Mon Oct 7 08:46:28 2024 -0400
more acs
commit 8dcb2eae17
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sun Oct 6 23:33:53 2024 -0400
adds abort controllers to docinfo and form actions
commit 0da4326e43
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sun Oct 6 23:05:14 2024 -0400
adds back remaining actions
commit 292d8b53e4
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sun Oct 6 22:53:44 2024 -0400
thrads abort controller to onchange
commit ca8629e5a6
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sun Oct 6 22:02:20 2024 -0400
reintroduces some actions
commit 5f001c0f52
Merge: 75dd030e22ba40f333
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sat Oct 5 09:15:25 2024 -0400
Merge branch 'beta' into feat/server-actions
commit 2ba40f3335
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Sat Oct 5 09:13:43 2024 -0400
chore: removes duplicative join field test (#8558)
There are two of the exact same e2e tests for the join field, which
throws an error when running these tests locally because they have
identical names.
commit 463490f670
Author: Elliot DeNolf <denolfe@users.noreply.github.com>
Date: Fri Oct 4 18:38:27 2024 -0700
fix(templates): await params/cookies properly (#8560)
commit d564cd44e9
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 17:29:38 2024 -0400
chore: deflakes lexical e2e test (#8559)
This has caused me great pain. The problem with this test is that the
page was waiting for a URL which includes a search query that never
arrives. This moves the check into a regex pattern for a more accurate
catch.
commit 75dd030e24
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 16:26:19 2024 -0400
reverts reset back to fetch to test
commit 7c62e2a327
Author: Paul <paul@payloadcms.com>
Date: Fri Oct 4 13:02:56 2024 -0600
feat(ui)!: scope all payload css to payload-default layer (#8545)
All payload css is now encapsulated inside CSS layers under `@layer
payload-default`
Any custom css will now have the highest possible specificity.
We have also provided a new layer `@layer payload` if you want to use
layers and ensure that your styles are applied after payload.
To override existing styles in a way that the existing rules of
specificity would be respected you can use the default layer like so
```css
@layer payload-default {
// my styles within the payload specificity
}
```
commit 400293b8ee
Author: Sasha <64744993+r1tsuu@users.noreply.github.com>
Date: Fri Oct 4 21:46:41 2024 +0300
fix: duplicate with upload collections (#8552)
Fixes the duplicate operation with uploads
Enables duplicate for upload collections by default
commit e4a413eb9a
Author: Elliot DeNolf <denolfe@gmail.com>
Date: Fri Oct 4 11:31:06 2024 -0700
chore(release): v3.0.0-beta.111 [skip ci]
commit b99590f477
Author: Sasha <64744993+r1tsuu@users.noreply.github.com>
Date: Fri Oct 4 21:28:43 2024 +0300
chore(templates): update templates with next.js promises (#8547)
Updates templates according to this PR
https://github.com/payloadcms/payload/pull/8489
commit a4704c1453
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 13:53:52 2024 -0400
moves docinfo back to fetch to test
commit 0d3416c96d
Author: Alessio Gravili <alessio@gravili.de>
Date: Fri Oct 4 13:39:03 2024 -0400
fix(db-postgres): missing types for db.pool by moving @types/pg from devDependencies to dependencies (#8556)
Fixes lack of types in installed project:

Since we expose stuff from @types/pg to the end user, we need it to be
installed in the end users project => move to dependencies.
commit 2f6ee80a6a
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 12:54:45 2024 -0400
changes addFieldRow back to fetch
commit 0128eedf70
Author: Sasha <64744993+r1tsuu@users.noreply.github.com>
Date: Fri Oct 4 19:25:05 2024 +0300
fix(drizzle)!: make radio and select column names to snake_case (#8439)
Fixes https://github.com/payloadcms/payload/issues/8402 and
https://github.com/payloadcms/payload/issues/8027
Before DB column names were camelCase:

After this change, they are snake_case:

#### Breaking SQLite / Postgres ⚠️
If you had any select (not `hasMany: true`) or radio fields with the
name in camelCase, for example:
```ts
{
name: 'selectReadOnly',
type: 'select',
admin: {
readOnly: true,
},
options: [
{
label: 'Value One',
value: 'one',
},
{
label: 'Value Two',
value: 'two',
},
],
},
```
This previously was mapped to the db column name `"selectReadOnly"`. Now
it's `select_read_only`.
Generate a new migration to rename your columns.
```sh
pnpm payload migrate:create
```
Then select "rename column" for targeted columns and Drizzle will handle
the migration.
---------
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
commit 414030e1f1
Author: Sasha <64744993+r1tsuu@users.noreply.github.com>
Date: Fri Oct 4 18:48:54 2024 +0300
fix(drizzle): row / collapsible inside of localized fields (#8539)
Fixes https://github.com/payloadcms/payload/issues/8405
commit 41efcbe4ac
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 10:02:48 2024 -0400
build err
commit 2203d6046c
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 08:32:13 2024 -0400
reverts default edit view onChange
commit 2cd9594f55
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 07:47:49 2024 -0400
brings back actions for everything except lexical
commit cc2cad3140
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 00:58:35 2024 -0400
more cleanup
commit 87e11bd6ad
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 00:20:02 2024 -0400
remove website lockfile
commit caf4c4a0df
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 00:12:25 2024 -0400
properly scopes effect cleanup return
commit 3ddd972de0
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 00:07:09 2024 -0400
adjusts abort controllers
commit 6c95f0a658
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Fri Oct 4 00:00:00 2024 -0400
fix api route
commit 9206adedee
Merge: 726f8b003f6eb027f2
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 23:45:17 2024 -0400
Merge branch 'beta' into feat/server-actions
commit 726f8b003d
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 23:11:53 2024 -0400
again
commit 40e5571c0e
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 22:56:55 2024 -0400
more
commit bdbe7dd41f
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 22:10:48 2024 -0400
temprarily brings back fetch to debug
commit 08bd461d4b
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 19:43:59 2024 -0400
properly aborts on unmount
commit cf617767e5
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 19:21:42 2024 -0400
prevents signal sent from client to server
commit ee853234fd
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 18:35:23 2024 -0400
temp debug
commit 23cd537a33
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 14:59:35 2024 -0400
removes auto gen upload dirs from test
commit 0a950c0f0b
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 14:47:56 2024 -0400
plz
commit f84822e7d9
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 13:48:10 2024 -0400
returns errors instead of throws
commit ee577f53f2
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 13:34:36 2024 -0400
increases test bodysizelimit
commit 6641bff085
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 13:25:44 2024 -0400
removes default server action body size limit
commit 53a6dcf213
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 12:49:04 2024 -0400
plz be it
commit 9e8e7c7c3d
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 11:48:11 2024 -0400
creates shared callback for common server fns
commit b4d081db3f
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Thu Oct 3 09:39:40 2024 -0400
some docs
commit bc36bf7984
Author: Jacob Fletcher <jacobsfletch@gmail.com>
Date: Wed Oct 2 16:26:25 2024 -0400
increases default serverActions.bodySizeLimit
_REQUIRED_: Please provide a link to your reproduction. Note, if the URL is invalid (404 or a private repository), we may close the issue.
Either use `npx create-payload-app@beta -t blank` then push to a repo or follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
validations:
required:true
- type:textarea
attributes:
label:Reproduction Steps
description:Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required:true
- type:dropdown
attributes:
label:Which area(s) are affected? (Select all that apply)
multiple:true
options:
- 'Not sure'
- 'area:core'
- 'area:docs'
- 'area:templates'
- 'area:ui'
- 'db-mongodb'
- 'db-postgres'
- 'db-sqlite'
- 'db-vercel-postgres'
- 'plugin:cloud'
- 'plugin:cloud-storage'
- 'plugin:form-builder'
- 'plugin:nested-docs'
- 'plugin:richtext-lexical'
- 'plugin:richtext-slate'
- 'plugin:search'
- 'plugin:sentry'
- 'plugin:seo'
- 'plugin:stripe'
- 'plugin:other'
validations:
required:true
- type:textarea
attributes:
label:Environment Info
description:Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
render:text
placeholder:|
Payload:
Node.js:
Next.js:
validations:
required:true
- type:markdown
attributes:
value:Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
- type:markdown
attributes:
value:Contributors should be able to follow the steps provided in order to reproduce the bug.
- type:markdown
attributes:
value:These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
description:'[SCREENSHOT REQUIRED] - Create a design issue report'
labels: ['status: needs-triage', 'v3', 'area:ui']
body:
- type:textarea
attributes:
label:Describe the Bug.
description:>-
_REQUIRED:_ Please a screenshot/video of the issue along with a detailed description of the problem.
validations:
required:true
- type:textarea
attributes:
label:Reproduction Steps
description:Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required:true
- type:textarea
attributes:
label:Environment Info
description:Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
render:text
placeholder:|
Payload:
Node.js:
Next.js:
validations:
required:true
- type:markdown
attributes:
value:Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
- type:markdown
attributes:
value:Contributors should be able to follow the steps provided in order to reproduce the bug.
- type:markdown
attributes:
value:These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
<!-- Please include a summary of the pull request and any related issues it fixes. Please also include relevant motivation and context. -->
Thank you for the PR! Please go through the checklist below and make sure you've completed all the steps.
- [ ] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
Please review the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository if you haven't already.
## Type of change
The following items will ensure that your PR is handled as smoothly as possible:
<!-- Please delete options that are not relevant. -->
- 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
- [ ] Chore (non-breaking change which does not add functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Change to the [templates](https://github.com/payloadcms/payload/tree/main/templates) directory (does not affect core functionality)
- [ ] Change to the [examples](https://github.com/payloadcms/payload/tree/main/examples) directory (does not affect core functionality)
- [ ] This change requires a documentation update
### What?
## Checklist:
### Why?
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
description: 'Either a string or a path to a .md file inside the repository. Example:".github/invalid-reproduction.md"'
default: '.github/invalid-reproduction.md'
reproduction-hosts:
description: 'Comma-separated list of hostnames that are allowed for reproductions. Example:"github.com,codesandbox.io"'
default: github.com
reproduction-invalid-label:
description: 'Label to apply to issues without a valid reproduction. Example:"invalid-reproduction"'
default: 'invalid-reproduction'
reproduction-issue-labels:
description: 'Comma-separated list of issue labels. If configured, only verify reproduction URLs of issues with one of these labels present. Adding a comma at the end will handle non-labeled issues as invalid. Example:"bug,",will consider issues with the label "bug" or no label.'
default:''
reproduction-link-section:
description:'A regular expression string with "(.*)" matching a valid URL in the issue body. The result is trimmed. Example: "### Link to reproduction(.*)### To reproduce"'
default:'### Link to reproduction(.*)### To reproduce'
actions-to-perform:
description: 'Comma-separated list of actions to perform on the issue. Example:"tag,comment,close"'
**Please add a reproduction in order for us to be able to investigate.**
Depending on the quality of reproduction steps, this issue may be closed if no reproduction is provided.
### Why was this issue marked with the `invalid-reproduction` label?
To be able to investigate, we need access to a reproduction to identify what triggered the issue. We prefer a link to a public GitHub repository created with `create-payload-app@beta -t blank` or a forked/branched version of this repository with tests added (more info in the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md)).
To make sure the issue is resolved as quickly as possible, please make sure that the reproduction is as **minimal** as possible. This means that you should **remove unnecessary code, files, and dependencies** that do not contribute to the issue. Ensure your reproduction does not depend on secrets, 3rd party registries, private dependencies, or any other data that cannot be made public. Avoid a reproduction including a whole monorepo (unless relevant to the issue). The easier it is to reproduce the issue, the quicker we can help.
Please test your reproduction against the latest version of Payload to make sure your issue has not already been fixed.
### I added a link, why was it still marked?
Ensure the link is pointing to a codebase that is accessible (e.g. not a private repository). "[example.com](http://example.com/)", "n/a", "will add later", etc. are not acceptable links -- we need to see a public codebase. See the above section for accepted links.
@@ -122,3 +122,19 @@ This is how you can preview changes you made locally to the docs:
4. Add a `DOCS_DIR` environment variable to the `.env` file which points to the absolute path of your modified docs folder. For example `DOCS_DIR=/Users/yourname/Documents/GitHub/payload/docs`
5. Run `yarn run fetchDocs:local`. If this was successful, you should see no error messages and the following output: _Docs successfully written to /.../website/src/app/docs.json_. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it
6. You're done! Now you can start the website locally using `yarn run dev` and preview the docs under [http://localhost:3000/docs/](http://localhost:3000/docs/)
## Internationalization (i18n)
If your PR adds a string to the UI, we need to make sure to translate it into all the languages that Payload supports. To do that:
- Find the appropriate internationalization file for your package. These are typically located in `packages/translations/src/languages`, although some packages (e.g., richtext-lexical) have separate i18n files for each feature.
- Add the string to the English locale "en".
- Translate it to other languages. You can use the `translateNewKeys` script if you have an OpenAI API key in your `.env` (under `OPENAI_KEY`), or you can use ChatGPT or Google translate - whatever is easier for you. For payload core translations (in packages/translations) you can run the `translateNewKeys` script using `cd packages/translations && pnpm translateNewKeys`. For lexical translations, you can run it using `cd packages/richtext-lexical && pnpm translateNewKeys`. External contributors can skip this step and leave it to us.
To display translation strings in the UI, make sure to use the `t` utility of the `useTranslation` hook:
> 🎉 <strong>Payload 2.0 is now available!</strong> Read more in the <a target="_blank" href="https://payloadcms.com/blog/payload-2-0" rel="dofollow"><strong>announcement post</strong></a>.
> 🚨 <strong>We're about to release 3.0 stable.</strong> Star this repo or keep an eye on it to follow along.
Payload is the first-ever Next.js native CMS that can install directly in your existing `/app` folder. It's the start of a new era for headless CMS.
<h3>Benefits over a regular CMS</h3>
<ul>
<li>Don’t hit some third-party SaaS API, hit your own API</li>
<li>Use your own database and own your data</li>
<li>It's just Express - do what you want outside of Payload</li>
<li>No need to learn how Payload works - if you know JS, you know Payload</li>
<li>Deploy anywhere, including serverless on Vercel for free</li>
<li>Combine your front+backend in the same <code>/app</code> folder if you want</li>
<li>Don't sign up for yet another SaaS - Payload is open source</li>
<li>Query your database in React Server Components</li>
<li>Both admin and backend are 100% extensible</li>
<li>No vendor lock-in</li>
<li>Avoid microservices hell - get everything (even auth) in one place</li>
<li>Never touch ancient WP code again</li>
<li>Build faster, never hit a roadblock</li>
<li>Both admin and backend are 100% extensible</li>
</ul>
## ☁️ Deploy instantly with Payload Cloud.
## Quickstart
Create a cloud account, connect your GitHub, and [deploy in minutes](https://payloadcms.com/new).
## 🚀 Get started by self-hosting completely free, forever.
Before beginning to work with Payload, make sure you have all of the [required software](https://payloadcms.com/docs/getting-started/installation).
Before beginning to work with Payload, make sure you have all of the [required software](https://payloadcms.com/docs/beta/getting-started/installation).
```text
npx create-payload-app@latest
pnpx create-payload-app@beta
```
Alternatively, it only takes about five minutes to [create an app from scratch](https://payloadcms.com/docs/getting-started/installation#from-scratch).
**If you're new to Payload, you should start with the 3.0 beta website template** (`pnpx create-payload-app@beta -t website`). It shows how to do _everything_ - including custom Rich Text blocks, on-demand revalidation, live preview, and more. It comes with a frontend built with Tailwind all in one `/app` folder.
## 🖱️ One-click templates
## One-click templates
Jumpstart your next project by starting with a pre-made template. These are production-ready, end-to-end solutions designed to get you to market as fast as possible.
Eliminate the need to combine Shopify and a CMS, and instead do it all with Payload + Stripe. Comes with a beautiful, fully functional front-end complete with shopping cart, checkout, orders, and much more.
We're constantly adding more templates to our [Templates Directory](https://github.com/payloadcms/payload/tree/beta/templates). If you maintain your own template, consider adding the `payload-template` topic to your GitHub repository for others to find.
Build any kind of website, blog, or portfolio from small to enterprise. Comes with a beautiful, fully functional front-end complete with posts, projects, comments, and much more.
We're constantly adding more templates to our [Templates Directory](https://github.com/payloadcms/payload/tree/main/templates). If you maintain your own template, consider adding the `payload-template` topic to your GitHub repository for others to find.
-[GraphQL](https://payloadcms.com/docs/graphql/overview), [REST](https://payloadcms.com/docs/rest-api/overview), and [Local](https://payloadcms.com/docs/local-api/overview) APIs
- [Document and field-level hooks](https://payloadcms.com/docs/beta/hooks/overview) for every action Payload provides
- Intensely fast API
- Highly secure thanks to HTTP-only cookies, CSRF protection, and more
@@ -88,7 +84,7 @@ We're constantly adding more templates to our [Templates Directory](https://gith
## 🗒️ Documentation
Check out the [Payload website](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.
Check out the [Payload website](https://payloadcms.com/docs/beta/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.
Migrating from v1 to v2? Check out the [2.0 Release Notes](https://github.com/payloadcms/payload/releases/tag/v2.0.0) on how to do it.
The Payload [Admin Panel](./overview) is designed to be as minimal and straightforward as possible to allow for both easy customization and full control over the UI. In order for Payload to support this level of customization, Payload provides a pattern for you to supply your own React components through your [Payload Config](../configuration/overview).
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api/overview) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
<Banner type="success">
<strong>Note:</strong>
@@ -145,7 +145,7 @@ Instead, we utilize component paths to reference React Components. This method e
When constructing the `ClientConfig`, Payload uses the component paths as keys to fetch the corresponding React Component imports from the Import Map. It then substitutes the `PayloadComponent` with a `MappedComponent`. A `MappedComponent` includes the React Component and additional metadata, such as whether it's a server or a client component and which props it should receive. These components are then rendered through the `<RenderComponent />` component within the Payload Admin Panel.
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](/docs/beta/local-api/outside-nextjs#troubleshooting) section.
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](../local-api/outside-nextjs#troubleshooting) section.
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly on the front-end, among other things.
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api/overview) directly on the front-end, among other things.
To make building Custom Components as easy as possible, Payload automatically provides common props, such as the [`payload`](../local-api/overview) class and the [`i18n`](../configuration/i18n) object. This means that when building Custom Components within the Admin Panel, you do not have to get these yourself.
| **`_isPresentational`** | A boolean indicating that the field is purely visual and does not directly affect data or change data shape, i.e. the [UI Field](../fields/ui). |
| **`_path`** | A string representing the direct, dynamic path to the field at runtime, i.e. `myGroup.myArray[0].myField`. |
| **`_schemaPath`** | A string representing the direct, static path to the [Field Config](../fields/overview), i.e. `myGroup.myArray.myField` |
In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale`gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example:
In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale`gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example:
@@ -12,24 +12,24 @@ The lock is automatically triggered when a user begins editing a document within
## How it works
When a user starts editing a document, Payload locks the document for that user. If another user tries to access the same document, they will be notified that it is currently being edited and can choose one of the following options:
When a user starts editing a document, Payload locks it for that user. If another user attempts to access the same document, they will be notified that it is currently being edited. They can then choose one of the following options:
- View in Read-Only Mode: View the document without making any changes.
- Take Over Editing: Take over editing from the current user, which locks the document for the new editor and notifies the original user.
- View in Read-Only: View the document without the ability to make any changes.
- Take Over: Take over editing from the current user, which locks the document for the new editor and notifies the original user.
- Return to Dashboard: Navigate away from the locked document and continue with other tasks.
The lock will automatically expire after a set period of inactivity, configurable using the duration property in the lockDocuments configuration, after which others can resume editing.
The lock will automatically expire after a set period of inactivity, configurable using the `duration` property in the `lockDocuments` configuration, after which others can resume editing.
<Banner type="info"> <strong>Note:</strong> If your application does not require document locking, you can disable this feature for any collection by setting the <code>lockDocuments</code> property to <code>false</code>. </Banner>
<Banner type="info"> <strong>Note:</strong> If your application does not require document locking, you can disable this feature for any collection or global by setting the <code>lockDocuments</code> property to <code>false</code>. </Banner>
### Config Options
The lockDocuments property exists on both the Collection Config and the Global Config. By default, document locking is enabled for all collections and globals, but you can customize the lock duration or disable the feature entirely.
The `lockDocuments` property exists on both the Collection Config and the Global Config. Document locking is enabled by default, but you can customize the lock duration or turn off the feature for any collection or global.
Here’s an example configuration for document locking:
Document locking affects both the Local API and the REST API, ensuring that if a document is locked, concurrent users will not be able to perform updates or deletes on that document (including globals). If a user attempts to update or delete a locked document, they will receive an error.
Document locking affects both the Local and REST APIs, ensuring that if a document is locked, concurrent users will not be able to perform updates or deletes on that document (including globals). If a user attempts to update or delete a locked document, they will receive an error.
Once the document is unlocked or the lock duration has expired, other users can proceed with updates or deletes as normal.
#### Overriding Locks
For operations like update and delete, Payload includes an `overrideLock` option. This boolean flag, when set to `false`, enforces document locks, ensuring that the operation will not proceed if another user currently holds the lock.
For operations like `update` and `delete`, Payload includes an `overrideLock` option. This boolean flag, when set to `false`, enforces document locks, ensuring that the operation will not proceed if another user currently holds the lock.
By default, `overrideLock` is set to `true`, which means that document locks are ignored, and the operation will proceed even if the document is locked. To enforce locks and prevent updates or deletes on locked documents, set `overrideLock: false`.
@@ -93,7 +93,7 @@ For more granular control, pass a configuration object instead. Payload exposes
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| **`sensitive`** | When true, will match if the path is case sensitive.
| **`sensitive`** | When true, will match if the path is case sensitive.|
| **`meta`** | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
_\* An asterisk denotes that a property is required._
@@ -133,6 +133,12 @@ The above example shows how to add a new [Root View](#root-views), but the patte
route.
</Banner>
<Banner type="warning">
<strong>Custom views are public</strong>
<br />
Custom views are public by default. If your view requires a user to be logged in or to have certain access rights, you should handle that within your view component yourself.
</Banner>
## Collection Views
Collection Views are views that are scoped under the `/collections` route, such as the Collection List and Document Edit views.
@@ -97,7 +97,7 @@ Cookies can cross subdomains without being considered third party cookies, for e
##### 2. Configure cookies
If option 1 isn't possible, then you can get around this limitation by [configuring your cookies](https://payloadcms.com/docs/beta/authentication/overview#config-options) on your authentication collection to achieve the following setup:
If option 1 isn't possible, then you can get around this limitation by [configuring your cookies](./overview#config-options) on your authentication collection to achieve the following setup:
```
SameSite: None // allows the cookie to cross domains
@@ -122,7 +122,7 @@ Configuration example:
},
```
If you're configuring [cors](https://payloadcms.com/docs/beta/production/preventing-abuse#cross-origin-resource-sharing-cors) in your Payload config, you won't be able to use a wildcard anymore, you'll need to specify the list of allowed domains.
If you're configuring [cors](../production/preventing-abuse#cross-origin-resource-sharing-cors) in your Payload config, you won't be able to use a wildcard anymore, you'll need to specify the list of allowed domains.
@@ -38,7 +38,7 @@ At its core a strategy simply takes information from the incoming request and re
Your `authenticate` method should return an object containing a Payload user document and any optional headers that you'd like Payload to set for you when we return a response.
[Authentication](./overview) ties directly into the [Email](../email) functionality that Payload provides. This allows you to send emails to users for verification, password resets, and more. While Payload provides default email templates for these actions, you can customize them to fit your brand.
[Authentication](./overview) ties directly into the [Email](../email/overview) functionality that Payload provides. This allows you to send emails to users for verification, password resets, and more. While Payload provides default email templates for these actions, you can customize them to fit your brand.
## Email Verification
@@ -15,7 +15,7 @@ Email Verification forces users to prove they have access to the email address t
To enable Email Verification, use the `auth.verify` property on your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -42,7 +42,7 @@ The following options are available:
Function that accepts one argument, containing `{ req, token, user }`, that allows for overriding the HTML within emails that are sent to users indicating how to validate their account. The function should return a string that supports HTML, which can optionally be a full HTML email.
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -119,7 +119,7 @@ The following options are available:
This function allows for overriding the HTML within emails that are sent to users attempting to reset their password. The function should return a string that supports HTML, which can be a full HTML email.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -179,7 +179,7 @@ The following arguments are passed to the `generateEmailHTML` function:
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
@@ -25,7 +25,7 @@ When Authentication is enabled on a [Collection](../configuration/collections),
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collection#auth):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
// ...
@@ -48,7 +48,7 @@ Any [Collection](../configuration/collections) can opt-in to supporting Authenti
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Admins: CollectionConfig = {
// ...
@@ -86,7 +86,7 @@ The following options are available:
| **`loginWithUsername`** | Ability to allow users to login with username/password. [More](/docs/authentication/overview#login-with-username) |
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
| **`removeTokenFromResponses`** | Set to true if you want to remove the token from the returned authentication API responses such as login or refresh. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`strategies`** | Advanced - an array of custom authentication strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More details](./email#email-verification). |
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appeneded to the request for you.
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appended to the request for you.
Powered by [Resend](https://resend.com), Payload Cloud comes with integrated email support out of the box. No configuration is needed, and you can use `payload.sendEmail()` to send email right from your Payload app. To learn more about sending email with Payload, checkout the [Email Configuration](https://payloadcms.com/docs/email/overview) overview.
Powered by [Resend](https://resend.com), Payload Cloud comes with integrated email support out of the box. No configuration is needed, and you can use `payload.sendEmail()` to send email right from your Payload app. To learn more about sending email with Payload, checkout the [Email Configuration](../email/overview) overview.
If you are on the Pro or Enterprise plan, you can add your own custom Email domain name. From the Email page of your project’s Settings, add the domain you wish to use for email delivery. This will generate a set of DNS records. Add these records to your DNS provider and click verify to check that your records are resolving properly. Once verified, your emails will now be sent from your custom domain name.
@@ -98,14 +98,14 @@ From there, you are ready to make updates to your project. When you are ready to
Projects generated from a template will come pre-configured with the official Cloud Plugin, but if you are using your own repository you will need to add this into your project. To do so, add the plugin to your Payload Config:
`yarn add @payloadcms/plugin-cloud`
`yarn add @payloadcms/payload-cloud`
```js
import { payloadCloud } from '@payloadcms/plugin-cloud'
import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [payloadCloud()],
plugins: [payloadCloudPlugin()],
// rest of config
})
```
@@ -115,6 +115,11 @@ export default buildConfig({
over Payload Cloud's email service.
</Banner>
<Banner type="info">
Good to know: the Payload Cloud Plugin was previously named `@payloadcms/plugin-cloud`. If you are
using this plugin, you should update to the new package name.
</Banner>
#### **Optional configuration**
If you wish to opt-out of any Payload cloud features, the plugin also accepts options to do so.
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. |
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. |
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| **`defaultPopulate`** | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
_\* An asterisk denotes that a property is required._
@@ -163,7 +163,7 @@ In development mode, if the configuration file is not found at the root, Payload
**Production Mode**
In production mode, Payload will first attempt to find the config file in the `outDir` of your `tsconfig.json`, and if not found, will fallback to the `rootDor` directory:
In production mode, Payload will first attempt to find the config file in the `outDir` of your `tsconfig.json`, and if not found, will fallback to the `rootDir` directory:
```json
{
@@ -216,7 +216,7 @@ Cross-origin resource sharing (CORS) can be configured with either a whitelist a
Here's an example showing how to allow incoming requests from any domain:
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
// ...
@@ -227,7 +227,7 @@ export default buildConfig({
Here's an example showing how to append a new header (`x-custom-header`) in `Access-Control-Allow-Headers`:
@@ -157,7 +157,7 @@ You can disable this setting and solely use migrations to manage your local deve
For this reason, we suggest that you leave `push` as its default setting and treat your local dev database as a sandbox.
For more information about push mode and prototyping in development, [click here](/docs/beta/database/postgres#prototyping-in-dev-mode).
For more information about push mode and prototyping in development, [click here](./postgres#prototyping-in-dev-mode).
The typical workflow in Payload is to build out your Payload configs, install plugins, and make progress in development mode - allowing Drizzle to push your changes to your local database for you. Once you're finished, you can create a migration.
@@ -67,6 +67,6 @@ You should prefer a relational DB like Postgres or SQLite if:
## Payload Differences
It's important to note that nearly every Payload feature is available in all of our officially supported Database Adapters, including [Localization](../configuration/localization), [Arrays](../fields/array), [Blocks](../fields/blocks), etc. The only thing that is not supported in Postgres yet is the [Point Field](/docs/fields/point), but that should be added soon.
It's important to note that nearly every Payload feature is available in all of our officially supported Database Adapters, including [Localization](../configuration/localization), [Arrays](../fields/array), [Blocks](../fields/blocks), etc. The only thing that is not supported in SQLite yet is the [Point Field](/docs/fields/point), but that should be added soon.
It's up to you to choose which database you would like to use based on the requirements of your project. Payload has no opinion on which database you should ultimately choose.
@@ -16,7 +16,7 @@ By default, Payload will use transactions for all data changing operations, as l
MongoDB requires a connection to a replicaset in order to make use of transactions.
</Banner>
The initial request made to Payload will begin a new transaction and attach it to the `req.transactionID`. If you have a `hook` that interacts with the database, you can opt-in to using the same transaction by passing the `req` in the arguments. For example:
The initial request made to Payload will begin a new transaction and attach it to the `req.transactionID`. If you have a `hook` that interacts with the database, you can optin to using the same transaction by passing the `req` in the arguments. For example:
@@ -65,9 +65,9 @@ When writing your own scripts or custom endpoints, you may wish to have direct c
The following functions can be used for managing transactions:
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
`payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
- `payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
- `payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
- `payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
Payload uses the `req` object to pass the transaction ID through to the database adapter. If you are not using the `req` object, you can make a new object to pass the transaction ID directly to database adapter methods and local API calls.
@@ -24,7 +24,7 @@ Arrays are useful for many different types of content from simple to complex, su
To create an Array Field, set the `type` to `array` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyArrayField: Field = {
// ...
@@ -69,7 +69,7 @@ _\* An asterisk denotes that a property is required._
To customize the appearance and behavior of the Array Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyArrayField: Field = {
// ...
@@ -92,7 +92,7 @@ The Array Field inherits all of the default options from the base [Field Admin C
In this example, we have an Array Field called `slider` that contains a set of fields for a simple image slider. Each row in the array has a `title`, `image`, and `caption`. We also customize the row label to display the title if it exists, or a default label if it doesn't.
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can edit and view collections
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is stored on the collection with a Join
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can
edit and view collections
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is
stored on the collection with a Join
field. Instead, the Admin UI surfaces the related documents for a better editing experience and is surfaced by Payload's
APIs.
@@ -19,10 +21,10 @@ The Join field is useful in scenarios including:
- Displaying where a document or upload is used in other documents
For the Join field to work, you must have an existing [relationship](./relationship) or [upload](./upload) field in the
@@ -30,7 +32,7 @@ collection you are joining. This will reference the collection and path of the f
To add a Relationship Field, set the `type` to `join` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyJoinField: Field = {
// highlight-start
@@ -111,29 +113,42 @@ related docs from a new pseudo-junction collection called `categories_posts`. No
third junction collection, and can be surfaced on both Posts and Categories. But, importantly, you could add
additional "context" fields to this shared junction collection.
For example, on this `categories_posts` collection, in addition to having the `category` and `post` fields, we could add custom "context" fields like `featured` or `spotlight`,
For example, on this `categories_posts` collection, in addition to having the `category` and `post` fields, we could add
custom "context" fields like `featured` or `spotlight`,
which would allow you to store additional information directly on relationships.
The `join` field gives you complete control over any type of relational architecture in Payload, all wrapped up in a powerful Admin UI.
The `join` field gives you complete control over any type of relational architecture in Payload, all wrapped up in a
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`where`** \* | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth). |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`defaultLimit`** | The number of documents to return. Set to 0 to return all related documents. |
| **`defaultSort`** | The field name used to specify the order the joined documents are returned. |
@@ -356,7 +356,7 @@ For full details on Admin Options, see the [Field Admin Options](../admin/fields
## Custom ID Fields
All [Collections](../configuration/collections) automatically generate their own ID field. If needed, you can override this behavior by providing an explicit ID field to your config. This will force users to provide a their own ID value when creating a record.
All [Collections](../configuration/collections) automatically generate their own ID field. If needed, you can override this behavior by providing an explicit ID field to your config. This field should either be required or have a hook to generate the ID dynamically.
To define a custom ID field, add a new field with the `name` property set to `id`:
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`*relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
| **`relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
| **`hasMany`** | Boolean which, if set to true, allows this field to have many relations instead of only one. |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. Used with hasMany. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. Used with hasMany. |
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](../queries/depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -73,7 +76,7 @@ _\* An asterisk denotes that a property is required._
This will add a the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
This will add the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
desc: Payload provides all you need to run job queues, which are helpful to offload long-running processes into separate workers.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
Payload's Jobs Queue gives you a simple, yet powerful way to offload large or future tasks to separate compute resources.
For example, when building applications with Payload, you might run into a case where you need to perform some complex logic in a Payload [Hook](/docs/hooks/overview) but you don't want that hook to "block" or slow down the response returned from the Payload API.
Instead of running long or expensive logic in a Hook, you can instead create a Job and add it to a Queue. It can then be picked up by a separate worker which periodically checks the queue for new jobs, and then executes each job accordingly. This way, your Payload API responses can remain as fast as possible, and you can still perform logic as necessary without blocking or affecting your users' experience.
Jobs are also handy for delegating certain actions to take place in the future, such as scheduling a post to be published at a later date. In this example, you could create a Job that will automatically publish a post at a certain time.
#### How it works
There are a few concepts that you should become familiarized with before using Payload's Jobs Queue - [Tasks](#tasks), [Workflows](#workflows), [Jobs](#jobs), and finally [Queues](#queues).
## Tasks
<Banner type="default">
A <strong>"Task"</strong> is a function definition that performs business logic and whose input and output are both strongly typed.
</Banner>
You can register Tasks on the Payload config, and then create Jobs or Workflows that use them. Think of Tasks like tidy, isolated "functions that do one specific thing".
Payload Tasks can be configured to automatically retried if they fail, which makes them valuable for "durable" workflows like AI applications where LLMs can return non-deterministic results, and might need to be retried.
Tasks can either be defined within the `jobs.tasks` array in your payload config, or they can be defined inline within a workflow.
### Defining tasks in the config
Simply add a task to the `jobs.tasks` array in your Payload config. A task consists of the following fields:
| `slug` | Define a slug-based name for this job. This slug needs to be unique among both tasks and workflows.|
| `handler` | The function that should be responsible for running the job. You can either pass a string-based path to the job function file, or the job function itself. If you are using large dependencies within your job, you might prefer to pass the string path because that will avoid bundling large dependencies in your Next.js app. |
| `inputSchema` | Define the input field schema - payload will generate a type for this schema. |
| `interfaceName` | You can use interfaceName to change the name of the interface that is generated for this task. By default, this is "Task" + the capitalized task slug. |
| `outputSchema` | Define the output field schema - payload will generate a type for this schema. |
| `label` | Define a human-friendly label for this task. |
| `onFail` | Function to be executed if the task fails. |
| `onSuccess` | Function to be executed if the task succeeds. |
| `retries` | Specify the number of times that this step should be retried if it fails. |
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks picks up a Job that includes this task.
It should return an object with an `output` key, which should contain the output of the task as you've defined.
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
{
// Configure this task to automatically retry
// up to two times
retries: 2,
// This is a unique identifier for the task
slug: 'createPost',
// These are the arguments that your Task will accept
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
// These are the properties that the function should output
outputSchema: [
{
name: 'postID',
type: 'text',
required: true,
},
],
// This is the function that is run when the task is invoked
handler: async ({ input, job, req }) => {
const newPost = await req.payload.create({
collection: 'post',
req,
data: {
title: input.title,
},
})
return {
output: {
postID: newPost.id,
},
}
},
} as TaskConfig<'createPost'>,
]
}
})
```
In addition to defining handlers as functions directly provided to your Payload config, you can also pass an _absolute path_ to where the handler is defined. If your task has large dependencies, and you are planning on executing your jobs in a separate process that has access to the filesystem, this could be a handy way to make sure that your Payload + Next.js app remains quick to compile and has minimal dependencies.
In general, this is an advanced use case. Here's how this would look:
`payload.config.ts:`
```ts
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export default buildConfig({
jobs: {
tasks: [
{
// ...
// The #createPostHandler is a named export within the `createPost.ts` file
A <strong>"Workflow"</strong> is an optional way to <em>combine multiple tasks together</em> in a way that can be gracefully retried from the point of failure.
</Banner>
They're most helpful when you have multiple tasks in a row, and you want to configure each task to be able to be retried if they fail.
If a task within a workflow fails, the Workflow will automatically "pick back up" on the task where it failed and **not re-execute any prior tasks that have already been executed**.
#### Defining a workflow
The most important aspect of a Workflow is the `handler`, where you can declare when and how the tasks should run by simply calling the `runTask` function. If any task within the workflow, fails, the entire `handler` function will re-run.
However, importantly, tasks that have successfully been completed will simply re-return the cached and saved output without running again. The Workflow will pick back up where it failed and only task from the failure point onward will be re-executed.
To define a JS-based workflow, simply add a workflow to the `jobs.wokflows` array in your Payload config. A workflow consists of the following fields:
| `slug` | Define a slug-based name for this workflow. This slug needs to be unique among both tasks and workflows.|
| `handler` | The function that should be responsible for running the workflow. You can either pass a string-based path to the workflow function file, or workflow job function itself. If you are using large dependencies within your workflow, you might prefer to pass the string path because that will avoid bundling large dependencies in your Next.js app. |
| `inputSchema` | Define the input field schema - payload will generate a type for this schema. |
| `interfaceName` | You can use interfaceName to change the name of the interface that is generated for this workflow. By default, this is "Workflow" + the capitalized workflow slug. |
| `label` | Define a human-friendly label for this workflow. |
| `queue` | Optionally, define the queue name that this workflow should be tied to. Defaults to "default". |
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
// ...
]
workflows: [
{
slug: 'createPostAndUpdate',
// The arguments that the workflow will accept
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
// The handler that defines the "control flow" of the workflow
// Notice how it calls `runTask` to execute tasks
handler: async ({ job, runTask }) => {
// This workflow first runs a task called `createPost`
const output = await runTask({
task: 'createPost',
// You need to define a unique ID for this task invocation
// that will always be the same if this workflow fails
// and is re-executed in the future
id: '1',
input: {
title: job.input.title,
},
})
// Once the prior task completes, it will run a task
// called `updatePost`
await runTask({
task: 'updatePost',
id: '2',
input: {
post: job.taskStatus.createPost['1'].output.postID, // or output.postID
title: job.input.title + '2',
},
})
},
} as WorkflowConfig<'updatePost'>
]
}
})
```
#### Running tasks inline
In the above example, our workflow was executing tasks that we already had defined in our Payload config. But, you can also run tasks without predefining them.
To do this, you can use the `runTaskInline` function.
The drawbacks of this approach are that tasks cannot be re-used across workflows as easily, and the **task data stored in the job** will not be typed. In the following example, the inline task data will be stored on the job under `job.taskStatus.inline['2']` but completely untyped, as types for dynamic tasks like these cannot be generated beforehand.
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
// ...
]
workflows: [
{
slug: 'createPostAndUpdate',
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
handler: async ({ job, runTask }) => {
// Here, we run a predefined task.
// The `createPost` handler arguments and return type
// are both strongly typed
const output = await runTask({
task: 'createPost',
id: '1',
input: {
title: job.input.title,
},
})
// Here, this task is not defined in the Payload config
// and is "inline". Its output will be stored on the Job in the database
// however its arguments will be untyped.
const { newPost } = await runTaskInline({
task: async ({ req }) => {
const newPost = await req.payload.update({
collection: 'post',
id: '2',
req,
retries: 3,
data: {
title: 'updated!',
},
})
return {
output: {
newPost
},
}
},
id: '2',
})
},
} as WorkflowConfig<'updatePost'>
]
}
})
```
## Jobs
Now that we have covered Tasks and Workflows, we can tie them together with a concept called a Job.
<Banner type="default">
Whereas you define Workflows and Tasks, which control your business logic, a <strong>Job</strong> is an individual instance of either a Task or a Workflow which contains many tasks.
</Banner>
For example, let's say we have a Workflow or Task that describes the logic to sync information from Payload to a third-party system. This is how you'd declare how to sync that info, but it wouldn't do anything on its own. In order to run that task or workflow, you'd create a Job that references the corresponding Task or Workflow.
Jobs are stored in the Payload database in the `payload-jobs` collection, and you can decide to keep a running list of all jobs, or configure Payload to delete the job when it has been successfully executed.
#### Queuing a new job
In order to queue a job, you can use the `payload.jobs.queue` function.
Here's how you'd queue a new Job, which will run a `createPostAndUpdate` workflow:
```ts
const createdJob = await payload.jobs.queue({
// Pass the name of the workflow
workflow: 'createPostAndUpdate',
// The input type will be automatically typed
// according to the input you've defined for this workflow
input: {
title: 'my title',
},
})
```
In addition to being able to queue new Jobs based on Workflows, you can also queue a job for a single Task:
```ts
const createdJob = await payload.jobs.queue({
task: 'createPost',
input: {
title: 'my title',
},
})
```
## Queues
Now let's talk about how to _run these jobs_. Right now, all we've covered is how to queue up jobs to run, but so far, we aren't actually running any jobs. This is the final piece of the puzzle.
<Banner type="default">
A <strong>Queue</strong> is a list of jobs that should be executed in order of when they were added.
</Banner>
When you go to run jobs, Payload will query for any jobs that are added to the queue and then run them. By default, all queued jobs are added to the `default` queue.
**But, imagine if you wanted to have some jobs that run nightly, and other jobs which should run every five minutes.**
By specifying the `queue` name when you queue a new job using `payload.jobs.queue()`, you can queue certain jobs with `queue: 'nightly'`, and other jobs can be left as the default queue.
Then, you could configure two different runner strategies:
1. A `cron` that runs nightly, querying for jobs added to the `nightly` queue
2. Another that runs any jobs that were added to the `default` queue every ~5 minutes or so
## Executing jobs
As mentioned above, you can queue jobs, but the jobs won't run unless a worker picks up your jobs and runs them. This can be done in two ways:
#### Endpoint
You can execute jobs by making a fetch request to the `/api/payload-jobs/run` endpoint:
```ts
// Here, we're saying we want to run only 100 jobs for this invocation
// and we want to pull jobs from the `nightly` queue:
This endpoint is automatically mounted for you and is helpful in conjunction with serverless platforms like Vercel, where you might want to use Vercel Cron to invoke a serverless function that executes your jobs.
**Vercel Cron Example**
If you're deploying on Vercel, you can add a `vercel.json` file in the root of your project that configures Vercel Cron to invoke the `run` endpoint on a cron schedule.
Here's an example of what this file will look like:
```json
{
"crons": [
{
"path": "/api/payload-jobs/run",
"schedule": "*/5 * * * *"
}
]
}
```
The configuration above schedules the endpoint `/api/payload-jobs/run` to be invoked every 5 minutes.
The last step will be to secure your `run` endpoint so that only the proper users can invoke the runner.
To do this, you can set an environment variable on your Vercel project called `CRON_SECRET`, which should be a random string—ideally 16 characters or longer.
Then, you can modify the `access` function for running jobs by ensuring that only Vercel can invoke your runner.
This works because Vercel automatically makes the `CRON_SECRET` environment variable available to the endpoint as the `Authorization` header when triggered by the Vercel Cron, ensuring that the jobs can be run securely.
After the project is deployed to Vercel, the Vercel Cron job will automatically trigger the `/api/payload-jobs/run` endpoint in the specified schedule, running the queued jobs in the background.
#### Local API
If you want to process jobs programmatically from your server-side code, you can use the Local API:
```ts
const results = await payload.jobs.run()
// You can customize the queue name and limit by passing them as arguments:
The `.setEditorState()` function immediately updates your editor state. Thus, there's no need for the `discrete: true` flag when reading the state afterward.
## Lexical => Plain Text
Export content from the Lexical editor into plain text using these steps:
@@ -401,8 +404,13 @@ const yourEditorState: SerializedEditorState // <= your current editor state her
// Import editor state into your headless editor
try {
headlessEditor.setEditorState(headlessEditor.parseEditorState(yourEditorState)) // This should commit the editor state immediately
and done! Now, everytime this lexical editor is initialized, it converts the slate date to lexical on-the-fly. If the data is already in lexical format, it will just pass it through.
and done! Now, everytime this lexical editor is initialized, it converts the slate date to lexical on-the-fly. If the data is already in lexical format, it will just pass it through.
This is by far the easiest way to migrate from Slate to Lexical, although it does come with a few caveats:
@@ -71,27 +71,29 @@ import config from '@payload-config'
const payload = await getPayload({ config })
```
Both options function in exactly the same way outside of one having HMR support and the other not. For more information about using Payload outside of Next.js, [click here](/docs/beta/local-api/outside-nextjs).
Both options function in exactly the same way outside of one having HMR support and the other not. For more information about using Payload outside of Next.js, [click here](./outside-nextjs).
## Local options available
You can specify more options within the Local API vs. REST or GraphQL due to the server-only context that they are executed in.
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
| `data` | The data to use within the operation. Required for `create`, `update`. |
| `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. |
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
| `overrideLock` | By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](../admin/locked-documents). |
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
| `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. |
| `disableErrors` | When set to `true`, errors will not be thrown. Instead, the `findByID` operation will return `null`, and the `find` operation will return an empty documents array. |
| `disableTransaction` | When set to `true`, a [database transactions](../database/transactions) will not be initialized. |
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
| `data` | The data to use within the operation. Required for `create`, `update`. |
| `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. |
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
| `select` | Specify [select](../queries/select) to control which fields to include to the result. |
| `populate` | Specify [populate](../queries/select#populate) to control which fields to include to the result from populated documents. |
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
| `overrideLock` | By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](../admin/locked-documents). |
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
| `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. |
| `disableErrors` | When set to `true`, errors will not be thrown. Instead, the `findByID` operation will return `null`, and the `find` operation will return an empty documents array. |
| `disableTransaction` | When set to `true`, a [database transactions](../database/transactions) will not be initialized. |
_There are more options available on an operation by operation basis outlined below._
Provide a fallback for the email address to send form submissions to. If the email in form configuration does not have a to email set, this email address will be used. If this is not provided then it falls back to the `defaultFromAddress` in your [email configuration](https://payloadcms.com/docs/beta/email/overview).
Provide a fallback for the email address to send form submissions to. If the email in form configuration does not have a to email set, this email address will be used. If this is not provided then it falls back to the `defaultFromAddress` in your [email configuration](../email/overview).
```ts
// payload.config.ts
@@ -343,12 +343,12 @@ Maps to a `checkbox` input on your front-end. Used to collect a boolean value.
Maps to a `number` input on your front-end. Used to collect a number.
| `defaultValue` | string | The default value of the field. |
| `defaultValue` | number | The default value of the field. |
| `width` | string | The width of the field on the front-end. |
| `required` | checkbox | Whether or not the field is required when submitted. | | `defaultValue` | number | The default value of the field. |
| `required` | checkbox | Whether or not the field is required when submitted. |
### Message
@@ -412,11 +412,11 @@ formBuilder({
## Email
This plugin relies on the [email configuration](https://payloadcms.com/docs/beta/email/overview) defined in your payload configuration. It will read from your config and attempt to send your emails using the credentials provided.
This plugin relies on the [email configuration](../email/overview) defined in your payload configuration. It will read from your config and attempt to send your emails using the credentials provided.
### Email formatting
The email contents supports rich text which will be serialised to HTML on the server before being sent. By default it reads the global configuration of your rich text editor.
The email contents supports rich text which will be serialized to HTML on the server before being sent. By default it reads the global configuration of your rich text editor.
The email subject and body supports inserting dynamic fields from the form submission data using the `{{field_name}}` syntax. For example, if you have a field called `name` in your form, you can include this in the email body like so:
@@ -39,7 +39,7 @@ This plugin is a great way to implement a fast, immersive search experience such
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-search
pnpm add @payloadcms/plugin-search@beta
```
## Basic Usage
@@ -81,6 +81,10 @@ export default config
The `collections` property is an array of collection slugs to enable syncing to search. Enabled collections receive a `beforeChange` and `afterDelete` hook that creates, updates, and deletes its respective search record as it changes over time.
### `localize`
By default, the search plugin will add `localization: true` to the `title` field of the newly added `search` collection if you have localization enabled. If you would like to disable this behavior, you can set this to `false`.
#### `defaultPriorities`
This plugin automatically adds a `priority` field to the `search` collection that can be used as the `?sort=` parameter in your queries. For example, you may want to list blog posts before pages. Or you may want one specific post to always take appear first.
@@ -139,7 +143,8 @@ Before creating or updating a search record, the `beforeSync` function runs. Thi
searchPlugin({
beforeSync: ({ originalDoc, searchDoc }) => ({
...searchDoc,
// Modify your docs in any way here, this can be async
// - Modify your docs in any way here, this can be async
// - You also need to add the `excerpt` field in the `searchOverrides` config
excerpt: originalDoc?.excerpt || 'This is a fallback excerpt',
@@ -37,7 +37,7 @@ To help you visualize what your page might look like in a search engine, a previ
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-seo
pnpm add @payloadcms/plugin-seo@beta
```
## Basic Usage
@@ -89,12 +89,23 @@ An array of global slugs to enable SEO. Enabled globals receive a `meta` field w
##### `fields`
An array of fields that allows you to inject your own custom fields onto the `meta` field group. The following fields are provided by default:
A function that takes in the default fields via an object and expects an array of fields in return. You can use this to modify existing fields or add new ones.
- `title`: text
- `description`: textarea
- `image`: upload (if an `uploadsCollection` is provided)
- `preview`: ui
```ts
// payload.config.ts
{
// ...
seoPlugin({
fields: ({ defaultFields }) => [
...defaultFields,
{
name: 'customField',
type: 'text',
}
]
})
}
```
##### `uploadsCollection`
@@ -209,25 +220,6 @@ Rename the meta group interface name that is generated for TypeScript and GraphQ
}
```
#### `fieldOverrides`
Pass any valid field props to the base fields: Title, Description or Image.
```ts
// payload.config.ts
seoPlugin({
// ...
fieldOverrides: {
title: {
required: true,
},
description: {
localized: true,
},
},
})
```
## Direct use of fields
There is the option to directly import any of the fields from the plugin so that you can include them anywhere as needed.
@@ -276,6 +268,10 @@ OverviewField({
})
```
<Banner type="info">
Tip: You can override the length rules by changing the minLength and maxLength props on the fields. In the case of the OverviewField you can use `titleOverrides` and `descriptionOverrides` to override the length rules.
You may not need the full data from your Local API / REST queries, but only some specific fields. The select fields API can help you to optimize those cases.
## Local API
To specify select in the [Local API](../local-api/overview), you can use the `select` option in your query:
```ts
// Include mode
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
select: {
text: true,
// select a specific field from group
group: {
number: true
},
// select all fields from array
array: true,
}, // highlight-line
})
return posts
}
// Exclude mode
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
// Select everything except for array and group.number
select: {
array: false,
group: {
number: false
}
}, // highlight-line
})
return posts
}
```
<Banner type="warning">
<strong>Important:</strong>
To perform querying with `select` efficiently, it works on the database level. Because of that, your `beforeRead` and `afterRead` hooks may not receive the full `doc`.
</Banner>
## REST API
To specify select in the [REST API](../rest-api/overview), you can use the `select` parameter in your query:
To understand the syntax, you need to understand that complex URL search strings are parsed into a JSON object. This one isn't too bad, but more complex queries get unavoidably more difficult to write.
For this reason, we recommend to use the extremely helpful and ubiquitous [`qs`](https://www.npmjs.com/package/qs) package to parse your JSON / object-formatted queries into query strings:
```ts
import { stringify } from 'qs-esm'
const select = {
text: true,
group: {
number: true
}
// This query could be much more complex
// and QS would handle it beautifully
}
const getPosts = async () => {
const stringifiedQuery = stringify(
{
select, // ensure that `qs` adds the `select` property, too!
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order.
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order. In Local API multiple fields can be specified by using an array of strings. In REST API multiple fields can be specified by separating fields with comma. The minus symbol can be in front of individual fields.
Because sorting is handled by the database, the field cannot be a [Virtual Field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges). It must be stored in the database to be searchable.
@@ -30,6 +30,19 @@ const getPosts = async () => {
}
```
To sort by multiple fields, you can use the `sort` option with fields in an array:
@@ -43,7 +43,7 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
</Banner>
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
@@ -98,7 +98,7 @@ _An asterisk denotes that an option is required._
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
| **`filenameCompoundIndex`** | Field slugs to use for a compount index instead of the default filename index.
| **`filenameCompoundIndex`** | Field slugs to use for a compound index instead of the default filename index.
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
@@ -144,7 +144,7 @@ export default buildConfig({
If you specify an array of `imageSizes` to your `upload` config, Payload will automatically crop and resize your uploads to fit each of the sizes specified by your config.
The [Admin Panel](../admin/overview) will also automatically display all available files, including width, height, and filesize, for each of your uploaded files.
The [Admin Panel](../admin/overview) will also automatically display all available files, including width, height, and filesize, for each of your uploaded files.
Behind the scenes, Payload relies on [`sharp`](https://sharp.pixelplumbing.com/api-resize#resize) to perform its image resizing. You can specify additional options for `sharp` to use while resizing your images.
@@ -217,7 +217,7 @@ You can specify how Payload retrieves admin thumbnails for your upload-enabled C
1. `adminThumbnail` as a **string**, equal to one of your provided image size names.
@@ -22,7 +22,7 @@ Payload offers additional storage adapters to handle file uploads. These adapter
### Installation
```sh
pnpm add @payloadcms/storage-vercel-blob
pnpm add @payloadcms/storage-vercel-blob@beta
```
### Usage
@@ -71,12 +71,12 @@ export default buildConfig({
### Installation
```sh
pnpm add @payloadcms/storage-s3
pnpm add @payloadcms/storage-s3@beta
```
### Usage
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the S3 Storage adapter. The slug _must_ match one of your existing collection slugs.
- The `config` object can be any [`S3ClientConfig`](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3) object (from [`@aws-sdk/client-s3`](https://github.com/aws/aws-sdk-js-v3)). _This is highly dependent on your AWS setup_. Check the AWS documentation for more information.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
@@ -119,12 +119,12 @@ See the the [AWS SDK Package](https://github.com/aws/aws-sdk-js-v3) and [`S3Clie
### Installation
```sh
pnpm add @payloadcms/storage-azure
pnpm add @payloadcms/storage-azure@beta
```
### Usage
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the Azure Blob adapter. The slug _must_ match one of your existing collection slugs.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the Google Cloud Storage adapter. The slug _must_ match one of your existing collection slugs.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
```ts
@@ -218,7 +218,7 @@ export default buildConfig({
### Installation
```sh
pnpm add @payloadcms/storage-uploadthing
pnpm add @payloadcms/storage-uploadthing@beta
```
### Usage
@@ -261,7 +261,7 @@ If you need to create a custom storage adapter, you can use the [`@payloadcms/pl
### Installation
`pnpm add @payloadcms/plugin-cloud-storage`
`pnpm add @payloadcms/plugin-cloud-storage@beta`
### Usage
@@ -310,7 +310,7 @@ This plugin is configurable to work across many different Payload collections. A
| `collections` \* | `Record<string, CollectionOptions>` | Object with keys set to the slug of collections you want to enable the plugin for, and values set to collection-specific options. |
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
importconfigPromisefrom'@payload-config'
import'@payloadcms/next/css'
import{RootLayout}from'@payloadcms/next/layouts'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
importReactfrom'react'
import'./custom.scss'
Some files were not shown because too many files have changed in this diff
Show More
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.