Compare commits

...

329 Commits

Author SHA1 Message Date
Elliot DeNolf
8c2fc71149 chore(release): v3.0.0-beta.129 [skip ci] 2024-11-12 17:07:25 -05:00
Patrik
88bef2e140 chore: updates flaky uploads tests (#9149)
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
2024-11-12 16:41:08 -05:00
Alessio Gravili
a1c99c8b45 fix(richtext-lexical): inline blocks drawer not rendering any fields due to incorrect schemapath suffix (#9158) 2024-11-12 16:31:20 -05:00
Elliot DeNolf
d3cd9baa9b chore(release): v3.0.0-beta.128 [skip ci] 2024-11-12 15:52:52 -05:00
Sasha
64967e4ca6 fix(next): disable turbopack serverExternalPackages warnings (#9147)
### What?
Disables these annoying warnings when running `pnpm dev --turbo`
<img width="656" alt="image"
src="https://github.com/user-attachments/assets/7d0a2990-b5fd-4f5d-a025-665e8e3a7880">
https://github.com/vercel/next.js/issues/68805

### How?
Patches `console.warn` in `withPayload.js`

Can be disabled with `PAYLOAD_PATCH_TURBOPACK_WARNINGS=false` env
variable
2024-11-12 20:20:11 +00:00
James Mikrut
e0309a1dd0 fix: allow specifying queue (#9151)
Allows user to specify a queue when calling `payload.jobs.queue()`.
Closes #9133
2024-11-12 15:00:32 -05:00
James Mikrut
6bb4067bb3 feat: adds option to mongoose to ensure indexes (#9155)
Adds option `ensureIndexes` to Mongoose adapter, which will ensure
indexes are ready prior to completing connection.
2024-11-12 14:42:25 -05:00
Jarrod Flesch
a3ebf51d6e fix: incorrectly looking for schema paths when upload is not enabled (#9146)
### What?
![CleanShot 2024-11-12 at 12 17
56](https://github.com/user-attachments/assets/74b906a3-7e76-4ee9-8b18-bd24dd7fca82)

### Why?
Should not be attaching fields that it does not need.

### How?
Conditionally render slate upload drawer like we do with the toggler.
2024-11-12 14:02:08 -05:00
Elliot DeNolf
280448dd02 chore: remove e-commerce template from readme 2024-11-12 13:36:12 -05:00
Tobias Odendahl
09c41d5c86 fix(db-mongodb)!: use dbName for mongodb model (#9107)
### What?
Uses the `collection.dbName` property for the Mongoose model, if
defined.

### Why?
Currently, `collection.dbName` is used for the version name but not for
the actual collection name. Additionally, `autoPluralization` modifies
the `dbName` regardless. This behavior is inconsistent and contradicts
the documentation.

### How?
- Utilize `collection.dbName` instead of `collection.slug`.
- Disable `autoPluralization` for collections with a defined `dbName`.

Related: https://github.com/payloadcms/payload/discussions/9058

**BREAKING CHANGES**
If a `dbName` was previously provided, it will now be used as the
MongoDB collection name instead of the collection `slug`.
`autoPluralization` will not be applied to `dbName`.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-11-12 13:31:23 -05:00
Elliot DeNolf
def595e645 feat(templates): add with-vercel-website (#9144)
Add new `with-vercel-website` that uses the website template as a base.
2024-11-12 13:12:37 -05:00
James Mikrut
8dd7e989ef Chore/next 15 docs (#9148)
Closes #8995
2024-11-12 17:59:52 +00:00
Nate
7619592fb6 chore: update README asset image (#9143) 2024-11-12 12:51:25 -05:00
James Mikrut
432741bca3 chore: docs improvements (#9142)
Improvements to `select` docs and `jobs-queue` docs
2024-11-12 17:00:21 +00:00
Jarrod Flesch
97cffa51f8 chore: improves abort controller logic for server functions (#9131)
### What?
Removes abort controllers that were shared globally inside the server
actions provider.

### Why?
Constructing them in this way will cause different fetches using the
same function to cancel one another accidentally.

These are currently causing issues when two components call server
functions, even different functions, because the global ref inside was
being overwritten and aborting the previous one.

### How?
Standardizes how we construct and destroy abort controllers. This PR is focused around creating them to pass into the exposed serverAction provider functions. There are other places where this pattern can be applied.
2024-11-12 11:20:17 -05:00
Elliot DeNolf
7cd805adb9 fix(cpa): use proper branch tag (#9141)
The pinned git tag was not being threaded all the way through to where
the download was occurring.
2024-11-12 16:13:19 +00:00
Patrik
48d0faecae fix(next, ui): respect access of user for document locking (#9139) 2024-11-12 15:49:58 +00:00
Alessio Gravili
4f6651433c chore: ensure all packages have consistent licenses and package.json metadata (#9079) 2024-11-12 10:27:36 -05:00
Elliot DeNolf
8a67098f6c chore: add lint commit to .git-blame-ignore-revs 2024-11-12 10:20:42 -05:00
Alessio Gravili
03291472d6 chore: bump all eslint dependencies, run lint and prettier (#9128)
This fixes a peer dependency error in our monorepo, as
eslint-plugin-jsx-a11y finally supports eslint v9.

Additionally, this officially adds TypeScript 5.6 support for
typescript-eslint.
2024-11-12 10:18:22 -05:00
Sasha
3298113a93 fix(ui): pass correct relationTo to locked documents creation (#9137)
### What?
Relationships within `payload-locked-documents` collection were stored
incorrectly with `relationTo` as an array:
<img width="316" alt="image"
src="https://github.com/user-attachments/assets/f84b9807-6032-4ea2-8563-5c7d13306a4a">

Example how it should be:
<img width="405" alt="image"
src="https://github.com/user-attachments/assets/80fb54fd-7c2e-4c90-bd2b-dec8e7a06040">


This additionally caused issue that `value` wasn't converted to
`ObjectID`
2024-11-12 16:14:28 +02:00
Sasha
b878daf27a feat(db-postgres): deep querying on json and rich text fields (#9102)
### What?
Allows to query on JSON / Rich Text fields in Postgres the same way as
in Mongodb with any nesting level.

Example:
Data:
```js
{
  json: {
    array: [
      {
        text: 'some-text', // nested to array + object
        object: {
          text: 'deep-text', // nested to array + 2x object
          array: [10], // number is nested to array + 2x object + array
        },
      },
    ],
  }
}
```
Query:
```ts
payload.find({
  collection: 'json-fields',
  where: {
    and: [
      {
        'json.array.text': {
          equals: 'some-text',
        },
      },
      {
        'json.array.object.text': {
          equals: 'deep-text',
        },
      },
      {
        'json.array.object.array': {
          in: [10, 20],
        },
      },
      {
        'json.array.object.array': {
          exists: true,
        },
      },
      {
        'json.array.object.notexists': {
          exists: false,
        },
      },
    ],
  },
})
```

### How?
Utilizes [the `jsonb_path_exists` postgres
function](https://www.postgresql.org/docs/current/functions-json.html)
2024-11-12 09:26:04 +02:00
Germán Jabloñski
23907e432e feat(richtext-lexical): add useAsTitle to the popup links label (#8718)
Now we show not only the collection being linked to, but also the
document title:

![image](https://github.com/user-attachments/assets/5ba5713a-b051-4f11-ae2a-d5b50a25966b)

Previously this example was just displayed as: `Linked to Users`

- I've added a loading state in case the request is slow (verified with
fake slow connection).
- I have verified that if the `useAsTitle` is not defined, it correctly
fallbacks to the id

Please let me know if the same needs to be done with Slate.

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-11-12 05:07:50 +00:00
Alessio Gravili
a30eeaf644 feat(richtext-lexical): backport relevant from lexical playground between 0.18.0 and 0.20.0 (#9129) 2024-11-12 04:58:28 +00:00
Jacob Fletcher
df764dbbef docs: improves component paths and import map (#9118) 2024-11-11 22:42:48 -05:00
Alessio Gravili
6899a3cc27 fix(db-mongodb): destructuring error when trying to filter date fields by string query (#9116)
Previously, when filtering the internal link relationship in lexical by
typing in the relationship field, it would throw an error, as that
relationship field has a relation to "date-fields".
2024-11-11 20:41:02 -07:00
Alessio Gravili
7261faac57 perf: upgrade pino-pretty. This reduces bundle size and total amount of dependencies from 94 => 85 (#9127)
Previous:

![CleanShot 2024-11-11 at 19 48
05@2x](https://github.com/user-attachments/assets/e1ab5602-92f0-4221-9e7c-98bbba17db71)

94 Dependencies

Now:

![CleanShot 2024-11-11 at 19 48
43@2x](https://github.com/user-attachments/assets/ce5b7ecb-5128-4173-9109-9ddf3493301b)

85 Dependencies
2024-11-11 20:40:20 -07:00
Germán Jabloñski
7767c94bd8 feat(richtext-lexical)!: upgrade lexical from 0.18.0 to 0.20.0 (#9126)
I'm needing https://github.com/facebook/lexical/pull/6693

I'm going to keep the dependency bump and feature updates in separate
PRs unless they're breaking changes.*

**BREAKING:**

This upgrades our lexical dependencies from 0.18.0 to 0.20.0. If you
have lexical dependencies installed in your project, you will have to
upgrade those.

Additionally, the lexical team may introduce breaking changes in this
upgrade. If you use lexical APIs directly, please consult their
changelog for more information:
https://github.com/facebook/lexical/releases
2024-11-12 03:39:36 +00:00
Alessio Gravili
2ad991759f fix(ui): error in filtered relationship field component while scrolling, if the select option label is a number (#9117)
1. Open fields test suite
2. Type in relationship field, that has a relation to the numbers
collection
3. Scroll

You will get an error, as the label for the entry corresponding to the
numbers collection is of type number, and it attempts to use the
.toString() method on it
2024-11-12 03:37:53 +00:00
Alessio Gravili
9c559d7304 chore: fix live-preview tests against prod (#9122)
Live preview e2e tests had no CSS when tested against prod.

For all our other tests, we have a separate test/app directory that
imports CSS. Otherwise, the root-level /app directory is used.

For live-preview, we currently always run against test/live-preview/app,
that has no CSS import.

This PR adds a new test/live-preview/prod/app directory that imports CSS
and is used when we run tests against prod.

In order for this to work, I had to make import map generation smarter
2024-11-11 19:28:55 -07:00
Paul
d8391389ab feat(docs): add example for customising the filename of an upload via hooks (#9124) 2024-11-12 00:59:27 +00:00
Alessio Gravili
570c610eed docs: fix queue docs examples, link to qs-esm instead of qs (#9120) 2024-11-11 23:35:51 +00:00
Jarrod Flesch
9dbf1b7279 chore: imports reInitializeDB into live-preview test suite 2024-11-11 16:48:43 -05:00
Jarrod Flesch
71db10d68f chore: stabalize live preview test suite 2024-11-11 16:24:45 -05:00
Jacob Fletcher
c96fa613bc feat!: on demand rsc (#8364)
Currently, Payload renders all custom components on initial compile of
the admin panel. This is problematic for two key reasons:
1. Custom components do not receive contextual data, i.e. fields do not
receive their field data, edit views do not receive their document data,
etc.
2. Components are unnecessarily rendered before they are used

This was initially required to support React Server Components within
the Payload Admin Panel for two key reasons:
1. Fields can be dynamically rendered within arrays, blocks, etc.
2. Documents can be recursively rendered within a "drawer" UI, i.e.
relationship fields
3. Payload supports server/client component composition 

In order to achieve this, components need to be rendered on the server
and passed as "slots" to the client. Currently, the pattern for this is
to render custom server components in the "client config". Then when a
view or field is needed to be rendered, we first check the client config
for a "pre-rendered" component, otherwise render our client-side
fallback component.

But for the reasons listed above, this pattern doesn't exactly make
custom server components very useful within the Payload Admin Panel,
which is where this PR comes in. Now, instead of pre-rendering all
components on initial compile, we're able to render custom components
_on demand_, only as they are needed.

To achieve this, we've established [this
pattern](https://github.com/payloadcms/payload/pull/8481) of React
Server Functions in the Payload Admin Panel. With Server Functions, we
can iterate the Payload Config and return JSX through React's
`text/x-component` content-type. This means we're able to pass
contextual props to custom components, such as data for fields and
views.

## Breaking Changes

1. Add the following to your root layout file, typically located at
`(app)/(payload)/layout.tsx`:

    ```diff
    /* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
    /* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
    + import type { ServerFunctionClient } from 'payload'

    import config from '@payload-config'
    import { RootLayout } from '@payloadcms/next/layouts'
    import { handleServerFunctions } from '@payloadcms/next/utilities'
    import React from 'react'

    import { importMap } from './admin/importMap.js'
    import './custom.scss'

    type Args = {
      children: React.ReactNode
    }

+ const serverFunctions: ServerFunctionClient = async function (args) {
    +  'use server'
    +  return handleServerFunctions({
    +    ...args,
    +    config,
    +    importMap,
    +  })
    + }

    const Layout = ({ children }: Args) => (
      <RootLayout
        config={config}
        importMap={importMap}
    +  serverFunctions={serverFunctions}
      >
        {children}
      </RootLayout>
    )

    export default Layout
    ```

2. If you were previously posting to the `/api/form-state` endpoint, it
no longer exists. Instead, you'll need to invoke the `form-state` Server
Function, which can be done through the _new_ `getFormState` utility:

    ```diff
    - import { getFormState } from '@payloadcms/ui'
    - const { state } = await getFormState({
    -   apiRoute: '',
    -   body: {
    -     // ...
    -   },
    -   serverURL: ''
    - })

    + const { getFormState } = useServerFunctions()
    +
    + const { state } = await getFormState({
    +   // ...
    + })
    ```

## Breaking Changes

```diff
- useFieldProps()
- useCellProps()
```

More details coming soon.

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-11-11 13:59:05 -05:00
Jessica Chowdhury
3e954f45c7 fix: empty publish dropdown when localization is false (#9106)
Closes https://github.com/payloadcms/payload/issues/9092
2024-11-11 12:19:29 -05:00
Paul
9a970d21a9 fix: custom id field not shown depending on field and db types (#9091)
Closes https://github.com/payloadcms/payload/issues/9080
2024-11-11 16:42:06 +00:00
Elliot DeNolf
8a20231d40 ci: debug publish-canary job 2024-11-11 11:21:16 -05:00
Nate
26691377d2 chore: update README.md asset URL (#9104)
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

-->
2024-11-11 10:41:48 -05:00
Paul
8201a6cacd chore(templates): remove old ecommerce template (#8916)
removes the previous v2 ecommerce template from the repo ahead of v3
launch until ecomm v3 is ready
2024-11-11 10:19:24 -05:00
Nate
d7fc944792 fix: update README with new asset, image URL (#9099) 2024-11-11 10:18:11 -05:00
Elliot DeNolf
0c19afcf91 chore(release): v3.0.0-beta.127 [skip ci] 2024-11-11 09:56:14 -05:00
Sasha
0a15388edb feat(db-postgres): add point field support (#9078)
### 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/8996
https://github.com/payloadcms/payload/discussions/8644
2024-11-11 09:31:47 -05:00
Ruy Monteiro
a421503111 docs(storage-uploadthing): fix typo in README.md (#9090) 2024-11-10 07:59:46 +00:00
Nathan Clevenger
b86594f3f9 docs: fixed typo in onSuccess (#9096)
Changed `if the task fails` to `if the task succeeds`
2024-11-10 00:23:32 -07:00
Dan Ribbens
e3172f1e39 fix: migrateRefresh migrates without previously ran migrations (#9073)
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>
2024-11-08 15:35:46 -05:00
Dan Ribbens
ee117bb616 fix!: handle custom id logic in mongodb adapter (#9069)
### 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.
2024-11-08 15:34:19 -05:00
Jessica Chowdhury
dc111041cb fix: incorrect form changed state after doc drawer edit (#9025)
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.
2024-11-08 14:04:37 -05:00
Sasha
f67761fe22 fix(db-mongodb): totalDocs with joins (#9056)
### 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.
2024-11-08 14:04:24 -05:00
Jessica Chowdhury
010ac2ac0c fix: login redirect missing route (#8990)
Closes #8920 - login form does not redirect after form submit.

In `handleAuthRedirect` the route parameter was unintentionally getting
overwritten.
2024-11-08 13:41:15 -05:00
Dan Ribbens
d20445b6f3 fix(db-mongodb): write migrations index file (#9071)
fix: remove 'undefined' written into mongodb migrations
fix: write migrations index file
2024-11-08 13:26:45 -05:00
Kendell Joseph
1f26237ba1 chore: correctly redirects after in-activity (#9070)
Issues: 
  - https://github.com/payloadcms/payload/issues/5009
  - https://github.com/payloadcms/payload/pull/8809
2024-11-08 12:20:44 -06:00
Sasha
721ae79716 fix: populate with find operation (#9087)
### 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.
2024-11-08 18:45:11 +02:00
Paul
1584c41790 fix(docs): auth page email broken link (#9089) 2024-11-08 16:14:26 +00:00
James Mikrut
963fee83e0 Update README.md 2024-11-08 09:18:19 -05:00
Paul
b32c4defd9 fix(templates): use direct blocks props instead of drilling them out of pages (#9074) 2024-11-08 04:36:40 +00:00
Steve
a6e7305696 fix(translations): improves Bulgarian translations (#9031)
### 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>
2024-11-07 17:56:57 -05:00
Alessio Gravili
0cd83f0591 perf: upgrade json-schema-to-typescript and various other dependencies (#9076)
This further reduces the amount of dependencies installed by payload.
Special thanks to @benmccann for this PR
(https://github.com/bcherny/json-schema-to-typescript/pull/639) !

json-schema-to-typescript before this PR (15.0.1):

![CleanShot 2024-11-07 at 15 35
53@2x](https://github.com/user-attachments/assets/83cb671c-82a8-4b59-b488-cf941d673c8e)

14mb, 37 dependencies

json-schema-to-typescript after this PR (15.0.3):

![CleanShot 2024-11-07 at 15 36
08@2x](https://github.com/user-attachments/assets/d9463275-37e5-452e-aca5-9c1bdeb2a435)

11 MB, 14 dependencies

This PR also upgrades:
- console-table-printer
- croner
- get-tsconfig
- jose
- pino-pretty
- ts-essentials
- tsx
2024-11-07 22:54:45 +00:00
James Mikrut
cd49783105 Update README.md 2024-11-07 17:53:55 -05:00
Elliot DeNolf
5b77653fe7 ci: run build when templates change 2024-11-07 15:45:57 -05:00
Paul
1d5d30391e fix(templates): fix website template's missing paragraph feature allowing you to change text from headings (#9072) 2024-11-07 20:36:01 +00:00
Elliot DeNolf
2c0caab761 ci: remove unused generated-templates, replaced with template build job 2024-11-07 15:30:11 -05:00
Mikkel Madsen
57e535e646 fix: corrected translation emailOrPasswordIncorrect for Danish (da) (#9063)
## 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)
2024-11-07 15:26:32 -05:00
Elliot DeNolf
8c10a23fa2 test: naming 2024-11-07 13:10:05 -05:00
Elliot DeNolf
80b69ac53d test: naming with matrix (#9064)
Better test naming when tests are in a matrix.
2024-11-07 13:08:32 -05:00
Dan Ribbens
e2607d4faa chore: database transactions docs formatting (#9068) 2024-11-07 12:48:17 -05:00
Tylan Davis
1267aedfd3 docs: closes <strong> tags properly on jobs queue documentation (#9067)
### 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.
2024-11-07 12:42:16 -05:00
Elliot DeNolf
e907724af7 chore(cpa): use git tags for template urls (#9065)
`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`
2024-11-07 11:47:26 -05:00
Elliot DeNolf
320916f542 ci: build templates with packed deps (#8970)
Build templates using packed deps from the repo.
2024-11-07 10:49:21 -05:00
Paul
015580aa32 feat(templates): add adminThumbnail to media in website template (#9059) 2024-11-07 03:25:27 +00:00
Patrik
f1ba9ca82a chore: updates flaky locked-documents e2e tests (#9055) 2024-11-06 16:49:06 -05:00
Elliot DeNolf
f878e35cc7 chore(release): v3.0.0-beta.126 [skip ci] 2024-11-06 16:23:57 -05:00
Dan Ribbens
f0f96e7558 fix: allow workflows to be empty or undefined (#9039)
### 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.
2024-11-06 15:50:17 -05:00
Javier
0165ab8930 fix: replace console.error with logger.errors (#9044)
## 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">
2024-11-06 15:49:27 -05:00
Sasha
213b7c6fb6 feat: generate types for joins (#9054)
### 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`
2024-11-06 22:43:07 +02:00
Jessica Chowdhury
7dc52567f1 fix: publish locale with autosave enabled and close dropdown (#8719)
1. Fix publish specific locale option when no published versions exist
2. Close the publish locale dropdown on click
2024-11-06 14:36:28 -05:00
Sasha
a22c0e62fa feat: add populate property to Local / REST API (#8969)
### 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.
2024-11-06 13:50:19 -05:00
Sasha
147d28e62c fix(db-postgres): handle special characters in createDatabase (#9022)
### 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`.
2024-11-06 13:29:57 -05:00
Sasha
f507305192 fix: handle bulk upload sequentially to prevent conflicts (#9052)
### 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>
2024-11-06 12:54:16 -05:00
Timothy Choi
d42529055a fix(richtext-slate, ui): use PointerEvents to show tooltips on enabled / disabled buttons (#9006)
Fixes #9005

Note: I did not replace all instances of `onMouseEnter`, just the ones
that can be disabled and have `tooltip` set.
2024-11-06 12:43:06 -05:00
Jacob Fletcher
4b4ecb386d fix(ui): dedupes custom id fields (#9050)
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.
2024-11-06 12:19:19 -05:00
Andreas Bernhard
becf56d582 fix(ui): edit many modal draft action button order and style (#9047)
PR adjusts "draft" action button order and style on the edit-many-modal
to be consistent with default collection edit view action buttons.

This is the `v3` PR version of
https://github.com/payloadcms/payload/pull/9046 and fixes
https://github.com/payloadcms/payload/issues/9045
2024-11-06 11:19:44 -05:00
Elliot DeNolf
8a5f6f044d chore(release): v3.0.0-beta.125 [skip ci] 2024-11-06 10:24:31 -05:00
Dan Ribbens
93a55d1075 feat: add join field config where property (#8973)
### 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/8936
https://github.com/payloadcms/payload/discussions/8937

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-11-06 10:06:25 -05:00
Elliot DeNolf
cdcefa88f2 fix(cpa): remove lock file on project creation 2024-11-06 10:02:29 -05:00
Elliot DeNolf
5c049f7c9c ci(triage): adjust tag condition 2024-11-05 23:03:27 -05:00
Elliot DeNolf
ae6fb4dd1b ci(triage): add granularity in actions to be performed, enable comments 2024-11-05 22:58:33 -05:00
Sasha
9ce2ba6a3f fix: custom endpoints with method: 'put' (#9037)
### 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

-->
2024-11-05 23:14:34 +02:00
Sasha
f52b7c45c0 fix: type augmentation of RequestContext (#9035)
### 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
2024-11-05 23:14:04 +02:00
Elliot DeNolf
2eeed4a8ae chore(templates): add lock file to with-payload-cloud 2024-11-05 15:55:57 -05:00
Elliot DeNolf
c0335aa49e chore(templates): add lock files 2024-11-05 15:27:27 -05:00
Paul
3ca203e08c fix(ui): json fields can now take a maxHeight in admin props and there's a mininum height of 3 lines (#9018)
JSON fields are now 3 lines minimum in height like so:

![image](https://github.com/user-attachments/assets/0b2ad47e-6929-4836-ac9d-022ffcdc6f27)


This helps fix an issue where long content is wrapped:

![image](https://github.com/user-attachments/assets/40fc2426-11d7-4ca5-a716-3347bb0d5a4b)

Previously it would show like this:

![image](https://github.com/user-attachments/assets/7f321220-ffa2-40ff-bc4b-2b26d21d4911)
2024-11-05 13:43:51 -06:00
James Mikrut
50f3ca93ee docs: improves jobs queue (#9038)
improves docs for jobs queue
2024-11-05 19:25:14 +00:00
Friggo
4652e8d56e feat(plugin-seo): add czech translation (#8998)
Adds Czech translation to SEO plugin.
2024-11-05 18:28:12 +00:00
Patrik
2175e5cdfb fix(ui): ensure upload field updates reflect in edit popup changes (#9034)
### 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
2024-11-05 13:03:12 -05:00
Paul
201d68663e feat(templates): website template now has configured image sizes, updated readme and simplified env vars for setting up (#9036) 2024-11-05 17:59:29 +00:00
Patrik
ebd3c025b7 fix(ui): updatedAt field in locked-docs collection able to be updated by non-owner (#9026)
### 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
2024-11-05 12:39:48 -05:00
Paul
ddc9d9731a feat: adds x-powered-by Payload header in next config (#9027)
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
2024-11-04 18:11:51 -06:00
Jesper We
3e31b7aec9 feat(plugin-seo): add Swedish translations (#9007)
### What?

Swedish text translations

### Why?

There was no Swedish before
2024-11-04 21:25:08 +00:00
Elliot DeNolf
e390835711 chore(release): v3.0.0-beta.124 [skip ci] 2024-11-04 14:47:38 -05:00
James Mikrut
35b107a103 fix: prefetch causing stale data (#9020)
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.
2024-11-04 19:24:28 +00:00
Paul
6b9f178fcb fix: graphql missing options route resulting in failed cors preflight checks in production (#8987)
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
2024-11-04 14:20:09 -05:00
vahacreative
cca6746e1e feat(plugin-seo): add Turkish translation v3 (#8993) 2024-11-04 11:54:57 -06:00
Sasha
4349b78a2b fix: invalid select type with strictNullChecks: true (#8991)
### 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
2024-11-04 19:16:37 +02:00
Sasha
5b97ac1a67 fix: querying relationships by id path with REST (#9013)
### 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
2024-11-04 17:57:41 +02:00
Patrik
f10a160462 docs: improves clarity for better readability of document-locking docs (#9010) 2024-11-04 09:26:08 -05:00
Elliot DeNolf
59ff8c18f5 chore: add project id source (#8983)
Add `projectIDSource` to analytics event.
2024-11-01 09:46:44 -04:00
Elliot DeNolf
10d5a8f9ae ci: force add triage action 2024-11-01 09:00:05 -04:00
Said Akhrarov
48d2ac1fce docs: include hasMany in upload field config options (#8978)
### 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`
2024-11-01 05:40:04 -04:00
Elliot DeNolf
c33791d1f8 chore(release): v3.0.0-beta.123 [skip ci] 2024-10-31 16:10:52 -04:00
Paul
9eb79c1b5f fix(templates): website template error inside the populateAuthors hook (#8972) 2024-10-31 17:51:23 +00:00
Germán Jabloñski
4246b36e06 docs: improve docs about beforeSync in searchPlugin (#8946)
This clarification was made to prevent anyone from wasting time on this
again:

https://github.com/payloadcms/payload/issues/5173
2024-10-31 12:14:04 -04:00
Sasha
3175541c80 fix: select with unnamed tabs (#8966)
### 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.
2024-10-31 12:06:05 -04:00
Patrik
090831c92c fix(next): overly large width on document locked modal content (#8967) 2024-10-31 11:02:17 -04:00
Patrik
55ce8e68fc fix: locked documents with read access for users (#8950)
### 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`.
2024-10-31 09:23:18 -04:00
Paul
b417c1f61a feat(plugin-seo)!: support overriding default fields via a function instead and fixes bugs regarding localized labels (#8958)
## 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
2024-10-31 06:03:39 +00:00
Elliot DeNolf
2c6635fe20 ci: port all templates, actions, and workflows from main (#8949)
Port all templates, actions, and workflows from `main` in preparation
for making `beta` the default branch.
2024-10-30 21:36:51 -04:00
Sasha
c0397c35a2 fix(ui): increase z-index of ReactSelect (#8735)
Fixes https://github.com/payloadcms/payload/issues/8728

Before:
<img width="698" alt="Screenshot 2024-10-16 at 15 28 55"
src="https://github.com/user-attachments/assets/eee45448-5e97-4c2a-bbe3-727c41ed9b08">
After:
<img width="509" alt="Screenshot 2024-10-16 at 15 29 27"
src="https://github.com/user-attachments/assets/7e0a2af6-71be-41e7-ad84-4ae3bcece9b6">
2024-10-31 03:22:14 +02:00
Sasha
08251ec98d fix: return type of findByID with strict: true (#8953)
### What?
Corrects the return type of `findByID` when `strict: true` /
`strictNullChecks: true` is used, adds `null` to the return type _only_
when `disableErrors: true` is passed.





![image](https://github.com/user-attachments/assets/fb59312c-6a79-457c-8d27-d2a91473bcb3)

![image](https://github.com/user-attachments/assets/2116acbf-730c-4ae6-b662-f83a40c5d9f2)
2024-10-31 03:11:20 +02:00
Elliot DeNolf
d192f1414d chore(release): v3.0.0-beta.122 [skip ci] 2024-10-30 21:02:15 -04:00
Said Akhrarov
755355ea68 fix(ui): description undefined error on empty tabs array (#8830)
Fixes an error that occurs when `tabs` array is empty or active tab
config is undefined due to missing optional chaining operator.
2024-10-30 20:57:54 -04:00
Manuel Leitold
58441c2bcc fix(graphql): avoid adding extra password fields when running mutations (#8032) (#8845)
<!--

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.
2024-10-31 00:45:07 +00:00
Gregor Gabrič
3918c09013 feat(translations): added sl to exported date locales (#8817)
added sl to exported date locales
2024-10-30 18:26:12 -06:00
Konsequanzheng
bf989e6041 docs: fix copy paste oversights in storage-adapters.mdx (#8919)
### What?
S3, Azure Blob, and Google Cloud storage sections were referring to
Vercel Blob Storage (presumably because of copy pasting)
2024-10-30 18:15:25 -06:00
Paul
57fba36257 fix(ui): overly large width on stay logged in modal content (#8952) 2024-10-31 00:01:58 +00:00
Sasha
df4661a388 docs: fix defaultPopulate docs formatting (#8951)
### What?
Fixes this
[here](https://payloadcms.com/docs/beta/queries/select#rest-api)
<img width="535" alt="image"
src="https://github.com/user-attachments/assets/a9fec4a7-c1c2-43f3-ba36-a07505deb012">
2024-10-31 00:37:45 +02:00
James Mikrut
03e5ae8095 fix: bulk upload mimetype wildcard file selection (#8954)
Fixes an issue where using wildcards in upload-enabled collection
mimeType restrictions would prevent files from being selected in the
bulk upload file selector.
2024-10-30 16:26:36 -06:00
Elliot DeNolf
d89db00295 chore(release): v3.0.0-beta.121 [skip ci] 2024-10-30 14:25:34 -04:00
James Mikrut
8970c6b3a6 feat: adds jobs queue (#8228)
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>
2024-10-30 17:56:50 +00:00
Said Akhrarov
0574155e59 docs: fix docs-wide spelling errors and formatting issues (#8942)
### 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).~~
2024-10-30 11:54:44 -06:00
Paul
03331de2ac fix(ui): perf improvements in bulk upload (#8944) 2024-10-30 13:44:09 -04:00
Sasha
d64946c2e2 fix(db-mongodb): ensure relationships are stored in ObjectID (#8932)
### 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.
2024-10-30 13:42:07 -04:00
Sasha
c41ef65a2b feat: add defaultPopulate property to collection config (#8934)
### 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.
2024-10-30 13:41:34 -04:00
Paul
d38d7b8932 fix(ui): broken buttons in the bulk upload drawer (#8926)
Fixes the mobile bottom interface and the arrow buttons in the actions
at the top.

Before:

![image](https://github.com/user-attachments/assets/26902eb0-5d1a-480d-b6f5-c36a800a6bff)


After:

![image](https://github.com/user-attachments/assets/7837684c-37a7-4b2e-a875-47972cf1671f)
2024-10-30 11:29:58 -06:00
Paul
01ccbd48b0 feat!: custom views are now public by default and fixed some issues with notFound page (#8820)
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
2024-10-30 11:29:29 -06:00
Kendell Joseph
61b4f2efd7 chore: updates payload cloud plugin docs (#8943)
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.
2024-10-30 12:52:56 -04:00
Sasha
f4041ce6e2 fix(db-mongodb): joins with singular collection name (#8933)
### 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`.
2024-10-30 12:06:03 -04:00
James Mikrut
123125185c fix!: plugin-search with localization enabled (#8938)
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.
2024-10-30 11:49:54 -04:00
Kendell Joseph
04bd502d37 chore: uses custom live preview component if one is provided (#8930)
Issue: https://github.com/payloadcms/payload/issues/8273
2024-10-30 11:37:01 -04:00
Sasha
dae832c288 feat: select fields (#8550)
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>
2024-10-29 21:47:18 +00:00
Dan Ribbens
6cdf141380 feat: prevent create new for joins (#8929)
### 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.

![image](https://github.com/user-attachments/assets/152abed4-a174-498b-835c-aa4779c46834)

### After

Initial document creation: 
![Screenshot 2024-10-29
125132](https://github.com/user-attachments/assets/f33b1532-5b72-4c94-967d-bda618dadd34)

Prevented using `allowCreate: false`
![Screenshot 2024-10-29
130409](https://github.com/user-attachments/assets/69c3f601-fab3-4f5a-9df5-93fd133682ca)
2024-10-29 16:49:27 -04:00
Kendell Joseph
29704428bd chore: corrects package import paths for live preview test (#8925)
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.
2024-10-29 16:12:45 -04:00
Sasha
6c341b5661 fix(ui): sanitize limit for preferences (#8913)
### 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.
2024-10-29 16:03:31 -04:00
Kendell Joseph
9c530e47bb chore: changes admin API key field visuals based on read and update permissions (#8923)
Issue: https://github.com/payloadcms/payload/issues/8785
2024-10-29 18:56:29 +00:00
Elliot DeNolf
7ba19e03d6 ci: add payload-cloud as valid pr scope 2024-10-29 13:47:37 -04:00
Paul
c0aa96f59a fix(ui): missing localization label on text area fields (#8927) 2024-10-29 17:19:38 +00:00
Patrik
c7bde52aba chore: adds additional locked documents e2e tests (#8921)
Additional tests for global locked documents
2024-10-29 10:03:09 -04:00
Paul
915a3ce3f5 docs: fix dead link for local API (#8917) 2024-10-29 05:56:05 +00:00
Said Akhrarov
b6867f222b docs: form builder number field table unformatted (#8915)
### 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`
2024-10-28 23:29:21 -06:00
Elliot DeNolf
43fcccab93 chore(release): v3.0.0-beta.120 [skip ci] 2024-10-28 22:08:50 -04:00
Patrik
e74906f555 fix(next, ui): exclude expired locks for globals (#8914)
Continued PR off of https://github.com/payloadcms/payload/pull/8899
2024-10-28 21:49:50 -04:00
Patrik
1e002acce9 fix(next, ui): only show locked docs that are not expired (#8899)
`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
2024-10-28 20:05:26 -04:00
Sasha
7a7a2f3918 fix(db-mongodb): query 'in' with a comma-delimited value (#8910)
### 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
2024-10-28 19:41:28 -04:00
Dan Ribbens
f0edbb79f9 feat: join field defaultLimit and defaultSort (#8908)
### 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
2024-10-28 17:52:37 -04:00
Said Akhrarov
3605da1e3f docs: update metadata icons example to use url and fix images type in table (#8898)
<!--

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`:

![image](https://github.com/user-attachments/assets/086dc44c-5c1b-4b5e-9658-521eb60fff0d)

### How?
Changes to `metadata.mdx`

Fixes #8887

Credit to @thgh for the `href` to `url` find
2024-10-28 17:02:06 -04:00
Brandon Kocur
7127c5507c docs: update database adpater installation commands to use beta version (#8895)
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.
2024-10-28 17:00:38 -04:00
James Mikrut
00ed66b4ee fix: autosave potentially losing latest: true w/ race condition (#8894)
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.
2024-10-28 16:28:57 -04:00
James Mikrut
44e52b0305 fix: #8903, form-builder payment static value field (#8905)
Fixes #8903
2024-10-28 16:28:41 -04:00
Sasha
aea1b41f90 fix(cpa): write POSTGRES_URL to .env for vercel postgres (#8743)
Fixes https://github.com/payloadcms/payload/issues/8877
Current behaviour:
`pnpx create-payload-app@beta`, select "Vercel Postgres",

`.env` file:
```env
# Added by Payload
# should be POSTGRES_URL here!
DATABASE_URI=postgres://postgres:<password>@127.0.0.1:5432/f
PAYLOAD_SECRET=4415faad68a15727b4ebf582
```

`payload.config.ts`:
```ts
db: vercelPostgresAdapter({
  pool: {
    connectionString: process.env.POSTGRES_URL || '',
  },
}),
```
2024-10-28 17:34:58 +00:00
Alessio Gravili
a8569b9e78 fix(richtext-lexical): ensure editor cursor / selection state is preserved when working with drawers (#8872)
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
2024-10-27 22:32:31 +00:00
Elliot DeNolf
07a8a37fbd chore(templates): use payload cloud (#8871)
Update templates to use `@payloadcms/payload-cloud`. 

**NOTE:** This should not be merged until beta.119 is released.
2024-10-25 16:20:58 -04:00
Elliot DeNolf
6c2eecc47e chore(release): v3.0.0-beta.119 [skip ci] 2024-10-25 16:11:53 -04:00
Paul
4f88fb046f chore: update docs mention on payload cloud plugin (#8869) 2024-10-25 13:09:35 -06:00
Elliot DeNolf
1b1dc82cfb feat!: rename @payloadcms/plugin-cloud (#8828)
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.
2024-10-24 21:19:15 -04:00
Paul
2df8f94a75 fix(plugin-search): issues with overriding the search collection slug consistently across hooks (#8847)
Fixes https://github.com/payloadcms/payload/issues/8842
2024-10-25 00:29:39 +00:00
Paul
e72e81c3da fix(ui): upload buttons being hidden at mobile screen widths (#8860) 2024-10-24 22:29:29 +00:00
Elliot DeNolf
b1b571d53e ci: do not run pr-title on synchronize event 2024-10-24 16:48:05 -04:00
Paul
085e127217 fix(ui): leave without saving when changing /account theme (#8724)
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.
2024-10-24 16:46:19 -04:00
Anders Semb Hermansen
4d44c378ed feat: sort by multiple fields (#8799)
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>
2024-10-24 15:46:30 -04:00
Sasha
6e919cc83a perf: index globals versions timestamps by default (#8821) 2024-10-24 14:58:59 -04:00
Elliot DeNolf
1a15425b59 fix(cpa): properly detect if pnpm exists on windows (#8855)
Use `where <command>` if using windows when detecting package manager
2024-10-24 14:53:11 -04:00
Sasha
9069bd3fac fix(db-postgres): sort by localized fields (#8839)
### 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)`
2024-10-24 14:47:58 -04:00
Hristiyan Dodov
2e11068f49 feat(richtext-slate): add useElement hook to richtext-slate client exports (#8856)
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'
```
2024-10-24 11:50:09 -06:00
Elliot DeNolf
749a7d9131 chore(cpa): remove beta from postgres selection 2024-10-24 13:07:38 -04:00
Elliot DeNolf
b482da63c6 chore(release): v3.0.0-beta.118 [skip ci] 2024-10-23 22:07:05 -04:00
MotorcycleEnjoyer
0fcbce3a01 feat(templates): add a copy button to website template code blocks (#8794)
## WHAT
- Adds a copy code button to the Code Blocks in V3 Beta Website
Template.
- Uses the existing button from `@/components/ui/button`
- SVG from this website: https://uxwing.com/copy-icon/


https://github.com/user-attachments/assets/2f6e720a-de37-40b5-a3bf-c748a69502b5

## WHY
- Copy-Code button is convenient for users looking at code blocks in
tutorials/documentation/etc

## ISSUES
- Button color invert isn't immediate on refresh in darkmode


https://github.com/user-attachments/assets/f1093a27-73dd-47cb-8fc9-2f4bc301b80c
2024-10-23 20:47:15 +00:00
Sasha
1caa383608 fix: reduce import map diff when config changes (#8846)
### What?
Reduces difference in the `importMap.js` file when config changes.

### How?
Instead of appending the length, appends the hash of the path.

#### Before: 
Example of the diff when 1 component gets removed
<img width="374" alt="image"
src="https://github.com/user-attachments/assets/7aff02bd-ef55-4e40-963f-1cc3890e5957">
output:
```ts
import { TestComponent as TestComponent_84 } from 'test/admin/components/TestComponent.js'
```

#### After:
Targets only necessary for this component lines:
<img width="359" alt="image"
src="https://github.com/user-attachments/assets/99ba0ebd-cff4-4169-9622-e4c491e23eef">

Output:
```ts
import { TestComponent as TestComponent_d010fadde249c7cd3feed0eef58fe83c } from 'test/admin/components/TestComponent.js'
```

Fixes https://github.com/payloadcms/payload/issues/8841
2024-10-23 23:33:53 +03:00
Jessica Chowdhury
03c07026c5 feat: add localized indicator to field label (#8602)
On any localized field, appends `locale` on the end of the label.
2024-10-23 15:06:30 -04:00
Sasha
9f66114577 chore: jest reporter log failed tests count (#8810)
for example 3 tests passed but 1 failed, shows:
> 1 FAILED

instead of

> 4 FAILED

example of the previous behaviour

![image](https://github.com/user-attachments/assets/78c4bc76-caa4-4bf8-943f-2b6b690ce763)

![image](https://github.com/user-attachments/assets/7f261ac3-17dd-474d-87a3-47ad6cbacd68)
2024-10-22 23:22:20 +03:00
Sasha
52b1d332db chore: fixes dev server doesn't drop the database (#8834)
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`.
2024-10-22 23:19:48 +03:00
Sasha
5ea8d2c196 docs: append the beta tag to plugins installation commands (#8831)
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
2024-10-22 19:50:48 +03:00
Sasha
8af00f2deb fix: join field works on collections with versions enabled (#8715)
- Fixes errors with drizzle when building the schema
https://github.com/payloadcms/payload/issues/8680
- Adds `joins` to `db.queryDrafts` to have them when doing `.find` with
`draft: true`
2024-10-22 11:05:55 -04:00
Sasha
4c396c720e fix(db-postgres): alias already in use in this query (#8823)
Fixes https://github.com/payloadcms/payload/issues/8517

Reuses existing joins instead of adding new, duplicate ones which
causes:
```
Error: Alias "" is already used in this query.
```
2024-10-22 10:14:38 -04:00
Elliot DeNolf
69125504af chore(release): v3.0.0-beta.117 [skip ci] 2024-10-22 09:33:50 -04:00
Elliot DeNolf
74266bdd9a feat!: bump next.js to 15.0.0 (#8825)
Bump Next.js to 15.0.0
2024-10-21 23:12:22 -04:00
Elliot DeNolf
9fb86655a9 fix: drizzle init args (#8818)
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 🤔
2024-10-21 21:39:37 -04:00
Patrik
2908c9adde fix(next, ui): ensures selectAll in the list view ignores locked documents (#8813)
Fixes #8783
2024-10-21 16:18:34 -04:00
Sasha
fe25b54fff fix(ui): unique ids for nested rows on row duplicate to prevent errors with postgres (#8790)
Fixes https://github.com/payloadcms/payload/issues/8784

This works for any deep level, both arrays and blocks.
2024-10-21 08:51:26 -04:00
Anders Semb Hermansen
ef8a5b1f3e perf: replace jsonwebtoken with jose (#8217)
The jose package has 0 dependencies and is tree shakable ESM.
So we get lower bundle size and get rid of 10 dependencies.
2024-10-18 10:04:37 -06:00
Sasha
197e3bc010 docs: corrects old imports (#8769)
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'`
2024-10-18 10:47:47 +03:00
Because789
36acfee288 docs: fix missing TextField import (#8688)
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.

 -->
2024-10-18 10:47:31 +03:00
Alessio Gravili
062a333779 perf: upgrade pino and pino-pretty, reducing the total amount of dependencies (#8776)
BEFORE:

22 dependencies, 2MB total size

![CleanShot 2024-10-18 at 00 11
48@2x](https://github.com/user-attachments/assets/abd20ac1-fc66-4d5b-bbda-bdcf89846a0a)

AFTER:

12 dependencies, 1MB total size

![CleanShot 2024-10-18 at 00 12
44@2x](https://github.com/user-attachments/assets/6f22e2e3-0eed-4b48-8e51-1f5156e9efd3)
2024-10-18 06:58:56 +00:00
Alessio Gravili
fa929120e7 chore: upgrade typescript from 5.6.2 to 5.6.3, upgrade playwright from 1.46.0 to 1.48.1 (#8775) 2024-10-18 06:09:51 +00:00
Alessio Gravili
f3bec93d76 fix(richtext-lexical): richtext fields in drawers aren't editable, inline toolbar artifacts are shown for readOnly editors (#8774)
Fixes this:


https://github.com/user-attachments/assets/cf78082d-9054-4324-90cd-c81219a4f26d
2024-10-18 05:38:48 +00:00
Germán Jabloñski
fa49215078 chore: add internationalization guidelines to CONTRIBUTING.md (#8755) 2024-10-18 03:50:31 +00:00
Alessio Gravili
aedf3c8a76 fix(richtext-*): ensure admin panel doesn't freeze with some field configurations consisting of 2+ richtext fields (#8773)
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
2024-10-18 03:22:05 +00:00
Sasha
9056b9fe9b fix(db-mongodb): virtual fields within row / collapsible / tabs (#8733)
Fixes https://github.com/payloadcms/payload/issues/8674
2024-10-17 16:23:45 -04:00
Paul
82f278931b fix(ui): padding on relationship fields when no options or loading text is displayed (#8767) 2024-10-17 19:46:28 +00:00
Germán Jabloñski
a7895560a6 fix(richtext-lexical): fix CLS on collapsed/expanded state of Lexical blocks (#8029)
## 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
2024-10-17 19:36:14 +00:00
Paul
1f0d8da182 fix(plugin-seo): description and title fields now respect given minLength and maxLength rules for passing validation (#8765)
Previously minLength or maxLength was not being respected and the
components would use default values only.
2024-10-17 19:28:54 +00:00
Said Akhrarov
c91f21bb78 docs: fix incorrect link for outside-nextjs in local-api importing it section (#8764)
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>
2024-10-17 13:13:37 -06:00
Elliot DeNolf
7136515f8d chore(release): v3.0.0-beta.116 [skip ci] 2024-10-17 09:05:45 -04:00
Sasha
73102e97fe fix(drizzle): bump drizzle-orm in drizzle package to 0.35.1 (#8759)
Fixes https://github.com/payloadcms/payload/issues/8757. Other packages
have `drizzle-orm` `0.35.1`, but this does not (`0.34.1-1f15bfd`).
2024-10-17 07:14:02 -04:00
Sasha
f37e476758 fix(db-postgres): esm compatible import of pg (#8758)
Fixes this error that doesn't occur in our monorepo but on users
projects.
<img width="1040" alt="image"
src="https://github.com/user-attachments/assets/6b410959-9108-4022-ae0a-64bc4be6de67">
2024-10-17 10:02:30 +00:00
Sasha
90bca15f52 fix(drizzle): enforce uniqueness on index names (#8754)
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>
2024-10-17 02:05:27 +00:00
Sasha
872b205acc fix(drizzle): select hasMany nested to array + tab/group (#8737)
Fixes https://github.com/payloadcms/payload/issues/8732
2024-10-16 21:52:48 -04:00
Jarrod Flesch
99b4359e89 fix: pg where filters not respected in policy generation (#8753)
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.
2024-10-16 16:54:23 -04:00
Dan Ribbens
b269d33278 chore: bump drizzle-kit 0.26.2 (#8750) 2024-10-16 16:32:54 -04:00
Patrik
c63b7bc606 fix: disables document locking of payload-locked-documents, preferences, & migrations collections (#8744)
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
2024-10-16 14:46:39 -04:00
Elliot DeNolf
0fb92d3a0a chore(release): v3.0.0-beta.115 [skip ci] 2024-10-16 14:20:27 -04:00
Jarrod Flesch
99228b62ce chore: improves getLatestCollectionVersion where constraints (#8746) 2024-10-16 14:12:43 -04:00
Dan Ribbens
7019f22aad chore: bump drizzle-orm 0.35.1 (#8742) 2024-10-16 15:14:20 +00:00
Said Akhrarov
c4fa885e84 fix(ui): restrict file picking via upload config mimetypes (#8710)
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.
2024-10-16 09:24:21 -04:00
Jarrod Flesch
a9c6a91c1c chore(examples): correct where path comes from in multi-tenant (#8698) 2024-10-16 08:28:28 -04:00
Jarrod Flesch
a19e8d382d fix: corrects schemaPath passing (#8726)
Fixes https://github.com/payloadcms/payload/issues/8690

Fixes an issue where unrelated schema paths were being joined and passed
into nested sanitizeFields function calls.
2024-10-16 06:59:37 -04:00
Paul
e6a1ca5049 fix(ui): add missing styles under the payload-default css layer (#8723) 2024-10-16 01:58:50 +00:00
Dan Ribbens
6d0676ab09 chore: bump drizzle-kit 0.26.1 (#8721) 2024-10-15 21:12:40 +00:00
Dan Ribbens
93545f3103 fix(db-postgres, db-sqlite)!: bump drizzle-kit drizzle-orm @libsql/client (#8617)
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
2024-10-15 20:20:50 +00:00
Patrik
8d10737b2f fix(ui): removes overflow: hidden style from actions wrapper (#8717)
`Before`:
![Screenshot 2024-10-15 at 2 55
22 PM](https://github.com/user-attachments/assets/39b261c4-bb72-4497-ab47-01d430255773)

`After`:
![Screenshot 2024-10-15 at 2 55
07 PM](https://github.com/user-attachments/assets/8913479a-9e0b-4edf-baa1-130dc179af34)
2024-10-15 15:58:36 -04:00
Paul
303a224072 fix(templates): website template issue with previewing drafts (#8714)
Fixes https://github.com/payloadcms/payload/issues/8708
2024-10-15 15:10:34 +00:00
Elliot DeNolf
2315719c28 chore(deps): bump turbo 2024-10-15 09:58:28 -04:00
Elliot DeNolf
85e87c15fa chore(release): v3.0.0-beta.114 [skip ci] 2024-10-15 09:51:54 -04:00
Jacob Fletcher
35a5199c87 fix(next): returns proper document id type from init page result (#8700) 2024-10-14 19:39:30 -04:00
Patrik
3f2b828298 fix(drizzle, ui): properly filters out number field values with the exists operator filter (#8706)
Filtering by `null` `number` field values or normal values with the
`exists` operator was not working in `postgres` & `sqlite`.

Was previously fixed for `mongodb`
[here](https://github.com/payloadcms/payload/pull/8416)

Now fixed for `postgres` & `sqlite` adapters as well.
2024-10-14 19:23:22 -04:00
Jessica Chowdhury
a9e7d4884e fix: ensure beforeValidate hook runs for reset password (#8433)
Adds `beforeValidate` hook to reset password operation.

**Closes** https://github.com/payloadcms/payload/issues/7582
2024-10-14 19:12:28 -04:00
Dan Ribbens
3110c1b01b fix: local update limit (#8704) 2024-10-14 19:05:13 -04:00
Alessio Gravili
f1ebf56691 chore: when dev server restarts, ensure exiting the parent process kills child process (#8703) 2024-10-14 20:02:26 +00:00
Paul
e3957d746b fix(ui): react-datepicker in number fields and datepicker visual issues (#8694)
Fixes https://github.com/payloadcms/payload/issues/8683

Number fields now display correctly 

![image](https://github.com/user-attachments/assets/edf5e8d9-2292-49d2-99b7-c10e940b2a49)

Fixes issue with react-datepicker by manually copying in the css of the
library so it can be layered in

![image](https://github.com/user-attachments/assets/fcaec51a-5914-4fb5-be12-7fa2cf44a176)
2024-10-14 13:20:52 -06:00
Dan Ribbens
d781624a86 feat: add disableTransaction to local api (#8697) 2024-10-14 14:39:20 -04:00
Patrik
08f883166e fix(ui): prevents react-select styles being injected into hasMany number fields (#8695)
Before:
![Screenshot 2024-10-14 at 1 35
16 PM](https://github.com/user-attachments/assets/0b121693-1160-493c-8c73-638394fe542e)

After:
![Screenshot 2024-10-14 at 1 35
30 PM](https://github.com/user-attachments/assets/2c73d345-30b1-49ba-826b-fb20066a2e43)
2024-10-14 14:36:47 -04:00
Jarrod Flesch
8bbc833812 fix: validate should not always equate valid to true (#8696)
In some instances, form states incorrectly setting valid to true even
when they should not be, just because no validate function is present.

This was apparent when using bulk upload drawers inside the multi-tenant
example which inserts a custom field for the TenantSelector on
documents.

Reported internally
https://payloadcms.slack.com/archives/C079W6WT0R1/p1726670927732309
2024-10-14 14:29:37 -04:00
Said Akhrarov
65d4f37dfb fix(ui): show configured description on active tabs (#8675)
<!--

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.

 -->
fixes #8672
2024-10-14 17:51:52 +00:00
Jarrod Flesch
3f128c5b28 fix: ensure dropzone respects canCreate permissions (#8689)
Prioritize user permissions for upload creation instead of only looking
at `admin.allowCreate`
2024-10-14 11:35:51 -04:00
Dan Ribbens
e4fd1e3e0b fix(ui): export useListRelationships (#8658)
fixes https://github.com/payloadcms/payload/issues/8568
2024-10-14 11:25:49 -04:00
Paul
a4f1af48b4 fix(ui): hasMany selecting single docs clicking through instead of selecting a document (#8624)
Fixes https://github.com/payloadcms/payload/issues/8500
2024-10-14 08:52:00 -06:00
Alessio Gravili
793dfe87e7 fix: ensure Component is not required in MappedComponent types (#8687)
Component is not required if RenderedComponent is passed
2024-10-14 14:46:29 +00:00
Because789
855fcf34bc docs: correct useTranslation import in i18n docs (#8645) 2024-10-14 09:08:09 -04:00
Sasha
6be665f887 chore(eslint): payload-logger proper usage works with template literals (#8660)
Improves this https://github.com/payloadcms/payload/pull/8578 to work
with template literals as well,

This is invalid:
```ts
this.payload.logger.error('Failed to create database', err)
```

But this is valid:
```ts
this.payload.logger.error(`Failed to create database ${dbName}`, err)
```

This PR fixes that

<img width="577" alt="image"
src="https://github.com/user-attachments/assets/b867da53-4f81-4b1b-8423-598e0419946a">
2024-10-13 19:10:47 -04:00
Alessio Gravili
c731940239 chore: use custom jest reporter to achieve sane jest logs (#8607)
The default jest log reporter is garbage. Webstorm replaces it with
their own (which is pretty good), but vscode unfortunately uses the
default one.

This PR does the following to the jest reporter

**1. Replace the default reporter with the jest-ci-spec-reporter
reporter.**

The default reporter is hiding console logs and incorrectly rewriting
console history. Now, logs like these:

```
[20:56:16] INFO: ---- DROPPING DATABASE ----
[20:56:17] INFO: ---- DROPPED DATABASE ----
```

will be visible again. The default reporter was showing them for half a
second, then rewrites log history and hides them.

**2. add custom logger to showcase hidden error messages**

Some error messages are hidden and are only displayed at the end of the
test, in a very ugly way. If the test hangs, you might have to wait a
long time to see those errors. This PR makes sure that errors are logged
when they were intended to be logged.

They will not be printed in a pretty way (Webstorm for example prints
them in red and clickable, like a proper error message) - but at least
they will be printed instead of leaving you in the dark

**Override console global in jest setup to hide console log spam**

This turns logs like

```
  console.log
    initPayloadInt done

      at log (helpers/initPayloadInt.ts:27:11)
```
      
 into
 
`initPayloadInt done`

## CI

Yes, CI logs are actually usable now. We no longer have random console
logs floating around! It was horrible!

Finally, you can actually see which console logs belong to which test.

Before:
https://github.com/payloadcms/payload/actions/runs/11241674859/job/31253918825
After:
https://github.com/payloadcms/payload/actions/runs/11242035327/job/31255031760?pr=8607

**BEFORE**
![CleanShot 2024-10-08 at 21 27
23@2x](https://github.com/user-attachments/assets/7c83ced7-b4fd-4e90-95ff-2c240829c3cd)

What test triggered this "ValidationError: The following field is
invalid: filteredRelation" error? Who knows!! Could have been any test.
We will never know...

**AFTER:**

Finally, clarity 

![CleanShot 2024-10-08 at 21 28
15@2x](https://github.com/user-attachments/assets/a259950e-3213-4faa-9f87-e54fd970f6dc)

## Screenshots - Passing database test suite

## Passing database test suite

### Before
![CleanShot 2024-10-08 at 21 07
39@2x](https://github.com/user-attachments/assets/00a07d30-fbeb-4a52-8982-3e0bc198e278)
![CleanShot 2024-10-08 at 21 08
05@2x](https://github.com/user-attachments/assets/0bc02982-83e4-4205-a1e9-0c0277390ab2)

### After
![CleanShot 2024-10-08 at 21 06
52@2x](https://github.com/user-attachments/assets/cd1e6ac1-17c0-4859-a374-2176e698784e)

## Screenshots - Failing test

### Before - that's where it hangs
![CleanShot 2024-10-08 at 21 09
52@2x](https://github.com/user-attachments/assets/088b1074-bd57-4d9d-8de4-81f1a5edf407)

### After - that's where it hangs

Actually shows me the error without having to wait 3 minutes for test to
timeout:

![CleanShot 2024-10-08 at 21 13
13@2x](https://github.com/user-attachments/assets/ec91f530-2f5e-4b6d-872a-f483b9a421f4)


### Before - after waiting for 3 minutes for test to timeout:

![CleanShot 2024-10-08 at 21 12
08@2x](https://github.com/user-attachments/assets/64ac9945-3a3c-4eb5-991c-943859500bb5)
(1000 lines of same error spam...)
![CleanShot 2024-10-08 at 21 19
28@2x](https://github.com/user-attachments/assets/ccd33c38-f6d9-47a8-8c5a-41c118cfe849)

### After - after waiting for 3 minutes for test to timeout:

![CleanShot 2024-10-08 at 21 14
54@2x](https://github.com/user-attachments/assets/c2240305-21da-4b4c-9e28-ee68f8b2899d)
![CleanShot 2024-10-08 at 21 15
09@2x](https://github.com/user-attachments/assets/d6f7fab6-acd4-4bcc-a560-9e86792fdbbf)
(Error spam)
![CleanShot 2024-10-08 at 21 15
20@2x](https://github.com/user-attachments/assets/6be43e88-f881-4598-bb32-d7cfc90ef710)
2024-10-11 18:54:39 +00:00
Patrik
21606ded08 fix(db-mongodb): add validation to relationship ids (#8395)
fixes https://github.com/payloadcms/payload/issues/8652
2024-10-11 13:49:07 -04:00
Sasha
7a0b419c10 feat: add limit property to bulk update operation (#8656)
Adds `limit` to `payload.update`(bulk)  / REST
2024-10-11 13:14:18 -04:00
Sasha
1ffb6c3e13 fix(drizzle): indexes / unique with relationships (#8432)
Fixes https://github.com/payloadcms/payload/issues/8413 and
https://github.com/payloadcms/payload/issues/6460

- Builds indexes for relationships by default in the SQL schema
- Fixes `unique: true` handling with Postgres / SQLite for every type of
relationships (non-polymorphic. hasMany, polymorphic, polymorphic
hasMany) _note_: disables unique for nested to arrays / blocks
relationships in the `_rels` table.
- adds tests

2.0 PR tha ports only indexes creation
https://github.com/payloadcms/payload/pull/8446, because `unique: true`
could be a breaking change if someone has incosistent unique data in the
database.
2024-10-11 13:13:54 -04:00
Sasha
256949e331 feat(db-postgres, db-vercel-postgres): createDatabase, auto database create if it does not exist (#8655)
Adds `createDatabase` method to Postgres adapters which can be used
either independently like this:
```ts
payload.db.createDatabase({
  name: "some-database",
  schemaName: "custom-schema"
})
```
Or
```ts
payload.db.createDatabase()
```
Which creates a database from the current configuration, this is used in
`connect` if `autoDatabaseCreate` is set to `true` (default).
You can disable this behaviour with:
```ts
postgresAdapter({ autoDatabaseCreate: false })
```

Example:
<img width="470" alt="image"
src="https://github.com/user-attachments/assets/8d08c79d-9672-454c-af0f-eb802f9dcd99">
2024-10-11 14:17:32 +00:00
Sasha
8daac4e670 fix: properly store timestamps in versions (#8646)
This PR makes a more clear gap between `version_createdAt` /
`version_updatedAt` and `createdAt` / `updatedAt` columns / fields in
mongodb.

- `createdAt` - This should be a new value in a new version. Before this
change it was the same all the time. Should remain the same on autosave.
- The same for `updatedAt`, but it should be updated on every change
(including autosave)
- `version_createdAt` - Should remain equal to `createdAt` from the
parent collection / table
- `version_updatedAt` - On a latest version it makes sense this be the
same as `updatedAt` from the parent collection / table, as all the
`version_*` fields should be just synced with it
2024-10-11 10:01:21 -04:00
Elliot DeNolf
067d353cdd chore(release): v3.0.0-beta.113 [skip ci] 2024-10-10 16:42:05 -04:00
Elliot DeNolf
a15765395d chore: add plugin-sentry to publish list 2024-10-10 16:40:01 -04:00
Paul
d0a5560629 fix: commonjs exports missing for withPayload (#8643)
Closes https://github.com/payloadcms/payload/issues/8635

`withPayload.cjs` is now correctly named in the exports

The final exports in package.json looks like this
```
"./withPayload": {
  "import": "./dist/withPayload.js",
  "require": "./dist/cjs/withPayload.cjs",
  "default": "./dist/withPayload.js"
},
```

You can now use withPayload with require inside `next.config.js` files
```
const { withPayload } = require('@payloadcms/next/withPayload')

const nextConfig = {
  // Your Next.js config here
  experimental: {
    reactCompiler: false,
  },
}

module.exports = withPayload(nextConfig)
```
2024-10-10 15:25:17 -04:00
Jarrod Flesch
aec4d7b8d5 chore: improve i18n docs (#8638)
Fixes https://github.com/payloadcms/payload/issues/8632
2024-10-10 13:12:54 -04:00
Sasha
fdebc84d4f fix: sanitize virtual fields in admin.useAsTitle (#8620)
Fixes https://github.com/payloadcms/payload/issues/8525. Disallows to
set `admin.useAsTitle` with a virtual field. Updates docs / jsdoc
accordingly
2024-10-10 13:11:44 -04:00
Sasha
f6acfdb1f5 fix(drizzle): hasMany joins - localized, limit and schema paths (#8633)
Fixes https://github.com/payloadcms/payload/issues/8630

- Fixes `hasMany: true` and `localized: true` on the foreign field
- Adds `limit` to the subquery instead of hardcoded `11`.
- Adds the schema path `field.on` to the subquery, without this having 2
or more relationship fields to the same collection breaks joins
- Properly checks if the field is `hasMany`
2024-10-10 12:58:30 -04:00
Germán Jabloñski
1dcae37e58 chore: add instructions to run the examples to the readme (#8623) 2024-10-10 09:50:32 -04:00
Sasha
a3bf938862 chore: do not use withSentryConfig for dev/e2e next config if not needed (#8629)
This fixes this error when executing particular e2e test with playwright
extension
<img width="347" alt="image"
src="https://github.com/user-attachments/assets/5f7608fc-7896-4014-b312-a0c36f21b7d1">
2024-10-10 16:10:11 +03:00
Jarrod Flesch
a70b193527 chore: improve setUser type, uses generic from useAuth (#8636)
Create specific type for setUser in auth provider that uses the generic.
2024-10-10 08:47:15 -04:00
Jarrod Flesch
5e94d9b1ca fix: corrects useAuth generics (#8627)
Corrects AuthContext and useAuth generics due to regression in
https://github.com/payloadcms/payload/pull/8600
2024-10-09 23:36:18 -04:00
Elliot DeNolf
f8bae0e7b0 ci: remove payload as valid scope, payload is implied if no scope 2024-10-09 22:09:31 -04:00
Gregor Gabrič
28c3a770ee feat(translations): add slovenian lang (#8603)
Add Slovenian language
2024-10-09 20:23:05 +00:00
Elliot DeNolf
123022969f chore(release): eslint/3.0.0-beta.112 2024-10-09 15:48:40 -04:00
Patrik
4343b970eb chore(examples): adds optional tenant-based cookie handling by domain in multi-tenant example (#8490)
- Adds optional tenant-based cookie handling based by domain (commented
out to leave functionality out by default)

- Removes 2.0 multi-tenant example

- Updates `examples/multi-tenant-single-domain` -->
`examples/multi-tenant`
2024-10-09 14:32:48 -04:00
Sasha
0b2a7a3606 feat(plugin-sentry): update plugin to 3.0 (#8613)
Updates the plugin to 3.0

Test:
```sh
NEXT_PUBLIC_SENTRY_DSN=<DSN here> pnpm dev plugin-sentry
```

Example:
```ts
sentryPlugin({
  options: {
    captureErrors: [400, 403],
    context: ({ defaultContext, req }) => {
      return {
        ...defaultContext,
        tags: {
          locale: req.locale,
        },
      }
    },
    debug: true,
  },
  Sentry,
})
```
2024-10-09 14:26:58 -04:00
Jarrod Flesch
769c94b4fd chore: clarifies i18n docs (#8619)
Fixes https://github.com/payloadcms/payload/issues/8562

Removes `debug` option from i18n docs - never existed.

Corrects hallucinations in the docs and lays out exactly how custom
translations should be used when you want to use them in custom
components.
2024-10-09 14:15:45 -04:00
Paul
f507530214 fix(ui): react select fields not increasing height when items overflow (#8618)
Fixes this instance 

![image](https://github.com/user-attachments/assets/b2acc493-727e-4a26-8623-de28ff1dbe3c)
2024-10-09 18:00:03 +00:00
Elliot DeNolf
39825dfce5 chore(release): v3.0.0-beta.112 [skip ci] 2024-10-09 09:56:36 -04:00
Patrik
e904981943 chore(next): adds export for mergeHeaders utility function (#8609)
Need this utility function exported for this PR: #8490
2024-10-08 15:45:50 -04:00
Patrik
c14c4298e2 fix(payload): calculates correct aspect ratio dimensions on sharp based files (#8537)
v2 PR [here](https://github.com/payloadcms/payload/pull/8510)
2024-10-08 14:45:51 -04:00
Patrik
9a0568c72e fix(payload): applies resize after cropping if resizeOptions are defined (#8528)
Fixes #7592
2024-10-08 14:40:41 -04:00
Jarrod Flesch
829996a126 chore!: improve auth provider setting user and user cookie (#8600)
### Improvements
- Uses overlay modal for "logging out..." display on logout view
- If user manually logs out it takes them directly to the login page
after logout, if caused by inactivity then they will see the logout page
that explains that they were logged out due to inactivity
- Fixes issue with cookie refresh triggering even after the user logs
out
- Cleans up auth provider timeouts for refresh and force logout
- `setUser` now expects the result similar to the response from the
`/me` endpoint, which includes the token, exp, and user

### BREAKING CHANGE

If you are using the `setUser` function exposed from the `useAuth()`
provider, then you will need to make some adjustments.

`setUser` now expects the response data from auth enabled endpoints, ie
the `/me` route. This is so the cookie and expiration can be properly
set in sync when a new user is set on the provider.
```ts
// before
setUser({
  id: 670524817048be0fa222fc01,
  email: dev@payloadcms.com,
  // ... other user properties
})

// new
setUser({
  user: {
    id: 670524817048be0fa222fc01,
    email: dev@payloadcms.com,
    // ... other user properties
  },
  exp: 1728398351,
  token: "....eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVC...."
})
```
2024-10-08 11:49:18 -04:00
Jessica Chowdhury
f6e5244204 chore(templates): hide admin bar for website template on small screens (#8601)
Hides the admin bar component for website template on mobile.
2024-10-08 15:45:43 +00:00
Dan Ribbens
1bf580fac3 feat: join field works with hasMany relationships (#8493)
Join field works on relationships and uploads having `hasMany: true`

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-10-08 11:40:34 -04:00
Elliot DeNolf
ca779441a3 fix(db-vercel-postgres): add pg dep (#8598) 2024-10-08 10:32:28 -04:00
Elliot DeNolf
7e2f4e62de chore(templates): more next.js promises (#8599)
Continuation of #8547 . Missed some type updates.
2024-10-08 09:50:31 -04:00
Jarrod Flesch
1b63ad4cb3 fix: verify view is inaccessible (#8557)
Fixes https://github.com/payloadcms/payload/issues/8470

Cleans up the way we redirect and where it happens.

## Improvements
- When you verify, the admin panel will display a toast when it
redirects you to the login route. This is contextually helpful as to
what is happening.
- Removes dead code path, as we always set the _verifiedToken to null
after it is used.

## `handleAdminPage` renamed to `getRouteInfo`
This function no longer handles routing. It kicks that responsibility
back up to the initPage function.

## `isAdminAuthRoute` renamed to `isPublicAdminRoute`
This was inversely named as it determines if a given route is public.
Also simplifies deterministic logic here.

## `redirectUnauthenticatedUser` argument
This is no longer used or needed. We can determine these things by using
the `isPublicAdminRoute` function.

## View Style fixes
- Reset Password
- Forgot Password
- Unauthorized
2024-10-07 14:20:07 -04:00
Paul
2a1321c813 fix(ui): add unstyled prop to react-select so that payload styles take priority (#8572)
Adds `unstyled={true}` prop to the react-select element so that
payload's styles take priority. Due to the way react-select adds its own
styles (injected into the page) they were higher specificity due to not
being in a layer.

Fixes this bug with our styles' specificity not being applied 

![image](https://github.com/user-attachments/assets/1cd216a4-8125-4312-949e-168c7eb96186)


Also fixes https://github.com/payloadcms/payload/issues/8507
2024-10-07 10:36:15 -06:00
Patrik
67e6ad8168 docs: specifies defaultLocale as a required property for localization (#8585)
Fixes #8567
2024-10-07 12:07:03 -04:00
Germán Jabloñski
6cb128aa60 fix(richtext-lexical): linkFeature doesn't respect admin.routes from payload.config.ts (#8513)
Fix #8452
2024-10-07 09:48:04 -04:00
Because789
bb3496d7b5 feat(plugin-seo): adds german translation (#8580)
Adds a a German translation to the SEO Plugin. Credits to @fsyntax, since he got it rolling.
2024-10-06 22:07:32 -04:00
Sasha
bf50716fc5 docs: updates array field admin.components.RowLabel example (#8548)
Fixes https://github.com/payloadcms/payload/issues/8536
2024-10-06 21:37:59 -04:00
Because789
c473db7879 docs: fix typo in array.mdx (#8561) 2024-10-06 21:34:23 -04:00
Elliot DeNolf
7aed0d7c2e chore(eslint): payload logger usage (#8578)
Payload uses `pino` for a logger. When using the error logger
`payload.logger.error` it is possible to pass any number of arguments
like this: `payload.logger.error('Some error ocurred', err)`. However,
in this scenario, the full error will not be serialized by `pino`. It
must be passed as the `err` property inside of an object in order to be
properly serialized.

This rule ensures that a user is using this function call to properly serialize the error.
2024-10-06 13:23:30 -07:00
Elliot DeNolf
d88e0617d6 chore: sort release note sections 2024-10-06 09:59:51 -07:00
Jacob Fletcher
2ba40f3335 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.
2024-10-05 09:13:43 -04:00
Elliot DeNolf
463490f670 fix(templates): await params/cookies properly (#8560) 2024-10-04 18:38:27 -07:00
Jacob Fletcher
d564cd44e9 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.
2024-10-04 21:29:38 +00:00
Paul
7c62e2a327 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
}
```
2024-10-04 13:02:56 -06:00
Sasha
400293b8ee fix: duplicate with upload collections (#8552)
Fixes the duplicate operation with uploads
Enables duplicate for upload collections by default
2024-10-04 21:46:41 +03:00
Elliot DeNolf
e4a413eb9a chore(release): v3.0.0-beta.111 [skip ci] 2024-10-04 11:31:06 -07:00
Sasha
b99590f477 chore(templates): update templates with next.js promises (#8547)
Updates templates according to this PR
https://github.com/payloadcms/payload/pull/8489
2024-10-04 21:28:43 +03:00
Alessio Gravili
0d3416c96d fix(db-postgres): missing types for db.pool by moving @types/pg from devDependencies to dependencies (#8556)
Fixes lack of types in installed project:

![CleanShot 2024-10-04 at 19 18
58@2x](https://github.com/user-attachments/assets/e7c519ee-72fd-424b-8f6c-41032322fa5e)

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.
2024-10-04 17:39:03 +00:00
Sasha
0128eedf70 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:

![image](https://github.com/user-attachments/assets/d2965bcf-290a-4f86-9bf4-dfe7e8613934)

After this change, they are snake_case:
![Screenshot 2024-10-04
114226](https://github.com/user-attachments/assets/bbc8c20b-6745-4dd3-b0c8-56263a4e37b1)

#### 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>
2024-10-04 16:25:05 +00:00
Sasha
414030e1f1 fix(drizzle): row / collapsible inside of localized fields (#8539)
Fixes https://github.com/payloadcms/payload/issues/8405
2024-10-04 11:48:54 -04:00
Jacob Fletcher
f6eb027f23 chore: repairs auto-generated file comments (#8549)
The comments injected into auto-generated files have gotten misformatted
due to linting. Here is the proper format, where both comments are
adjacent to one another:

```js
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
```

Some comments were also written with casing issues, here's an example:

```js
/* DO NOT MODIFY it because it could be re-written at any time. */
```
2024-10-03 23:37:08 -04:00
Sasha
cf8347f208 fix(ui): disableBulkEdit on ui fields, defaults to true (#8540)
Fixes https://github.com/payloadcms/payload/issues/8534

UI fields are now excluded by default from the bulk edit view fields
options.
If you need to have the UI field there, you can provide:
```ts
admin: {
  disableBulkEdit: false
}
```
2024-10-04 01:07:47 +00:00
Paul
157b1e13ac fix(plugin-seo): now respects serverURL and api routes configuration (#8546) 2024-10-04 00:04:20 +00:00
Sasha
a735f40310 docs: change req.params to req.routeParams (#8380)
`req.params` is an old notation, now we use `req.routeParams`
2024-10-04 02:59:05 +03:00
Alessio Gravili
e306c927a8 docs: fix broken link (#8543) 2024-10-03 18:46:23 +00:00
Paul
dffdb22a69 fix(templates): dark and light mode not correctly working on website template's header (#8542) 2024-10-03 17:42:20 +00:00
Alessio Gravili
8789b0b20d chore: enable databaseAdapter writing again for pnpm dev (#8532) 2024-10-02 23:08:49 +00:00
Paul
eb4e3711ac fix(templates): add no search results text to website template search page (#8531) 2024-10-02 22:16:29 +00:00
Paul
132131a4b9 fix(templates): static generation from incorrect params provided (#8530) 2024-10-02 21:36:46 +00:00
Dan Ribbens
9ef4fab65d fix: ui crashes editing doc with deleted upload (#8526)
fix #8133

UI of a deleted item (will need another iteration).

![clear-upload-state](https://github.com/user-attachments/assets/2d9baebe-9a12-4905-9449-457972f4505b)
2024-10-02 15:22:57 -04:00
Paul
65015aa750 fix(templates): add force-static to pages and posts (#8527) 2024-10-02 18:41:54 +00:00
Patrik
0f7d444e6d fix(next): safely checks user within useEffect (#8524) 2024-10-02 14:17:15 -04:00
Jacob Fletcher
ca90d2b1c9 fix: properly resolves cjs withPayload export (#8521)
Importing `withPayload` as CommonJS using `require` does not properly
resolve. This was because the exported file path was using the `.cjs`
extension instead of `.js`.
2024-10-02 12:38:49 -04:00
Elliot DeNolf
ecfd90bc58 fix(templates): remove lock from website template (#8520)
Including this file was causing the dependency checker to error because
it was installing all `@lexical` packages on version 0.17.0, instead of
0.18.0.

![Uploading image.png…]()
2024-10-02 10:59:26 -04:00
Paul
86371449b8 fix(templates): fixed drafts not being unpublished in the frontend of the website template (#8514) 2024-10-01 23:01:06 +00:00
Paul
69203c5515 docs: fix formatting on join field specifying additional fields section (#8509) 2024-10-01 20:24:26 +00:00
Sasha
a8eceb03b6 fix(next): current published version label (#8505)
Fixes https://github.com/payloadcms/payload/issues/8502

includes `parent` to the `getLatestVersion` query
2024-10-01 21:22:00 +03:00
Sasha
fa59d4c0b2 feat!: update next@15.0.0-canary.173, react@19.0.0-rc-3edc000d-20240926 (#8489)
Updates the minimal supported versions of next.js to
[`15.0.0-canary.173`](https://github.com/vercel/next.js/releases/tag/v15.0.0-canary.173)
and react to `19.0.0-rc-3edc000d-20240926`.

Adds neccessary awaits according to this breaking change
https://github.com/vercel/next.js/pull/68812

## Breaking Changes

The `params` and `searchParams` types in
`app/(payload)/admin/[[...segments]]/page.tsx` and
`app/(payload)/admin/[[...segments]]/not-found.tsx` must be changed to
promises:

```diff
- type Args = {
-   params: {
-     segments: string[]
-   }
-   searchParams: {
-     [key: string]: string | string[]
-   }
- }

+ type Args = {
+   params: Promise<{
+     segments: string[]
+   }>
+   searchParams: Promise<{
+     [key: string]: string | string[]
+   }>
+ }

```
2024-10-01 13:16:11 -04:00
Germán Jabloñski
d80410b228 fix(ui): admin.allowCreate in upload field (#8484)
The admin.allowCreate property on the upload field was not doing what it
was supposed to do. In fact, it was doing nothing.

From now on, when set to false, the option to create a new upload from
the UI disappears.


![image](https://github.com/user-attachments/assets/f6776c4e-833c-4a65-8ea0-68edc0a57235)


![image](https://github.com/user-attachments/assets/b99f1969-1a07-4f9f-8b5e-0d5a708f7802)


![image](https://github.com/user-attachments/assets/519e19ea-f0ba-410e-8930-dd5231556bf5)


The tests cover:
- the create new button disappears.
- the option to create one by drag and drop disappears.
- the create new button inside the drawer disappears.
2024-09-30 18:54:34 -03:00
Dan Ribbens
27b1629927 fix(db-postgres, db-sqlite): joins relation name (#8491)
A join field on a relationship with a camelCase name would cause an
error from drizzle due to the relation name not matching.
2024-09-30 16:47:21 -04:00
Paul
dfdea0d4eb chore: update vscode launch settings for debugging test suites (#8399) 2024-09-30 15:18:03 -04:00
Elliot DeNolf
96d99cb361 chore(release): v3.0.0-beta.110 [skip ci] 2024-09-30 13:19:32 -04:00
Dan Ribbens
3f375cc6ee feat: join field on upload fields (#8379)
This PR makes it possible to use the new `join` field in connection with
an `upload` field. Previously `join` was reserved only for
relationships.
2024-09-30 13:12:30 -04:00
Dan Ribbens
3847428f0a fix(db-*): make db.begintransactions required (#8419)
Changing the transcations functions on the db so that projects using
typescript `strict: true` do not need to type narrow before using it.
2024-09-30 13:12:07 -04:00
Sasha
7b6a760e97 fix(db-mongodb): duplicate versions with parent string ids (#8487)
Fixes https://github.com/payloadcms/payload/issues/8441

we may want to add a predifined migration that changes all what's needed
to ObjectIDs @DanRibbens
2024-09-30 13:06:48 -04:00
James Mikrut
0c1004537d fix: draft status access control checks (#8486) 2024-09-30 16:41:54 +00:00
Sasha
e765a5e866 fix: reset password link extra slash and thread admin.routes.reset property (#8448)
Removes extra slash
from: 
`http://host/admin//reset/token`
to:
`http://host/admin/reset/token`

Threads `admin.routes.reset`:
```ts
const config: Config = {
  admin: {
    routes: {
      reset: '/custom-reset',
    },
  },
}
```
2024-09-30 19:06:19 +03:00
Ante
f543e8963e chore(translations): croatian translation improvements (#7413)
Croatian translation is improved for better choice of words in given
context, typos, extra whitespaces and consistency of formal pronouns
use.
2024-09-30 12:04:34 -04:00
Alessio Gravili
163f3c0692 feat(richtext-lexical): export $createInlineBlockNode, $isInlineBlockNode and InlineBlockNode (#8480) 2024-09-30 13:42:49 +00:00
Dan Ribbens
4241811fa9 fix: sorting by id incorrectly orders by version.id (#8442)
fixes #7187
2024-09-30 09:16:41 -04:00
Patrik
8110cb9956 fix(db-mongodb): properly filters out number field values with the exists operator filter (#8416)
V2 PR [here](https://github.com/payloadcms/payload/pull/8415)
2024-09-30 08:59:58 -04:00
Paul
e5ca476d7f fix(ui): RTL not applying for localised textarea fields (#8474) 2024-09-29 19:25:09 +00:00
Alessio Gravili
161749bde9 chore: fix build by adding missing translation keys (#8471) 2024-09-29 10:56:36 +00:00
Mike Bailey
22f120dc85 feat(translations): add danish translations (#7809)
Added Danish (da-DK) translations for Beta
2024-09-28 18:13:31 -04:00
Alessio Gravili
e7b44dc545 chore: add workaround for unsettled top-level await script failures (#8467)
currently only for pnpm dev
2024-09-28 17:53:45 +00:00
Germán Jabloñski
8b44676b0d feat(richtext-lexical)!: upgrade lexical from 0.17.0 to 0.18.0, make tables more reliable (#8444)
This PR

- Introduces multiline markdown transformers / mdx support
- Introduce `shouldMergeAdjacentLines` option in
`$convertFromMarkdownString`. If true, merges adjacent lines as per
commonmark spec. This would allow to close:
https://github.com/payloadcms/payload/issues/8049
- Many new features and bug fixes!
- Ports over changes from the lexical playground. Most notably:
  - add support for enabling table row stripping
  - make table resizing & table cell selection more reliable

**BREAKING**: This upgrades lexical from 0.17.0 to 0.18.0. If you have
any lexical packages installed in your project, please update them
accordingly. Additionally, if you depend on the lexical APIs, please
consult their changelog, as lexical may introduce breaking changes:
https://github.com/facebook/lexical/releases/tag/v0.18.0

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-09-28 13:10:44 -04:00
Sasha
613d3b090e fix(drizzle): hasMany / poly relationships nested to localized fields / nested blocks to localized fields (#8456)
fixes https://github.com/payloadcms/payload/issues/8455 and
https://github.com/payloadcms/payload/issues/8462

- Builds the `_locale` column for the `_rels` when it's inside of a
localized group / tab
- Properly builds `sanitizedPath` for blocks in the transform-read
function when it's inside of a localized field. This fixes with fields
inside that have its own table (like `_rels`, select `hasMany: true`
etc)

Adds _more_ tests!
2024-09-28 17:33:50 +03:00
Paul
fb603448d8 feat(templates): add search functionality to the website template (#8454)
- adds a /search and search plugin example to website template
- adds an additional check for valid paths on /preview
- fixes a few bugs around the site
2024-09-27 18:01:58 -06:00
Germán Jabloñski
f50174f5b8 fix(richtext-lexical): match the indentation spacing of paragraphs and lists (#8437)
Before this, indented paragraphs, un/ordered list-items, and checkbox
list-items had 3 different sizes.

This PR unifies all 3 to match.

Related:
- https://github.com/payloadcms/payload/pull/8138
- https://github.com/facebook/lexical/pull/4025

List-items were using a custom indentation size, instead of the
browser's default. The reason I'm adapting list-items to this default
size and not the paragraphs to list-items, is because when
importing/exporting html in contexts where our CSS isn't present, visual
consistency is maintained.

Also, the browsers' default looks fine to me.

Note: Lexical's detection of whether the checkbox is clicked is a bit
hacky. I've made sure it doesn't break and added an explanatory comment
to prevent anyone from breaking it in the future.

## Before


![image](https://github.com/user-attachments/assets/7195a592-a695-4131-af1a-df016c215758)

## After


![image](https://github.com/user-attachments/assets/ef3b708f-2ce6-4bf0-951e-15c550cdcc65)
2024-09-27 13:28:36 -03:00
Germán Jabloñski
17e0547db3 feat(payload, ui): add admin.allowEdit relationship field (#8398)
This PR adds a new property `allowEdit` to the admin of the relationship
field. It is very similar to the existing `allowCreate`, only in this
case it hides the edit icon:

<img width="796" alt="image"
src="https://github.com/user-attachments/assets/bbe79bb2-db06-4ec4-b023-2f1c53330fcb">
2024-09-27 09:22:03 -04:00
2320 changed files with 171713 additions and 85001 deletions

View File

@@ -28,3 +28,6 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
# Prettier and lint remaining db packages
7fd736ea5b2e9fc4ef936e9dc9e5e3d722f6d8bf
# Bump all eslint deps, lint and format
03291472d6e427ff94e61fca0616cca7796a3a95

View File

@@ -0,0 +1,76 @@
name: Functionality Bug
description: '[REPRODUCTION REQUIRED] - Create a bug report'
labels: ['status: needs-triage', 'v3', 'validate-reproduction']
body:
- type: textarea
attributes:
label: Describe the Bug
validations:
required: true
- type: input
id: reproduction-link
attributes:
label: Link to the code that reproduces this issue
description: >-
_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!

View File

@@ -0,0 +1,40 @@
name: Design Issue
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!

View File

@@ -1,11 +1,11 @@
name: Bug Report
description: Create a bug report for Payload
labels: ['[possible-bug]']
name: v2 Bug Report
description: Report a bug for Payload v2. ONLY CRITICAL bugs will be fixed in v2.
labels: ['status: needs-triage', 'v2']
body:
- type: markdown
attributes:
value: |
*Note:* Feature requests should be opened as [discussions](https://github.com/payloadcms/payload/discussions/new?category=feature-requests-ideas).
ONLY CRITICAL bugs will be fixed in v2.
- type: input
id: reproduction-link
attributes:

View File

@@ -1,23 +1,23 @@
## Description
<!--
<!-- 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
### How?
Fixes #
-->

22
.github/actions/triage/LICENSE vendored Normal file
View File

@@ -0,0 +1,22 @@
MIT License
Copyright (c) 2024 Payload <info@payloadcms.com>. All modification and additions are copyright of Payload.
---
Original license:
ISC License
Copyright (c) 2023, Balázs Orbán
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

21
.github/actions/triage/README.md vendored Normal file
View File

@@ -0,0 +1,21 @@
# Triage
Modified version of https://github.com/balazsorban44/nissuer
## Modifications
- Port to TypeScript
- Remove issue locking
- Remove reproduction blocklist
- Uses `@vercel/ncc` for packaging
## Development
> [!IMPORTANT]
> Whenever a modification is made to the action, the action built to `dist` must be committed to the repository.
This is done by running:
```sh
pnpm build
```

40
.github/actions/triage/action.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
name: Triage
description: Initial triage for issues
inputs:
reproduction-comment:
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"'
default: 'tag,comment,close'
runs:
using: 'composite'
steps:
- name: Checkout code
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
- name: Run action
run: node ${{ github.action_path }}/dist/index.js
shell: sh
# https://github.com/actions/runner/issues/665#issuecomment-676581170
env:
'INPUT_REPRODUCTION_COMMENT': ${{inputs.reproduction-comment}}
'INPUT_REPRODUCTION_HOSTS': ${{inputs.reproduction-hosts}}
'INPUT_REPRODUCTION_INVALID_LABEL': ${{inputs.reproduction-invalid-label}}
'INPUT_REPRODUCTION_ISSUE_LABELS': ${{inputs.reproduction-issue-labels}}
'INPUT_REPRODUCTION_LINK_SECTION': ${{inputs.reproduction-link-section}}
'INPUT_ACTIONS_TO_PERFORM': ${{inputs.actions-to-perform}}

34068
.github/actions/triage/dist/index.js vendored Normal file

File diff suppressed because one or more lines are too long

7
.github/actions/triage/jest.config.js vendored Normal file
View File

@@ -0,0 +1,7 @@
module.exports = {
testEnvironment: 'node',
testPathIgnorePatterns: ['/node_modules/', '<rootDir>/dist/'],
transform: {
'^.+\\.(t|j)sx?$': ['@swc/jest'],
},
}

34
.github/actions/triage/package.json vendored Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "triage",
"version": "0.0.0",
"private": true,
"description": "GitHub Action to triage new issues",
"license": "MIT",
"main": "dist/index.js",
"scripts": {
"build": "pnpm build:typecheck && pnpm build:ncc",
"build:ncc": "ncc build src/index.ts -t -o dist",
"build:typecheck": "tsc",
"clean": "rimraf dist",
"test": "jest"
},
"dependencies": {
"@actions/core": "^1.3.0",
"@actions/github": "^5.0.0"
},
"devDependencies": {
"@octokit/webhooks-types": "^7.5.1",
"@swc/jest": "^0.2.36",
"@types/jest": "^27.5.2",
"@types/node": "^20.16.5",
"@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0",
"@vercel/ncc": "0.38.1",
"concurrently": "^8.2.2",
"eslint": "^7.32.0",
"jest": "^29.7.0",
"prettier": "^3.3.3",
"ts-jest": "^26.5.6",
"typescript": "^4.9.5"
}
}

5419
.github/actions/triage/pnpm-lock.yaml generated vendored Normal file

File diff suppressed because it is too large Load Diff

215
.github/actions/triage/src/index.ts vendored Normal file
View File

@@ -0,0 +1,215 @@
import { debug, error, getBooleanInput, getInput, info, setFailed } from '@actions/core'
import { context, getOctokit } from '@actions/github'
import { readFile, access } from 'node:fs/promises'
import { join } from 'node:path'
// Ensure GITHUB_TOKEN and GITHUB_WORKSPACE are present
if (!process.env.GITHUB_TOKEN) throw new TypeError('No GITHUB_TOKEN provided')
if (!process.env.GITHUB_WORKSPACE) throw new TypeError('Not a GitHub workspace')
const validActionsToPerform = ['tag', 'comment', 'close'] as const
type ActionsToPerform = (typeof validActionsToPerform)[number]
// Define the configuration object
interface Config {
invalidLink: {
comment: string
bugLabels: string[]
hosts: string[]
label: string
linkSection: string
}
actionsToPerform: ActionsToPerform[]
token: string
workspace: string
}
const config: Config = {
invalidLink: {
comment: getInput('reproduction_comment') || '.github/invalid-reproduction.md',
bugLabels: getInput('reproduction_issue_labels')
.split(',')
.map((l) => l.trim()),
hosts: (getInput('reproduction_hosts') || 'github.com').split(',').map((h) => h.trim()),
label: getInput('reproduction_invalid_label') || 'invalid-reproduction',
linkSection:
getInput('reproduction_link_section') || '### Link to reproduction(.*)### To reproduce',
},
actionsToPerform: (getInput('actions_to_perform') || validActionsToPerform.join(','))
.split(',')
.map((a) => {
const action = a.trim().toLowerCase() as ActionsToPerform
if (validActionsToPerform.includes(action)) {
return action
}
throw new TypeError(`Invalid action: ${action}`)
}),
token: process.env.GITHUB_TOKEN,
workspace: process.env.GITHUB_WORKSPACE,
}
// Attempt to parse JSON, return parsed object or error
function tryParse(json: string): Record<string, unknown> {
try {
return JSON.parse(json)
} catch (e) {
setFailed(`Could not parse JSON: ${e instanceof Error ? e.message : e}`)
return {}
}
}
// Retrieves a boolean input or undefined based on environment variables
function getBooleanOrUndefined(value: string): boolean | undefined {
const variable = process.env[`INPUT_${value.toUpperCase()}`]
return variable === undefined || variable === '' ? undefined : getBooleanInput(value)
}
// Returns the appropriate label match type
function getLabelMatch(value: string | undefined): 'name' | 'description' {
return value === 'name' ? 'name' : 'description'
}
// Function to check if an issue contains a valid reproduction link
async function checkValidReproduction(): Promise<void> {
const { issue, action } = context.payload as {
issue: { number: number; body: string; labels: { name: string }[] } | undefined
action: string
}
if (action !== 'opened' || !issue?.body) return
const labels = issue.labels.map((l) => l.name)
const issueMatchingLabel =
labels.length &&
config.invalidLink.bugLabels.length &&
labels.some((l) => config.invalidLink.bugLabels.includes(l))
if (!issueMatchingLabel) {
info(
`Issue #${issue.number} does not match required labels: ${config.invalidLink.bugLabels.join(', ')}`,
)
info(`Issue labels: ${labels.join(', ')}`)
return
}
info(`Issue #${issue.number} labels: ${labels.join(', ')}`)
const { rest: client } = getOctokit(config.token)
const common = { ...context.repo, issue_number: issue.number }
const labelsToRemove = labels.filter((l) => config.invalidLink.bugLabels.includes(l))
if (await isValidReproduction(issue.body)) {
await Promise.all(
labelsToRemove.map((label) => client.issues.removeLabel({ ...common, name: label })),
)
return info(`Issue #${issue.number} contains a valid reproduction 💚`)
}
info(`Invalid reproduction, issue will be closed/labeled/commented...`)
// Adjust labels
await Promise.all(
labelsToRemove.map((label) => client.issues.removeLabel({ ...common, name: label })),
)
// Tag
if (config.actionsToPerform.includes('tag')) {
info(`Added label: ${config.invalidLink.label}`)
await client.issues.addLabels({ ...common, labels: [config.invalidLink.label] })
} else {
info('Tag - skipped, not provided in actions to perform')
}
// Comment
if (config.actionsToPerform.includes('comment')) {
const comment = join(config.workspace, config.invalidLink.comment)
await client.issues.createComment({ ...common, body: await getCommentBody(comment) })
info(`Commented with invalid reproduction message`)
} else {
info('Comment - skipped, not provided in actions to perform')
}
// Close
if (config.actionsToPerform.includes('close')) {
await client.issues.update({ ...common, state: 'closed' })
info(`Closed issue #${issue.number}`)
} else {
info('Close - skipped, not provided in actions to perform')
}
}
/**
* Determine if an issue contains a valid/accessible link to a reproduction.
*
* Returns `true` if the link is valid.
* @param body - The body content of the issue
*/
async function isValidReproduction(body: string): Promise<boolean> {
const linkSectionRe = new RegExp(config.invalidLink.linkSection, 'is')
const link = body.match(linkSectionRe)?.[1]?.trim()
if (!link) {
info('Missing link')
info(`Link section regex: ${linkSectionRe}`)
info(`Link section: ${body}`)
return false
}
info(`Checking validity of link: ${link}`)
if (!URL.canParse(link)) {
info(`Invalid URL: ${link}`)
return false
}
const url = new URL(link)
if (!config.invalidLink.hosts.includes(url.hostname)) {
info('Link did not match allowed reproduction hosts')
return false
}
try {
// Verify that the link can be accessed
const response = await fetch(link)
const isOk = response.status < 400 || response.status >= 500
info(`Link status: ${response.status}`)
if (!isOk) {
info(`Link returned status ${response.status}`)
}
return isOk
} catch (error) {
info(`Error fetching link: ${(error as Error).message}`)
return false
}
}
/**
* Return either a file's content or a string
* @param {string} pathOrComment
*/
async function getCommentBody(pathOrComment: string) {
try {
await access(pathOrComment)
return await readFile(pathOrComment, 'utf8')
} catch (error: any) {
if (error.code === 'ENOENT') return pathOrComment
throw error
}
}
async function run() {
const { token, workspace, ...safeConfig } = config
info('Configuration:')
info(JSON.stringify(safeConfig, null, 2))
await checkValidReproduction()
}
run().catch(setFailed)

15
.github/actions/triage/tsconfig.json vendored Normal file
View File

@@ -0,0 +1,15 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["es2020.string"],
"noEmit": true,
"strict": true,
"noUnusedLocals": false, // Undo this
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"downlevelIteration": true,
"skipLibCheck": true,
},
"exclude": ["src/**/*.test.ts"]
}

View File

@@ -0,0 +1,20 @@
**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.
### Useful Resources
- [Reproduction Guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md)
- [Contributing to Payload](https://www.youtube.com/watch?v=08Qa3ggR9rw)

74
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,74 @@
# docs: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: github-actions
directories:
- /
- /.github/workflows
- /.github/actions/* # Not working until resolved: https://github.com/dependabot/dependabot-core/issues/6345
- /.github/actions/setup
target-branch: beta
schedule:
interval: monthly
timezone: America/Detroit
time: '06:00'
groups:
github_actions:
patterns:
- '*'
- package-ecosystem: npm
directory: /
target-branch: beta
schedule:
interval: weekly
day: sunday
timezone: America/Detroit
time: '06:00'
commit-message:
prefix: 'chore(deps)'
labels:
- dependencies
groups:
production-deps:
dependency-type: production
update-types:
- minor
- patch
patterns:
- '*'
exclude-patterns:
- 'drizzle*'
dev-deps:
dependency-type: development
update-types:
- minor
- patch
patterns:
- '*'
exclude-patterns:
- 'drizzle*'
# Only bump patch versions for 2.x
- package-ecosystem: npm
directory: /
target-branch: main
schedule:
interval: weekly
day: sunday
timezone: America/Detroit
time: '06:00'
commit-message:
prefix: 'chore(deps)'
labels:
- dependencies
groups:
production-deps:
dependency-type: production
update-types:
- patch
patterns:
- '*'
exclude-patterns:
- 'drizzle*'

49
.github/pnpm-lock.yaml generated vendored
View File

@@ -55,6 +55,55 @@ importers:
specifier: ^4.9.5
version: 4.9.5
actions/triage:
dependencies:
'@actions/core':
specifier: ^1.3.0
version: 1.10.1
'@actions/github':
specifier: ^5.0.0
version: 5.1.1
devDependencies:
'@octokit/webhooks-types':
specifier: ^7.5.1
version: 7.5.1
'@swc/jest':
specifier: ^0.2.36
version: 0.2.36(@swc/core@1.7.26)
'@types/jest':
specifier: ^27.5.2
version: 27.5.2
'@types/node':
specifier: ^20.16.5
version: 20.16.5
'@typescript-eslint/eslint-plugin':
specifier: ^4.33.0
version: 4.33.0(@typescript-eslint/parser@4.33.0(eslint@7.32.0)(typescript@4.9.5))(eslint@7.32.0)(typescript@4.9.5)
'@typescript-eslint/parser':
specifier: ^4.33.0
version: 4.33.0(eslint@7.32.0)(typescript@4.9.5)
'@vercel/ncc':
specifier: 0.38.1
version: 0.38.1
concurrently:
specifier: ^8.2.2
version: 8.2.2
eslint:
specifier: ^7.32.0
version: 7.32.0
jest:
specifier: ^29.7.0
version: 29.7.0(@types/node@20.16.5)
prettier:
specifier: ^3.3.3
version: 3.3.3
ts-jest:
specifier: ^26.5.6
version: 26.5.6(jest@29.7.0(@types/node@20.16.5))(typescript@4.9.5)
typescript:
specifier: ^4.9.5
version: 4.9.5
packages:
'@actions/core@1.10.1':

View File

@@ -1,68 +0,0 @@
name: label-author
on:
pull_request:
types: [opened]
issues:
types: [opened]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
debug-context:
runs-on: ubuntu-latest
steps:
- name: View context attributes
uses: actions/github-script@v7
with:
script: console.log(context)
label-created-by:
name: Label pr/issue on opening
runs-on: ubuntu-latest
steps:
- name: Tag with 'created-by'
uses: actions/github-script@v7
if: github.event.action == 'opened'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const type = context.payload.pull_request ? 'pull_request' : 'issue';
const association = context.payload[type].author_association;
let label = '';
if (
association === 'MEMBER' ||
association === 'OWNER' ||
[
'denolfe',
'jmikrut',
'danribbens',
'alessiogr',
'jacobsfletch',
'jarrodmflesch',
'jesschowdhury',
'kendelljoseph',
'patrikkozak',
'paulpopus',
'r1tsuu',
'tylandavis',
].includes(context.actor.toLowerCase())
) {
label = 'created-by: Payload team';
} else if (association === 'CONTRIBUTOR') {
label = 'created-by: Contributor';
}
if (!label) return;
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [label],
});
console.log(`Added '${label}' label`);

116
.github/workflows/label-on-change.yml vendored Normal file
View File

@@ -0,0 +1,116 @@
name: label-on-change
on:
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
issues:
types:
- assigned
- closed
- labeled
- reopened
# TODO: Handle labeling on comment
jobs:
on-labeled-ensure-one-status:
runs-on: ubuntu-latest
permissions:
issues: write
# Only run on issue labeled and if label starts with 'status:'
if: github.event.action == 'labeled' && startsWith(github.event.label.name, 'status:')
steps:
- name: Ensure only one status label
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Get all labels that start with 'status:' and are not the incoming label
const incomingLabelName = context.payload.label.name;
const labelNamesToRemove = context.payload.issue.labels
.filter(label => label.name.startsWith('status:') && label.name !== incomingLabelName)
.map(label => label.name);
if (!labelNamesToRemove.length) {
console.log('No labels to remove');
return;
}
console.log(`Labels to remove: '${labelNamesToRemove}'`);
// If there is more than one status label, remove all but the incoming label
for (const labelName of labelNamesToRemove) {
await github.rest.issues.removeLabel({
issue_number: context.issue.number,
name: labelName,
owner: context.repo.owner,
repo: context.repo.repo,
});
console.log(`Removed '${labelName}' label`);
}
on-issue-close:
runs-on: ubuntu-latest
permissions:
issues: write
if: github.event.action == 'closed'
steps:
- name: Remove all labels on issue close
uses: actions/github-script@v7
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
// Get all labels that start with 'status:' and 'stale'
const labelNamesToRemove = context.payload.issue.labels
.filter(label => label.name.startsWith('status:') || label.name === 'stale')
.map(label => label.name);
if (!labelNamesToRemove.length) {
console.log('No labels to remove');
return;
}
console.log(`Labels to remove: '${labelNamesToRemove}'`);
for (const labelName of labelNamesToRemove) {
await github.rest.issues.removeLabel({
issue_number: context.issue.number,
name: labelName,
owner: context.repo.owner,
repo: context.repo.repo,
});
console.log(`Removed '${labelName}' label`);
}
on-issue-reopen:
runs-on: ubuntu-latest
permissions:
issues: write
if: github.event.action == 'reopened'
steps:
- name: Add needs-triage label on issue reopen
uses: actions-ecosystem/action-add-labels@v1
with:
labels: 'status: needs-triage'
on-issue-assigned:
runs-on: ubuntu-latest
permissions:
issues: write
if: >
github.event.action == 'assigned' &&
contains(github.event.issue.labels.*.name, 'status: needs-triage')
steps:
- name: Remove needs-triage label on issue assign
uses: actions-ecosystem/action-remove-labels@v1
with:
labels: 'status: needs-triage'
# on-pr-merge:
# runs-on: ubuntu-latest
# if: github.event.pull_request.merged == true
# steps:
# on-pr-close:
# runs-on: ubuntu-latest
# if: github.event_name == 'pull_request_target' && github.event.pull_request.merged == false
# steps:

26
.github/workflows/lock-issues.yml vendored Normal file
View File

@@ -0,0 +1,26 @@
name: lock-issues
on:
schedule:
# Run nightly at 12am EST
- cron: '0 4 * * *'
workflow_dispatch:
permissions:
issues: write
jobs:
lock_issues:
runs-on: ubuntu-latest
steps:
- name: Lock issues
uses: dessant/lock-threads@v5
with:
process-only: 'issues'
issue-inactive-days: '1'
exclude-any-issue-labels: 'status: awaiting-reply'
log-output: true
issue-comment: >
This issue has been automatically locked.
Please open a new issue if this issue persists with any additional detail.

View File

@@ -48,6 +48,7 @@ jobs:
- 'test/**'
- 'pnpm-lock.yaml'
- 'package.json'
- 'templates/**'
templates:
- 'templates/**'
- name: Log all filter results
@@ -187,6 +188,7 @@ jobs:
tests-int:
runs-on: ubuntu-latest
needs: build
name: int-${{ matrix.database }}
strategy:
fail-fast: false
matrix:
@@ -206,6 +208,19 @@ jobs:
AWS_SECRET_ACCESS_KEY: localstack
AWS_REGION: us-east-1
services:
postgres:
image: ${{ (startsWith(matrix.database, 'postgres') ) && 'postgis/postgis:16-3.4' || '' }}
env:
# must specify password for PG Docker container image, see: https://registry.hub.docker.com/_/postgres?tab=description&page=1&name=10
POSTGRES_USER: ${{ env.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
POSTGRES_DB: ${{ env.POSTGRES_DB }}
ports:
- 5432:5432
# needed because the postgres container does not provide a healthcheck
options: --health-cmd pg_isready --health-interval 10s --health-timeout 5s --health-retries 5
steps:
- uses: actions/checkout@v4
with:
@@ -230,15 +245,6 @@ jobs:
- name: Start LocalStack
run: pnpm docker:start
- name: Start PostgreSQL
uses: CasperWA/postgresql-action@v1.2
with:
postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions
postgresql db: ${{ env.POSTGRES_DB }}
postgresql user: ${{ env.POSTGRES_USER }}
postgresql password: ${{ env.POSTGRES_PASSWORD }}
if: startsWith(matrix.database, 'postgres')
- name: Install Supabase CLI
uses: supabase/setup-cli@v1
with:
@@ -251,10 +257,6 @@ jobs:
supabase start
if: matrix.database == 'supabase'
- name: Wait for PostgreSQL
run: sleep 30
if: startsWith(matrix.database, 'postgres')
- name: Configure PostgreSQL
run: |
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;"
@@ -282,6 +284,7 @@ jobs:
tests-e2e:
runs-on: ubuntu-latest
needs: build
name: ${{ matrix.suite }}
strategy:
fail-fast: false
matrix:
@@ -390,10 +393,33 @@ jobs:
# report-tag: ${{ matrix.suite }}
# job-summary: true
app-build-with-packed:
if: false # Disable until package resolution in tgzs can be figured out
# Build listed templates with packed local packages
build-templates:
runs-on: ubuntu-latest
needs: build
strategy:
matrix:
include:
- template: blank
database: mongodb
- template: website
database: mongodb
- template: with-payload-cloud
database: mongodb
- template: with-vercel-mongodb
database: mongodb
# Postgres
- template: with-postgres
database: postgres
- template: with-vercel-postgres
database: postgres
name: ${{ matrix.template }}-${{ matrix.database }}
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: payloadtests
steps:
# https://github.com/actions/virtual-environments/issues/1187
@@ -418,22 +444,35 @@ jobs:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Start PostgreSQL
uses: CasperWA/postgresql-action@v1.2
with:
postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions
postgresql db: ${{ env.POSTGRES_DB }}
postgresql user: ${{ env.POSTGRES_USER }}
postgresql password: ${{ env.POSTGRES_PASSWORD }}
if: matrix.database == 'postgres'
- name: Wait for PostgreSQL
run: sleep 30
if: matrix.database == 'postgres'
- name: Configure PostgreSQL
run: |
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "CREATE ROLE runner SUPERUSER LOGIN;"
psql "postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" -c "SELECT version();"
echo "POSTGRES_URL=postgresql://$POSTGRES_USER:$POSTGRES_PASSWORD@localhost:5432/$POSTGRES_DB" >> $GITHUB_ENV
if: matrix.database == 'postgres'
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: 6.0
- name: Pack and build app
- name: Build Template
run: |
set -ex
pnpm run script:pack --dest templates/blank
cd templates/blank
cp .env.example .env
ls -la
pnpm add ./*.tgz --ignore-workspace
pnpm install --ignore-workspace --no-frozen-lockfile
cat package.json
pnpm run build
pnpm run script:pack --dest templates/${{ matrix.template }}
pnpm runts scripts/build-template-with-local-pkgs.ts ${{ matrix.template }} $POSTGRES_URL
tests-type-generation:
runs-on: ubuntu-latest
@@ -468,72 +507,6 @@ jobs:
- name: Generate GraphQL schema file
run: pnpm dev:generate-graphql-schema graphql-schema-gen
templates:
needs: changes
if: false # Disable until templates are updated for 3.0
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
template: [blank, website, ecommerce]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 25
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
run: sudo ethtool -K eth0 tx off rx off
- name: Setup Node@${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: 6.0
- name: Build Template
run: |
cd templates/${{ matrix.template }}
cp .env.example .env
yarn install
yarn build
yarn generate:types
generated-templates:
needs: build
if: false # Needs to pull in tgz files from build
runs-on: ubuntu-latest
steps:
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
run: sudo ethtool -K eth0 tx off rx off
- name: Setup Node@${{ env.NODE_VERSION }}
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build all generated templates
run: pnpm tsx ./scripts/build-generated-templates.ts
all-green:
name: All Green
if: always()
@@ -552,6 +525,7 @@ jobs:
publish-canary:
name: Publish Canary
runs-on: ubuntu-latest
if: ${{ needs.all-green.result == 'success' && github.ref_name == 'beta' }}
needs:
- all-green
@@ -560,4 +534,3 @@ jobs:
- run: |
echo github.ref: ${{ github.ref }}
echo isBeta: ${{ github.ref == 'refs/heads/beta' }}
echo isMain: ${{ github.ref == 'refs/heads/main' }}

View File

@@ -5,7 +5,6 @@ on:
types:
- opened
- edited
- synchronize
permissions:
pull-requests: write
@@ -47,7 +46,7 @@ jobs:
live-preview
live-preview-react
next
payload
payload-cloud
plugin-cloud
plugin-cloud-storage
plugin-form-builder

42
.github/workflows/stale.yml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: stale
on:
workflow_dispatch:
jobs:
stale:
runs-on: ubuntu-latest
permissions:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v9
id: stale
with:
debug-only: true
days-before-stale: 90
days-before-close: 7
ascending: true
operations-per-run: 300
# Ignore all assigned
exempt-all-assignees: false
# Issues
stale-issue-label: 'stale'
exempt-issue-labels: 'blocked,must,should,keep,created-by: Payload team,created-by: Contributor'
stale-issue-message: >
This issue has been marked as stale due to lack of activity. To keep the ticket open, please indicate that it is still relevant in a comment below.
close-issue-message: >
This issue was automatically closed due to lack of activity.
# Pull Requests
stale-pr-label: 'stale'
exempt-pr-labels: 'blocked,must,should,keep,created-by: Payload team,created-by: Contributor'
stale-pr-message: >
This PR is stale due to lack of activity. To keep the PR open, please indicate that it is still relevant in a comment below.
close-pr-message: >
This pull request was automatically closed due to lack of activity.
- name: Print outputs
run: echo ${{ format('{0},{1}', toJSON(steps.stale.outputs.staled-issues-prs), toJSON(steps.stale.outputs.closed-issues-prs)) }}

102
.github/workflows/triage.yml vendored Normal file
View File

@@ -0,0 +1,102 @@
name: triage
on:
pull_request:
types:
- opened
issues:
types:
- opened
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
permissions:
contents: read
issues: write
pull-requests: write
jobs:
debug-context:
runs-on: ubuntu-latest
steps:
- name: View context attributes
uses: actions/github-script@v7
with:
script: console.log({ context })
label-created-by:
name: label-on-open
runs-on: ubuntu-latest
steps:
- name: Tag with 'created-by'
uses: actions/github-script@v7
if: github.event.action == 'opened'
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const payloadTeamUsernames = [
'denolfe',
'jmikrut',
'DanRibbens',
'jacobsfletch',
'JarrodMFlesch',
'AlessioGr',
'JessChowdhury',
'kendelljoseph',
'PatrikKozak',
'tylandavis',
'paulpopus',
'r1tsuu',
'GermanJablo',
];
const type = context.payload.pull_request ? 'pull_request' : 'issue';
const isTeamMember = payloadTeamUsernames
.map(n => n.toLowerCase())
.includes(context.payload[type].user.login.toLowerCase());
if (isTeamMember) {
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: ['created-by: Payload team'],
});
console.log(`Added 'created-by: Payload team' label`);
return;
}
const association = context.payload[type].author_association;
let label = ''
if (association === 'MEMBER' || association === 'OWNER') {
label = 'created-by: Payload team';
} else if (association === 'CONTRIBUTOR') {
label = 'created-by: Contributor';
}
if (!label) return;
github.rest.issues.addLabels({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
labels: [label],
});
console.log(`Added '${label}' label.`);
triage:
name: initial-triage
if: github.event_name == 'issues'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: ./.github/actions/triage
with:
reproduction-comment: '.github/comments/invalid-reproduction.md'
reproduction-link-section: '### Link to the code that reproduces this issue(.*)### Reproduction Steps'
reproduction-issue-labels: 'validate-reproduction'
actions-to-perform: 'tag,comment'

3
.gitignore vendored
View File

@@ -314,3 +314,6 @@ test/app/(payload)/admin/importMap.js
/test/app/(payload)/admin/importMap.js
test/pnpm-lock.yaml
test/databaseAdapter.js
/filename-compound-index
/media-with-relation-preview
/media-without-relation-preview

30
.vscode/launch.json vendored
View File

@@ -10,14 +10,14 @@
"cwd": "${workspaceFolder}"
},
{
"command": "node --no-deprecation test/dev.js _community",
"command": "pnpm tsx --no-deprecation test/dev.ts _community",
"cwd": "${workspaceFolder}",
"name": "Run Dev Community",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js storage-uploadthing",
"command": "pnpm tsx --no-deprecation test/dev.ts storage-uploadthing",
"cwd": "${workspaceFolder}",
"name": "Uploadthing",
"request": "launch",
@@ -25,7 +25,7 @@
"envFile": "${workspaceFolder}/test/storage-uploadthing/.env"
},
{
"command": "node --no-deprecation test/dev.js live-preview",
"command": "pnpm tsx --no-deprecation test/dev.ts live-preview",
"cwd": "${workspaceFolder}",
"name": "Run Dev Live Preview",
"request": "launch",
@@ -43,28 +43,28 @@
}
},
{
"command": "node --no-deprecation test/dev.js admin",
"command": "pnpm tsx --no-deprecation test/dev.ts admin",
"cwd": "${workspaceFolder}",
"name": "Run Dev Admin",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js auth",
"command": "pnpm tsx --no-deprecation test/dev.ts auth",
"cwd": "${workspaceFolder}",
"name": "Run Dev Auth",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js fields-relationship",
"command": "pnpm tsx --no-deprecation test/dev.ts fields-relationship",
"cwd": "${workspaceFolder}",
"name": "Run Dev Fields-Relationship",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js login-with-username",
"command": "pnpm tsx --no-deprecation test/dev.ts login-with-username",
"cwd": "${workspaceFolder}",
"name": "Run Dev Login-With-Username",
"request": "launch",
@@ -81,21 +81,21 @@
}
},
{
"command": "node --no-deprecation test/dev.js collections-graphql",
"command": "pnpm tsx --no-deprecation test/dev.ts collections-graphql",
"cwd": "${workspaceFolder}",
"name": "Run Dev GraphQL",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js fields",
"command": "pnpm tsx --no-deprecation test/dev.ts fields",
"cwd": "${workspaceFolder}",
"name": "Run Dev Fields",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js versions",
"command": "pnpm tsx --no-deprecation test/dev.ts versions",
"cwd": "${workspaceFolder}",
"name": "Run Dev Postgres",
"request": "launch",
@@ -105,35 +105,35 @@
}
},
{
"command": "node --no-deprecation test/dev.js versions",
"command": "pnpm tsx --no-deprecation test/dev.ts versions",
"cwd": "${workspaceFolder}",
"name": "Run Dev Versions",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js localization",
"command": "pnpm tsx --no-deprecation test/dev.ts localization",
"cwd": "${workspaceFolder}",
"name": "Run Dev Localization",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js locked-documents",
"command": "pnpm tsx --no-deprecation test/dev.ts locked-documents",
"cwd": "${workspaceFolder}",
"name": "Run Dev Locked Documents",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js uploads",
"command": "pnpm tsx --no-deprecation test/dev.ts uploads",
"cwd": "${workspaceFolder}",
"name": "Run Dev Uploads",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js field-error-states",
"command": "pnpm tsx --no-deprecation test/dev.ts field-error-states",
"cwd": "${workspaceFolder}",
"name": "Run Dev Field Error States",
"request": "launch",

View File

@@ -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:
```ts
const { t } = useTranslation()
// ...
t('yourStringKey')
```

View File

@@ -1,4 +1,4 @@
<a href="https://payloadcms.com"><img width="100%" src="https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/assets/images/github-banner-alt.jpg?raw=true" alt="Payload headless CMS Admin panel built with React" /></a>
<a href="https://payloadcms.com"><img width="100%" src="https://github.com/payloadcms/payload/blob/beta/packages/payload/src/assets/images/github-banner-nextjs-native.jpg" alt="Payload headless CMS Admin panel built with React" /></a>
<br />
<br />
@@ -13,74 +13,66 @@
</p>
<hr/>
<h4>
<a target="_blank" href="https://payloadcms.com/docs/getting-started/what-is-payload" rel="dofollow"><strong>Explore the Docs</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://demo.payloadcms.com/" rel="dofollow"><strong>Try Live Demo</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow"><strong>View G2 Reviews</strong></a>
<a target="_blank" href="https://payloadcms.com/docs/beta/getting-started/what-is-payload" rel="dofollow"><strong>Explore the Docs</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow"><strong>View G2 Reviews</strong></a>
</h4>
<hr/>
> [!IMPORTANT]
> 🎉 <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>Dont 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.
### [🛒 E-Commerce](https://github.com/payloadcms/payload/tree/main/templates/ecommerce)
### [🌐 Website](https://github.com/payloadcms/payload/tree/beta/templates/website)
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.
Build any kind of website, blog, or portfolio from small to enterprise. Comes with a fully functional front-end built with RSCs and Tailwind.
### [🌐 Website](https://github.com/payloadcms/payload/tree/main/templates/website)
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.
- [Official Templates](https://github.com/payloadcms/payload/tree/main/templates)
- [Official Templates](https://github.com/payloadcms/payload/tree/beta/templates)
- [Community Templates](https://github.com/topics/payload-template)
## ✨ Features
- Completely free and open-source
- [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
- [Easily customizable ReactJS Admin](https://payloadcms.com/docs/admin/overview)
- [Fully self-hosted](https://payloadcms.com/docs/production/deployment)
- [Extensible Authentication](https://payloadcms.com/docs/authentication/overview)
- [Local file storage & upload](https://payloadcms.com/docs/upload/overview)
- [Version History and Drafts](https://payloadcms.com/docs/versions/overview)
- [Field-based Localization](https://payloadcms.com/docs/configuration/localization)
- [Block-based Layout Builder](https://payloadcms.com/docs/fields/blocks)
- [Extensible SlateJS rich text editor](https://payloadcms.com/docs/fields/rich-text)
- [Array field type](https://payloadcms.com/docs/fields/array)
- [Field conditional logic](https://payloadcms.com/docs/fields/overview#conditional-logic)
- Extremely granular [Access Control](https://payloadcms.com/docs/access-control/overview)
- [Document and field-level hooks](https://payloadcms.com/docs/hooks/overview) for every action Payload provides
- Built with Typescript & very Typescript-friendly
- Next.js native, built to run inside _your_ `/app` folder
- Use server components to extend Payload UI
- Query your database directly in server components, no need for REST / GraphQL
- Fully TypeScript with automatic types for your data
- [Auth out of the box](https://payloadcms.com/docs/beta/authentication/overview)
- [Versions and drafts](https://payloadcms.com/docs/beta/versions/overview)
- [Localization](https://payloadcms.com/docs/beta/configuration/localization)
- [Block-based kayout builder](https://payloadcms.com/docs/beta/fields/blocks)
- [Customizable React admin](https://payloadcms.com/docs/beta/admin/overview)
- [Lexical rich text editor](https://payloadcms.com/docs/beta/fields/rich-text)
- [Conditional field logic](https://payloadcms.com/docs/beta/fields/overview#conditional-logic)
- Extremely granular [Access Control](https://payloadcms.com/docs/beta/access-control/overview)
- [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 +80,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.
@@ -100,6 +92,10 @@ If you want to add contributions to this repository, please follow the instructi
The [Examples Directory](./examples) is a great resource for learning how to setup Payload in a variety of different ways, but you can also find great examples in our blog and throughout our social media.
If you'd like to run the examples, you can either copy them to a folder outside this repo or run them directly by (1) navigating to the example's subfolder (`cd examples/your-example-folder`) and (2) using the `--ignore-workspace` flag to bypass workspace restrictions (e.g., `pnpm --ignore-workspace install` or `pnpm --ignore-workspace dev`).
You can see more examples at:
- [Examples Directory](./examples)
- [Payload Blog](https://payloadcms.com/blog)
- [Payload YouTube](https://www.youtube.com/@payloadcms)

View File

@@ -1,19 +1,19 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
import { generatePageMetadata, NotFoundPage } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
params: Promise<{
segments: string[]
}
searchParams: {
}>
searchParams: Promise<{
[key: string]: string | string[]
}
}>
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>

View File

@@ -1,19 +1,19 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import type { Metadata } from 'next'
import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
import { generatePageMetadata, RootPage } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
params: Promise<{
segments: string[]
}
searchParams: {
}>
searchParams: Promise<{
[key: string]: string | string[]
}
}>
}
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>

View File

@@ -1,5 +1,5 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from '@payload-config'
import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes'

View File

@@ -1,5 +1,5 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from '@payload-config'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'

View File

@@ -1,6 +1,8 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import config from '@payload-config'
import { GRAPHQL_POST } from '@payloadcms/next/routes'
import { GRAPHQL_POST, REST_OPTIONS } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)
export const OPTIONS = REST_OPTIONS(config)

View File

@@ -1,21 +1,30 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import { RootLayout } from '@payloadcms/next/layouts'
import { importMap } from './admin/importMap.js'
// import '@payloadcms/ui/styles.css' // Uncomment this line if `@payloadcms/ui` in `tsconfig.json` points to `/ui/dist` instead of `/ui/src`
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
// import '@payloadcms/ui/styles.css' // Uncomment this line if `@payloadcms/ui` in `tsconfig.json` points to `/ui/dist` instead of `/ui/src`
import type { ServerFunctionClient } from 'payload'
import config from '@payload-config'
import { handleServerFunctions, RootLayout } from '@payloadcms/next/layouts'
import React from 'react'
import { importMap } from './admin/importMap.js'
import './custom.scss'
type Args = {
children: React.ReactNode
}
const serverFunction: ServerFunctionClient = async function (args) {
'use server'
return handleServerFunctions({
...args,
config,
importMap,
})
}
const Layout = ({ children }: Args) => (
<RootLayout config={configPromise} importMap={importMap}>
<RootLayout config={config} importMap={importMap} serverFunction={serverFunction}>
{children}
</RootLayout>
)

27
app/global-error.tsx Normal file
View File

@@ -0,0 +1,27 @@
/* eslint-disable no-restricted-exports */
'use client'
import * as Sentry from '@sentry/nextjs'
import NextError from 'next/error.js'
import { useEffect } from 'react'
export default function GlobalError({ error }: { error: { digest?: string } & Error }) {
useEffect(() => {
if (process.env.NEXT_PUBLIC_SENTRY_DSN) {
Sentry.captureException(error)
}
}, [error])
return (
<html lang="en-US">
<body>
{/* `NextError` is the default Next.js error page component. Its type
definition requires a `statusCode` prop. However, since the App Router
does not expose status codes for errors, we simply pass 0 to render a
generic error message. */}
{/* @ts-expect-error types repo */}
<NextError statusCode={0} />
</body>
</html>
)
}

View File

@@ -79,7 +79,7 @@ Returns a boolean which allows/denies access to the `create` request.
To add create Access Control to a Collection, use the `create` property in the [Collection Config](../collections/overview):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const CollectionWithCreateAccess: CollectionConfig = {
// ...

View File

@@ -33,7 +33,7 @@ Access Control is specific to the operation of the request.
To add Access Control to a Field, use the `access` property in the [Field Config](../fields/overview):
```ts
import { CollectionConfig } from 'payload';
import type { CollectionConfig } from 'payload';
export const Posts: CollectionConfig = {
slug: 'posts',

View File

@@ -18,7 +18,7 @@ There are many use cases for Access Control, including:
- Only allowing public access to posts where a `status` field is equal to `published`
- Giving only users with a `role` field equal to `admin` the ability to delete posts
- Allowing anyone to submit contact forms, but only logged in users to `read`, `update` or `delete` them
- Restricting a user to only be able to see their own orders, but noone else's
- Restricting a user to only be able to see their own orders, but no-one else's
- Allowing users that belong to a certain organization to access only that organization's resources
There are three main types of Access Control in Payload:

View File

@@ -11,7 +11,7 @@ The behavior of [Collections](../configuration/collections) within the [Admin Pa
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
@@ -25,23 +25,23 @@ export const MyCollection: CollectionConfig = {
The following options are available:
| Option | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. |
| Option | Description |
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. A field with `virtual: true` cannot be used as the title. |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#components). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](./metadata). |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](./metadata). |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
### Components
@@ -89,7 +89,7 @@ It is possible to display a Preview Button within the Edit View of the Admin Pan
To configure the Preview Button, set the `admin.preview` property to a function in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
@@ -126,7 +126,7 @@ All Collections receive their own List View which displays a paginated list of d
To configure pagination options, use the `admin.pagination` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
@@ -155,7 +155,7 @@ In the List View, there is a "search" box that allows you to quickly find a docu
To define which fields should be searched, use the `admin.listSearchableFields` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...

View File

@@ -6,9 +6,9 @@ desc: Fully customize your Admin Panel by swapping in your own React components.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
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).
The Payload [Admin Panel](./overview) is designed to be as minimal and straightforward as possible to allow for 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>
@@ -22,47 +22,41 @@ There are four main types of Custom Components in Payload:
- [Global Components](./globals#components)
- [Field Components](./fields)
To swap in your own Custom Component, consult the list of available components. Determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
To swap in your own Custom Component, first consult the list of available components, determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
## Defining Custom Components
## Defining Custom Components in the Payload Config
As Payload compiles the Admin Panel, it checks your config for Custom Components. When detected, Payload either replaces its own default component with yours, or if none exists by default, renders yours outright. While are many places where Custom Components are supported in Payload, each is defined in the same way using [Component Paths](#component-paths).
In the Payload Config, you can define custom React Components to enhance the admin interface. However, these components should not be imported directly into the server-only Payload Config to avoid including client-side code. Instead, you specify the path to the component. Heres how you can do it:
To add a Custom Component, point to its file path in your Payload Config:
src/components/Logout.tsx
```tsx
'use client'
import React from 'react'
export const MyComponent = () => {
return (
<button>Click me!</button>
)
}
```
payload.config.ts:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
admin: {
components: {
logout: {
Button: '/src/components/Logout#MyComponent'
Button: '/src/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
In the path `/src/components/Logout#MyComponent`, `/src/components/Logout` is the file path, and `MyComponent` is the named export. If the component is the default export, the export name can be omitted. Path and export name are separated by a `#`.
<Banner type="success">
<strong>Note:</strong>
All Custom Components can be either Server Components or Client Components, depending on the presence of the `use client` directive at the top of the file.
</Banner>
### Configuring the Base Directory
### Component Paths
Component paths, by default, are relative to your working directory - this is usually where your Next.js config lies. To simplify component paths, you have the option to configure the *base directory* using the `admin.baseDir.baseDir` property:
In order to ensure the Payload Config is fully Node.js compatible and as lightweight as possible, components are not directly imported into your config. Instead, they are identified by their file path for the Admin Panel to resolve on its own.
Component Paths, by default, are relative to your project's base directory. This is either your current working directory, or the directory specified in `config.admin.baseDir`. To simplify Component Paths, you can also configure the base directory using the `admin.importMap.baseDir` property.
Components using named exports are identified either by appending `#` followed by the export name, or using the `exportName` property. If the component is the default export, this can be omitted.
```ts
import { buildConfig } from 'payload'
@@ -73,137 +67,72 @@ const dirname = path.dirname(filename)
const config = buildConfig({
// ...
admin: { // highlight-line
importMap: {
baseDir: path.resolve(dirname, 'src'),
admin: {
importMap: {
baseDir: path.resolve(dirname, 'src'), // highlight-line
},
components: {
logout: {
Button: '/components/Logout#MyComponent'
Button: '/components/Logout#MyComponent' // highlight-line
}
}
},
})
```
In this example, we set the base directory to the `src` directory - thus we can omit the `/src/` part of our component path string.
In this example, we set the base directory to the `src` directory, and omit the `/src/` part of our component path string.
### Passing Props
### Config Options
Each React Component in the Payload Config is typed as `PayloadComponent`. This usually is a string, but can also be an object containing the following properties:
While Custom Components are usually defined as a string, you can also pass in an object with additional options:
| Property | Description |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| `clientProps` | Props to be passed to the React Component if it's a Client Component |
| `exportName` | Instead of declaring named exports using `#` in the component path, you can also omit them from `path` and pass them in here. |
| `path` | Path to the React Component. Named exports can be appended to the end of the path, separated by a `#` |
| `serverProps` | Props to be passed to the React Component if it's a Server Component |
To pass in props from the config, you can use the `clientProps` and/or `serverProps` properties. This alleviates the need to use an HOC (Higher-Order-Component) to declare a React Component with props passed in.
Here is an example:
src/components/Logout.tsx
```tsx
'use client'
import React from 'react'
export const MyComponent = ({ text }: { text: string }) => {
return (
<button>Click me! {text}</button>
)
}
```
payload.config.ts:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
admin: {
components: {
logout: {
// highlight-start
Button: {
path: '/src/components/Logout',
clientProps: {
text: 'Some Text.'
},
exportName: 'MyComponent'
exportName: 'MyComponent',
}
// highlight-end
}
}
},
})
```
### Import Maps
The following options are available:
It's essential to understand how `PayloadComponent` paths function behind the scenes. Directly importing React Components into your Payload Config using import statements can introduce client-only modules like CSS into your server-only config. This could error when attempting to load the Payload Config in server-only environments and unnecessarily increase the size of the Payload Config, which should remain streamlined and efficient for server use.
| Property | Description |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| **`clientProps`** | Props to be passed to the Custom Components if it's a Client Component. [More details](#custom-props). |
| **`exportName`** | Instead of declaring named exports using `#` in the component path, you can also omit them from `path` and pass them in here. |
| **`path`** | File path to the Custom Component. Named exports can be appended to the end of the path, separated by a `#`. |
| **`serverProps`** | Props to be passed to the Custom Component if it's a Server Component. [More details](#custom-props). |
Instead, we utilize component paths to reference React Components. This method enhances the Payload Config with actual React Component imports on the client side, without affecting server-side usage. A script is deployed to scan the Payload Config, collecting all component paths and creating an `importMap.js`. This file, located in app/(payload)/admin/importMap.js, must be statically imported by your Next.js root page and layout. The script imports all the React Components from the specified paths into a Map, associating them with their respective paths (the ones you defined).
For more details on how to build Custom Components, see [Building Custom Components](#building-custom-components).
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 Map
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.
In order for Payload to make use of [Component Paths](#component-paths), an "Import Map" is automatically generated at `app/(payload)/admin/importMap.js`. This file contains every Custom Component in your config, keyed to their respective paths. When Payload needs to lookup a component, it uses this file to find the correct import.
### Component paths in external packages
The Import Map is automatically regenerated at startup and whenever Hot Module Replacement (HMR) runs, or you can run `payload generate:importmap` to manually regenerate it.
Component paths are resolved relative to your project's base directory, which is either your current working directory or the directory specified in `config.admin.baseDir`. When using custom components from external packages, you can't use relative paths. Instead, use an import path that's accessible as if you were writing an import statement in your project's base directory.
#### Custom Imports
For example, to export a field with a custom component from an external package named `my-external-package`:
If needed, custom items can be appended onto the Import Map. This is mostly only relevant for plugin authors who need to add a custom import that is not referenced in a known location.
To add a custom import to the Import Map, use the `admin.dependencies` property in your [Payload Config](../getting-started/overview):
```ts
import type { Field } from 'payload'
export const MyCustomField: Field = {
type: 'text',
name: 'MyField',
admin: {
components: {
Field: 'my-external-package/client#MyFieldComponent'
}
}
}
```
import { buildConfig } from 'payload'
Despite `MyFieldComponent` living in `src/components/MyFieldComponent.tsx` in `my-external-package`, this will not be accessible from the consuming project. Instead, we recommend exporting all custom components from one file in the external package. For example, you can define a `src/client.ts file in `my-external-package`:
```ts
'use client'
export { MyFieldComponent } from './components/MyFieldComponent'
```
Then, update the package.json of `my-external-package:
```json
{
...
"exports": {
"./client": {
"import": "./dist/client.js",
"types": "./dist/client.d.ts",
"default": "./dist/client.js"
}
}
}
```
This setup allows you to specify the component path as `my-external-package/client#MyFieldComponent` as seen above. The import map will generate:
```ts
import { MyFieldComponent } from 'my-external-package/client'
```
which is a valid way to access MyFieldComponent that can be resolved by the consuming project.
### Custom Components from unknown locations
By default, any component paths from known locations are added to the import map. However, if you need to add any components from unknown locations to the import map, you can do so by adding them to the `admin.dependencies` array in your Payload Config. This is mostly only relevant for plugin authors and not for regular Payload users.
Example:
```ts
export default {
export default buildConfig({
// ...
admin: {
// ...
@@ -220,24 +149,6 @@ export default {
}
```
This way, `TestComponent` is added to the import map, no matter if it's referenced in a known location or not. On the client, you can then use the component like this:
```tsx
'use client'
import { RenderComponent, useConfig } from '@payloadcms/ui'
import React from 'react'
export const CustomView = () => {
const { config } = useConfig()
return (
<div>
<RenderComponent mappedComponent={config.admin.dependencies?.myTestComponent} />
</div>
)
}
```
## Root Components
Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo or the main nav.
@@ -329,7 +240,9 @@ export const useMyCustomContext = () => useContext(MyCustomContext)
## Building Custom Components
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.
### Default Props
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.
@@ -359,12 +272,46 @@ Each Custom Component receives the following props by default:
| `payload` | The [Payload](../local-api/overview) class. |
| `i18n` | The [i18n](../configuration/i18n) object. |
Custom Components also receive various other props that are specific to the context in which the Custom Component is being rendered. For example, [Custom Views](./views) receive the `user` prop. For a full list of available props, consult the documentation related to the specific component you are working with.
<Banner type="success">
See [Root Components](#root-components), [Collection Components](#collection-components), [Global Components](#global-components), or [Field Components](#custom-field-components) for a complete list of all available components.
<Banner type="warning">
<strong>Reminder:</strong>
All Custom Components also receive various other props that are specific component being rendered. See [Root Components](#root-components), [Collection Components](#collection-components), [Global Components](#global-components), or [Field Components](#custom-field-components) for a complete list of all default props per component.
</Banner>
### Custom Props
To pass in custom props from the config, you can use either the `clientProps` or `serverProps` properties depending on whether your prop is [serializable](https://react.dev/reference/rsc/use-client#serializable-types), and whether your component is a Server or Client Component.
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
components: {
logout: {
Button: {
path: '/src/components/Logout#MyComponent',
clientProps: {
myCustomProp: 'Hello, World!' // highlight-line
},
}
}
}
},
})
```
```tsx
'use client'
import React from 'react'
export const MyComponent = ({ myCustomProp }: { myCustomProp: string }) => {
return (
<button>{myCustomProp}</button>
)
}
```
### Client Components
When [Building Custom Components](#building-custom-components), it's still possible to use client-side code such as `useState` or the `window` object. To do this, simply add the `use client` directive at the top of your file. Payload will automatically detect and remove all default, [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component.

View File

@@ -33,6 +33,19 @@ Here is an example of how you might target the Dashboard View and change the bac
If you are building [Custom Components](./overview), it is best to import your own stylesheets directly into your components, rather than using the global stylesheet. You can continue to use the [CSS library](#css-library) as needed.
</Banner>
### Specificity rules
All Payload CSS is encapsulated inside CSS layers under `@layer payload-default`. Any custom css will now have the highest possible specificity.
We have also provided a 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 previous rules of specificity would be respected you can use the default layer like so
```css
@layer payload-default {
// my styles within the payload specificity
}
```
## Re-using Payload SCSS variables and utilities
You can re-use Payload's SCSS variables and utilities in your own stylesheets by importing it from the UI package.

View File

@@ -40,21 +40,21 @@ export const CollectionConfig: CollectionConfig = {
The following options are available:
| Option | Description |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`condition`** | Programmatically show / hide fields based on other fields. [More details](../admin/fields#conditional-logic). |
| **`components`** | All Field Components can be swapped out for [Custom Components](../admin/components) that you define. [More details](../admin/fields). |
| **`description`** | Helper text to display alongside the field to provide more information for the editor. [More details](../admin/fields#description). |
| Option | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`condition`** | Programmatically show / hide fields based on other fields. [More details](../admin/fields#conditional-logic). |
| **`components`** | All Field Components can be swapped out for [Custom Components](../admin/components) that you define. [More details](../admin/fields). |
| **`description`** | Helper text to display alongside the field to provide more information for the editor. [More details](../admin/fields#description). |
| **`position`** | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
| **`width`** | Restrict the width of a field. You can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
| **`style`** | [CSS Properties](https://developer.mozilla.org/en-US/docs/Web/CSS) to inject into the root element of the field. |
| **`className`** | Attach a [CSS class attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors) to the root DOM element of a field. |
| **`style`** | [CSS Properties](https://developer.mozilla.org/en-US/docs/Web/CSS) to inject into the root element of the field. |
| **`className`** | Attach a [CSS class attribute](https://developer.mozilla.org/en-US/docs/Web/CSS/Class_selectors) to the root DOM element of a field. |
| **`readOnly`** | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
| **`disabled`** | If a field is `disabled`, it is completely omitted from the [Admin Panel](../admin/overview). |
| **`disableBulkEdit`** | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. |
| **`disabled`** | If a field is `disabled`, it is completely omitted from the [Admin Panel](../admin/overview). |
| **`disableBulkEdit`** | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. Defaults to `true` for UI fields. |
| **`disableListColumn`** | Set `disableListColumn` to `true` to prevent fields from appearing in the list view column selector. |
| **`disableListFilter`** | Set `disableListFilter` to `true` to prevent fields from appearing in the list view filter options. |
| **`hidden`** | Will transform the field into a `hidden` input type. Its value will still submit with requests in the Admin Panel, but the field itself will not be visible to editors. |
| **`hidden`** | Will transform the field into a `hidden` input type. Its value will still submit with requests in the Admin Panel, but the field itself will not be visible to editors. |
## Field Components
@@ -217,6 +217,7 @@ Client Component:
'use client'
import React from 'react'
import type { TextFieldClientComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
export const MyTextField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />
@@ -227,7 +228,6 @@ The following additional properties are also provided to the `field` prop:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`_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` |

View File

@@ -760,7 +760,7 @@ const LinkFromCategoryToPosts: React.FC = () => {
## useLocale
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:
```tsx
'use client'

View File

@@ -2,7 +2,7 @@
title: Document Locking
label: Document Locking
order: 90
desc: Ensure your documents are locked while being edited, preventing concurrent edits from multiple users and preserving data integrity.
desc: Ensure your documents are locked during editing to prevent concurrent changes from multiple users and maintain data integrity.
keywords: locking, document locking, edit locking, document, concurrency, Payload, headless, Content Management System, cms, javascript, react, node, nextjs
---
@@ -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.
Heres an example configuration for document locking:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
@@ -55,13 +55,13 @@ export const Posts: CollectionConfig = {
### Impact on APIs
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`.

View File

@@ -36,7 +36,7 @@ To customize Root Metadata, use the `admin.meta` key in your Payload Config:
{
rel: 'icon',
type: 'image/png',
href: '/favicon.png',
url: '/favicon.png',
},
],
},
@@ -80,12 +80,12 @@ To customize icons, use the `icons` key within the `admin.meta` object in your P
{
rel: 'icon',
type: 'image/png',
href: '/favicon.png',
url: '/favicon.png',
},
{
rel: 'apple-touch-icon',
type: 'image/png',
href: '/apple-touch-icon.png',
url: '/apple-touch-icon.png',
},
],
},
@@ -140,7 +140,7 @@ The following options are available for Open Graph Metadata:
| Key | Type | Description |
| --- | --- | --- |
| **`description`** | `string` | The description of the Admin Panel. |
| **`images`** | `OGImageConfig | OGImageConfig[]` | An array of image objects. |
| **`images`** | `OGImageConfig` or `OGImageConfig[]` | An array of image objects. |
| **`siteName`** | `string` | The name of the site. |
| **`title`** | `string` | The title of the Admin Panel. |
@@ -151,7 +151,7 @@ Collection Metadata is the metadata that is applied to all pages within any give
To customize Collection Metadata, use the `admin.meta` key within your Collection Config:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...

View File

@@ -195,7 +195,7 @@ app/
<Banner type="warning">
<strong>Note:</strong>
If you set Root-level Routes _before_ auto-generating the Admin Panel, your [Project Structure](#project-structure) will already be set up correctly.
If you set Root-level Routes _before_ auto-generating the Admin Panel via `create-payload-app`, your [Project Structure](#project-structure) will already be set up correctly.
</Banner>
### Admin-level Routes

View File

@@ -15,7 +15,7 @@ There are four types of views within the Admin Panel:
- [Global Views](#global-views)
- [Document Views](#document-views)
To swap in your own Custom Views, consult the list of available components. Determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-views) accordingly.
To swap in your own Custom View, first consult the list of available components, determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-views) accordingly.
## Root Views
@@ -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.

View File

@@ -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.
<Banner type="success">

View File

@@ -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.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
slug: 'users',

View File

@@ -6,7 +6,7 @@ desc: Email Verification allows users to verify their email address before they'
keywords: authentication, email, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
[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.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -74,7 +74,7 @@ export const Customers: CollectionConfig = {
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.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -95,7 +95,7 @@ export const Customers: CollectionConfig = {
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.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...

View File

@@ -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). |

View File

@@ -6,7 +6,7 @@ desc: Storing data for read on the request object.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
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.
### Definining Token Data

View File

@@ -84,7 +84,7 @@ export default buildConfig({
## Email
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 projects 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.

View File

@@ -37,7 +37,7 @@ It's often best practice to write your Collections in separate files and then im
Here is what a simple Collection Config might look like:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
@@ -57,26 +57,27 @@ export const Posts: CollectionConfig = {
The following options are available:
| Option | Description |
|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`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). |
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`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._

View File

@@ -40,7 +40,6 @@ export default buildConfig({
// highlight-start
i18n: {
fallbackLanguage: 'en', // default
debug: false, // default
}
// highlight-end
})
@@ -51,7 +50,6 @@ The following options are available:
| Option | Description |
| --------------------- | --------------------------------|
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
| **`debug`** | Whether to log debug information to the console. Default is `false`. |
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
@@ -119,7 +117,7 @@ While Payload's built-in features come fully translated, you may also want to tr
To do this, provide the translations wherever applicable, keyed to the language code:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Articles: CollectionConfig = {
slug: 'articles',
@@ -178,60 +176,80 @@ Anywhere in your Payload app that you have access to the `req` object, you can a
In order to use custom translations in your project, you need to provide the types for the translations.
Here is an example of how you can define the types for the custom translations in a [Custom Component](../admin/components):
Here we create a shareable translations object. We will import this in both our custom components and in our Payload config.
```ts
'use client'
// <rootDir>/custom-translations.ts
import type { Config } from 'payload'
import type { NestedKeysStripped } from '@payloadcms/translations'
import type React from 'react'
import { useTranslation } from '@payloadcms/ui/providers/Translation'
const customTranslations = {
export const customTranslations: Config['i18n']['translations'] = {
en: {
general: {
test: 'Custom Translation',
myCustomKey: 'My custom english translation',
},
fields: {
addLabel: 'Add!',
}
},
}
type CustomTranslationObject = typeof customTranslations.en
type CustomTranslationKeys = NestedKeysStripped<CustomTranslationObject>
export type CustomTranslationsObject = typeof customTranslations.en
export type CustomTranslationsKeys = NestedKeysStripped<CustomTranslationsObject>
```
Import the shared translations object into our Payload config so they are available for use:
```ts
// <rootDir>/payload.config.ts
import { buildConfig } from 'payload'
import { customTranslations } from './custom-translations'
export default buildConfig({
//...
i18n: {
translations: customTranslations,
},
//...
})
```
Import the shared translation types to use in your [Custom Component](../admin/components):
```ts
// <rootDir>/components/MyComponent.tsx
'use client'
import type React from 'react'
import { useTranslation } from '@payloadcms/ui'
import type { CustomTranslationsObject, CustomTranslationsKeys } from '../custom-translations'
export const MyComponent: React.FC = () => {
const { i18n, t } = useTranslation<CustomTranslationObject, CustomTranslationKeys>() // These generics merge your custom translations with the default client translations
const { i18n, t } = useTranslation<CustomTranslationsObject, CustomTranslationsKeys>() // These generics merge your custom translations with the default client translations
return t('general:test')
return t('general:myCustomKey')
}
```
Additionally, Payload exposes the `t` function in various places, for example in labels. Here is how you would type those:
```ts
import type {
DefaultTranslationKeys,
NestedKeysStripped,
TFunction,
} from '@payloadcms/translations'
// <rootDir>/fields/myField.ts
import type { DefaultTranslationKeys, TFunction } from '@payloadcms/translations'
import type { Field } from 'payload'
const customTranslations = {
en: {
general: {
test: 'Custom Translation',
},
},
}
type CustomTranslationObject = typeof customTranslations.en
type CustomTranslationKeys = NestedKeysStripped<CustomTranslationObject>
import { CustomTranslationsKeys } from '../custom-translations'
const field: Field = {
name: 'myField',
type: 'text',
label: (
{ t }: { t: TFunction<CustomTranslationKeys | DefaultTranslationKeys> }, // The generic passed to TFunction does not automatically merge the custom translations with the default translations. We need to merge them ourselves here
{ t }: { t: TFunction<CustomTranslationsKeys | DefaultTranslationKeys> }, // The generic passed to TFunction does not automatically merge the custom translations with the default translations. We need to merge them ourselves here
) => t('fields:addLabel'),
}
```

View File

@@ -35,7 +35,8 @@ import { buildConfig } from 'payload'
export default buildConfig({
// ...
localization: {
locales: ['en', 'es', 'de'] // highlight-line
locales: ['en', 'es', 'de'] // required
defaultLocale: 'en', // required
},
})
```
@@ -63,7 +64,7 @@ export default buildConfig({
rtl: true,
},
],
defaultLocale: 'en',
defaultLocale: 'en', // required
fallback: true,
},
})

View File

@@ -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`:
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
// ...

View File

@@ -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.

View File

@@ -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.

View File

@@ -60,6 +60,7 @@ export default buildConfig({
| `schemaName` (experimental) | A string for the postgres schema to use, defaults to 'public'. |
| `idType` | A string of 'serial', or 'uuid' that is used for the data type given to id columns. |
| `transactionOptions` | A PgTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
| `disableCreateDatabase` | Pass `true` to disale auto database creation if it doesn't exist. Defaults to `false`. |
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |
| `versionsSuffix` | A string appended to the end of table names for storing versions. Defaults to '_v'. |
@@ -98,7 +99,7 @@ Alternatively, you can disable `push` and rely solely on migrations to keep your
In Postgres, migrations are a fundamental aspect of working with Payload and you should become familiar with how they work.
For more information about migrations, [click here](/docs/beta/database/migrations#when-to-run-migrations).
For more information about migrations, [click here](./migrations#when-to-run-migrations).
## Drizzle schema hooks

View File

@@ -78,7 +78,7 @@ Alternatively, you can disable `push` and rely solely on migrations to keep your
In SQLite, migrations are a fundamental aspect of working with Payload and you should become familiar with how they work.
For more information about migrations, [click here](/docs/beta/database/migrations#when-to-run-migrations).
For more information about migrations, [click here](./migrations#when-to-run-migrations).
## Drizzle schema hooks

View File

@@ -8,7 +8,7 @@ desc: Database transactions are fully supported within Payload.
Database transactions allow your application to make a series of database changes in an all-or-nothing commit. Consider an HTTP request that creates a new **Order** and has an `afterChange` hook to update the stock count of related **Items**. If an error occurs when updating an **Item** and an HTTP error is returned to the user, you would not want the new **Order** to be persisted or any other items to be changed either. This kind of interaction with the database is handled seamlessly with transactions.
By default, Payload will use transactions for all operations, as long as it is supported by the configured database. Database changes are contained within all Payload operations and any errors thrown will result in all changes being rolled back without being committed. When transactions are not supported by the database, Payload will continue to operate as expected without them.
By default, Payload will use transactions for all data changing operations, as long as it is supported by the configured database. Database changes are contained within all Payload operations and any errors thrown will result in all changes being rolled back without being committed. When transactions are not supported by the database, Payload will continue to operate as expected without them.
<Banner type="info">
<strong>Note:</strong>
@@ -16,7 +16,7 @@ By default, Payload will use transactions for all operations, as long as it is s
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 opt in to using the same transaction by passing the `req` in the arguments. For example:
```ts
const afterChange: CollectionAfterChangeHook = async ({ req }) => {
@@ -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.
Example:
@@ -114,3 +114,18 @@ standalonePayloadScript()
## Disabling Transactions
If you wish to disable transactions entirely, you can do so by passing `false` as the `transactionOptions` in your database adapter configuration. All the official Payload database adapters support this option.
In addition to allowing database transactions to be disabled at the adapter level. You can prevent Payload from using a transaction in direct calls to the local API by adding `disableTransaction: true` to the args. For example:
```ts
await payload.update({
collection: 'posts',
data: {
some: 'data',
},
where: {
slug: { equals: 'my-slug' }
},
disableTransaction: true,
})
```

View File

@@ -6,7 +6,7 @@ desc: Array Fields are intended for sets of repeating fields, that you define. L
keywords: array, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Array Field is used when you need to have a set of "repeating" [Fields](./overview). It stores an array of objects containing fields that you define. These fields can be of any type, including other arrays to achieve infinitely nested structures.
The Array Field is used when you need to have a set of "repeating" [Fields](./overview). It stores an array of objects containing fields that you define. These fields can be of any type, including other arrays, to achieve infinitely nested data structures.
Arrays are useful for many different types of content from simple to complex, such as:
@@ -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 = {
// ...
@@ -66,10 +66,10 @@ _\* An asterisk denotes that a property is required._
## Admin Options
The customize the appearance and behavior of the Array Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
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 = {
// ...
@@ -81,18 +81,18 @@ export const MyArrayField: Field = {
The Array Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
| **`initCollapsed`** | Set the initial collapsed state |
| **`components.RowLabel`** | Function or React component to be rendered as the label on the array row. Receives `({ data, index, path })` as args |
| **`isSortable`** | Disable order sorting by setting this value to `false` |
| Option | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| **`initCollapsed`** | Set the initial collapsed state |
| **`components.RowLabel`** | React component to be rendered as the label on the array row. [Example](#example-of-a-custom-rowlabel-component) |
| **`isSortable`** | Disable order sorting by setting this value to `false` |
## Example
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.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -127,12 +127,27 @@ export const ExampleCollection: CollectionConfig = {
],
admin: {
components: {
RowLabel: ({ data, index }) => {
return data?.title || `Slide ${String(index).padStart(2, '0')}`
},
RowLabel: '/path/to/ArrayRowLabel#ArrayRowLabel',
},
},
},
],
}
```
### Example of a custom RowLabel component
```tsx
'use client'
import { useRowLabel } from '@payloadcms/ui'
export const ArrayRowLabel = () => {
const { data, rowNumber } = useRowLabel<{ title?: string }>()
const customLabel = `${data.title || 'Slide'} ${String(rowNumber).padStart(2, '0')} `
return <div>Custom Label: {customLabel}</div>
}
```

View File

@@ -24,7 +24,7 @@ Blocks are a great way to create a flexible content model that can be used to bu
To add a Blocks Field, set the `type` to `blocks` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyBlocksField: Field = {
// ...
@@ -67,7 +67,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Blocks 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 MyBlocksField: Field = {
// ...

View File

@@ -18,7 +18,7 @@ The Checkbox Field saves a boolean in the database.
To add a Checkbox Field, set the `type` to `checkbox` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyCheckboxField: Field = {
// ...
@@ -53,7 +53,7 @@ _\* An asterisk denotes that a property is required._
Here is an example of a Checkbox Field in a Collection:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -19,7 +19,7 @@ The Code Field saves a string in the database, but provides the [Admin Panel](..
To add a Code Field, set the `type` to `code` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyBlocksField: Field = {
// ...
@@ -57,7 +57,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Code 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 MyCodeField: Field = {
// ...
@@ -79,7 +79,7 @@ The Code Field inherits all of the default options from the base [Field Admin Co
`collections/ExampleCollection.ts
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Collapsible Field is presentational-only and only affects the Admin Panel. B
To add a Collapsible Field, set the `type` to `collapsible` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyCollapsibleField: Field = {
// ...
@@ -47,7 +47,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Collapsible 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 MyCollapsibleField: Field = {
// ...
@@ -68,7 +68,7 @@ The Collapsible Field inherits all of the default options from the base [Field A
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Date Field saves a Date in the database and provides the [Admin Panel](../ad
To add a Date Field, set the `type` to `date` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyDateField: Field = {
// ...
@@ -53,7 +53,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Date 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 MyDateField: Field = {
// ...
@@ -97,7 +97,7 @@ When only `pickerAppearance` is set, an equivalent format will be rendered in th
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Email Field enforces that the value provided is a valid email address.
To create an Email Field, set the `type` to `email` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyEmailField: Field = {
// ...
@@ -54,7 +54,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Email 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 MyEmailField: Field = {
// ...
@@ -76,7 +76,7 @@ The Email Field inherits all of the default options from the base [Field Admin C
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Group Field allows [Fields](./overview) to be nested under a common property
To add a Group Field, set the `type` to `group` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyGroupField: Field = {
// ...
@@ -58,7 +58,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Group 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 MyGroupField: Field = {
// ...
@@ -79,7 +79,7 @@ The Group Field inherits all of the default options from the base [Field Admin C
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,8 +6,10 @@ desc: The Join field provides the ability to work on related documents. Learn ho
keywords: join, relationship, junction, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Join Field is used to make Relationship fields in the opposite direction. It is used to show the relationship from
the other side. 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.
@@ -16,20 +18,21 @@ The Join field is useful in scenarios including:
- To surface `Order`s for a given `Product`
- To view and edit `Posts` belonging to a `Category`
- To work with any bi-directional relationship data
- Displaying where a document or upload is used in other documents
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/join.png"
srcDark="https://payloadcms.com/images/docs/fields/join-dark.png"
alt="Shows Join field in the Payload Admin Panel"
caption="Admin Panel screenshot of Join field"
srcLight="https://payloadcms.com/images/docs/fields/join.png"
srcDark="https://payloadcms.com/images/docs/fields/join-dark.png"
alt="Shows Join field in the Payload Admin Panel"
caption="Admin Panel screenshot of Join field"
/>
For the Join field to work, you must have an existing [relationship](./relationship) field in the collection you are
joining. This will reference the collection and path of the field of the related documents.
For the Join field to work, you must have an existing [relationship](./relationship) or [upload](./upload) field in the
collection you are joining. This will reference the collection and path of the field of the related documents.
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
@@ -49,8 +52,7 @@ export const MyRelationshipField: Field = {
```
In this example, the field is defined to show the related `posts` when added to a `category` collection. The `on`
property is used to
specify the relationship field name of the field that relates to the collection document.
property is used to specify the relationship field name of the field that relates to the collection document.
With this example, if you navigate to a Category in the Admin UI or an API response, you'll now see that the Posts which
are related to the Category are populated for you. This is extremely powerful and can be used to define a wide variety
@@ -111,30 +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`, 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.
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.
## Config Options
| Option | Description |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`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 relationship field name of the field that relates to 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 |
| Option | Description |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`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. |
| **`admin`** | Admin-specific configuration. [More details](#admin-config-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
_\* An asterisk denotes that a property is required._
## Admin Config Options
You can control the user experience of the join field using the `admin` config properties. The following options are supported:
| Option | Description |
|------------------------|----------------------------------------------------------------------------------------|
| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. |
| **`components.Label`** | Override the default Label of the Field Component. [More details](#the-label-component). |
## Join Field Data
When a document is returned that for a Join field is populated with related documents. The structure returned is an
@@ -151,12 +165,12 @@ object with:
{
"id": "66e3431a3f23e684075aaeb9",
// other fields...
"category": "66e3431a3f23e684075aae9c",
},
"category": "66e3431a3f23e684075aae9c"
}
// { ... }
],
"hasNextPage": false
},
}
// other fields...
}
```
@@ -169,11 +183,11 @@ returning. This is useful for performance reasons when you don't need the relate
The following query options are supported:
| Property | Description |
|-------------|--------------------------------------------------------------|
| **`limit`** | The maximum related documents to be returned, default is 10. |
| **`where`** | An optional `Where` query to filter joined documents. |
| **`sort`** | A string used to order related results |
| Property | Description |
|-------------|-----------------------------------------------------------------------------------------------------|
| **`limit`** | The maximum related documents to be returned, default is 10. |
| **`where`** | An optional `Where` query to filter joined documents. Will be merged with the field `where` object. |
| **`sort`** | A string used to order related results |
These can be applied to the local API, GraphQL, and REST API.
@@ -214,7 +228,8 @@ You can specify as many `joins` parameters as needed for the same or different j
### GraphQL
The GraphQL API supports the same query options as the local and REST APIs. You can specify the query options for each join field in your query.
The GraphQL API supports the same query options as the local and REST APIs. You can specify the query options for each
join field in your query.
Example:
@@ -227,9 +242,9 @@ query {
limit: 5
where: {
author: {
equals: "66e3431a3f23e684075aaeb9"
}
equals: "66e3431a3f23e684075aaeb9"
}
}
) {
docs {
title

View File

@@ -7,7 +7,7 @@ desc: The JSON field type will store any string in the Database. Learn how to us
keywords: json, jsonSchema, schema, validation, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The JSON Field saves actual JSON in the database, which differs from the Code field that saves the value as a string in the database.
The JSON Field saves raw JSON to the database and provides the [Admin Panel](../admin/overview) with a code editor styled interface. This is different from the [Code Field](./code) which saves the value as a string in the database.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/json.png"
@@ -19,7 +19,7 @@ The JSON Field saves actual JSON in the database, which differs from the Code fi
To add a JSON Field, set the `type` to `json` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyJSONField: Field = {
// ...
@@ -56,7 +56,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the JSON 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 MyJSONField: Field = {
// ...
@@ -77,7 +77,7 @@ The JSON Field inherits all of the default options from the base [Field Admin Co
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -102,7 +102,7 @@ If you only provide a URL to a schema, Payload will fetch the desired schema if
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -135,7 +135,7 @@ export const ExampleCollection: CollectionConfig = {
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Number Field stores and validates numeric entry and supports additional nume
To add a Number Field, set the `type` to `number` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyNumberField: Field = {
// ...
@@ -59,7 +59,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Number 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 MyNumberField: Field = {
// ...
@@ -82,7 +82,7 @@ The Number Field inherits all of the default options from the base [Field Admin
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -93,6 +93,7 @@ Presentational Fields do not store data in the database. Instead, they are used
Here are the available Presentational Fields:
- [Collapsible](/docs/fields/collapsible) - nests fields within a collapsible component
- [Join](/docs/fields/join) - achieves two-way data binding between fields
- [Row](/docs/fields/row) - aligns fields horizontally
- [Tabs (Unnamed)](/docs/fields/tabs) - nests fields within a tabbed layout
- [UI](/docs/fields/ui) - blank field for custom UI components
@@ -123,7 +124,7 @@ export const MyField: Field = {
### Field Names
All [Data Fields](#data-fields) require a `name` property. This is the key that will be used to store and retrieve the field's value in the database. This property must be unique within the Collection, Global, or nested group that it is defined in.
All [Data Fields](#data-fields) require a `name` property. This is the key that will be used to store and retrieve the field's value in the database. This property must be unique amongst this field's siblings.
To set a field's name, use the `name` property in your Field Config:
@@ -205,7 +206,7 @@ export const MyField: Field = {
}
```
Default values can be defined as a static value or a function that returns a value. When a `defaultValue` is defined statically, Payload's DB adapters will apply it to the database schema or models.
Default values can be defined as a static value or a function that returns a value. When a `defaultValue` is defined statically, Payload's [Database Adapters](../database/overview) will apply it to the database schema or models.
Functions can be written to make use of the following argument properties:
@@ -264,7 +265,7 @@ The following arguments are provided to the `validate` function:
#### Validation Context
The `ctx` argument contains full document data, sibling field data, the current operation, and other useful information such as currently authenticated in user:
The `ctx` argument contains full document data, sibling field data, the current operation, and other useful information such as currently authenticated user:
```ts
import type { Field } from 'payload'
@@ -356,9 +357,9 @@ 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`:
To define a custom ID field, add a top-level field with the `name` property set to `id`:
```ts
import type { CollectionConfig } from 'payload'
@@ -368,6 +369,7 @@ export const MyCollection: CollectionConfig = {
fields: [
{
name: 'id', // highlight-line
required: true,
type: 'number',
},
],

View File

@@ -18,7 +18,7 @@ The Point Field saves a pair of coordinates in the database and assigns an index
To add a Point Field, set the `type` to `point` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyPointField: Field = {
// ...
@@ -28,7 +28,7 @@ export const MyPointField: Field = {
<Banner type="warning">
<strong>Important:</strong>
The Point Field is currently only supported in MongoDB.
The Point Field currently is not supported in SQLite.
</Banner>
## Config
@@ -59,7 +59,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Radio Field allows for the selection of one value from a predefined set of p
To add a Radio Field, set the `type` to `radio` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRadioField: Field = {
// ...
@@ -69,7 +69,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Radio 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 MyRadioField: Field = {
// ...
@@ -83,14 +83,14 @@ The Radio Field inherits all of the default options from the base [Field Admin C
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`layout`** | Allows for the radio group to be styled as a horizonally or vertically distributed list. The default value is `horizontal`. |
| **`layout`** | Allows for the radio group to be styled as a horizontally or vertically distributed list. The default value is `horizontal`. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -24,7 +24,7 @@ The Relationship field is used in a variety of ways, including:
To add a Relationship Field, set the `type` to `relationship` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRelationshipField: Field = {
// ...
@@ -74,7 +74,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Relationship 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 MyRelationshipField: Field = {
// ...
@@ -90,6 +90,7 @@ The Relationship Field inherits all of the default options from the base [Field
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **`isSortable`** | Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany` is set to `true`). |
| **`allowCreate`** | Set to `false` if you'd like to disable the ability to create new documents from within the relationship field. |
| **`allowEdit`** | Set to `false` if you'd like to disable the ability to edit documents from within the relationship field. |
| **`sortOptions`** | Define a default sorting order for the options within a Relationship field's dropdown. [More](#sortOptions) |
### Sort Options
@@ -158,7 +159,7 @@ called with an argument object with the following properties:
## Example
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -25,11 +25,7 @@ Right now, Payload is officially supporting two rich text editors:
<Banner type="success">
<strong>
Consistent with Payload's goal of making you learn as little of Payload as possible, customizing
and using the Rich Text Editor does not involve learning how to develop for a
{' '}
<em>Payload</em>
{' '}
rich text editor.
and using the Rich Text Editor does not involve learning how to develop for a{' '}<em>Payload</em>{' '}rich text editor.
</strong>
Instead, you can invest your time and effort into learning the underlying open-source tools that
@@ -63,7 +59,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Rich Text 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 MyRichTextField: Field = {
// ...

View File

@@ -18,7 +18,7 @@ The Row Field is presentational-only and only affects the [Admin Panel](../admin
To add a Row Field, set the `type` to `row` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRowField: Field = {
// ...
@@ -46,7 +46,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Select Field provides a dropdown-style interface for choosing options from a
To add a Select Field, set the `type` to `select` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MySelectField: Field = {
// ...
@@ -71,7 +71,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Select 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 MySelectField: Field = {
// ...
@@ -93,7 +93,7 @@ The Select Field inherits all of the default options from the base [Field Admin
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -156,8 +156,7 @@ You can import the existing Select component directly from Payload, then extend
```ts
import * as React from 'react';
import { SelectInput, useField } from 'payload/components/forms';
import { useAuth } from 'payload/components/utilities';
import { SelectInput, useAuth, useField } from '@payloadcms/ui';
type CustomSelectProps = {
path: string;

View File

@@ -18,7 +18,7 @@ The Tabs Field is presentational-only and only affects the [Admin Panel](../admi
To add a Tabs Field, set the `type` to `tabs` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyTabsField: Field = {
// ...
@@ -59,7 +59,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Text Field is one of the most commonly used fields. It saves a string to the
To add a Text Field, set the `type` to `text` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyTextField: Field = {
// ...
@@ -59,7 +59,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Text 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 MyTextField: Field = {
// ...
@@ -82,7 +82,7 @@ The Text Field inherits all of the default options from the base [Field Admin Co
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ The Textarea Field is nearly identical to the [Text Field](./text) but it featur
To add a Textarea Field, set the `type` to `textarea` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyTextareaField: Field = {
// ...
@@ -56,7 +56,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Textarea 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 MyTextareaField: Field = {
// ...
@@ -79,7 +79,7 @@ The Textarea Field inherits all of the default options from the base [Field Admi
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -18,7 +18,7 @@ With the UI Field, you can:
To add a UI Field, set the `type` to `ui` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyUIField: Field = {
// ...
@@ -28,14 +28,14 @@ export const MyUIField: Field = {
## Config Options
| Option | Description |
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | A unique identifier for this field. |
| **`label`** | Human-readable label for this UI field. |
| Option | Description |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | A unique identifier for this field. |
| **`label`** | Human-readable label for this UI field. |
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit View. [More](../admin/components/#field-component) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/components/#field-component) |
| **`admin.disableListColumn`** | Set `disableListColumn` to `true` to prevent the UI field from appearing in the list view column selector. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`admin.disableListColumn`** | Set `disableListColumn` to `true` to prevent the UI field from appearing in the list view column selector. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
@@ -44,7 +44,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,7 +6,8 @@ desc: Upload fields will allow a file to be uploaded, only from a collection sup
keywords: upload, images media, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Upload Field allows for the selection of a Document from a Collection supporting [Uploads](../upload/overview), and formats the selection as a thumbnail in the Admin Panel.
The Upload Field allows for the selection of a Document from a Collection supporting [Uploads](../upload/overview), and
formats the selection as a thumbnail in the Admin Panel.
Upload fields are useful for a variety of use cases, such as:
@@ -15,16 +16,16 @@ Upload fields are useful for a variety of use cases, such as:
- To give a layout building block the ability to feature a background image
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/upload.png"
srcDark="https://payloadcms.com/images/docs/fields/upload-dark.png"
alt="Shows an upload field in the Payload Admin Panel"
caption="Admin Panel screenshot of an Upload field"
srcLight="https://payloadcms.com/images/docs/fields/upload.png"
srcDark="https://payloadcms.com/images/docs/fields/upload-dark.png"
alt="Shows an upload field in the Payload Admin Panel"
caption="Admin Panel screenshot of an Upload field"
/>
To create an Upload Field, set the `type` to `upload` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyUploadField: Field = {
// ...
@@ -43,10 +44,13 @@ export const MyUploadField: Field = {
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`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. |
@@ -72,7 +76,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -97,7 +101,7 @@ prevent all, or a `Where` query. When using a function, it will be
called with an argument object with the following properties:
| Property | Description |
| ------------- | ----------------------------------------------------------------------------------------------------- |
|---------------|-------------------------------------------------------------------------------------------------------|
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property |
| `data` | An object containing the full collection or global document currently being edited |
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
@@ -127,3 +131,10 @@ You can learn more about writing queries [here](/docs/queries/overview).
unless you call the default upload field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
</Banner>
## Bi-directional relationships
The `upload` field on its own is used to reference documents in an upload collection. This can be considered a "one-way"
relationship. If you wish to allow an editor to visit the upload document and see where it is being used, you may use
the `join` field in the upload enabled collection. Read more about bi-directional relationships using
the [Join field](./join)

View File

@@ -35,6 +35,10 @@ Adding Payload to an existing Next.js app is super straightforward. You can eith
If you don't have a Next.js app already, but you still want to start a project from a blank Next.js app, you can create a new Next.js app using `npx create-next-app` - and then just follow the steps below to install Payload.
<Banner type="info">
<strong>Note:</strong> Next.js version 15 or higher is required for Payload.
</Banner>
#### 1. Install the relevant packages
First, you'll want to add the required Payload packages to your project and can do so by running the command below:
@@ -54,12 +58,12 @@ To install a Database Adapter, you can run **one** of the following commands:
- To install the [MongoDB Adapter](../database/mongodb), run:
```bash
pnpm i @payloadcms/db-mongodb
pnpm i @payloadcms/db-mongodb@beta
```
- To install the [Postgres Adapter](../database/postgres), run:
```bash
pnpm i @payloadcms/db-postgres
pnpm i @payloadcms/db-postgres@beta
```
<Banner type="success">

View File

@@ -13,7 +13,7 @@ In Payload the schema is controlled by your collections and globals. All you nee
Install `@payloadcms/graphql` as a dev dependency:
```bash
pnpm add @payloadcms/graphql --save-dev
pnpm add @payloadcms/graphql@beta -D
```
Run the following command to generate the schema:

View File

@@ -139,4 +139,4 @@ declare module 'payload' {
}
```
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.

46
docs/jobs-queue/jobs.mdx Normal file
View File

@@ -0,0 +1,46 @@
---
title: Jobs
label: Jobs
order: 40
desc: A Job is a set of work that is offloaded from your APIs and will be processed at a later date.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
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',
},
})
```

View File

@@ -0,0 +1,70 @@
---
title: Jobs Queue
label: Overview
order: 10
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 which is a very powerful feature of many application frameworks.
### Example use cases
**Non-blocking workloads**
You might need to perform some complex, slow-running 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 this logic directly in a hook, which would block your API response from returning until the expensive work is completed, you can queue a new Job and let it run at a later date.
Examples:
- Create vector embeddings from your documents, and keep them in sync as your documents change
- Send data to a third-party API on document change
- Trigger emails based on customer actions
**Scheduled actions**
If you need to schedule an action to be run or processed at a certain date in the future, you can queue a job with the `waitUntil` property set. This will make it so the job is not "picked up" until that `waitUntil` date has passed.
Examples:
- Process scheduled posts, where the scheduled date is at a time set in the future
- Unpublish posts at a given time
- Send a reminder email to a customer after X days of signing up for a trial
**Periodic sync or similar scheduled action**
Some applications may need to perform a regularly scheduled operation of some type. Jobs are perfect for this because you can execute their logic using `cron`, scheduled nightly, every twelve hours, or some similar time period.
Examples:
- You'd like to send emails to all customers on a regular, scheduled basis
- Periodically trigger a rebuild of your frontend at night
- Sync resources to or from a third-party API during non-peak times
**Offloading complex operations**
You may run into the need to perform computationally expensive functions which might slow down your main Payload API server(s). The Jobs Queue allows you to offload these tasks a separate compute resource rather than slowing down the server(s) that run your Payload APIs. With Payload Task definitions, you can even keep large dependencies out of your main Next.js bundle by dynamically importing them only when they are used. This keeps your Next.js + Payload compilation fast and ensures large dependencies do not get bundled into your Payload production build.
Examples:
- You need to create (and then keep in sync) vector embeddings of your documents as they change, but you use an open source model to generate embeddings
- You have a PDF generator that needs to dynamically build and send PDF versions of documents to customers
- You need to use a headless browser to perform some type of logic
- You need to perform a series of actions, each of which depends on a prior action and should be run in as "durable" of a fashion as possible
### How it works
There are a few concepts that you should become familiarized with before using Payload's Jobs Queue. We recommend learning what each of these does in order to fully understand how to leverage the power of Payload's Jobs Queue.
1. [Tasks](/docs/beta/jobs-queue/tasks)
1. [Workflows](/docs/beta/jobs-queue/workflows)
1. [Jobs](/docs/beta/jobs-queue/jobs)
1. [Queues](/docs/beta/jobs-queue/queues)
All of these pieces work together in order to allow you to offload long-running, expensive, or future scheduled work from your main APIs.
Here's a quick overview:
- A Task is a specific function that performs business logic
- Workflows are groupings of specific tasks which should be run in-order, and can be retried from a specific point of failure
- A Job is an instance of a single task or workflow which will be executed
- A Queue is a way to segment your jobs into different "groups" - for example, some to run nightly, and others to run every 10 minutes

120
docs/jobs-queue/queues.mdx Normal file
View File

@@ -0,0 +1,120 @@
---
title: Queues
label: Queues
order: 50
desc: A Queue is a specific group of jobs which can be executed in the order that they were added.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
Queues are the final aspect of Payload's Jobs Queue and deal with how to _run your jobs_. Up to this point, all we've covered is how to queue up jobs to run, but so far, we aren't actually running any jobs.
<Banner type="default">
A <strong>Queue</strong> is a grouping 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:
await fetch('/api/payload-jobs/run?limit=100&queue=nightly', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
},
});
```
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.
```ts
export default buildConfig({
// Other configurations...
jobs: {
access: {
run: ({ req }: { req: PayloadRequest }): boolean => {
// Allow logged in users to execute this endpoint (default)
if (req.user) return true
// If there is no logged in user, then check
// for the Vercel Cron secret to be present as an
// Authorization header:
const authHeader = req.headers.get('authorization');
return authHeader === `Bearer ${process.env.CRON_SECRET}`;
},
},
// Other job configurations...
}
})
```
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:
await payload.jobs.run({ queue: 'nightly', limit: 100 })
```
#### Bin script
Finally, you can process jobs via the bin script that comes with Payload out of the box.
```sh
npx payload jobs:run --queue default --limit 10
```
In addition, the bin script allows you to pass a `--cron` flag to the `jobs:run` command to run the jobs on a scheduled, cron basis:
```sh
npx payload jobs:run --cron "*/5 * * * *"
```

141
docs/jobs-queue/tasks.mdx Normal file
View File

@@ -0,0 +1,141 @@
---
title: Tasks
label: Tasks
order: 20
desc: A Task is a distinct function declaration that can be run within Payload's Jobs Queue.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
<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](/docs/beta/jobs-queue/jobs) or [Workflows](/docs/beta/jobs-queue/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:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |
| `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
handler: path.resolve(dirname, 'src/tasks/createPost.ts') + '#createPostHandler',
}
]
}
})
```
Then, the `createPost` file itself:
`src/tasks/createPost.ts:`
```ts
import type { TaskHandler } from 'payload'
export const createPostHandler: TaskHandler<'createPost'> = async ({ input, job, req }) => {
const newPost = await req.payload.create({
collection: 'post',
req,
data: {
title: input.title,
},
})
return {
output: {
postID: newPost.id,
},
}
}
```

View File

@@ -0,0 +1,150 @@
---
title: Workflows
label: Workflows
order: 30
desc: A Task is a distinct function declaration that can be run within Payload's Jobs Queue.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
<Banner type="default">
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:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |
| `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 uses the `tasks` argument to execute your predefined tasks.
// These are strongly typed!
handler: async ({ job, tasks }) => {
// This workflow first runs a task called `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. Here, we hard-code it to '1'
const output = await tasks.createPost('1', {
input: {
title: job.input.title,
},
})
// Once the prior task completes, it will run a task
// called `updatePost`
await tasks.updatePost('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 `inlineTask` 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, tasks, inlineTask }) => {
// Here, we run a predefined task.
// The `createPost` handler arguments and return type
// are both strongly typed
const output = await tasks.createPost('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 inlineTask('2', {
task: async ({ req }) => {
const newPost = await req.payload.update({
collection: 'post',
id: '2',
req,
retries: 3,
data: {
title: 'updated!',
},
})
return {
output: {
newPost
},
}
},
})
},
} as WorkflowConfig<'updatePost'>
]
}
})
```

View File

@@ -370,7 +370,12 @@ 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
headlessEditor.update(
() => {
headlessEditor.setEditorState(headlessEditor.parseEditorState(yourEditorState))
},
{ discrete: true }, // This should commit the editor state immediately
)
} catch (e) {
logger.error({ err: e }, 'ERROR parsing editor state')
}
@@ -382,8 +387,6 @@ headlessEditor.getEditorState().read(() => {
})
```
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
} catch (e) {
headlessEditor.update(
() => {
headlessEditor.setEditorState(headlessEditor.parseEditorState(yourEditorState))
},
{ discrete: true }, // This should commit the editor state immediately
)
} catch (e) {
logger.error({ err: e }, 'ERROR parsing editor state')
}

View File

@@ -52,7 +52,7 @@ const Pages: CollectionConfig = {
}
```
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, every time 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:

View File

@@ -178,7 +178,7 @@ Notice how even the toolbars are features? That's how extensible our lexical edi
## Creating your own, custom Feature
You can find more information about creating your own feature in our [building custom feature docs](lexical/building-custom-features).
You can find more information about creating your own feature in our [building custom feature docs](/docs/lexical/building-custom-features).
## TypeScript

View File

@@ -71,26 +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.
| Local Option | Description |
| ------------------ | ------------ |
| `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. |
| Local Option | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `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._

View File

@@ -36,7 +36,7 @@ Forms can be as simple or complex as you need, from a basic contact form, to a m
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-form-builder
pnpm add @payloadcms/plugin-form-builder@beta
```
## Basic Usage
@@ -138,7 +138,7 @@ const beforeEmail: BeforeEmail<FormSubmission> = (emailsToSend, beforeChangePara
### `defaultToEmail`
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.
| Property | Type | Description |
| -------------- | -------- | ---------------------------------------------------- | --- | -------------- | ------ | ------------------------------- |
| -------------- | -------- | ---------------------------------------------------- |
| `name` | string | The name of the field. |
| `label` | string | The label of the field. |
| `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:

View File

@@ -48,7 +48,7 @@ Install the plugin using any JavaScript package manager like [Yarn](https://yarn
or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-nested-docs
pnpm add @payloadcms/plugin-nested-docs@beta
```
## Basic Usage
@@ -177,7 +177,7 @@ You can also extend the built-in `parent` and `breadcrumbs` fields per collectio
and `createBreadcrumbField` methods. They will merge your customizations overtop the plugin's base field configurations.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
import { createParentField } from '@payloadcms/plugin-nested-docs/fields'
import { createBreadcrumbsField } from '@payloadcms/plugin-nested-docs/fields'

View File

@@ -32,7 +32,7 @@ For example, if you have a page at `/about` and you want to change it to `/about
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-redirects
pnpm add @payloadcms/plugin-redirects@beta
```
## Basic Usage

Some files were not shown because too many files have changed in this diff Show More