Compare commits

...

251 Commits

Author SHA1 Message Date
Sasha
5447004791 chore(plugin-stripe): replace deprecated import path 2025-01-09 23:54:49 +02:00
Germán Jabloñski
bdb96ddbcc fix(richtext-lexical): inline Block drawers opened when document mounts (#10480)
Fixes #10439
2025-01-09 20:54:09 +00:00
Sasha
686e48d171 feat: consolidates REST API handling, decouple from next.js (#10466)
This PR improves how we handle REST API.
Problems before:
* `packages/next/src/routes/rest/*` had a huge amount of code that
didn't depend on next.js at all.
* `packages/next/src/routes/rest/index.ts` itself was not only huge but
also really hard to follow. Every method (`GET`, `POST` etc. was almost
full copy of another).
* `packages/next/src/utilities` had some utilities like
`headersWithCors` or `createPayloadRequest` that again, weren't depend
on next.js and potentially can be used outside of next.js.

Now:
All the logic that's not related to next.js now is inside
`packages/payload`, `packages/next/src/routes/rest/index.ts` now is only
_40_ lines instead of 900+
Functions like `headersWithCors` are now implemented and exported in
`payload`. To keep bc, we re-export them from the same path but marked
as `@deprecated`.

You can attach Payload REST API to any backend framework that uses Fetch
API (like Remix / SolidStart / Bun / Hono) if you don't need the admin
panel in your server instance, but you still want to have REST API. The
main function [`handleEndpoints`

](https://github.com/payloadcms/payload/pull/10466/files#diff-82e97630068f9fc40256f3f46e06226215ab150d16012281810586b51b0cfd51R28)
accepts `Request` and returns `Response`.
It's also doable with Express, but you'd have to convert node.js'
req/res to fetch.
2025-01-09 15:34:03 -05:00
Jacob Fletcher
ae1542be26 feat: exports ListPreferences from payload (#10474)
The `ListPreferences` and `ColumnPreferences` types were defined
multiple times in different places, making it difficult to make changes
across the board. Now, the `ListPreferences` type is exported directly
from `payload` alongside the other preferences types, and
`ColumnPreferences` has been merged directly into this type to simplify
usage as this is not a standalone preference.
2025-01-09 12:36:23 -05:00
Alessio Gravili
34a0d006cf fix(payload-cloud): infinite recursion on init (#10467) 2025-01-09 08:34:31 -07:00
Jacob Fletcher
a78bc6c65e fix(next): properly instantiates locale context (#10451)
Currently, unless a locale is present in the URL search params, the
locale context is instantiated using the default locale until prefs load
in client-side. This causes the locale selector to briefly render in
with the incorrect (default) locale before being replaced by the proper
locale of the request. For example, if the default locale is `en`, and
the page is requested in `es`, the locale selector will flash with
English before changing to the correct locale, even though the page data
itself is properly loaded in Spanish. This is especially evident within
slow networks.

The fix is to query the user's locale preference server-side and thread
it into the locale provider to initialize state. Because search params
are not available within server layouts, we cannot pass the locale param
in the same way, so we rely on the provider itself to read them from the
`useSearchParams` hook. If present, this takes precedence over the
user's preference if it exists.

Since the root page also queries the user's locale preference to
determine the proper locale across navigation, we use React's cache
function to dedupe these function calls and ensure only a single query
is made to the db for each request.
2025-01-08 23:57:42 -05:00
Germán Jabloñski
36e50dd6a6 feat(payload-cloud): set up cron jobs on init (#10106)
If the user has tasks configured, we set up cron jobs on init.
We also make sure to only run on one instance using a instance
identifier stored in a global.

This adds a new property to the payloadCloudPlugin: `jobs`.
2025-01-08 23:30:32 -05:00
Jacob Fletcher
6a262ab809 fix: properly validates preferences json (#10465)
It is currently possible to set all types of valid JSON within the
`payload-preferences` collection via the REST API, but not the Local
API. For example, locales are currently saved as plain strings to the
`value` field, something that is only possible through REST. This is
because there is a custom POST handler that submits the data directly to
the db using the update operation itself, bypassing typical `json` field
validation. However, when using the Local API, it does not behave in the
same way, and throws a validation error instead. The fix is to add a
custom `validate` function to this field that attempts to parse the
value, and if it succeeds, returns true. This way both APIs behave the
same.
2025-01-08 23:19:50 -05:00
Dan Ribbens
3349a4c5e5 fix: schedule publish allowed before saving draft (#10461)
### What?

In the scheduled publish feature, it is possible to open the modal to
schedule publishing a document even before you have saved a draft. This
change removes the option to open the drawer to even attempt this.
This also fixes an issue if you do not have permission to publish, you
cannot schedule publish either.

### Why?

There were numerous problems:
1. The schedule publish events would show all other publish events for
the collection without an ID in the query
2. Scheduling a publish would not work without an ID for a document to
publish

### How?
Removes the Schedule Publish menu item and drawer if you are on a
collection without an ID or you do not have permission to publish.

Without an ID:
![Screenshot 2025-01-08
162850](https://github.com/user-attachments/assets/fae0b8d4-6dac-45d7-a565-63fede7aa372)

With an ID:
![Screenshot 2025-01-08
162918](https://github.com/user-attachments/assets/c1f4d4f5-1321-43c1-991d-29747db1685d)

Perviously, you would always have the option to Schedule Publish.
2025-01-08 23:18:25 -05:00
Dan Ribbens
81c1e47747 feat: export the default JWTAuthentication strategy (#10430)
### What?
Export the default Payload JWTAuthentication strategy function for
extending and using in your own custom auth strategies that need to rely
on JWT.

### Why?
This makes it more simple to implement your own custom auth strategy.
All you need to do is set a valid JWT token as a cookie and then import
the default auth strategy so that the user will be recognized.

### How?
Exports the function and makes it reusable by adding a to the args a
strategyName prop. In the `executeAuthStrategies` function we assign the
strategyName from the configured `auth.strategies` own `name` property.
2025-01-08 23:18:07 -05:00
Paul
5318d24601 chore(templates): generate new migrations for vercel (#10458) 2025-01-08 20:40:52 +00:00
Paul
d9ff2e08dc templates: adjusted the cron job schedule so its compatible with hobby tiers as well (#10457) 2025-01-08 20:14:56 +00:00
Germán Jabloñski
c0dc0cca37 feat: autoRun jobs (#10401)
This pull request introduces the ability to configure cron jobs for
automatically running tasks in the job queue.
2025-01-08 14:51:26 -05:00
Paul
7321f9f3d5 templates: add support for scheduled publish to the website template [no lint] (#10455)
Adds configuration for vercel cron jobs and scheduled publish/unpublish
in website templates
2025-01-08 13:43:47 -06:00
Jarrod Flesch
17e7ee2315 fix(ui): stale doc status when publishing, reverting and unpublishing (#10405)
### What?
The status indicator was not updating properly when users were clicking
"unpublish" and "revert changes"

### Why?
hasPublishedDoc, unpublishedVersionCount and
mostRecentVersionIsAutosaved states were not being updated properly.

### How?
This PR updates the variables when interacting with the status actions
and sets mostRecentVersionIsAutosaved to false when the publish button
is clicked.

Fixes https://github.com/payloadcms/payload/issues/9531
2025-01-08 10:10:48 -05:00
Patrik
9701fc6970 fix(ui): removes edit drawer button from uploads collection edit view (#10426)
### What?

Previously, the `uploads` collection edit view contained an unnecessary
button in the file details which allowed opening the same document in a
drawer.

### Why?

This button was left over from `v2` when it was originally built to
allow editing of uploads from different collection edit views that had
`upload` type fields (relationship) within them.

This edit drawer button is now a separate button on the Upload
relationship component
[here](4d7587d26a/packages/ui/src/fields/Upload/RelationshipContent/index.tsx (L109)).

### How?

Removes edit drawer button from the FileDetails component.

#### Before:
![Screenshot 2025-01-07 at 1 49
18 PM](https://github.com/user-attachments/assets/50b2e789-69e7-47a5-99b8-ddbe1bf42f03)

#### After:
![Screenshot 2025-01-07 at 1 47
51 PM](https://github.com/user-attachments/assets/31a56aac-cb96-4fda-bad5-00759820da02)
2025-01-08 09:06:50 -05:00
Jarrod Flesch
ac97bfdc47 chore: import copy icon from nested folder (#9223)
Corrects imports in templates to go directly to
`@payloadcms/ui/path-to-file` instead of using the barrel export.
2025-01-08 08:37:29 -05:00
Elliot DeNolf
81188fc8bb chore(release): v3.15.1 [skip ci] 2025-01-07 21:49:22 -05:00
Elliot DeNolf
7a21b44bbf fix: vercel upload adapter warning false positive (#10434)
Adjust logic for warning message.
2025-01-07 21:47:49 -05:00
Jacob Fletcher
b09275419a fix: deprecates admin.disable property (#10429)
Fixes #10284. The `admin.disable` property is no longer supported as of
v3. Instead, to opt-out of serving the Admin Panel, REST API, or GraphQL
API, you must delete their corresponding directories within your Next.js
app. For example, to opt-out of everything, delete the `/app/(payload)`
directory entirely. Or to remove specifically the Admin Panel or API
routes, delete the `/app/(payload)/admin` or `/app/(payload)/api`
directories, respectively. Note: if you've modified the default paths
for these routes via `admin.routes`, delete those directories instead.
2025-01-07 20:28:05 +00:00
Germán Jabloñski
4d7587d26a fix(richtext-lexical): fix default arg in normalizeMarkdown (#10424)
Fix https://github.com/payloadcms/payload/issues/10387

The default argument was true and then in the nested function false.
2025-01-07 13:26:19 -05:00
Elliot DeNolf
a5443a1c6c chore(release): v3.15.0 [skip ci] 2025-01-07 12:46:11 -05:00
Alessio Gravili
08fb159943 feat: allow running sub-tasks from tasks (#10373)
Task handlers now receive `inlineTask` as an arg, which can be used to
run inline sub-tasks. In the task log, those inline tasks will have a
`parent` property that points to the parent task.

Example:

```ts
{
        slug: 'subTask',
        inputSchema: [
          {
            name: 'message',
            type: 'text',
            required: true,
          },
        ],
        handler: async ({ job, inlineTask }) => {
          await inlineTask('create two docs', {
            task: async ({ input, inlineTask }) => {
            
              const { newSimple } = await inlineTask('create doc 1', {
                task: async ({ req }) => {
                  const newSimple = await req.payload.create({
                    collection: 'simple',
                    req,
                    data: {
                      title: input.message,
                    },
                  })
                  return {
                    output: {
                      newSimple,
                    },
                  }
                },
              })

              const { newSimple2 } = await inlineTask('create doc 2', {
                task: async ({ req }) => {
                  const newSimple2 = await req.payload.create({
                    collection: 'simple',
                    req,
                    data: {
                      title: input.message,
                    },
                  })
                  return {
                    output: {
                      newSimple2,
                    },
                  }
                },
              })
              return {
                output: {
                  simpleID1: newSimple.id,
                  simpleID2: newSimple2.id,
                },
              }
            },
            input: {
              message: job.input.message,
            },
          })
        },
      } as WorkflowConfig<'subTask'>
```

Job log example:

```ts
[
  {
    executedAt: '2025-01-06T03:55:44.682Z',
    completedAt: '2025-01-06T03:55:44.684Z',
    taskSlug: 'inline',
    taskID: 'create doc 1',
    output: { newSimple: [Object] },
    parent: { taskSlug: 'inline', taskID: 'create two docs' }, // <= New
    state: 'succeeded',
    id: '677b5440ba35d345d1214d1b'
  },
  {
    executedAt: '2025-01-06T03:55:44.690Z',
    completedAt: '2025-01-06T03:55:44.692Z',
    taskSlug: 'inline',
    taskID: 'create doc 2',
    output: { newSimple2: [Object] },
    parent: { taskSlug: 'inline', taskID: 'create two docs' }, // <= New
    state: 'succeeded',
    id: '677b5440ba35d345d1214d1c'
  },
  {
    executedAt: '2025-01-06T03:55:44.681Z',
    completedAt: '2025-01-06T03:55:44.697Z',
    taskSlug: 'inline',
    taskID: 'create two docs',
    input: { message: 'hello!' },
    output: {
      simpleID1: '677b54401e34772cc63c8693',
      simpleID2: '677b54401e34772cc63c8697'
    },
    parent: {},
    state: 'succeeded',
    id: '677b5440ba35d345d1214d1d'
  }
]
```
2025-01-07 17:24:00 +00:00
Paul
ab53ababc8 fix(ui): drawer component missing closing bracket in style calc (#10411) 2025-01-07 16:25:32 +00:00
Alessio Gravili
b774f557be docs: minor lexical docs improvements (#10414) 2025-01-07 16:22:40 +00:00
Boyan Bratvanov
7fc6227310 fix(richtext-lexical): make div container optional (#10383)
Makes the wrapper container `<div class='payload-richtext'>` optional.
This is useful when importing and re-using the `<RichText/>` component
as part of another custom component already providing a container.
2025-01-07 09:55:50 -06:00
Alessio Gravili
827c75a3d2 fix(richtext-lexical): formatted inline code resulted in incorrect markdown export (#10413)
If the following markdown:

```md
**`text`**
```

was imported and then re-exported, the result was

```md
`**text**`
```

Which would have been rendered as

```html
<code>**text**</code>
```

Instead of

```html
<strong><code>text</code></strong>
```
2025-01-07 06:13:00 +00:00
Jacob Fletcher
5991a2e60f test: fixes flaky localization e2e once and for all (#10406)
The localization e2e test is notorious for flaking, consuming a lot of
time and resources continually retrying. This was because the test was
attempting to click DOM elements using selectors that never resolve, or
attempting to click inaccessible DOM nodes such as those behind a modal.
The fix is to ensure that the dot nav, for example, is disabled while
form state loads, and that modals are properly closed prior to executing
subsequent tests, etc. Tests also needed to explicitly check for
_enabled_ states before performing click actions, rather than simply
awaiting their visibility.
2025-01-07 04:45:38 +00:00
Alessio Gravili
ef7191b39a fix(next): live preview tab did not display custom edit view components (#10412)
This PR passes them through the same way it's done in the default edit
view tab
2025-01-07 03:13:38 +00:00
Paul
c7f21fc2e2 fix(email-resend): add reply_to to the API when sending emails (#10407)
Fixes https://github.com/payloadcms/payload/issues/10361

Adds reply_to to the resend mapping
2025-01-06 23:54:32 +00:00
Jacob Fletcher
a83a430a3a fix(ui): sort resets columns (#10402)
Fixes #10018. When toggling columns, then sorting them, the table is
reset to the collection's default columns instead of the user's
preferred columns. This is because when sorting columns, a stale
client-side cache of the user's preferences is used to update their sort
preference. This is because when column state is constructed
server-side, it completely bypasses the client-side cache. To fix this,
sort preferences are now also set on the server right alongside column
preferences, which performs an upsert-like operation to ensure that no
existing preferences are lost.
2025-01-06 16:57:19 -05:00
Amir Aryan
df827c0fdd chore(examples): set HTML dir attribute for RTL locales #10344 (#10345)
fix [#10344](https://github.com/payloadcms/payload/issues/10344)

The template was missing defining direction.

direction property is necessary because HTML direction will be LTR for
RTL languages by default.
2025-01-06 14:40:22 -06:00
Paul
398b6096f2 templates: fix nested docs url generation for categories (#10403)
Fixes https://github.com/payloadcms/payload/issues/10374
2025-01-06 14:18:54 -06:00
Patrik
eadce5ea57 fix: extends type all to the locale type definition in req (#10399)
### What?

If you query with all locales using the `'all'` value for locales, the
`req.locale` value is `'all'` but the type definition only contains the
available locales.

### Why?

The `CustomPayloadRequestProperties.locale` property was only being
typed as `TypedLocale` and was not extending `'all'.`

### How?

Extends type all to the locale type definition in req

Fixes #10244
2025-01-06 15:18:08 -05:00
Elliot DeNolf
f629709797 fix: increase safety of findConfig (#10400)
If `@payload-config` is not set in tsconfig, findConfig could fail when
performing a `path.extname` on an undefined value.

Example error in this scenario:
```
TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received undefined.
```
2025-01-06 14:11:11 -05:00
Germán Jabloñski
d772b2b7eb fix(richtext-lexical): modify JSXConvertersFunction type to support block types in strict mode (#10398)
Reproduction steps:
1. Set `strict: true` in `templates/website/tsconfig.json`
2. You will find a ts error in
`templates/website/src/components/RichText/index.tsx`.

This is because the blockType property of blocks is generated by Payload
as a literal (e.g. "mediaBlock") and cannot be assigned to a string.

To test this PR, you can make the change to `JSXConvertersFunction` in
node_modules of the website template
2025-01-06 18:01:38 +00:00
Elliot DeNolf
22c4dee5a0 feat: warn if deploying to vercel and any upload collection missing storage adapter (#10391)
A large number of users have been confused why their upload collection
doesn't work as expected when deploying to Vercel. This is because by
default, Payload uses local disk storage for file uploads - which will
not function properly in that environment.

This adds a warning if a user is deploying on Vercel, and they have any
upload collection missing an adapter - aka, writing to disk.
2025-01-06 16:21:07 +00:00
Sasha
c1abd16a7f templates: use cross-env in the plugin template to achieve compatibility with Windows (#10390)
### What?
Uses `cross-env` for the `dev:payload` script in the plugin template.

### Why?
To achieve compatibility with Windows. 

### How?
Adds `cross-env` as a dev dependency and modifies the `dev:payload`
script.
2025-01-06 18:00:12 +02:00
bakaptr
d2127335b9 fix: handle withoutEnlargement for undefined height or width (#10078)
<!--

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?

This patch implements the functionality in `imageResizer` to omit the
generation of the image when either width or height is undefined and
`withoutEnlargement` is set to `undefined`

### Why?

#9986: `withoutEnlargement` doesn't work when `height` is undefined in
`upload.imageSizes`

### How?

This code checks if `withoutEnlargement` is undefined and either
`targetWidth` or `targetHeight` is missing. If so, it further checks
whether the target dimensions (if provided) are larger than the original
image dimensions. If the target would enlarge the image, it returns
'omit', skipping the resizing to prevent enlargement

Fixes #9986

---------

Co-authored-by: Patrik Kozak <patrik@payloadcms.com>
2025-01-06 10:50:44 -05:00
Sasha
1525cc6e3a fix(db-postgres): handle undefined fallback for adapter.schemaName in relationships migration (#10384)
Fixes from https://github.com/payloadcms/payload/pull/10322
2025-01-06 15:19:21 +00:00
Boyan Bratvanov
53aea622f9 docs: fix all other links to live-preview example (#10385)
Continuation of #10380.
2025-01-06 10:15:25 -05:00
Elliot DeNolf
422e8e3620 chore(templates): unpin payload packages (#10386)
Unpin payload package versions in templates.

Generated w/ `pnpm script:gen-templates`
2025-01-06 10:07:53 -05:00
Nacho Martin
556b8ed393 fix(db-postgres): added missing quotes and schema name to sql statement in v2-v3 migration (#10322)
### What?

* Added missing schema name to the SQL statement
* Added missing quotes to the `parent_id`'s in the SQL statement

### Why?

* Migrations script isn't working for databases that don't use the
`public` schema
* They were missing, causing the database to throw an error.

### Fixes:

- [Discord
Discussion](https://discord.com/channels/967097582721572934/1319313926885736448)
- [Discord
Discussion](https://discord.com/channels/967097582721572934/1324352204915609661)
- [Discord
Discussion](https://discord.com/channels/967097582721572934/1323445259606429716)

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2025-01-06 16:40:32 +02:00
Said Akhrarov
0ce7c666d2 templates: prevent plugin template from including nested next folder in git (#10364)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR adjusts the `.gitignore` file in the plugin template to prevent
tracking of the nested `.next` folder.

### Why?
The existing rule excludes a top-level `.next` folder. However, in the
plugin template, next generates the folder in `/dev` instead.

### How?
Adjusting `.gitignore` to consider that `.next` may be nested in
different folders.

Notes:
- Initially I made it explicit, after judging the rest of the file I
realized not everyone likes explicit rules so I simplified. Both
`**/.next/` & `.next/` should be functionally equivalent though.
2025-01-06 16:10:07 +02:00
Danilo Lemes
fd52de6d8f docs: fix CORS anchor link (#10333) 2025-01-06 08:26:49 -05:00
Boyan Bratvanov
1e247f8509 docs: fix link to live-preview example and remove empty placeholder (#10380) 2025-01-06 08:22:53 -05:00
Alessio Gravili
1a9fba5f00 chore: export RunInlineTaskFunction type (#10372) 2025-01-06 04:00:17 +00:00
Alessio Gravili
4a15b866e0 feat(next): pass through query params from document view to find operations (#10343)
Say you opened
`http://localhost:3000/admin/collections/posts/67786e917283ec71ce4ab058?branch=main`,
the `branch=main` query param would not be passed to the find operation.

This means that reading `req.query` in, say, an `afterRead` hook, you
would get an empty object back.

This PR threads through `query`, `search` and `searchParams` with the
main goal of making them accessible in hooks.

## Use-case

Custom branch selector component in a collection's edit view.

Select branch => `branch` query param is added to the URL.

Collection `afterRead` hook then fetches the respective content from
that branch (which it gets from `req.query`) and returns its data
2025-01-05 19:31:28 -07:00
Alessio Gravili
5ba477b810 chore(examples): remove outdated testing example (#10370)
This deletes the outdated testing example, as it has not been updated to
Payload v3 yet.

We can add it back in the future once we updated it. Generally, the
Next.js testing docs should now be valid:
https://nextjs.org/docs/app/building-your-application/testing. However,
it might still make sense to provide a v3 testing example to showcase
things like booting up an in-memory db
2025-01-06 00:43:53 +00:00
Jacob Fletcher
8d245283b3 chore(deps): bumps react-datepicker to v7.6.0 to suppress react 19 warnings (#10366) 2025-01-05 19:21:53 -05:00
Alessio Gravili
09d6c60e96 chore(richtext-lexical): improve block not found error message (#10348) 2025-01-04 05:16:26 +00:00
Said Akhrarov
5e4e27460e docs: fix links and formatting (#10346)
### What?
This PR fixes numerous links across the docs, both internal docs links
and external links. This PR also fixes some minor formatting issues in
some places, as well as optically aligns the markdown tables in tables
that had broken links.

### Why?
To properly link readers to the correct location in the docs, and for
better formatting and easier consumption.

### How?
Changes to many `.mdx` files in the `docs` folder.

Notes:
- There are duplicative section id's in `docs/authentication/email.mdx`,
I've fixed one such link, but have left it as is for now.
2025-01-03 21:41:33 -07:00
Germán Jabloñski
be84ad7bfa fix(ui): make relationship fields update the collection when it is changed in the drawer dropdown (#10338)
To reproduce the bug:
1. Within a Lexical editor, insert a relationship field.
2. In the drawer, change the selected collection.
3. The table below changes correctly, but the title and the "create new"
button quickly revert to the original option.


https://github.com/user-attachments/assets/e4b7c615-4b98-4c11-a4b9-a828606edb6f



<!--

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 #

-->
2025-01-03 21:11:43 +00:00
James Mikrut
3ea1d393fd fix(ui): properly reflects hook changes in ui (#10268)
Fixes #9882 and #9691

In 2.0, we would accept data coming back from an update operation and
then reflect those changes in UI.

However, in 3.0, we did not do that anymore - meaning you could change a
document with hooks in `beforeChange` or `afterChange`, but then not see
the changes made on the server.

This PR updates the way that `mergeServerFormState` works, and adds a
property to optionally allow values from server form state - which can
then be used in the `onSuccess` form handler which may need to define
new field values.
2025-01-03 14:55:52 -05:00
Jacob Fletcher
b44aadee65 fix(ui): ensures list drawer does not change underlying step nav (#10339)
When opening the list drawer, such as when selecting an existing upload,
the underlying step nav of the document view changes but shouldn't.
2025-01-03 19:48:55 +00:00
Sasha
ba228dd0f3 fix: allow to set maxDepth: 0 for join fields, improve join field JSDoc (#10336)
Allows to set `maxDepth: 0` for join fields and improves JSDoc about
`maxDepth`, adds tests to confirm that
https://github.com/payloadcms/payload/issues/10243 is not an issue, but
just happens because the default `maxDepth` is `1`.
2025-01-03 14:25:19 -05:00
Sasha
c7b3204439 fix: copy to locale with localized arrays and blocks generate new IDs to prevent errors in postgres (#10292)
Fixes https://github.com/payloadcms/payload/issues/10093
2025-01-03 14:23:16 -05:00
Anders Semb Hermansen
d68a1eaafb fix(storage-vercel-blob): return 404 when file is not found (#10327)
### What

The vercel storage adapter returns a 500 internal server error when a
file is not found.
It's expected that it will return 404 when a file is not found.

### Why

The `head` function from vercel blob sdk does not return undefined when
a blob is not found, but throws an error as documented here:
https://vercel.com/docs/storage/vercel-blob/using-blob-sdk#head

### How

Check if exception thrown is of type BlobNotFoundError and return a 404
in that case.

### Testing

***Note***: I have not been able to test this inside payload itself as
I'm unable to build a package to test with. I have tested the
implementation outside. Is it possible to get a canary build so proper
testing with package can be done?

Fixes #10326
2025-01-03 13:52:32 -05:00
Jacob Fletcher
1f4790a314 chore(examples): removes all instances of React.forwardRef (#10334)
Similar to #10331. Since React 19, refs can now be passed directly
through props without the need for `React.forwardRef`. This greatly
simplifies components types and overall syntax.
2025-01-03 18:10:46 +00:00
Jacob Fletcher
47e8158d1e chore(templates): removes all instances of React.forwardRef (#10331)
Fixes #10325. Since React 19, refs can now be passed directly through
props without the need for `React.forwardRef`. This greatly simplifies
components types and overall syntax.
2025-01-03 17:39:31 +00:00
Said Akhrarov
1cade17440 feat(next): adds support for resetting preferences (#10304)
This PR adds a button to the `/account` view which allows users to reset
their preferences on-demand. This is to that editors can quickly reset their
preferences via the admin ui without the need of accessing the db directly,
which was simply not possible before. To do this, we add a new button at
the bottom of the account view which performs a standard `DELETE`
request using the REST API to the `'payload-preferences'` collection.

Related: #9949

Demo: [Posts-reset-prefs--Payload.webm](https://github.com/user-attachments/assets/560cbbe3-06ef-4b7c-b3c2-9702883b1fc6)
2025-01-03 12:08:15 -05:00
Germán Jabloñski
5997aa1c69 fix(richtext-lexical): open inline block drawer on mount (#10318)
fix #9816
2025-01-03 09:54:46 -07:00
Jacob Fletcher
f2fab39d67 fix(live-preview-react): allows react peer deps of v16.8.0 or later (#10328)
Since the `@payloadcms/live-preview-react` package could be installed
within headless front-ends, it does not necessarily need to be
restricted to only React 19. This package does not use any newer React
features since hooks were introduced in v16.8.0. For this reason, the
peer deps have been loosened to allow this and all other major versions
up to React 19. This change was first introduced in #6387.
2025-01-03 16:41:02 +00:00
Jarrod Flesch
e97c43eec3 fix: adds path to server field component prop types (#10330)
### What?
`path` was missing in server component prop types.

### How?
Adds a BaseFieldServerProps for each field type that accepts takes
`path` as a prop.
2025-01-03 11:03:27 -05:00
Patrik
38477184e0 fix(cpa): ensures .env & .env.example file modifications occur before git initialization (#10312)
### What?

Previously, `.env` & `.env.example` modifications during `cpa` occurred
after a project was initialized.

### Why?

As a result, these modifications would be seen as uncommitted
modifications in the project repo.

### How?

Now, we make these modifications in the `createProject` script before
the project is initialized.

Also, updates the **template** `.env.example` files to use the generic
db name `your-database-name` for better alignment & clarity.

Fixes #10232
2025-01-03 09:40:53 -05:00
Elliot DeNolf
daf314caea chore: change base image for template base dockerfile [skip ci] 2025-01-03 09:29:11 -05:00
Elliot DeNolf
3d5b9f031f templates: bump for v3.14.0 (#10324)
🤖 Automated bump of templates for v3.14.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2025-01-03 09:23:11 -05:00
Elliot DeNolf
6dcf817c22 ci(scripts): create draft release with release script, cleanup [skip ci] 2025-01-03 09:00:01 -05:00
Elliot DeNolf
766b67f0be chore(release): v3.14.0 [skip ci] 2025-01-03 08:34:41 -05:00
Sasha
4e57054bb7 fix: ensure scheduled publish restriction (#10317) 2025-01-03 08:26:21 -05:00
Angel P.
d6d9edc304 docs: warn when using defaultPopulate on collections with uploads enabled (#10138)
When `defaultPopulate` is enabled without specifying `filename: true`
and `url: true` for collections with an upload field. The upload will
not have a valid URL when returned from Payload APIs and will instead be
returned with a value of `null`

<!--

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 #

-->

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2025-01-02 23:08:07 +00:00
Jacob Fletcher
b14935ce28 fix(ui): unable to find user field schemas when updating password (#10305)
When updating password within the account view, the server console
throws an error because it is unable to find the remaining user fields
when building form state. This was because the field schema map sets
these fields within its own `_users.auth` key, separate from the other
fields. When the form submits, it uses this key as the schema path,
which may not contain all user fields, even though it sends full
document data through the request.
2025-01-02 17:54:49 -05:00
Sasha
2e58a4ad27 fix: ensure loggingLevels is respected (#10308)
Issue https://github.com/payloadcms/payload/issues/10272

Adds `logError` utility that can be used across the codebase for logging
errors
2025-01-02 21:42:08 +00:00
Paul
d9e0cd360b fix: 'oldValue' must be a string error when viewing version diffs in postgres (#10313)
Fixes https://github.com/payloadcms/payload/issues/10068

We were accidentally not catching that in postgres IDs return as strings
but the react diff viewer expects a string
2025-01-02 21:25:51 +00:00
Jacob Fletcher
abb51b98eb fix(ui): properly instantiates abort controllers (#10309)
Fixes #10296. When an async `useEffect` runs twice or more before
resolving, we use the Abort Controller API to cancel previous events.
This works by instantiating a new ref on each run, and if a previous ref
was detected, it will be aborted and a new instance will be set up for
the next run. However, while the logic was aborting previous instances
as expected, it was failing to instantiate a new one.
2025-01-02 15:08:38 -05:00
Alexander Cato
b2042c5754 docs: fix typo in join.mdx (#10190) 2025-01-02 19:44:25 +00:00
Tristan
38f34551a2 feat: add Estonian language support (#10169)
Adding Estonian language support for the Payload CMS.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2025-01-02 19:41:47 +00:00
Paul
951c38e587 templates: fix media block generating an error if referenced media is missing (#10310)
Fixes https://github.com/payloadcms/payload/issues/10231
2025-01-02 19:13:24 +00:00
Jacob Fletcher
7928ecaee7 fix: safely executes form state conditions, validations, and default values (#10275)
Whenever form state fails, like when field conditions, validations, or
default value functions throw errors, blocks and array rows are stuck
within an infinite loading state. Examples of this might be when
accessing properties of undefined within these functions, etc. Although
these errors are logged to the server console, the UI is be misleading,
where the user often waits for the request to resolve rather than
understanding that an underlying API error has occurred. Now, we safely
execute these functions within a `try...catch` block and handle their
failures accordingly. On the client, form state will resolve as expected
using the default return values for these functions.
2025-01-02 14:12:28 -05:00
Said Akhrarov
2ae7d8e5d4 fix(ui): gracefully handle deletions in collection with upload hasMany (#9426)
### What?
This PR aims to prevent a runtime error by allowing deletions in media
collections and preventing them from impacting workflows while using
`hasMany` upload fields.

### Why?
To prevent runtime issues during common tasks.

### How?
By treating deleted media documents as empty placeholders instead of
undefined objects.

Fixes #9328

Before:

[Dashboard-before--Payload.webm](https://github.com/user-attachments/assets/32cbfe1d-2569-43bc-be05-abd2d9913b9b)

After:

[Dashboard-after--Payload.webm](https://github.com/user-attachments/assets/b5cb67b8-21de-403c-879c-680e49fd380c)

Notes:
- There is room for improvement here: allow selection of existing media
in upload collection instead of forcing user to upload new. Workaround
is to remove the row and choose existing as usual.
- New uploads chosen will always replace the first instance of undefined
placeholder due to the simple check. If you have 3 deleted entries and
open the drawer on the second one, then it will populate the first one
anyway. This can be improved but will require more laborious code
changes.
- Noticed an issue where deleted non-hasMany upload fields do not
re-render after a file is uploaded. It only shows the previous deleted
doc, ie id: "untitled - ID: ...". Re-renders correctly when choosing
from existing. This is unrelated to this PR. I will investigate further.
- I'm realizing this actually diverges from what `db-postgres` does, as
deleted entries in a `hasMany` upload gets removed from the field in the
initial deletion probably due to cascading the deletion...
2025-01-02 18:55:24 +00:00
Jacob Fletcher
d38ca839cb fix(next): returns proper verb tenses from update and delete routes (#10307)
When hitting the delete or updates routes and no docs were effected, the
API returns success messages with improper verb tenses, i.e. `Deleted 0
Post successfully`.
2025-01-02 13:30:52 -05:00
Sondre Ørland
c65802233c chore(translations): adjust Norwegian translation of events (#10300)
`Hendelse` makes more sense in the context of the new scheduled publish
feature.
2025-01-02 17:30:16 +00:00
Germán Jabloñski
018c1933b0 fix(richtext-lexical): allow any priority of FOCUS_COMMAND (#10128)
This revert patch behavior on indent in Firefox, in order to fix #10049
2025-01-02 17:16:18 +00:00
Germán Jabloñski
510968f65d chore(examples): fix JSX rendering of internal links (#10303)
fix #10197

The template was missing defining internalDocToHref.

This callback is necessary because Payload does not know which URLs each
document will be displayed on.
2025-01-02 16:04:39 +00:00
Grant Kennedy
a000e4a505 templates: reorders postcss plugins in the website template for tailwind compatibility (#10176)
<!--

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 #

-->

This The plugin order in postcss.config.js was causing UI rendering
issues in mobile Safari (#10135). This pull request affects the website
template and the vercel website template.

Current version:
```
// Website template:  /templates/website/postcss.config.js
// Vercel website template: /templates/with-vercel-website/postcss.config.js

export default {
  plugins: {
    autoprefixer: {},
    tailwindcss: {},
  },
}
```
PostCSS was loading Autoprefixer before Tailwind and the vendor prefixes
were not properly being prepended.

Fixed version (per [Tailwind
docs](https://tailwindcss.com/docs/browser-support)):

```
export default {
  plugins: {
    tailwindcss: {}, // this is first
    autoprefixer: {}, // this is second
  },
}
```
2025-01-02 09:55:58 -06:00
Patrik
bd7f70545a fix(ui): disable save button until the upload file is uploaded / ready (#10083)
### What?

Previously, while uploading a file - if the uploading process took a bit
of time, users could still save the document prior to the upload fully
completing.

### Why?

During the uploading process - the save button should be disabled until
the upload is complete to prevent premature saving of an upload
document.

### How?

Now, we keep track of the state of the upload in a provider and disable
the save button until the file is fully uploaded.
2025-01-02 09:35:53 -05:00
Elliot DeNolf
b0ebd92a1e chore(release): v3.13.0 [skip ci] 2025-01-01 23:15:48 -05:00
Sasha
76e44024cc docs: explicit payload usage from req to avoid import payload confusion (#10291) 2025-01-01 01:49:20 +00:00
James Mikrut
f3f36d8010 fix(ui): checkboxes as first field were crashing WhereBuilder (#10290)
Fixes an issue where if a checkbox field was in the first position of a
collection, and you tried to filter on it via the List view, the page
would crash.
2024-12-31 23:55:43 +00:00
Alessio Gravili
ee3c2cc16f fix(richtext-lexical): empty lines were incorrectly stripped from mdx blocks if doNotTrimChildren was set to true (#10287)
This caused empty lines to disappear from code blocks
2024-12-31 21:58:46 +00:00
Said Akhrarov
b6de432ab2 docs: fix all missing vertical lines in tables (#10288) 2024-12-31 14:11:47 -07:00
Boyan Bratvanov
950f8ce80a docs: add missing vertical line to Collection Upload options table (#10282)
The missing line doesn't break Github's markdown table row rendering,
but it does break it on the website.
2024-12-31 20:06:56 +00:00
Elliot DeNolf
c3eb272d3c fix(cpa): do not overwrite custom.scss file on update (#10285)
No longer overwrite an existing `custom.scss` file if using
`create-payload-app` to update an existing project.

Fixes #9983
2024-12-31 12:04:42 -05:00
Jacob Fletcher
be87ba0ecd docs: adds useListQuery to list of React hooks and updates useDocumentInfo (#10186)
The `useListQuery` was currently undocumented and the `useDocumentInfo`
hook was out of date.
2024-12-31 16:31:23 +00:00
Elliot DeNolf
c4b31c079f fix(plugin-cloud-storage): actually deprecate adapters (#9640)
In v2, plugin-cloud-storage exported some adapters that were marked for
deprecation. These were replaced by standalone `@payloadcms/storage-*`
packages. More detail located in [this section of the migration
guide](https://github.com/payloadcms/payload/blob/main/docs/migration-guide/overview.mdx#payloadcmsplugin-cloud-storage).

Unfortunately, these exports were not removed prior to releasing 3.0.
2024-12-31 09:14:56 -05:00
Alessio Gravili
07e86c0f20 fix(richtext-lexical): throw toast error when attempting to create upload node without any upload collections enabled (#10277)
Fixes https://github.com/payloadcms/payload/issues/9136
2024-12-31 07:30:32 +00:00
Alessio Gravili
182eaa3433 feat(richtext-lexical): ability to override default placeholder (#10278)
![CleanShot 2024-12-30 at 23 28
01@2x](https://github.com/user-attachments/assets/0bab3a2a-bded-440f-9bfe-cb8bf5b74e2a)

![CleanShot 2024-12-30 at 23 28
08@2x](https://github.com/user-attachments/assets/589b7be0-f662-4c4a-b66b-66f9b88ee7c6)
2024-12-31 07:09:03 +00:00
Alessio Gravili
943798a784 docs(richtext-lexical): minor improvements (#10280) 2024-12-31 00:04:27 -07:00
Alessio Gravili
6e19e8288f docs(richtext-lexical): improve building custom feature docs, add example for custom blocks (code field within lexical) (#10279) 2024-12-31 06:56:33 +00:00
Alessio Gravili
35df899547 fix(richtext-lexical): various issues for lexical sub-fields due to incorrectly generated client field schema map (#10276)
Fixes https://github.com/payloadcms/payload/issues/9905,
https://github.com/payloadcms/payload/issues/9660

Single lexical fields were represented file in the schema map (`path =>
field`). In the client schema map however, they were incorrectly
represented like this: `path => { fields: [field] } `
2024-12-31 06:33:43 +00:00
Gerard Du Pre
5188a9b2a0 feat(translations): add Catalan translations (#10260)
### What?
Translated payload to Catalan
### Why?
I needed to have payload in Catalan
### How?
By following the
[readme](https://github.com/payloadcms/payload/blob/main/packages/translations/README.md)

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-12-31 04:37:54 +00:00
Jesper We
c5b1cd600b chore(translations): fine-tune some Swedish texts (#10224)
### What?

Fix some minor nits with Swedish translations

### Why?

För att ge ett mer professionellt intryck.
2024-12-30 19:35:10 -07:00
Said Akhrarov
313b4ba535 docs: fix dispatch actions link for useFormFields and useAllFormFields (#10273) 2024-12-30 19:28:15 -07:00
Said Akhrarov
cdaebcc79c fix(plugin-search): respect custom api route in reindexButton (#10258)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue with `plugin-search` where the ReindexButton was
not directing the reindex call to the correct endpoint location if the
user defined a custom config api route.

### Why?
To allow collection reindexing even when the default base api path gets
overriden with a user-provided one.

### How?
By threading the custom route to the ReindexButton component that calls
the reindex endpoint.

Fixes #10245

Notes:
- I think the `basePath` check/manipulation might be better in the RSC
instead of the client

Edit: @JessChowdhury Didn't see you were assigned until after! Felt bad
about this since it's my bad, wanted to take some ownership over the bug
here, my mistake!
2024-12-31 00:08:58 +00:00
Alessio Gravili
5b4730d13c docs: fix incorrect escaping of * (#10274) 2024-12-30 17:02:13 -07:00
James Mikrut
6dac4c5777 fix(ui): relationship edit drawers now respect current locale (#10262)
Fixes #9979
2024-12-30 23:46:00 +00:00
Jacob Fletcher
f5a955d906 fix(ui): properly filters fields from list view columns and conditions (#10246)
Fixes #10234. Some fields, such as focal point fields for upload enabled
collections, were rendering in the condition selector despite being
hidden from the column selector. This was because the logic for the
column selector was filtering fields without labels, but the same was
not being done for the filter conditions. This, however, is not a good
way to filter these fields as it requires this specific logic to be
written in multiple places. Instead, they need to explicitly check for
`hidden` and `disabled` in addition to `disableListFilter` and
`disableListColumn`. The actual filtering logic has been improved across
the two instances as well, removing multiple duplicative loops.

This change has also exposed a underlying issue with the way columns
were handled within the table columns provider. When row selections were
enabled, the selector columns were present in column state. This caused
problems when interacting with column indices, such as when reordering
columns. Instead of needing to manually filter these out every time we
need to work with column state, they no longer appear there in the first
place. Instead, we inject the row selectors directly into the table
itself, completely isolating these row selectors from the column state.
2024-12-30 23:39:48 +00:00
Alessio Gravili
885e96636d fix(richtext-lexical): formatted link markdown conversion not working (#10269)
Fixes https://github.com/payloadcms/payload/issues/8279

Ports over https://github.com/facebook/lexical/pull/7004
2024-12-30 22:48:03 +00:00
James Mikrut
7a59e7da46 feat: adds more control over how to disable graphql for collections /… (#10265)
Adds more control over how you can disable GraphQL queries / mutations
for collections and globals.

For example, you might want to disable all GraphQL queries and mutations
for a given collection, but you still have relationship fields that
relate to that collection, therefore depend on the types being
generated.

Now, instead of passing `graphQL: false` (which completely disables
everything, including types, which would break relationship fields) you
can now specify `graphQL.disableQueries: true` and
`graphQL.disableMutations: true`to keep the types, but disable just the
queries / mutations.

Closes #9893
2024-12-30 22:20:31 +00:00
Dan Ribbens
039b489cb8 fix(ui): disableListColumn on first field breaks filter condition selection (#10267)
What?
This PR fixes an issue with the WhereBuilder where if the first field in
a collection had disableListFilter enabled, the select in that fields
Condition would be rendered disabled, making it impossible to query docs
in list view.

Why?
To allow users to query their documents while still being able to set
disableListFilter on fields regardless of where they are in the
collection hierarchy.

How?
By setting the intitial field selection to the first
`admin.listDisabledColumn: false` field when clicking the Add Condition
button in the WhereBuilder and Condition components.

Fixes https://github.com/payloadcms/payload/issues/10110
2024-12-30 16:44:20 -05:00
Violet Rosenzweig
16c6abeee4 fix(graphql): Change config from raw path to file: url (#9311)
### What?

On windows, the `payload-graphql generate:schema` command fails.

### Why?

Because the config it's trying to load is `c:\path\to\config.js`, which
node interprets as `\path\to\config.js` on the `c:` protocol.

### How?

By changing it to use a file URL, as in `file:\\\c:\path\to\config.js`.
The change is the same as what the main `payload` cli does:
https://github.com/payloadcms/payload/blob/main/packages/payload/src/bin/index.ts#L54

Fixes #9309

Co-authored-by: Violet Rosenzweig <rosenzweigv@leoncountyfl.gov>
2024-12-30 16:43:58 -05:00
James Mikrut
5d6064a419 fix(translations): adds missing max validations keys to client (#10266)
Fixes #9836
2024-12-30 16:13:06 -05:00
Jacob Fletcher
270ac10fb4 test: consolidates list view e2e tests (#10263)
There were a handful of list view e2e tests written into the text and
email field test suite, making them hard to find as they were isolated
from other related tests. A few of these tests were also duplicative
across suites, making CI run them twice unnecessarily.
2024-12-30 21:09:42 +00:00
Anders Semb Hermansen
eb69885a89 fix: close db connections after running jobs from command line. (#9994)
### What?

Exit process after `payload jobs:run` without cron is executed

### Why?

I would expect the `payload jobs:run` command to exit normally after
execution. With mongodb this is not the case as database connections are
open so the node process itself will not exit.

### How?

Execute `payload.db.destroy` to close all db connections after queue is
execution is done.

Fixes: #9851
2024-12-30 15:03:29 -05:00
James Mikrut
8671e856ed fix(ui): removes useless verified checkbox on user create (#10252)
Removes the useless `_verified` checkbox from user creation. We can't
make it functional from the admin UI, because if we respected the
incoming `_verified` property from a user creation, then any user could
auto-verify themselves via REST / GraphQL APIs.

Fixes #10158
2024-12-30 19:58:01 +00:00
James Mikrut
ef7242cd85 fix(ui): autosave wasnt firing on first change (#10256)
Fixes #10111
2024-12-30 17:04:17 +00:00
James Mikrut
fe010b9373 Update drafts.mdx 2024-12-30 11:26:21 -05:00
Sasha
63bca12f87 docs: fix docs for generate db schema (#10251)
<!--

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 #

-->
2024-12-30 16:03:46 +00:00
James Mikrut
6af6e44683 docs: adds notes about importance of serverURL for verify / forgot-pa… (#10248)
Fixes #10235
2024-12-30 10:20:28 -05:00
James Mikrut
363a24cea5 docs: add clarity about forgot-password and verify tokens (#10247)
Adds clarity to `verifyEmail` docs, noting that the token for
`forgotPassword` is different.

Fixes #10236
2024-12-30 10:04:54 -05:00
Jacob Fletcher
6f5a1e3cf7 test: adds custom pagination e2e tests (#10240)
There is currently no e2e test coverage for custom
`admin.pagination.defaultLimit` or `admin.pagination.limits`.
2024-12-30 07:18:30 +00:00
Alessio Gravili
c01b4bfb79 fix(richtext-lexical): ensure markdown normalization does not merge escaped code block lines (#10230) 2024-12-30 01:52:12 +00:00
Elliot DeNolf
2111a860f7 chore(cpa): remove success message outline (#10233)
The usage of clack's `note` on the success message (contains long urls)
would often wrap on terminals that did not have a very wide window
and/or do not support [terminal
hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda)

This swaps the usage of `note` for more plain log output that does not
have an outline and eliminates the possibility for this issue.

Before:
<img width="726" alt="CleanShot 2024-12-29 at 02 54 18"
src="https://github.com/user-attachments/assets/4fcb028c-58f0-4102-9268-53aca8124111"
/>


After:
<img width="716" alt="CleanShot 2024-12-29 at 02 54 39"
src="https://github.com/user-attachments/assets/30615fa8-5f2c-43f5-a6a5-9f0b9cc415fb"
/>
2024-12-29 07:52:28 -05:00
Alessio Gravili
68a5f5ca2f feat(ui): expose onMount to CodeField (#10223)
This is useful for modifying the monaco instance, e.g. to add external
types to the editor:

```tsx
<CodeField
        autoComplete={autoComplete}
        field={props}
        forceRender={forceRender}
        key={key}
        onMount={(editor, monaco) => {
          console.log('editor mounted')
          monaco.languages.typescript.typescriptDefaults.setCompilerOptions({
            allowNonTsExtensions: true,
            moduleResolution: monaco.languages.typescript.ModuleResolutionKind.NodeJs,
            paths: {
              payload: ['file:///node_modules/payload/index.d.ts'],
            },
            target: monaco.languages.typescript.ScriptTarget.ESNext,
            typeRoots: ['node_modules/@types', 'node_modules/payload'],
          })
          const run = async () => {
            const types = await fetch('https://unpkg.com/payload@latest/dist/index.d.ts')
            const typesText = await types.text()
            monaco.languages.typescript.typescriptDefaults.addExtraLib(
              typesText,
              'file:///node_modules/payload/index.d.ts',
            )
          }
          void run()
        }}
        path={path}
        permissions={permissions}
        readOnly={readOnly}
        renderedBlocks={renderedBlocks}
        schemaPath={schemaPath}
        validate={validate}
      />
```
2024-12-28 19:09:51 +00:00
Elliot DeNolf
fabe5411f4 chore(release): v3.12.0 [skip ci] 2024-12-28 12:02:39 -05:00
Sasha
7a4d53afbf chore: bump next to 15.1.3 in the monorepo (#10211)
Bumps Next.js to the latest version `15.1.3`. This affects only internal
`package.json` files (in the root dir and test)

Fixes errors from here https://github.com/payloadcms/payload/pull/10209
2024-12-28 00:11:17 -07:00
Alessio Gravili
3218b0dcb6 docs: fix backtick escaping in TableWithDrawers blocks (#10220) 2024-12-28 06:39:55 +00:00
Jacob Fletcher
0be1a1d880 test: semantically splits admin e2e (#10213)
Improves the admin e2e test splitting by grouping them by type with
semantic names as opposed to numerically. This will provide much needed
clarity to exactly _where_ new admin tests should be written and help to
quickly distinguish the areas of failure within the CI overview.
2024-12-28 05:28:37 +00:00
Alessio Gravili
466ea292b9 docs: correctly escape backticks (#10217) 2024-12-28 05:18:15 +00:00
Alessio Gravili
3278f450c7 docs: correctly escape backticks (#10216) 2024-12-28 04:57:29 +00:00
Alessio Gravili
67db04c660 fix(richtext-lexical): newlines in mdx props were stripped, even though objects inside props may expect there to be newlines (#10215) 2024-12-28 04:53:44 +00:00
Seno
da518f53e8 docs: fix typo (#10214) 2024-12-28 04:40:20 +00:00
Alessio Gravili
78b6d51e58 docs: fix incorrect docs for complex mdx components (#10212) 2024-12-27 19:57:00 -07:00
Alessio Gravili
181fc410bf feat(richtext-lexical): multiline string support for objects in MDX parser (#10208) 2024-12-27 23:14:55 +00:00
Alessio Gravili
29c5bcdc18 docs: fix syntax that couldn't be parsed (#10207) 2024-12-27 15:12:14 -07:00
James Mikrut
37d1f2d04b feat: scheduled publish / unpublish (#10203)
Adds a feature to allow editors to schedule publish / unpublish events
in the future. Must be enabled by setting
`versions.drafts.schedulePublish: true` in your Collection / Global
configs.


https://github.com/user-attachments/assets/ca1d7a8b-946a-4eac-b911-c2177dbe3b1c

Todo:

- [x] Translate new i18n keys
- [x] Wire up locale-specific scheduled publish / unpublish actions
2024-12-27 16:52:18 -05:00
Alessio Gravili
a46609ef6b feat(richtext-lexical): more lenient MDX JSON object parser that allows unquoted property keys (#10205)
Previously, the following MDX could not be parsed by lexical:

```tsx
<RestExamples
  data={[
    {
      operation: "Find"
    }
]}
```

Instead, it had to be converted into valid JSON:

```tsx
<RestExamples
  data={[
    {
      "operation": "Find"
    }
]}
```

This PR permits using the first example, as it swaps out JSON.parse with
them ore lenient [json5](https://www.npmjs.com/package/json5) package
parser
2024-12-27 21:41:15 +00:00
James Mikrut
cf8c0ae959 feat: adds req to filterOptions args (#10204)
Adds `req` to `filterOptions` arguments.
2024-12-27 21:38:14 +00:00
Alessio Gravili
bb0c8a8c62 docs: fix incorrect mdx (#10201) 2024-12-27 20:18:31 +00:00
Jacob Fletcher
fad4ee6282 fix(ui): pagination resets perPage (#10199)
When using various controls within the List View, those selections are
sometimes not persisted. This is especially evident when selecting
`perPage` from the List View, where the URL and UI would reflect this
selection, but the controls would be stale. Similarly, after changing
`perPage` then navigating to another page through the pagination
controls, `perPage` would reset back to the original value. Same with
the sort controls, where sorting by a particular column would not be
reflected in the UI. This was because although we modify the URL search
params and fire off a new query with those changes, we were not updating
local component state.
2024-12-27 19:32:36 +00:00
Sasha
6b4842d44d feat(cpa): create project from example using --example CLI arg (#10172)
Adds the ability to create a project using an existing in the Payload
repo example through `create-payload-app`:

For example:
`pnpx create-payload-app --example custom-server` - creates a project
from the
[custom-server](https://github.com/payloadcms/payload/tree/main/examples/custom-server)
example.

This is much easier and faster then downloading the whole repo and
copying the example to another folder.
Note that we don't configure the payload config with the storage / DB
adapter there because examples can be very specific.
2024-12-27 20:16:34 +02:00
Elliot DeNolf
7e0975f970 feat: export defaultLoggerOptions (#10133)
Make `defaultLoggerOptions` available. Useful if you need to only tweak
the defaults for your logger.
2024-12-27 10:57:34 -05:00
Sasha
a5b9adce32 templates: use publishConfig for the plugin template (#10196)
Separates `exports`, `main`, `types` for publish / dev with
`publishConfig` for the plugin template. Previously, you needed a `dist`
folder to run payload bin scripts.
2024-12-27 17:22:25 +02:00
Sasha
98666eb016 perf(db-postgres): do not push database schema if not changed (#10155)
Based on https://github.com/payloadcms/payload/pull/10154

If the actual database schema is not changed (no new columns, enums,
indexes, tables) - skip calling Drizzle push. This, potentially can
significantly reduce overhead on reloads in development mode especially
when using remote databases.

If for whatever reason you need to preserve the current behavior you can
use `PAYLOAD_FORCE_DRIZZLE_PUSH=true` env flag.
2024-12-27 10:12:01 -05:00
Sasha
374b79d218 fix(db-postgres): prevent indexes from changing name on HMR (#10154)
As we didn't reset our `adapter.indexes` state, on every HMR reload we
incremented every single index name with the `buildIndexName`:

466f109152/packages/drizzle/src/utilities/buildIndexName.ts (L3-L24)

I found this while debugging our internal SQL schema:

Before reload:

```ts
 "payload_preferences": {
    "name": "payload_preferences",
    "columns": {
      "id": {
        "name": "id",
        "type": "serial",
        "primaryKey": true
      },
      "key": {
        "name": "key",
        "type": "varchar"
      },
      "value": {
        "name": "value",
        "type": "jsonb"
      },
      "updatedAt": {
        "name": "updated_at",
        "type": "timestamp",
        "defaultNow": true,
        "mode": "string",
        "notNull": true,
        "precision": 3,
        "withTimezone": true
      },
      "createdAt": {
        "name": "created_at",
        "type": "timestamp",
        "defaultNow": true,
        "mode": "string",
        "notNull": true,
        "precision": 3,
        "withTimezone": true
      }
    },
    "foreignKeys": {},
    "indexes": {
      "payload_preferences_key_idx": {
        "name": "payload_preferences_key_idx",
        "on": "key"
      },
      "payload_preferences_updated_at_idx": {
        "name": "payload_preferences_updated_at_idx",
        "on": "updatedAt"
      },
      "payload_preferences_created_at_idx": {
        "name": "payload_preferences_created_at_idx",
        "on": "createdAt"
      }
    }
  },
```

After:
```ts

"payload_preferences": {
    "name": "payload_preferences",
    "columns": {
      "id": {
        "name": "id",
        "type": "serial",
        "primaryKey": true
      },
      "key": {
        "name": "key",
        "type": "varchar"
      },
      "value": {
        "name": "value",
        "type": "jsonb"
      },
      "updatedAt": {
        "name": "updated_at",
        "type": "timestamp",
        "defaultNow": true,
        "mode": "string",
        "notNull": true,
        "precision": 3,
        "withTimezone": true
      },
      "createdAt": {
        "name": "created_at",
        "type": "timestamp",
        "defaultNow": true,
        "mode": "string",
        "notNull": true,
        "precision": 3,
        "withTimezone": true
      }
    },
    "foreignKeys": {},
    "indexes": {
      "payload_preferences_key_1_idx": {
        "name": "payload_preferences_key_1_idx",
        "on": "key"
      },
      "payload_preferences_updated_at_1_idx": {
        "name": "payload_preferences_updated_at_1_idx",
        "on": "updatedAt"
      },
      "payload_preferences_created_at_1_idx": {
        "name": "payload_preferences_created_at_1_idx",
        "on": "createdAt"
      }
    }
  },
```
Which isn't really great for dev performance and can potentially cause
errors
2024-12-27 10:04:48 -05:00
Tobias Arends
a49e63cd7a docs: fix arg name in live preview code example (#10127)
Updates outdated code example to match the current docs and api.
2024-12-27 09:53:54 -05:00
Sasha
eff75f9613 fix: deep querying, handle getLocalizedPaths for blocks (#10187)
Fixes https://github.com/payloadcms/payload/issues/10126

Properly handles the `getLocalizedPaths` function for blocks.

Previously, using collection with this config:
```
{
  slug: 'deep-nested',
  fields: [
    {
      type: 'tabs',
      tabs: [
        {
          name: 'content',
          fields: [
            {
              type: 'blocks',
              name: 'blocks',
              blocks: [
                {
                  slug: 'testBlock',
                  fields: [
                    {
                      type: 'tabs',
                      tabs: [
                        {
                          name: 'meta',
                          fields: [
                            {
                              type: 'relationship',
                              relationTo: 'movies',
                              name: 'movie',
                            },
                          ],
                        },
                      ],
                    },
                  ],
                },
              ],
            },
          ],
        },
      ],
    },
  ],
},

```
The following query didn't work in MongoDB:
```ts
const result = await payload.find({
  collection: 'deep-nested',
  where: {
    'content.blocks.meta.movie': {
      equals: movie.id,
    },
  },
})
```
2024-12-27 09:46:09 -05:00
Said Akhrarov
ebf3cee803 fix(ui): prevent many upload fields overwriting bulkUpload onSuccess (#10189)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where multiple `upload` fields would sequentially
overwrite the `BulkUpload` internal `onSuccess` function causing new
uploads to populate the incorrect field from which the interaction
started.

### Why?
Sequential `upload` fields use a `useEffect` to set the success function
of the `BulkUpload` provider component, however this did not take into
account many `upload` fields in a single document. This PR prevents many
`upload` fields from overriding their sibling's `onSuccess` function in
order to populate those fields correctly.

### How?
By changing the way the bulk upload component handles success functions
from a singular function to a map of functions based on a string path of
the field, or if necessary, using a collection slug in the case of a
bulk upload on an `upload` collection list view.

Fixes #10177

Before (One hasMany, one single):

[Editing-hasmany-single--Post-before--Payload.webm](https://github.com/user-attachments/assets/01aeaa64-a065-4e66-8ab4-6bb9d4fa8556)

Before (Many hasMany):

[Editing-hasmany-two--Post-before--Payload.webm](https://github.com/user-attachments/assets/a65c58aa-9a15-4cca-b2c4-17484c020ddc)

After (One hasMany, one single):

[Editing-hasmany-single--Post-after--Payload.webm](https://github.com/user-attachments/assets/7206f94e-4ce2-41b3-8b45-625f4974d28d)

After (Many hasMany):

[Editing-hasmany-two--Post-after--Payload.webm](https://github.com/user-attachments/assets/72dbbdee-d4a5-4488-8ef0-3dd3918115a9)
2024-12-27 09:41:19 -05:00
Sasha
d8a62b7022 feat: plugin template (#10150)
Updates the plugin template and adds it to the monorepo

Includes:
* Integration testing setup 
* Adding custom client / server components via a plugin
* The same building setup that we use for our plugins in the monorepo
* `create-payload-app` dynamically configures the project based on the
name:`dev/tsconfig.json`, `src/index.ts`, `dev/payload.config.ts`
For example, from project name: `payload-plugin-cool`
`src/index.ts`:
```ts
export type PayloadPluginCoolConfig = {
  /**
   * List of collections to add a custom field
   */
  collections?: Partial<Record<CollectionSlug, true>>
  disabled?: boolean
}

export const payloadPluginCool =
  (pluginOptions: PayloadPluginCoolConfig) =>
/// ...
```
`dev/tsconfig.json`:
```json
{
  "extends": "../tsconfig.json",
  "exclude": [],
  "include": [
    "**/*.ts",
    "**/*.tsx",
    "../src/**/*.ts",
    "../src/**/*.tsx",
    "next.config.mjs",
    ".next/types/**/*.ts"
  ],
  "compilerOptions": {
    "baseUrl": "./",
    "paths": {
      "@payload-config": [
        "./payload.config.ts"
      ],
      "payload-plugin-cool": [
        "../src/index.ts"
      ],
      "payload-plugin-cool/client": [
        "../src/exports/client.ts"
      ],
      "payload-plugin-cool/rsc": [
        "../src/exports/rsc.ts"
      ]
    },
    "noEmit": true
  }
}

```

`./dev/payload.config.ts`
```
import { payloadPluginCool } from 'payload-plugin-cool'
///
 plugins: [
    payloadPluginCool({
      collections: {
        posts: true,
      },
    }),
  ],
```

Example of published plugin
https://www.npmjs.com/package/payload-plugin-cool
2024-12-27 14:25:08 +00:00
Dan Ribbens
326b72072c chore: update rimraf and fix windows compatible clean script (#10152)
Previously we had been downgrading rimraf to v3 simply to handle clean
with glob patterns across platforms. In v4 and newer of rimraf you can
add `-g` to use glob patterns.

This change updates rimraf and adds the flag to handle globs in our
package scripts to be windows compatible.
2024-12-27 09:16:17 -05:00
Alessio Gravili
1dc4b2c5e1 chore(richtext-lexical): export $createServerBlockNode, $isServerBlockNode and ServerBlockNode for the server (#10192)
This is useful for working within custom markdown transformers on the
server, using a headless lexical editor
2024-12-27 07:17:51 +00:00
Jacob Fletcher
f3aebe3263 fix(ui): public users unable to log out (#10188)
Fixes #10180. When logged in as an unauthorized user who cannot access
the admin panel, the user is unable to log out through the prompted
`/admin/logout` page. This was because that page was using an incorrect
API endpoint, reading from `admin.user` instead of `user.collection`
when formatting the route. This page was also able to get stuck in an
infinite loading state when attempting to log out without any user at
all. Now, public users can properly log out and then back in with
another user who might have access. The messaging around this was also
misleading. Instead of displaying the "Unauthorized, you must be logged
in to make this request" message, we now display a new "Unauthorized,
this user does not have access to the admin panel" message for added
clarity.
2024-12-26 22:52:00 -05:00
Sasha
5613a7ebe1 templates: update Dockerfile for the website template, use the LTS version for Node.js image (#10184)
Fixes https://github.com/payloadcms/payload/issues/10153

With the current Node.js version - `18.8.0` Dockerfile in templates
doesn't build
<img width="498" alt="image"
src="https://github.com/user-attachments/assets/91229bf2-a760-4f37-913e-6cca3e6806d0"
/>

Updated to LTS - `22.12.0`. Also updated Dockerfile in the `website`
template as it was outdated and added comment that you need to set
`output: 'standalone'` in `next.config.mjs`.
<img width="791" alt="image"
src="https://github.com/user-attachments/assets/be78d2cc-2489-4a7f-8fa2-8e88fcce4d8f"
/>
2024-12-26 23:46:18 +02:00
Jacob Fletcher
5d3b816cd8 chore(ui): exports parseSearchParams (#10185)
As pointed out in #10164, parsing a `where` query from search params is
not exactly straightforward. Internally we rely on the `qs` module for
this, but it comes with a couple small nuances that are undocumented,
like the need to stringify them and specify depth. To standardize this,
we use a `parseSearchParams` utility internally that accepts the
`URLSearchParams` object that the `useSearchParams()` hook returns from
`next/navigation`. This PR exports that function for reuse and adds
JSDocs accordingly. Usage looks something like this:

```tsx
'use client'
import { useSearchParams } from 'next/navigation'
import { parseSearchParams } from '@payloadcms/ui'

function MyComponent() {
  const searchParams = useSearchParams()
  const parsedSearchParams = parseSearchParams(searchParams)
}
```
2024-12-26 16:02:53 -05:00
Sasha
a0d8131649 fix(db-postgres): joins to self collection (#10182)
### What?
With Postgres, before join to self like:
```ts
import type { CollectionConfig } from 'payload'

export const SelfJoins: CollectionConfig = {
  slug: 'self-joins',
  fields: [
    {
      name: 'rel',
      type: 'relationship',
      relationTo: 'self-joins',
    },
    {
      name: 'joins',
      type: 'join',
      on: 'rel',
      collection: 'self-joins',
    },
  ],
}
```
wasn't possible, even though it's a valid usage.

### How?
Now, to differentiate parent `self_joins` and children `self_joins` we
do additional alias for the nested select -
`"4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"`:
```sql
select 
  "id", 
  "rel_id", 
  "updated_at", 
  "created_at", 
  (
    select 
      coalesce(
        json_agg(
          json_build_object('id', "joins_alias".id)
        ), 
        '[]' :: json
      ) 
    from 
      (
        select 
          "created_at", 
          "rel_id", 
          "id" 
        from 
          "self_joins" "4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737" 
        where 
          "4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"."rel_id" = "self_joins"."id" 
        order by 
          "4d3cf2b6_1adf_46a8_b6d2_3e1c3809d737"."created_at" desc 
        limit 
          $1
      ) "joins_alias"
  ) as "joins_alias" 
from 
  "self_joins" 
where 
  "self_joins"."id" = $2 
order by 
  "self_joins"."created_at" desc 
limit 
  $3

```

Fixes https://github.com/payloadcms/payload/issues/10144

-->
2024-12-26 20:47:49 +02:00
Kethan Vegunta
6b45b2d7e9 chore: UnauthorizedError file misspelled as UnathorizedError (#10157)
Fixes misspelled file.

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2024-12-26 18:45:21 +00:00
Jacob Fletcher
b33f4b0143 fix(ui): infinite loading states when adding blocks or array rows (#10175)
Fixes #10070. Adding new blocks or array rows can randomly get stuck
within an infinite loading state. This was because the abort controllers
responsible for disregarding duplicate `onChange` and `onSave` events
was not properly resetting its refs across invocations. This caused
subsequent event handlers to incorrectly abort themselves, leading to
unresolved requests and a `null` form state. Similarly, the cleanup
effects responsible for aborting these requests on component unmount
were also referencing its `current` property directly off the refs,
which can possible be stale if not first set as a variable outside the
return function.

This PR also carries over some missing `onSave` logic from the default
edit view into the live preview view. In the future the logic between
these two views should be standardized, as they're nearly identical but
often become out of sync. This can likely be done through the use of
reusable hooks, such as `useOnSave`, `useOnChange`, etc. Same with the
document locking functionality which is complex and deeply integrated
into each of these views.
2024-12-26 12:17:06 -05:00
Sasha
8debb68db2 fix: generate types when no en language is defined in i18n (#10181)
Previously, if you had for example only `de` in `i18n` -
`generate:types` would fail
Fixes https://github.com/payloadcms/payload/issues/10145
2024-12-26 15:35:58 +00:00
Jacob Fletcher
466f109152 chore(live-preview): strongly types message events (#10148)
Live Preview message events were typed with the generic `MessageEvent`
interface without passing any of the Live Preview specific properties,
leading to unknown types upon use. To fix this, there is a new
`LivePreviewMessageEvent` which properly extends the underlying
`MessageEvent` interface, providing much needed type safety to these
functions. In the same vein, the `UpdatedDocument` type was not being
properly shared across packages, leading to multiple independent
definitions of this type. This type is now exported from `payload`
itself and renamed to `DocumentEvent` for improved semantics. Same with
the `FieldSchemaJSON` type. This PR also adjusts where globally scoped
variables are set, putting them within the shared `_payloadLivePreview`
namespace instead of setting them individually at the top-level.
2024-12-23 18:19:52 +00:00
Marcus Forsberg
0588394a47 docs: fix broken links to csrf and e-mail verification docs (#10140)
### What?

This fixes a couple of broken links, specifically to the CSRF and the
e-mail verification doc pages, which appear to have been moved from the
root Authentication page.

### Why?

While it makes sense to familiarize one self with the Authentication
Overview page as well, if you are specifically looking for info on CSRF
protection (which I was doing while evaluting Payload for my agency),
the link should go to the right place.
2024-12-23 03:09:50 -05:00
Germán Jabloñski
3bbc5bf949 chore(examples): localization example (#10134) 2024-12-22 19:21:56 +00:00
Germán Jabloñski
154ad9d132 fix(richtext-lexical): restore selection (#10129)
Fix #9964

Now we make sure that the node for the previous selection exists before
restoring it to avoid a runtime error.

I also optimized the performance of a function in the client feature.

In the future, we should centralize the insertion of all decorator
blocks in one place. There are several things to improve. For example,
currently an additional paragraph is inserted (in addition to the one
for the selection we delete).
2024-12-22 15:18:23 +00:00
Sasha
ed0d3395c7 test: ensure data strictness (#10123)
Ensures we don't save and read additional properties to the database
with both, Local API and `payload.db`.
2024-12-22 09:37:32 +02:00
Said Akhrarov
68b5f61641 fix: ensure tab label and description are serializable (#10115)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where assigning a label or description function
to a tab would cause a runtime error due to passing a function to a
client component.

### Why?
To prevent runtime errors when using non-static designations.

### How?
By properly evaluating label and description functions prior to
assignment to their `clientTab` counterpart.

Fixes #10114

Before:

![image](https://github.com/user-attachments/assets/e003780a-2f24-4988-96ce-27c22fd61854)

After:

![image](https://github.com/user-attachments/assets/0bd185a0-415d-4414-bead-48647e244ba7)
2024-12-22 00:33:40 +00:00
Elliot DeNolf
1372f2468d ci: only label stale issues/prs, disable closing 2024-12-21 14:12:16 -05:00
Elliot DeNolf
235eade08f templates: bump for v3.11.0 (#10121)
🤖 Automated bump of templates for v3.11.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-21 08:09:28 -05:00
Elliot DeNolf
e9a330d4b9 chore(release): v3.11.0 [skip ci] 2024-12-21 07:56:14 -05:00
Sasha
b08ff88fbd fix(db-mongodb): mongodb optimizations (#10120)
There are few issues introduced in #9594 that we need to look into with
these changes.
2024-12-21 07:42:44 -05:00
Sam
08eb13d189 docs: remove stray backtick from Nested Docs Plugin page (#10118)
### What?
Remove erroneous backtick from comment in code snippet from
https://payloadcms.com/docs/plugins/nested-docs#overrides
2024-12-21 07:23:01 -05:00
Alessio Gravili
f1901f6648 chore: pin templates to latest version (#10116)
pinning to an exact version number is clearer more reliable than using
"latest".
2024-12-21 01:18:03 -07:00
Said Akhrarov
a58b9fc230 fix(ui): join table row still shows after deletion (#9783)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where deleting an entry in a `Join` via the
`Drawer` accessed through the `DrawerLink` would not update the table
until the page was refreshed.

### Why?
For a better, more reactive, deletion experience for end-users. Ideally,
the deletion is reflected in the table right away.

### How?
By passing an `onDrawerDelete` function to the `DrawerLink` which simply
filters out the existing doc according to an id.

Fixes #9580

Before:

[Editing---Post--before-Payload.webm](https://github.com/user-attachments/assets/3dd4df78-bb63-46b1-bf5f-7643935e15ad)

After:

[Editing---Post--after-Payload.webm](https://github.com/user-attachments/assets/97bb604f-41df-4cc9-8c46-9a59a19c72b7)
2024-12-20 21:47:09 -05:00
Said Akhrarov
ec853c4336 fix(ui): ensure unpublish confirmation is reachable when opened in drawers (#10109)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where the unpublish modal was unreachable due to
the high `z-index` on `Drawer` components. This makes unpublishing
documents from a drawer impossible. For example, when editting a
document from the drawer opened in a `RelationshipTable`.

### Why?
To allow editors to be able to unpublish docs regardless of drawer depth
and context.

### How?
By rendering the unpublish modal at a sufficiently high z-index, while
taking into account edit depth.

Fixes #10108

Before:

[Dashboard-unpublish-before--Payload.webm](https://github.com/user-attachments/assets/7acf1002-138e-48bd-81ec-76f5eabfb2d4)

After:

[Dashboard-unpublish-after--Payload.webm](https://github.com/user-attachments/assets/ff109ee9-5b63-43d0-931f-500ded8f6d3a)
2024-12-20 23:52:05 +00:00
zuccs
2175451480 docs: fix broken links (#10010)
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2024-12-20 15:19:45 -05:00
Jacob Fletcher
957867f6e2 fix: ensures generated IDs persist on create (#10089)
IDs that are supplied directly through the API, such as client-side
generated IDs when adding new blocks and array rows, are overwritten on
create. This is because when adding blocks or array rows on the client,
their IDs are generated first before being sent to the server for
processing. Then when the server receives this data, it incorrectly
overrides them to ensure they are unique when using relational DBs. But
this only needs to happen when no ID was supplied on create, or
specifically when duplicating documents via the `beforeDuplicate` hook.
2024-12-20 15:14:23 -05:00
Sasha
4e953530df feat(db-sqlite): add autoIncrement option (#9427)
### What?
Exposes ability to enable
[AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for Primary Keys
which ensures that the same ID cannot be reused from previously deleted
rows.

```ts
sqliteAdapter({
  autoIncrement: true
})
```

### Why?
This may be essential for some systems. Enabled `autoIncrement: true`
also for the SQLite Adapter in our tests, which can be useful when
testing whether the doc was deleted or not when you also have other
create operations.

### How?
Uses Drizzle's `autoIncrement` option.

WARNING:
This cannot be enabled in an existing project without a custom
migration, as it completely changes how primary keys are stored in the
database.
2024-12-20 20:13:28 +00:00
Elliot DeNolf
99481cbc7d templates: bump for v3.10.0 (#10107)
🤖 Automated bump of templates for v3.10.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-20 15:07:51 -05:00
Elliot DeNolf
4d50046104 chore(release): v3.10.0 [skip ci] 2024-12-20 14:42:13 -05:00
Sasha
a7109ed048 refactor: consistent caps for acronyms in variable names (#10101)
Improves consistency for variable names like `docID`, `insertedID`,
`parentID`
For example: `docId` -> `docID`
2024-12-20 18:10:34 +00:00
Shrinidhi Shastri
dec87e971a chore(templates): remove console.log that logs payload secret for security (#10095)
I noticed that payload.secret was getting logged via console.log, adding
a significant security risk.
Removed the console.log statements from three preview/route.ts files.
2024-12-20 17:01:47 +00:00
James Mikrut
a501e604d6 chore(richtext-slate): exports useElementButton, useLeafButton (#10047)
Exports `useElementButton` and `useLeafButton` from the Slate package
for custom Slate components.
2024-12-20 09:48:49 -07:00
Dan Ribbens
6bba7bec4e feat(ui): export RelationshipTable component (#10084)
Fixes https://github.com/payloadcms/payload/discussions/9049
2024-12-20 11:47:22 -05:00
Elliot DeNolf
2a6bac97f5 chore(release): eslint/3.9.0 2024-12-20 11:35:52 -05:00
Patrik
52b1a9a720 templates: removes DATABASE_URI env var from with-vercel-website template .env.example (#10098)
### What?

Previously, the `with-vercel-website` template included a `DATABASE_URI`
env var in the `.env.example` file - which was unneeded.

### Why?

The `with-vercel-website` template uses a `POSTGRES_URL` env var for the
db connection string env var instead.

### How?

Removes the `DATABASE_URI` env var from the .env.example file.

Also, updates the `DATABASE_URI` db string names in the following
templates from `payloadtests` to `your-database-name` for a more generic
/ clear name:
- with-postgres
- with-vercel-mongodb
- with-vercel-postgres
- with-vercel-website
2024-12-20 11:02:06 -05:00
Jacob Fletcher
7bedd6d822 fix(examples): awaits getHeaders in auth example (#10100)
The auth example was not properly awaiting `getHeaders` from
`next/navigation`. This was simply outdated, as this function was
changed to async over the course of the various RC versions during our
beta phase.
2024-12-20 10:38:38 -05:00
Sasha
59fc9d094e fix(ui): close copy locale modal after locale is changed (#10096)
Ensures we close the modal _only_ after locale is changed. This caused
our localization e2e's to flake:

![image](https://github.com/user-attachments/assets/41205afe-0e45-499b-9aa6-07734a7f26fc)
2024-12-20 08:29:53 -05:00
Sasha
7c4ea5b86e refactor: optimize database schema generation bin script (#10086)
* Avoids additional file system writes (1 for `await writeFile` and then
`npx prettier --write`) instead prettier now formats the javascript
string directly. Went from 650 MS to 250 MS for the prettify block.
* Disables database connection, since the `db.generateSchema` doesn't
need connection, this also disables Drizzle schema push.
* Properly exits the bin script process.
2024-12-20 14:43:11 +02:00
Jacob Fletcher
7292220109 chore(examples): updates auth example to latest (#10090)
The auth example was still on `v3.0.0-beta.24`, was missing its users
collection config, and was not yet using the component paths pattern
established here: #7246. This updates to latest and fixes these issues.
This example can still use further improvements and housekeeping which
will come in future PRs.
2024-12-19 23:54:24 -05:00
Mason Yekta
dd3c2eb42b fix(examples): add missing header component in auth example (#10088) 2024-12-20 04:16:03 +00:00
Alessio Gravili
b3308736c4 feat: jsdocs for generated types, by using admin.description (#9917)
This makes use of admin.description to generate JSDocs for field,
collection and global generated types.


![image](https://github.com/user-attachments/assets/980d825f-49a2-426d-933a-2ff3d205ea24)


![image](https://github.com/user-attachments/assets/d0b1f288-1ea1-4d80-8c05-003d59a4e41a)

For the future, we should add a dedicated property to override these
JSDocs.

You can view the effect of this PR on our test suite generated types
here:
05f552bbbc
2024-12-19 22:22:43 -05:00
Elliot DeNolf
46e50c4572 templates: bump for v3.9.0 (#10087)
🤖 Automated bump of templates for v3.9.0

Triggered by user: @paulpopus

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-19 22:50:37 +00:00
Dan Ribbens
d03658de01 feat: join field with polymorphic relationships (#9990)
### What?
The join field had a limitation imposed that prevents it from targeting
polymorphic relationship fields. With this change we can support any
relationship fields.

### Why?
Improves the functionality of join field.

### How?
Extended the database adapters and removed the config sanitization that
would throw an error when polymorphic relationships were used.

Fixes #
2024-12-19 22:34:52 +00:00
Sasha
07be617963 fix(db-postgres): relationships v2-v3 migration errors when migrating from v2 to stable v3 (#10080)
When migrating from stable v2 to v3, the provided relationships
migration fails because of not having `payload_locked_documents` and
`payload_locked_documents_rels` tables in the migration generated in v2.


![image](https://github.com/user-attachments/assets/0dc57e6a-5e6e-4b74-bcab-70e660f4e939)
2024-12-19 19:09:07 +00:00
Alessio Gravili
d8c106cb2b fix(templates): broken preview if alternative auth strategy was used, invalid error handling (#9785)
Previously, live preview did not work with oauth, as no token is present
2024-12-19 13:23:47 -05:00
Sasha
e468292039 perf(db-mongodb): improve performance of all operations, up to 50% faster (#9594)
This PR improves speed and memory efficiency across all operations with
the Mongoose adapter.

### How?

- Removes Mongoose layer from all database calls, instead uses MongoDB
directly. (this doesn't remove building mongoose schema since it's still
needed for indexes + users in theory can use it)
- Replaces deep copying of read results using
`JSON.parse(JSON.stringify(data))` with the `transform` `operation:
'read'` function which converts Date's, ObjectID's in relationships /
joins to strings. As before, it also handles transformations for write
operations.
- Faster `hasNearConstraint` for potentially large `where`'s
- `traverseFields` now can accept `flattenedFields` which we use in
`transform`. Less recursive calls with tabs/rows/collapsible

Additional fixes
- Uses current transaction for querying nested relationships properties
in `buildQuery`, previously it wasn't used which could've led to wrong
results
- Allows to clear not required point fields with passing `null` from the
Local API. Previously it didn't work in both, MongoDB and Postgres

Benchmarks using this file
https://github.com/payloadcms/payload/blob/chore/db-benchmark/test/_community/int.spec.ts

### Small Dataset Performance

| Metric | Before Optimization | After Optimization | Improvement (%) |

|---------------------------|---------------------|--------------------|-----------------|
| Average FULL (ms) | 1170 | 844 | 27.86% |
| `payload.db.create` (ms) | 1413 | 691 | 51.12% |
| `payload.db.find` (ms) | 2856 | 2204 | 22.83% |
| `payload.db.deleteMany` (ms) | 15206 | 8439 | 44.53% |
| `payload.db.updateOne` (ms) | 21444 | 12162 | 43.30% |
| `payload.db.findOne` (ms) | 159 | 112 | 29.56% |
| `payload.db.deleteOne` (ms) | 3729 | 2578 | 30.89% |
| DB small FULL (ms) | 64473 | 46451 | 27.93% |

---

### Medium Dataset Performance

| Metric | Before Optimization | After Optimization | Improvement (%) |

|---------------------------|---------------------|--------------------|-----------------|
| Average FULL (ms) | 9407 | 6210 | 33.99% |
| `payload.db.create` (ms) | 10270 | 4321 | 57.93% |
| `payload.db.find` (ms) | 20814 | 16036 | 22.93% |
| `payload.db.deleteMany` (ms) | 126351 | 61789 | 51.11% |
| `payload.db.updateOne` (ms) | 201782 | 99943 | 50.49% |
| `payload.db.findOne` (ms) | 1081 | 817 | 24.43% |
| `payload.db.deleteOne` (ms) | 28534 | 23363 | 18.12% |
| DB medium FULL (ms) | 519518 | 342194 | 34.13% |

---

### Large Dataset Performance

| Metric | Before Optimization | After Optimization | Improvement (%) |

|---------------------------|---------------------|--------------------|-----------------|
| Average FULL (ms) | 26575 | 17509 | 34.14% |
| `payload.db.create` (ms) | 29085 | 12196 | 58.08% |
| `payload.db.find` (ms) | 58497 | 43838 | 25.04% |
| `payload.db.deleteMany` (ms) | 372195 | 173218 | 53.47% |
| `payload.db.updateOne` (ms) | 544089 | 288350 | 47.00% |
| `payload.db.findOne` (ms) | 3058 | 2197 | 28.14% |
| `payload.db.deleteOne` (ms) | 82444 | 64730 | 21.49% |
| DB large FULL (ms) | 1461097 | 969714 | 33.62% |
2024-12-19 13:20:39 -05:00
Sasha
034b442699 test: revert default db adapter in integration tests to mongodb (#10079) 2024-12-19 18:20:28 +00:00
Andrzej Kłapeć
6a8aecadf8 fix(richtext-lexical): incorrect string interpolation in the upload converter (#10069)
This fixes the incorrect `<source>` `media` attribute value generation
within the upload converter.

<img width="919" alt="Zrzut ekranu 2024-12-19 o 12 21 10"
src="https://github.com/user-attachments/assets/6f26de7e-26e0-446a-83c5-6e5a776fac1e"
/>
2024-12-19 11:03:51 -07:00
Sasha
23f1ed4a48 feat(db-postgres, db-sqlite): drizzle schema generation (#9953)
This PR allows to have full type safety on `payload.drizzle` with a
single command
```sh
pnpm payload generate:db-schema
```
Which generates TypeScript code with Drizzle declarations based on the
current database schema.

Example of generated file with the website template: 
https://gist.github.com/r1tsuu/b8687f211b51d9a3a7e78ba41e8fbf03

Video that shows the power:


https://github.com/user-attachments/assets/3ced958b-ec1d-49f5-9f51-d859d5fae236


We also now proxy drizzle package the same way we do for Lexical so you
don't have to install it (and you shouldn't because you may have version
mismatch).
Instead, you can import from Drizzle like this:
```ts
import {
  pgTable,
  index,
  foreignKey,
  integer,
  text,
  varchar,
  jsonb,
  boolean,
  numeric,
  serial,
  timestamp,
  uniqueIndex,
  pgEnum,
} from '@payloadcms/db-postgres/drizzle/pg-core'
import { sql } from '@payloadcms/db-postgres/drizzle'
import { relations } from '@payloadcms/db-postgres/drizzle/relations'
```


Fixes https://github.com/payloadcms/payload/discussions/4318

In the future we can also support types generation for mongoose / raw
mongodb results.
2024-12-19 11:08:17 -05:00
Elliot DeNolf
ba0e7aeee5 chore: proper docker-compose postgres url 2024-12-19 10:42:41 -05:00
Sasha
5753efb0a4 fix(db-mongodb): querying by localized polymorphic relationships using objects (#10037)
Previously, queries like this didn't work:
```ts
const res = await payload.find({
  collection: 'polymorphic-relationships',
  where: {
    polymorphicLocalized: {
      equals: {
        relationTo: 'movies',
        value: movie.id,
      },
    },
  },
})
```

This was due to the incorrectly passed path to MongoDB without
`.{locale}` suffix.
Additionally, to MongoDB now we send:
```

{
  $or: [
    {
      polymorphic: {
        $eq: {
          relationTo: formattedValue.relationTo,
          value: formattedValue.value,
        },
      },
    },
    {
      polymorphic: {
        $eq: {
          relationTo: 'movies',
          value: 'some-id',
        },
      },
    },
  ],
},
```

Instead of:
```
{
  $and: [
    {
      'polymorphic.relationTo': {
        $eq: 'movies ',
      },
    },
    {
      'polymorphic.value': {
        $eq: 'some-id ',
      },
    },
  ],
}
```

To match the _exact_ value. This is essential when we do querying by
relationships with `hasMany: true` and custom IDs that can be repeated.
`$or` is needed if for some reason keys are stored in the DB in a
different order
2024-12-19 10:42:15 -05:00
Germán Jabloñski
12dad35cf9 fix(richtext-lexical): ui bug when zooming in Safari (#10072)
Fix #10043
2024-12-19 15:00:31 +00:00
Elliot DeNolf
997aed346f templates: update dockerfiles (#10073)
- Dockerfiles needed to be updated to the Next.js `with-docker` example.
- docker-compose for postgres templates have been updated.
2024-12-19 09:48:38 -05:00
Sasha
0c57eef621 fix: unique error message regression (#10064)
Regression from https://github.com/payloadcms/payload/pull/9935, we need
to call `req.t` with `''error:valueMustBeUnique''` instead of just
`''error:valueMustBeUnique''`
2024-12-19 08:13:44 +00:00
Sasha
1d46b6d738 fix(ui): join field "add new" calculate initial drawer data with relationship inside blocks (#10057)
We merged https://github.com/payloadcms/payload/pull/9773 that adds
support for join field with relationships inside arrays, it just happens
that now it's also true for relationships inside blocks, added a test
case with blocks.
This just corrects initial data drawer calculation with the "add new"
button if we encounter a blocks field in join's `on`.
2024-12-19 08:45:22 +02:00
Sasha
03ff77544e feat(db-sqlite): add idType: 'uuid' support (#10016)
Adds `idType: 'uuid'` to the SQLite adapter support:
```ts
sqliteAdapter({
  idType: 'uuid',
})
```

Achieved through Drizzle's `$defaultFn()`
https://orm.drizzle.team/docs/latest-releases/drizzle-orm-v0283#-added-defaultfn--default-methods-to-column-builders
as SQLite doesn't have native UUID support. Added `sqlite-uuid` to CI.
2024-12-18 22:44:04 -05:00
Sasha
0e5bda9a74 feat: make req partial and optional in DB / Local API operations (#9935)
### What?
Previously, the `req` argument:
In database operations (e.g `payload.db`) was required and you needed to
pass the whole `req` with all the properties. This is confusing because
in database operations we never use its properties outside of
`req.transactionID` and `req.t`, both of which should be optional as
well.

Now, you don't have to do that cast:
```ts
payload.db.findOne({
  collection: 'posts',
  req: {} as PayloadRequest,
  where: {
    id: {
      equals: 1,
    },
  },
})
```
Becomes:
```ts
payload.db.findOne({
  collection: 'posts',
  where: {
    id: {
      equals: 1,
    },
  },
})
```

If you need to use transactions, you're not required to do the `as` cast
as well now, as the `req` not only optional but also partial -
`Partial<PayloadRequest>`.
`initTransaction`, `commitTransaction`, `killTransaction` utilities are
typed better now as well. They do not require to you pass all the
properties of `req`, but only `payload` -
`MarkRequired<Partial<PayloadRequest>, 'payload'>`
```ts
const req = { payload }
await initTransaction(req)
await payload.db.create({
  collection: "posts",
  data: {},
  req
})
await commitTransaction(req)
```

The same for the Local API. Internal operations (for example
`packages/payload/src/collections/operations/find.ts`) still accept the
whole `req`, but local ones
(`packages/payload/src/collections/operations/local/find.ts`) which are
used through `payload.` now accept `Partial<PayloadRequest>`, as they
pass it through to internal operations with `createLocalReq`.

So now, this is also valid, while previously you had to do `as` cast for
`req`.
```ts
const req = { payload }
await initTransaction(req)
await payload.create({
  collection: "posts",
  data: {},
  req
})
await commitTransaction(req)
```


Marked as deprecated `PayloadRequest['transactionIDPromise']` to remove
in the next major version. It was never used anywhere.
Refactored `withSession` that returns an object to `getSession` that
returns just `ClientSession`. Better type safety for arguments
Deduplicated in all drizzle operations to `getTransaction(this, req)`
utility:
```ts
const db = this.sessions[await req?.transactionID]?.db || this.drizzle
```
Added fallback for throwing unique validation errors in database
operations when `req.t` is not available.

In migration `up` and `down` functions our `req` is not partial, while
we used to passed `req` with only 2 properties - `payload` and
`transactionID`. This is misleading and you can't access for example
`req.t`.
Now, to achieve "real" full `req` - we generate it with `createLocalReq`
in all migration functions.

This all is backwards compatible. In all public API places where you
expect the full `req` (like hooks) you still have it.

### Why?
Better DX, more expected types, less errors because of types casting.
2024-12-18 22:43:37 -05:00
Sasha
eee6432715 fix(db-postgres): query has many relationships nested in row fields (#9944) (#9944)
### What?
Querying by nested to rows fields in has many relationships like this:
```ts
const result = await payload.find({
  collection: 'relationship-fields',
  where: {
    'relationToRowMany.title': { equals: 'some-title' },
  },
})
```
Where the related collection:
```ts
const RowFields: CollectionConfig = {
  slug: rowFieldsSlug,
  fields: [
    {
      type: 'row',
      fields: [
        {
          name: 'title',
          label: 'Title within a row',
          type: 'text',
          required: true,
        },
      ],
    },
  ],
}
```

was broken

### Why?
We migrated to use `flattenedFields`, but not in this specific case.
This error would be caught earlier we used `noImplictAny` typescript
rule. https://www.typescriptlang.org/tsconfig/#noImplicitAny which
wouldn't allow us to create variable like this:
```ts
let relationshipFields // relationshipFields is any here
```
Instead, we should write:
```ts
let relationshipFields: FlattenedField[]
```
We should migrate to it and `strictNullChecks` as well.

Fixes https://github.com/payloadcms/payload/issues/9534
2024-12-18 22:26:08 -05:00
Elliot DeNolf
044c22de54 chore(deps): bump turbo 2024-12-18 20:47:45 -05:00
Paul
ce74f1b238 fix(storage-vercel-blob): fixes issue where files with spaces in their name would not be retrieved correctly (#10062)
URI encodes filenames so that they're retrieved correctly from Vercel's
blob storage. Sometimes spaces would cause problems only in certain file
names
2024-12-19 00:32:59 +00:00
Paul
605cf42cbe templates: add Posts to internal links in website template (#10063)
Posts were previously not selectable as part of the internal links
(reference fields) in the website template.
2024-12-19 00:28:46 +00:00
Sasha
97c120ab28 fix(richtext-*): use correct "for" attribute for label (#10036)
Fixes https://github.com/payloadcms/payload/issues/10034
2024-12-18 16:58:59 -07:00
Jacob Fletcher
97a1f4afa9 test: consolidates custom id e2e tests (#10061)
Although we have a dedicated e2e test suite for custom IDs, tests for
custom unnamed tab and row IDs were still located within the admin test
suite. This consolidates these tests into the appropriate test suite as
expected.
2024-12-18 22:44:46 +00:00
Paul
439dd04ce9 fix: commit transaction if a user isnt found in forgotPassword operation (#10055)
The forgotPassword operation exits silently if no user is found, but
because we don't throw an error the transaction never gets committed
leading to a timeout.
2024-12-18 15:53:53 -06:00
Elliot DeNolf
a3457af36d templates: bump for v3.9.0 (#10060)
🤖 Automated bump of templates for v3.9.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-18 16:20:32 -05:00
Elliot DeNolf
d0d7b51ed5 chore(release): v3.9.0 [skip ci] 2024-12-18 15:58:11 -05:00
Paul
ef90ebb395 feat(storage-*): add support for browser-based caching via etags (#10014)
This PR makes changes to every storage adapter in order to add
browser-based caching by returning etags, then checking for them into
incoming requests and responding a status code of `304` so the data
doesn't have to be returned again.

Performance improvements for cached subsequent requests:

![image](https://github.com/user-attachments/assets/e51b812c-63a0-4bdb-a396-0f172982cb07)


This respects `disableCache` in the dev tools.



Also fixes a bug with getting the latest image when using the Vercel
Blob Storage adapter.
2024-12-18 15:54:36 -05:00
Alessio Gravili
194a8c189a feat: add shouldRestore config to job queue tasks (#10059)
By default, if a task has passed previously and a workflow is re-run,
the task will not be re-run. Instead, the output from the previous task
run will be returned. This is to prevent unnecessary re-runs of tasks
that have already passed.

This PR allows you to configure this behavior through the
`retries.shouldRestore` property. This property accepts a boolean or a
function for more complex restore behaviors.
2024-12-18 13:16:13 -07:00
Patrik
1446fe4694 fix: encodes upload filename urls (#10048)
### What?

Previously, upload files urls were not being encoded.

### Why?

As a result, this could lead to discrepancies where upload filenames
with spaces - the spaces would not be encoded as %20 in the URL.

### How?

To address this issue, we simply need to encode the filename of the
upload media.

Fixes #9698
2024-12-18 14:37:29 -05:00
Elliot DeNolf
f29e6335f6 fix(payload-cloud): improve not found logging (#10058)
In Payload Cloud, an unhelpful message would be surfaced if attempting
to retrieve a non-existent file. This improves the log message and
response to be more helpful.
2024-12-18 14:34:43 -05:00
Paul
93dde52fa9 ci: add email-resend and email-* to scopes for pr-title workflow (#10053) 2024-12-18 14:33:31 -05:00
Javier
198763a24e feat(db-mongodb): allow to customize mongoose schema options with collectionsSchemaOptions (#9885)
Adds the ability to pass additional schema options for collections with:
```ts
mongooseAdapter({
  collectionsSchemaOptions: {
    posts: {
      strict: false,
    },
  },
})
``` 

This changes relates to these:

-   https://github.com/payloadcms/payload/issues/4533
-   https://github.com/payloadcms/payload/discussions/4534

It is a proposal to set custom schema options for mongoose driver. 

I understand this got introduced into `main` v2 after `beta` branch was
created so this feature got lost.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.

<!--

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 #

-->

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-12-18 15:46:39 +00:00
Jacob Fletcher
b8de401195 chore: fixes package license file casing (#10021)
Fixes file casing for all package licenses where applicable, i.e.
`license.md` → `LICENSE.md` to comply with standards outlined
[here](https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-license-to-a-repository).
2024-12-18 10:36:42 -05:00
Sasha
2ee3e30b50 fix(db-postgres): select query on upload fields with hasMany: true (#10029)
Previously, if you selected only upload `hasMany: true` field, you would
receive an empty arrays always, because the `_rels` table wasn't joined
in this case. Fixes the condition to count `field.type === 'upload'` .
2024-12-18 06:33:12 +02:00
Patrik
61c5e0d3e0 fix(ui): properly allows configuring rows for the textarea field (#10031)
### What?

Previously, setting the `admin.rows` property did not change the height
of the `textarea` field input.

### Why?

Although `rows` was being properly set on the textarea element - it's
absolute positioning prevented the height from actually changing.

### How?

Updates the styles of the textarea field component to properly allow the
rows prop to change the height of the field.

Example w/:

```
{
  name: 'someTextArea',
  type: 'textarea',
  admin: {
    rows: 5,
  }
}
```
Before:
![Screenshot 2024-12-17 at 2 50
19 PM](https://github.com/user-attachments/assets/35d433c3-2fad-4930-9da6-b47b5e180af8)

After:
![Screenshot 2024-12-17 at 2 50
00 PM](https://github.com/user-attachments/assets/1a413639-ac29-46ce-b774-e1a30c5a21f0)

Fixes #10017
2024-12-17 15:46:11 -05:00
Elliot DeNolf
4bfa329fa4 templates: document local development (#10032)
Provide docker-compose for spinning up postgres locally along w/
relevant info in README.
2024-12-17 15:17:18 -05:00
Alessio Gravili
f5c13deb24 build: fix tsconfig monorepo setup (#10028)
Should fix messed up import suggestions and simplifies all tsconfigs
through inheritance.

One main issue was that packages were inheriting `baseURL: "."` from the
root tsconfig. This caused incorrect import suggestions that start with
"packages/...".

This PR ensures that packages do not inherit this baseURL: "." property,
while ensuring the root, non-inherited tsconfig still keeps it to get
tests to work (the importMap needs it)
2024-12-17 14:49:29 -05:00
Patrik
70666a0f7b fix(cpa): updates CPAs w/ vercel-postgres db types to use POSTGRES_URL & updates .env.example to use generic env var strings (#10027)
CPA projects generated with the `vercel-postgres` db type were not
receiving the proper DB env vars in the .env.example & .env files

With the `vercel-postgres` db type, the DB env var needs to be
`POSTGRES_URL` not `DATABASE_URI`.

Additionally, updates the generated .env.example file to show generic
env var strings.

#### Blank w/ MongoDB:
- `.env.example`:
```
DATABASE_URI=mongodb://127.0.0.1/your-database-name
PAYLOAD_SECRET=YOUR_SECRET_HERE
```
- `.env`:
```
# Added by Payload
DATABASE_URI=mongodb://127.0.0.1/test-cpa-blank-mongodb
PAYLOAD_SECRET=aef857429edc7f42a90bb374
```

#### Blank w/ Postgres:
- `.env.example`:
```
DATABASE_URI=postgres://postgres:<password>@127.0.0.1:5432/your-database-name
PAYLOAD_SECRET=YOUR_SECRET_HERE
```
- `.env`:
```
# Added by Payload
DATABASE_URI=postgres://postgres:<password>@127.0.0.1:5432/test-cpa-blank-postgres
PAYLOAD_SECRET=241bfe11fbe0a56dd9757019
```

#### Blank w/ SQLite:
- `.env.example`:
```
DATABASE_URI=file:./your-database-name.db
PAYLOAD_SECRET=YOUR_SECRET_HERE
```
- `.env`:
```
# Added by Payload
DATABASE_URI=file:./test-cpa-blank-sqlite.db
PAYLOAD_SECRET=a7808731b93240a73a11930c
```

#### Blank w/ vercel-postgres:
- `.env.example`:
```
POSTGRES_URL=postgres://postgres:<password>@127.0.0.1:5432/your-database-name
PAYLOAD_SECRET=YOUR_SECRET_HERE
```
- `.env`:
```
# Added by Payload
POSTGRES_URL=postgres://postgres:<password>@127.0.0.1:5432/test-cpa-blank-vercel-postgres
PAYLOAD_SECRET=af3951e923e8e4662c9c3d9e
```

Fixes #9996
2024-12-17 14:13:00 -05:00
Dan Ribbens
b0b2fc6c47 feat: join field support relationships inside arrays (#9773)
### What?

Allow the join field to have a configuration `on` relationships inside
of an array, ie `on: 'myArray.myRelationship'`.

### Why?

This is a more powerful and expressive way to use the join field and not
be limited by usage of array data. For example, if you have a roles
array for multinant sites, you could add a join field on the sites to
show who the admins are.

### How?

This fixes the traverseFields function to allow the configuration to
pass sanitization. In addition, the function for querying the drizzle
tables needed to be ehanced.

Additional changes from https://github.com/payloadcms/payload/pull/9995:

- Significantly improves traverseFields and the 'join' case with a raw
query injection pattern, right now it's internal but we could expose it
at some point, for example for querying vectors.
- Fixes potential issues with not passed locale to traverseFields (it
was undefined always)
- Adds an empty array fallback for joins with localized relationships

Fixes #
https://github.com/payloadcms/payload/discussions/9643

---------

Co-authored-by: Because789 <thomas@because789.ch>
Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-12-17 13:14:43 -05:00
Jacob Fletcher
eb037a0cc6 fix: passes field permissions to custom fields (#10024)
Fixes #9888. Field permissions were not being passed into custom
components. This led to custom components, such as arrays and blocks,
unable to render default Payload fields. This was because their props
lacked the permissions object required for rendering. For example:

```ts
'use client'
import type { ArrayFieldClientComponent } from 'payload'
import { ArrayField } from '@payloadcms/ui'

export const MyArray: ArrayFieldClientComponent = (props) => <ArrayField {...props} />
```

In this example the array field itself would render, but the fields
within each row would not, because the array field did not pass its
permissions down to the rows.
2024-12-17 12:17:42 -05:00
Jarrod Flesch
99ca1babc6 fix: beforeValidate previousValue argument (#10022)
### What?
`previousValue` was incorrect. It would always return the current value.

### Why?
It was accessing siblingData instead of siblingDoc. Other hooks use
siblingDoc, but this one was using siblingData.
2024-12-17 12:08:40 -05:00
urquico
13e050582b docs: fixes typo removeTokenFromRepsonse to removeTokenFromResponse (#10026) 2024-12-17 16:52:06 +00:00
Said Akhrarov
77871050b8 fix(ui): properly sync field values in bulk upload preventing stale data overriding old docs (#9918)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes an issue where bulk upload on an upload field with
hasMany, which had errors on sequential uploads, caused only the last
successful upload to be saved to the field value.

### Why?
To save all successful uploads to the field value and sync what was
shown in the ui to the actual field data.

### How?
By triggering a rerender that syncs `populatedDocs` to the fields
`value` on each sequential successful upload after form errors were
resolved.

Fixes #9890

Before:

[Bulk-upload-before--Post---Payload.webm](https://github.com/user-attachments/assets/6396a88b-21c2-4037-b1ef-fd7f8d16103f)

After:

[Bulk-upload-after---Payload.webm](https://github.com/user-attachments/assets/8566a022-6e86-46c7-87fe-78d01e6dd8c9)

Notes:
- The core issue was that onSuccess function was not properly syncing
the correct field values resulting in stale values that would overwrite
old docs.

---------

Co-authored-by: Patrik Kozak <patrik@payloadcms.com>
2024-12-17 10:08:57 -05:00
Elliot DeNolf
e04be4bf62 templates: improve gen-templates script (#10015)
- Allow gen templates script to take template dir name arg
- All `skipDockerCompose` and `skipConfig`
2024-12-17 10:00:17 -05:00
Hugo Knorr
7037983de0 fix(templates): prevent image priority and lazy loading incompatibility (#10023)
This PR fixes an issue in the hero banner of website templates where
`priority` was passed to `ImageMedia` component but was incompatible with
NextImage `loading="lazy"`, causing error. The fix is to add a ternary
condition to check if `priority` prop is passed before setting `loading.
2024-12-17 14:56:53 +00:00
Said Akhrarov
29ad1fcb77 fix(plugin-search): prevent error on undefined value in linkToDoc component (#9932)
<!--

Thank you for the PR! Please go through the checklist below and make
sure you've completed all the steps.

Please review the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository if you haven't already.

The following items will ensure that your PR is handled as smoothly as
possible:

- PR Title must follow conventional commits format. For example, `feat:
my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not
immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic
behind a change

### What?

### Why?

### How?

Fixes #

-->
### What?
This PR fixes a runtime error encountered when navigating into a search
doc that had its' related collection doc deleted, but it itself remained
(if for example `deleteFromSearch` deletion failed for some reason).

### Why?
To prevent runtime errors for end-users using `plugin-search`.

### How?
By returning earlier if the field value is undefined or missing required
values in `LinkToDoc`.

Fixes #9443 (partially, see also: #9623)
2024-12-17 04:39:15 +00:00
Elliot DeNolf
2d2a52b00f templates: bump for v3.8.0 (#10013)
🤖 Automated bump of templates for v3.8.0

Triggered by user: @denolfe

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-16 21:31:27 -05:00
Elliot DeNolf
3f35d36934 chore(release): v3.8.0 [skip ci] 2024-12-16 21:12:02 -05:00
Sasha
41167bfbeb feat(db-vercel-postgres): allow to use a local database using pg instead of @vercel/postgres (#9771)
### What?
This PR allows you to use a local database when using
`vercelPostgresAdapter`. This adapter doesn't work with them because it
requires an SSL connection and Neon's WS proxy. Instead we fallback to
using pool from `pg` if `hostname` is either `127.0.0.1` or `localhost`.

If you still want to use `@vercel/postgres` even locally you can pass
`disableUsePgForLocalDatabase: true` here and you'd have to spin up the
DB with a special Neon's Docker Compose setup -
https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker

### Why?
Forcing people to use a cloud database locally isn't great. Not only
they are slow but also paid.

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-12-16 16:55:08 -05:00
Jacob Fletcher
ed44ec0a9c fix(ui): does not render row labels until form state returns (#10002)
Extension of #9933. Custom components are returned by form state,
meaning that if we don't wait for form state to return before rendering
row labels, the default row label component will render in briefly
before being swapped by a custom component (if applicable). Using the
new `isLoading` prop on array and block rows, we can conditionally
render them just as we currently do for the row fields themselves.
2024-12-16 21:44:19 +00:00
Elliot DeNolf
fa49e04cf8 feat(storage-vercel-blob): allow fallback to disk if token not set (#10005)
Previously with `@payloadcms/plugin-storage-blob`, if token was not set,
the plugin would throw an error. This caused a less-than-ideal developer
experience.

With this change, if the `token` value is undefined:
- Local storage will be used as a fallback
- The error will no longer be thrown.
2024-12-16 21:40:22 +00:00
Jacob Fletcher
f54e180370 fix(templates): adds priority to hero images (#10003)
Hero images should use the `priority` property so that browsers will
preload them. This is because hero images, by definition, are rendered
"above the fold" and should be treated as such, optimizing LCP. This
also means these images should _not_ define a `loading` strategy, as
this disregards the priority flag.
2024-12-16 16:21:29 -05:00
Said Akhrarov
c50f4237a4 docs: fix links in rich-text referencing old lexical sections (#9972) 2024-12-16 14:42:56 -05:00
zuccs
b0d648bf30 docs: broken lexical link (#9991) 2024-12-16 19:40:04 +00:00
Paul
8258d5c943 templates: fix missing ts-ignore in seed script causing build errors (#10001) 2024-12-16 19:24:04 +00:00
Elliot DeNolf
0f63db055b templates: bump for v3.7.0 (#10000)
🤖 Automated bump of templates for v3.7.0

Triggered by user: @paulpopus

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2024-12-16 13:08:50 -06:00
Paul
12fa4fd2f9 templates: add hero image field to posts instead of using the meta image for the hero as well (#9999)
Adds a hero image field instead of using the meta image for the hero on
posts collection
2024-12-16 18:29:21 +00:00
Sasha
6dea111d28 feat: expose req to defaultValue function arguments (#9937)
Rework of https://github.com/payloadcms/payload/pull/5912

### What?
Now, when `defaultValue` is defined as function you can receive the
`req` argument:
```ts
{
  name: 'defaultValueFromReq',
  type: 'text',
  defaultValue: async ({ req, user, locale }) => {
    return Promise.resolve(req.context.defaultValue)
  },
},
```

`user` and `locale` even though are repeated in `req`, this potentially
leaves some room to add more args in the future without removing them
now.
This also improves type for `defaultValue`:
```ts
type SerializableValue = boolean | number | object | string
export type DefaultValue =
  | ((args: {
      locale?: TypedLocale
      req: PayloadRequest
      user: PayloadRequest['user']
    }) => SerializableValue)
  | SerializableValue
```

### Why?
To access the current URL / search params / Local API and other things
directly in `defaultValue`.

### How?
Passes `req` through everywhere where we call `defaultValue()`
2024-12-16 13:18:11 -05:00
Sasha
26a10ed071 perf: reduce generated types for select by respecting interfaceName (#9870)
This PR can significantly reduce your `payload-types.ts` file if you
have sharable fields / blocks that use the `interfaceName` property.
Previously we didn't respect it for select types.

Before:
```ts
export interface Collection1Select<T extends boolean = true> {
  testing?: T;
  title?: T;
  meta?:
    | T
    | {
        title?: T;
        description?: T;
        id?: T;
      };
  blocks?:
    | T
    | {
        block1?:
          | T
          | {
              b1title?: T;
              b1description?: T;
              id?: T;
              blockName?: T;
            };
        block2?:
          | T
          | {
              b2title?: T;
              b2description?: T;
              id?: T;
              blockName?: T;
            };
      };
  updatedAt?: T;
  createdAt?: T;
}
```
After:
```ts
export interface Collection1Select<T extends boolean = true> {
  testing?: T;
  title?: T;
  meta?: T | SharedMetaArraySelect<T>;
  blocks?:
    | T
    | {
        block1?: T | SharedMetaBlockSelect<T>;
        block2?: T | AnotherSharedBlockSelect<T>;
      };
  updatedAt?: T;
  createdAt?: T;
}

/**
 * This interface was referenced by `Config`'s JSON-Schema
 * via the `definition` "SharedMetaArray_select".
 */
export interface SharedMetaArraySelect<T extends boolean = true> {
  title?: T;
  description?: T;
  id?: T;
}
/**
 * This interface was referenced by `Config`'s JSON-Schema
 * via the `definition` "SharedMetaBlock_select".
 */
export interface SharedMetaBlockSelect<T extends boolean = true> {
  b1title?: T;
  b1description?: T;
  id?: T;
  blockName?: T;
}
/**
 * This interface was referenced by `Config`'s JSON-Schema
 * via the `definition` "AnotherSharedBlock_select".
 */
export interface AnotherSharedBlockSelect<T extends boolean = true> {
  b2title?: T;
  b2description?: T;
  id?: T;
  blockName?: T;
}
```

Regenerated all the types in `/test`. The diff is noticeable for
`fields` -
https://github.com/payloadcms/payload/pull/9870/files#diff-95beaac24c72c7bd60933e325cdcd94a4c3630a1ce22fabad624ec80cc74fc8c
2024-12-16 17:22:17 +02:00
Sasha
727fba7b1c refactor: deduplicate and abstract SQL schema building (#9987)
### What?
Abstracts SQL schema building, significantly reducing code duplication
for SQLite / Postgres

db-sqlite lines count From:
```sh
 wc -l **/*.ts
      62 src/connect.ts
      32 src/countDistinct.ts
       9 src/createJSONQuery/convertPathToJSONTraversal.ts
      86 src/createJSONQuery/index.ts
      15 src/defaultSnapshot.ts
       6 src/deleteWhere.ts
      21 src/dropDatabase.ts
      15 src/execute.ts
     178 src/index.ts
     139 src/init.ts
      19 src/insert.ts
      19 src/requireDrizzleKit.ts
     544 src/schema/build.ts
      27 src/schema/createIndex.ts
      38 src/schema/getIDColumn.ts
      13 src/schema/idToUUID.ts
      28 src/schema/setColumnID.ts
     787 src/schema/traverseFields.ts
      18 src/schema/withDefault.ts
     248 src/types.ts
    2304 total
```

To:
```sh
wc -l **/*.ts
      62 src/connect.ts
      32 src/countDistinct.ts
       9 src/createJSONQuery/convertPathToJSONTraversal.ts
      86 src/createJSONQuery/index.ts
      15 src/defaultSnapshot.ts
       6 src/deleteWhere.ts
      21 src/dropDatabase.ts
      15 src/execute.ts
     180 src/index.ts
      39 src/init.ts
      19 src/insert.ts
      19 src/requireDrizzleKit.ts
     149 src/schema/buildDrizzleTable.ts
      32 src/schema/setColumnID.ts
     258 src/types.ts
     942 total
```

Builds abstract schema in shared drizzle package that later gets
converted by SQLite/ Postgres specific implementation into drizzle
schema.
This, apparently can also help here
https://github.com/payloadcms/payload/pull/9953. It should be very
trivial to implement a MySQL adapter with this as well.
2024-12-16 17:17:18 +02:00
Sasha
c187bff581 fix: remove localized property from RowField and CollapsibleField (#9672)
### What?
Removes the `localized` property from typescript suggestion for row and
collapsible fields.

### Why?
Currently, this property doesn't do anything for them. This may be
changed when/if we support `name` for them, but it'll work only with
`name`.

Fixes https://github.com/payloadcms/payload/issues/4720
2024-12-16 09:57:21 -05:00
Sasha
00909ec5c4 fix(db-sqlite): working point field CRUD and default value (#9989)
Previously, the point field with SQLite was incorrectly built to the
schema and not parsed to the result.
Now, it works with SQLite, just doesn't support queries (`near` etc.).
Fixes
https://github.com/payloadcms/payload/pull/9987#discussion_r1885674299
2024-12-16 07:37:47 +02:00
Dan Ribbens
2ec4d0c2ef feat: join field admin.defaultColumns (#9982)
Add the ability to specify which columns should appear in the
relationship table of a join fields

The new property is in the Join field `admin.defaultColumns` and can be
set to an array of strings containing the field names in the desired
order.
2024-12-15 03:31:31 +00:00
1335 changed files with 60265 additions and 36577 deletions

View File

@@ -180,6 +180,7 @@ jobs:
- postgres-uuid
- supabase
- sqlite
- sqlite-uuid
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -277,9 +278,9 @@ jobs:
suite:
- _community
- access-control
- admin__e2e__1
- admin__e2e__2
- admin__e2e__3
- admin__e2e__general
- admin__e2e__list-view
- admin__e2e__document-view
- admin-root
- auth
- auth-basic
@@ -288,6 +289,7 @@ jobs:
- fields-relationship
- fields__collections__Array
- fields__collections__Blocks
- fields__collections__Checkbox
- fields__collections__Collapsible
- fields__collections__ConditionalLogic
- fields__collections__CustomID
@@ -413,6 +415,8 @@ jobs:
- template: with-vercel-postgres
database: postgres
- template: plugin
# Re-enable once PG conncection is figured out
# - template: with-vercel-website
# database: postgres
@@ -466,6 +470,7 @@ jobs:
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: 6.0
if: matrix.database == 'mongodb'
- name: Build Template
run: |

View File

@@ -41,7 +41,9 @@ jobs:
db-vercel-postgres
db-sqlite
drizzle
email-\*
email-nodemailer
email-resend
eslint
graphql
live-preview

View File

@@ -25,19 +25,16 @@ jobs:
with:
debug-only: ${{ inputs.dry-run || false }}
days-before-stale: 23
days-before-close: 7
days-before-pr-close: -1 # Never close PRs
days-before-stale: 30
days-before-close: -1 # Disable closing
ascending: true
operations-per-run: 300
exempt-all-assignees: true
# Issues
stale-issue-label: stale
exempt-issue-labels: 'prioritized,keep,created-by: Payload team,created-by: Contributor,status: verified'
stale-issue-message: |
This issue has been marked as stale due to lack of activity.
To keep this issue open, please indicate that it is still relevant in a comment below.
stale-issue-message: ''
close-issue-message: |
This issue was automatically closed due to lack of activity.
@@ -45,10 +42,7 @@ jobs:
# Pull Requests
stale-pr-label: stale
exempt-pr-labels: 'prioritized,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.
stale-pr-message: ''
close-pr-message: |
This pull request was automatically closed due to lack of activity.

View File

@@ -96,7 +96,11 @@ 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`).
If you'd like to run the examples, you can use `create-payload-app` to create a project from one:
```sh
npx create-payload-app --example example_name
```
You can see more examples at:

View File

@@ -76,7 +76,7 @@ If a Collection supports [Versions](../versions/overview), the following additio
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):
To add create Access Control to a Collection, use the `create` property in the [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
@@ -104,7 +104,7 @@ The following arguments are provided to the `create` function:
Returns a boolean which allows/denies access to the `read` request.
To add read Access Control to a Collection, use the `read` property in the [Collection Config](../collections/overview):
To add read Access Control to a Collection, use the `read` property in the [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
@@ -122,7 +122,7 @@ export const CollectionWithReadAccess: CollectionConfig = {
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
Return a [Query](../queries/overview) to limit the Documents to only those that match the constraint. This can be helpful to restrict users' access to specific Documents. [More details](../queries/overview).
</Banner>
@@ -158,7 +158,7 @@ The following arguments are provided to the `read` function:
Returns a boolean which allows/denies access to the `update` request.
To add update Access Control to a Collection, use the `update` property in the [Collection Config](../collections/overview):
To add update Access Control to a Collection, use the `update` property in the [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
@@ -176,7 +176,7 @@ export const CollectionWithUpdateAccess: CollectionConfig = {
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
Return a [Query](../queries/overview) to limit the Documents to only those that match the constraint. This can be helpful to restrict users' access to specific Documents. [More details](../queries/overview).
</Banner>
@@ -208,7 +208,7 @@ The following arguments are provided to the `update` function:
Similarly to the Update function, returns a boolean or a [query constraint](/docs/queries/overview) to limit which documents can be deleted by which users.
To add delete Access Control to a Collection, use the `delete` property in the [Collection Config](../collections/overview):
To add delete Access Control to a Collection, use the `delete` property in the [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'
@@ -252,10 +252,10 @@ export const canDeleteCustomer: Access = async ({ req, id }) => {
The following arguments are provided to the `delete` function:
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------- |
| Option | Description |
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object with additional `user` property, which is the currently logged in user. |
| **`id`** | `id` of document requested to delete.
| **`id`** | `id` of document requested to delete. |
### Admin
@@ -286,9 +286,9 @@ The following arguments are provided to the `admin` function:
### Unlock
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/overview#options).
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/overview#config-options).
To add Unlock Access Control to a Collection, use the `unlock` property in the [Collection Config](../collections/overview):
To add Unlock Access Control to a Collection, use the `unlock` property in the [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload'

View File

@@ -6,7 +6,7 @@ desc: Field-level Access Control is specified within a field's config, and allow
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Field Access Control is [Access Control](../overview) used to restrict access to specific [Fields](../fields/overview) within a Document.
Field Access Control is [Access Control](../access-control/overview) used to restrict access to specific [Fields](../fields/overview) within a Document.
To add Access Control to a Field, use the `access` property in your [Field Config](../fields/overview):
@@ -22,7 +22,7 @@ export const FieldWithAccessControl: Field = {
```
<Banner type="warning">
<strong>Note:</strong>
**Note:**
Field Access Controls does not support returning [Query](../queries/overview) constraints like [Collection Access Control](./collections) does.
</Banner>

View File

@@ -6,7 +6,7 @@ desc: Global-level Access Control is specified within each Global's `access` pro
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Global Access Control is [Access Control](../overview) used to restrict access to [Global](../globals/overview) Documents, as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Global.
Global Access Control is [Access Control](../access-control/overview) used to restrict access to [Global](../configuration/globals) Documents, as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Global.
To add Access Control to a Global, use the `access` property in your [Global Config](../configuration/globals):
@@ -25,7 +25,7 @@ export const GlobalWithAccessControl: GlobalConfig = {
Access Control is specific to the operation of the request.
To add Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../globals/overview):
To add Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):
```ts
import { GlobalConfig } from 'payload'
@@ -63,7 +63,7 @@ If a Global supports [Versions](../versions/overview), the following additional
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can read this global based on its current properties.
To add read Access Control to a [Global](../configuration/globals), use the `read` property in the [Global Config](../globals/overview):
To add read Access Control to a [Global](../configuration/globals), use the `read` property in the [Global Config](../configuration/globals):
```ts
import { GlobalConfig } from 'payload'
@@ -90,7 +90,7 @@ The following arguments are provided to the `read` function:
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can update this global based on its current properties.
To add update Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../globals/overview):
To add update Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../configuration/globals):
```ts
import { GlobalConfig } from 'payload'
@@ -118,7 +118,7 @@ The following arguments are provided to the `update` function:
If the Global has [Versions](../versions/overview) enabled, the `readVersions` Access Control function determines whether or not the currently logged in user can access the version history of a Document.
To add Read Versions Access Control to a Collection, use the `readVersions` property in the [Global Config](../globals/overview):
To add Read Versions Access Control to a Collection, use the `readVersions` property in the [Global Config](../configuration/globals):
```ts
import type { GlobalConfig } from 'payload'

View File

@@ -29,7 +29,7 @@ There are three main types of Access Control in Payload:
## Default Access Control
Payload provides default Access Control so that your data is secured behind [Authentication](../authentication) without additional configuration. To do this, Payload sets a default function that simply checks if a user is present on the request. You can override this default behavior by defining your own Access Control functions as needed.
Payload provides default Access Control so that your data is secured behind [Authentication](../authentication/overview) without additional configuration. To do this, Payload sets a default function that simply checks if a user is present on the request. You can override this default behavior by defining your own Access Control functions as needed.
Here is the default Access Control that Payload provides:
@@ -42,7 +42,7 @@ const defaultPayloadAccess = ({ req: { user } }) => {
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
In the [Local API](../local-api/overview), all Access Control is _skipped_ by default. This allows your server to have full control over your application. To opt back in, you can set the `overrideAccess` option to `false` in your requests.
</Banner>
@@ -53,7 +53,7 @@ The Admin Panel responds dynamically to your changes to Access Control. For exam
To accomplish this, Payload exposes the [Access Operation](../authentication/operations#access). Upon login, Payload executes each Access Control function at the top level, across all Collections, Globals, and Fields, and returns a response that contains a reflection of what the currently authenticated user can do within your application.
<Banner type="warning">
<strong>Important:</strong>
**Important:**
When your access control functions are executed via the [Access Operation](../authentication/operations#access), the `id` and `data` arguments will be `undefined`. This is because Payload is executing your functions without referencing a specific Document.
</Banner>

View File

@@ -65,21 +65,21 @@ export const MyCollection: SanitizedCollectionConfig = {
The following options are available:
| Path | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table
| **`Description`** | A component to render below the Collection label in the List View. An alternative to the `admin.description` property. |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| Path | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`Description`** | A component to render below the Collection label in the List View. An alternative to the `admin.description` property. |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
**Note:**
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
@@ -124,7 +124,7 @@ preview: (doc, { req }) => `${req.protocol}//${req.host}/${doc.slug}` // highlig
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>
@@ -177,6 +177,6 @@ export const Posts: CollectionConfig = {
```
<Banner type="warning">
<strong>Tip:</strong>
**Tip:**
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>

View File

@@ -11,7 +11,7 @@ The Payload [Admin Panel](./overview) is designed to be as minimal and straightf
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default. 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>
**Note:**
Client Components continue to be fully supported. To use Client Components in your app, simply include the `use client` directive. Payload will automatically detect and remove all default, [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types) before rendering your component. [More details](#client-components).
</Banner>
@@ -46,7 +46,7 @@ const config = buildConfig({
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
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>
@@ -127,7 +127,7 @@ The Import Map is automatically regenerated at startup and whenever Hot Module R
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):
To add a custom import to the Import Map, use the `admin.dependencies` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
@@ -184,7 +184,7 @@ Each Custom Component receives the following props by default:
| `i18n` | The [i18n](../configuration/i18n) object. |
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
All Custom Components also receive various other props that are specific component being rendered. See [Root Components](#root-components), [Collection Components](./collections#custom-components), [Global Components](./globals#custom-components), or [Field Components](./fields#custom-components) for a complete list of all default props per component.
</Banner>
@@ -243,7 +243,7 @@ export const MyClientComponent: React.FC = () => {
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
Client Components cannot be passed [non-serializable props](https://react.dev/reference/rsc/use-client#serializable-types). If you are rendering your Client Component _from within_ a Server Component, ensure that its props are serializable.
</Banner>
@@ -455,7 +455,7 @@ Payload also exports its [SCSS](https://sass-lang.com) library for reuse which i
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
You can also drill into Payload's own component styles, or easily apply global, app-wide CSS. More on that [here](./customizing-css).
</Banner>
@@ -464,7 +464,7 @@ Payload also exports its [SCSS](https://sass-lang.com) library for reuse which i
Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo or the main nav.
To override Root Components, use the `admin.components` property in your [Payload Config](../getting-started/overview):
To override Root Components, use the `admin.components` property in your [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
@@ -503,7 +503,7 @@ The following options are available:
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
**Note:**
You can also use set [Collection Components](./collections#custom-components) and [Global Components](./globals#custom-components) in their respective configs.
</Banner>
@@ -546,5 +546,5 @@ export const useMyCustomContext = () => useContext(MyCustomContext)
```
<Banner type="warning">
<strong>Reminder:</strong>React Context exists only within Client Components. This means they must include the `use client` directive at the top of their files and cannot contain server-only code. To use a Server Component here, simply _wrap_ your Client Component with it.
**Reminder:**React Context exists only within Client Components. This means they must include the `use client` directive at the top of their files and cannot contain server-only code. To use a Server Component here, simply _wrap_ your Client Component with it.
</Banner>

View File

@@ -29,7 +29,7 @@ Here is an example of how you might target the Dashboard View and change the bac
```
<Banner type="warning">
<strong>Note:</strong>
**Note:**
If you are building [Custom Components](./components), 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>
@@ -77,7 +77,7 @@ The following variables are defined and can be overridden:
For an up-to-date, comprehensive list of all available variables, please refer to the [Source Code](https://github.com/payloadcms/payload/blob/main/packages/ui/src/scss).
<Banner type="warning">
<strong>Warning:</strong>
**Warning:**
If you're overriding colors or theme elevations, make sure to consider how [your changes will affect dark mode](#dark-mode).
</Banner>

View File

@@ -11,7 +11,7 @@ keywords:
For example, your app might need to render a specific interface that Payload does not inherently support, such as a color picker. To do this, you could replace the default [Text Field](../fields/text) input with your own user-friendly component that formats the data into a valid color value.
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
Don't see a built-in field type that you need? Build it! Using a combination of [Field Validations](../fields/overview#validation)
and [Custom Components](./components), you can override the entirety of how a component functions within the [Admin Panel](./overview) to effectively create your own field type.
</Banner>
@@ -87,7 +87,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
To replace the Field Description with a [Custom Component](./components), use the `admin.components.Description` property. [More details](#description).
</Banner>
@@ -122,7 +122,7 @@ All Description Functions receive the following arguments:
| **`t`** | The `t` function used to internationalize the Admin Panel. [More details](../configuration/i18n) |
<Banner type="info">
<strong>Note:</strong>
**Note:**
If you need to subscribe to live updates within your form, use a Description Component instead. [More details](#description).
</Banner>
@@ -242,31 +242,31 @@ _For details on how to build Custom Components, see [Building Custom Components]
All Field Components receive the following props by default:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
| **`field`** | In Client Components, this is the sanitized Client Field Config. In Server Components, this is the original Field Config. Server Components will also receive the sanitized field config through the`clientField` prop (see below). |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`validate`** | A function that can be used to validate the field. |
| **`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. `posts.myGroup.myArray.myField`. |
| **`indexPath`** | A hyphen-notated string representing the path to the field _within the nearest named ancestor field_, i.e. `0-0` |
| Property | Description |
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document. |
| **`field`** | In Client Components, this is the sanitized Client Field Config. In Server Components, this is the original Field Config. Server Components will also receive the sanitized field config through the`clientField` prop (see below). |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`validate`** | A function that can be used to validate the field. |
| **`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. `posts.myGroup.myArray.myField`. |
| **`indexPath`** | A hyphen-notated string representing the path to the field _within the nearest named ancestor field_, i.e. `0-0` |
In addition to the above props, all Server Components will also receive the following props:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`clientField`** | The serializable Client Field Config. |
| **`field`** | The Field Config. [More details](../fields/overview). |
| **`data`** | The current document being edited. |
| **`i18n`** | The [i18n](../configuration/i18n) object.
| **`payload`** | The [Payload](../local-api/overview) class. |
| **`permissions`** | The field permissions based on the currently authenticated user. |
| **`siblingData`** | The data of the field's siblings. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`value`** | The value of the field at render-time. |
| Property | Description |
| ----------------- | ----------------------------------------------------------------------------- |
| **`clientField`** | The serializable Client Field Config. |
| **`field`** | The Field Config. [More details](../fields/overview). |
| **`data`** | The current document being edited. |
| **`i18n`** | The [i18n](../configuration/i18n) object. |
| **`payload`** | The [Payload](../local-api/overview) class. |
| **`permissions`** | The field permissions based on the currently authenticated user. |
| **`siblingData`** | The data of the field's siblings. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`value`** | The value of the field at render-time. |
#### Sending and receiving values from the form
@@ -399,7 +399,7 @@ import type {
### Description
Alternatively to the [Description Property](#the-description-property), you can also use a [Custom Component](./components) as the Field Description. This can be useful when you need to provide more complex feedback to the user, such as rendering dynamic field values or other interactive elements.
Alternatively to the [Description Property](#field-descriptions), you can also use a [Custom Component](./components) as the Field Description. This can be useful when you need to provide more complex feedback to the user, such as rendering dynamic field values or other interactive elements.
To add a Description Component to a field, use the `admin.components.Description` property in your [Field Config](../fields/overview):

View File

@@ -65,7 +65,7 @@ The following options are available:
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
**Note:**
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
@@ -102,6 +102,6 @@ The preview function receives two arguments:
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Note:</strong>
**Note:**
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>

View File

@@ -9,7 +9,7 @@ keywords: admin, components, custom, documentation, Content Management System, c
Payload provides a variety of powerful [React Hooks](https://react.dev/reference/react-dom/hooks) that can be used within your own [Custom Components](./components), such as [Custom Fields](./fields). With them, you can interface with Payload itself to build just about any type of complex customization you can think of.
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
All Custom Components are [React Server Components](https://react.dev/reference/rsc/server-components) by default. Hooks, on the other hand, are only available in client-side environments. To use hooks, [ensure your component is a client component](./components#client-components).
</Banner>
@@ -78,7 +78,7 @@ type FieldType<T> = {
There are times when a custom field component needs to have access to data from other fields, and you have a few options to do so. The `useFormFields` hook is a powerful and highly performant way to retrieve a form's field state, as well as to retrieve the `dispatchFields` method, which can be helpful for setting other fields' form states from anywhere within a form.
<Banner type="success">
<strong>This hook is great for retrieving only certain fields from form state</strong> because it
**This hook is great for retrieving only certain fields from form state** because it
ensures that it will only cause a rerender when the items that you ask for change.
</Banner>
@@ -150,15 +150,15 @@ You can send the following actions to the `dispatchFields` function.
| **`REPLACE_STATE`** | Completely replaces form state |
| **`UPDATE`** | Update any property of a specific field's state |
To see types for each action supported within the `dispatchFields` hook, check out the Form types [here](https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/components/forms/Form/types.ts).
To see types for each action supported within the `dispatchFields` hook, check out the Form types [here](https://github.com/payloadcms/payload/blob/main/packages/ui/src/forms/Form/types.ts).
## useForm
The `useForm` hook can be used to interact with the form itself, and sends back many methods that can be used to reactively fetch form state without causing rerenders within your components each time a field is changed. This is useful if you have action-based callbacks that your components fire, and need to interact with form state _based on a user action_.
<Banner type="warning">
<strong>Warning:</strong>
<br />
**Warning:**
This hook is optimized to avoid causing rerenders when fields change, and as such, its `fields`
property will be out of date. You should only leverage this hook if you need to perform actions
against the form in response to your users' actions. Do not rely on its returned "fields" as being
@@ -176,7 +176,7 @@ The `useForm` hook returns an object with the following properties:
rows={[
[
{
value: <strong><code>fields</code></strong>,
value: "**`fields`**",
},
{
value: "Deprecated. This property cannot be relied on as up-to-date.",
@@ -187,7 +187,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>submit</code></strong>,
value: "**`submit`**",
},
{
value: "Method to trigger the form to submit",
@@ -198,7 +198,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>dispatchFields</code></strong>,
value: "**`dispatchFields`**",
},
{
value: "Dispatch actions to the form field state",
@@ -209,7 +209,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>validateForm</code></strong>,
value: "**`validateForm`**",
},
{
value: "Trigger a validation of the form state",
@@ -220,10 +220,10 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>createFormData</code></strong>,
value: "**`createFormData`**",
},
{
value: <>Create a <code>multipart/form-data</code> object from the current form's state</>,
value: "Create a `multipart/form-data` object from the current form's state",
},
{
value: ''
@@ -231,7 +231,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>disabled</code></strong>,
value: "**`disabled`**",
},
{
value: "Boolean denoting whether or not the form is disabled",
@@ -242,7 +242,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>getFields</code></strong>,
value: "**`getFields`**",
},
{
value: 'Gets all fields from state',
@@ -253,7 +253,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>getField</code></strong>,
value: "**`getField`**",
},
{
value: 'Gets a single field from state by path',
@@ -264,7 +264,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>getData</code></strong>,
value: "**`getData`**",
},
{
value: 'Returns the data stored in the form',
@@ -275,7 +275,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>getSiblingData</code></strong>,
value: "**`getSiblingData`**",
},
{
value: 'Returns form sibling data for the given field path',
@@ -286,10 +286,10 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>setModified</code></strong>,
value: "**`setModified`**",
},
{
value: <>Set the form\'s <code>modified</code> state</>,
value: "Set the form\'s `modified` state",
},
{
value: '',
@@ -297,10 +297,10 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>setProcessing</code></strong>,
value: "**`setProcessing`**",
},
{
value: <>Set the form\'s <code>processing</code> state</>,
value: "Set the form\'s `processing` state",
},
{
value: '',
@@ -308,10 +308,10 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>setSubmitted</code></strong>,
value: "**`setSubmitted`**",
},
{
value: <>Set the form\'s <code>submitted</code> state</>,
value: "Set the form\'s `submitted` state",
},
{
value: '',
@@ -319,7 +319,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>formRef</code></strong>,
value: "**`formRef`**",
},
{
value: 'The ref from the form HTML element',
@@ -330,7 +330,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>reset</code></strong>,
value: "**`reset`**",
},
{
value: 'Method to reset the form to its initial state',
@@ -341,7 +341,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>addFieldRow</code></strong>,
value: "**`addFieldRow`**",
},
{
value: "Method to add a row on an array or block field",
@@ -350,8 +350,7 @@ The `useForm` hook returns an object with the following properties:
drawerTitle: 'addFieldRow',
drawerDescription: 'A useful method to programmatically add a row to an array or block field.',
drawerSlug: 'addFieldRow',
drawerContent: (
<>
drawerContent: `
<TableWithDrawers
columns={[
'Prop',
@@ -360,7 +359,7 @@ The `useForm` hook returns an object with the following properties:
rows={[
[
{
value: <strong><code>path</code></strong>,
value: "**\\\`path\\\`**",
},
{
value: "The path to the array or block field",
@@ -368,7 +367,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>rowIndex</code></strong>,
value: "**\\\`rowIndex\\\`**",
},
{
value: "The index of the row to add. If omitted, the row will be added to the end of the array.",
@@ -376,7 +375,7 @@ The `useForm` hook returns an object with the following properties:
],
[
{
value: <strong><code>data</code></strong>,
value: "**\\\`data\\\`**",
},
{
value: "The data to add to the row",
@@ -385,14 +384,9 @@ The `useForm` hook returns an object with the following properties:
]}
/>
{' '}
<br />
{' '}
<pre>
{`import { useForm } from "payload/components/forms";
\`\`\`tsx
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { addFieldRow } = useForm()
@@ -415,12 +409,13 @@ export const CustomArrayManager = () => {
Add Row
</button>
)
}`}
</pre>
}
\`\`\`
<p>An example config to go along with the Custom Component</p>
<pre>
{`const ExampleCollection = {
An example config to go along with the Custom Component
\`\`\`tsx
const ExampleCollection = {
slug: "example-collection",
fields: [
{
@@ -443,15 +438,14 @@ export const CustomArrayManager = () => {
},
},
],
}`}
</pre>
</>
)
}
\`\`\`
`
}
],
[
{
value: <strong><code>removeFieldRow</code></strong>,
value: "**`removeFieldRow`**",
},
{
value: "Method to remove a row from an array or block field",
@@ -460,8 +454,7 @@ export const CustomArrayManager = () => {
drawerTitle: 'removeFieldRow',
drawerDescription: 'A useful method to programmatically remove a row from an array or block field.',
drawerSlug: 'removeFieldRow',
drawerContent: (
<>
drawerContent: `
<TableWithDrawers
columns={[
'Prop',
@@ -470,7 +463,7 @@ export const CustomArrayManager = () => {
rows={[
[
{
value: <strong><code>path</code></strong>,
value: "**\\\`path\\\`**",
},
{
value: "The path to the array or block field",
@@ -478,7 +471,7 @@ export const CustomArrayManager = () => {
],
[
{
value: <strong><code>rowIndex</code></strong>,
value: "**\\\`rowIndex\\\`**",
},
{
value: "The index of the row to remove",
@@ -487,14 +480,10 @@ export const CustomArrayManager = () => {
]}
/>
{' '}
<br />
{' '}
<pre>
{`import { useForm } from "payload/components/forms";
\`\`\`tsx
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { removeFieldRow } = useForm()
@@ -512,12 +501,13 @@ export const CustomArrayManager = () => {
Remove Row
</button>
)
}`}
</pre>
}
\`\`\`
<p>An example config to go along with the Custom Component</p>
<pre>
{`const ExampleCollection = {
An example config to go along with the Custom Component
\`\`\`tsx
const ExampleCollection = {
slug: "example-collection",
fields: [
{
@@ -540,15 +530,14 @@ export const CustomArrayManager = () => {
},
},
],
}`}
</pre>
</>
)
}
\`\`\`
`
}
],
[
{
value: <strong><code>replaceFieldRow</code></strong>,
value: "**`replaceFieldRow`**",
},
{
value: "Method to replace a row from an array or block field",
@@ -557,8 +546,7 @@ export const CustomArrayManager = () => {
drawerTitle: 'replaceFieldRow',
drawerDescription: 'A useful method to programmatically replace a row from an array or block field.',
drawerSlug: 'replaceFieldRow',
drawerContent: (
<>
drawerContent: `
<TableWithDrawers
columns={[
'Prop',
@@ -567,7 +555,7 @@ export const CustomArrayManager = () => {
rows={[
[
{
value: <strong><code>path</code></strong>,
value: "**\\\`path\\\`**",
},
{
value: "The path to the array or block field",
@@ -575,7 +563,7 @@ export const CustomArrayManager = () => {
],
[
{
value: <strong><code>rowIndex</code></strong>,
value: "**\\\`rowIndex\\\`**",
},
{
value: "The index of the row to replace",
@@ -583,7 +571,7 @@ export const CustomArrayManager = () => {
],
[
{
value: <strong><code>data</code></strong>,
value: "**\\\`data\\\`**",
},
{
value: "The data to replace within the row",
@@ -592,14 +580,11 @@ export const CustomArrayManager = () => {
]}
/>
{' '}
<br />
{' '}
<pre>
{`import { useForm } from "payload/components/forms";
\`\`\`tsx
import { useForm } from "payload/components/forms";
export const CustomArrayManager = () => {
const { replaceFieldRow } = useForm()
@@ -622,12 +607,13 @@ export const CustomArrayManager = () => {
Replace Row
</button>
)
}`}
</pre>
}
\`\`\`
<p>An example config to go along with the Custom Component</p>
<pre>
{`const ExampleCollection = {
An example config to go along with the Custom Component
\`\`\`tsx
const ExampleCollection = {
slug: "example-collection",
fields: [
{
@@ -650,10 +636,9 @@ export const CustomArrayManager = () => {
},
},
],
}`}
</pre>
</>
)
}
\`\`\`
`
}
],
]}
@@ -694,20 +679,25 @@ const CustomComponent: React.FC = () => {
## useDocumentInfo
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
The `useDocumentInfo` hook provides information about the current document being edited, including the following:
| Property | Description |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
| **`collection`** | If the doc is a collection, its Collection Config will be returned |
| **`global`** | If the doc is a global, its Global Config will be returned |
| **`currentEditor`** | The user currently editing the document. |
| **`docConfig`** | Either the Collection or Global config of the document, depending on what is being edited. |
| **`documentIsLocked`** | Whether the document is currently locked by another user. |
| **`id`** | If the doc is a collection, its ID will be returned |
| **`preferencesKey`** | The `preferences` key to use when interacting with document-level user preferences |
| **`versions`** | Versions of the current doc |
| **`unpublishedVersions`** | Unpublished versions of the current doc |
| **`publishedDoc`** | The currently published version of the doc being edited |
| **`getVersions`** | Method to trigger the retrieval of document versions |
| **`docPermissions`** | The current documents permissions. Collection document permissions fallback when no id is present (i.e. on create) |
| **`getDocPermissions`** | Method to trigger the retrieval of document level permissions |
| **`getDocPermissions`** | Method to retrieve document-level user preferences. |
| **`getDocPreferences`** | Method to retrieve document-level user preferences. |
| **`hasPublishedDoc`** | Whether the document has a published version. |
| **`incrementVersionCount`** | Method to increment the version count of the document. |
| **`preferencesKey`** | The `preferences` key to use when interacting with document-level user preferences. |
| **`versions`** | Versions of the current doc. |
| **`unpublishedVersions`** | Unpublished versions of the current doc. |
| **`publishedDoc`** | The currently published version of the doc being edited. |
| **`getVersions`** | Method to retrieve document versions. |
| **`docPermissions`** | The current documents permissions. Collection document permissions fallback when no id is present (i.e. on create). |
| **`versionCount`** | The current version count of the document. |
**Example:**
@@ -733,6 +723,37 @@ const LinkFromCategoryToPosts: React.FC = () => {
}
```
## useListQuery
The `useListQuery` hook is used to subscribe to the data, current query, and other properties used within the List View. You can use this hook within any Custom Component rendered within the List View.
```tsx
'use client'
import { useListQuery } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// highlight-start
const { data, query } = useListQuery()
// highlight-end
// ...
}
```
The `useListQuery` hook returns an object with the following properties:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------- |
| **`data`** | The data that is being displayed in the List View. |
| **`defaultLimit`**| The default limit of items to display in the List View. |
| **`defaultSort`** | The default sort order of items in the List View. |
| **`handlePageChange`** | A method to handle page changes in the List View. |
| **`handlePerPageChange`** | A method to handle per page changes in the List View. |
| **`handleSearchChange`** | A method to handle search changes in the List View. |
| **`handleSortChange`** | A method to handle sort changes in the List View. |
| **`handleWhereChange`** | A method to handle where changes in the List View. |
| **`query`** | The current query that is being used to fetch the data in the List View. |
## 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:

View File

@@ -20,13 +20,13 @@ When a user starts editing a document, Payload locks it for that user. If anothe
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 or global by setting the <code>lockDocuments</code> property to <code>false</code>. </Banner>
<Banner type="info"> **Note:** If your application does not require document locking, you can disable this feature for any collection or global by setting the `lockDocuments` property to `false`. </Banner>
### Config Options
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:
Here's an example configuration for document locking:
```ts
import type { CollectionConfig } from 'payload'

View File

@@ -57,7 +57,7 @@ The following options are available for Root Metadata:
| **`titleSuffix`** | `string` | A suffix to append to the end of the title of every page. Defaults to "- Payload". |
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Metadata](./collections), [Global Metadata](./globals), and [Document Metadata](./documents) in their respective configs.
</Banner>

View File

@@ -10,7 +10,7 @@ Payload dynamically generates a beautiful, [fully type-safe](../typescript/overv
The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](./components)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors.
The Admin Panel is written in [TypeScript](https://www.typescriptlang.org) and built with [React](https://react.dev) using the [Next.js App Router](https://nextjs.org/docs/app). It supports [React Server Components](https://react.dev/reference/rsc/server-components), enabling the use of the [Local API](/docs/local-api/overview) on the front-end. You can install Payload into any [existing Next.js app in just one line](../getting-started/installation) and [deploy it anywhere](../production).
The Admin Panel is written in [TypeScript](https://www.typescriptlang.org) and built with [React](https://react.dev) using the [Next.js App Router](https://nextjs.org/docs/app). It supports [React Server Components](https://react.dev/reference/rsc/server-components), enabling the use of the [Local API](/docs/local-api/overview) on the front-end. You can install Payload into any [existing Next.js app in just one line](../getting-started/installation) and [deploy it anywhere](../production/deployment).
<Banner type="success">
The Payload Admin Panel is designed to be as minimal and straightforward as possible to allow easy customization and control. [Learn more](./components).
@@ -56,8 +56,8 @@ As shown above, all Payload routes are nested within the `(payload)` route group
The `admin` directory contains all the _pages_ related to the interface itself, whereas the `api` and `graphql` directories contains all the _routes_ related to the [REST API](../rest-api/overview) and [GraphQL API](../graphql/overview). All admin routes are [easily configurable](#customizing-routes) to meet your application's exact requirements.
<Banner type="warning">
<strong>Note:</strong>
If you don't use the [REST API](../rest/overview) or [GraphQL API](../graphql/overview), you can delete the [Next.js files corresponding to those routes](../admin/overview#project-structure), however, the overhead of this API is completely constrained to these endpoints, and will not slow down or affect Payload outside of the endpoints.
**Note:**
If you don't intend to use the Admin Panel, [REST API](../rest/overview), or [GraphQL API](../graphql/overview), you can opt-out by simply deleting their corresponding directories within your Next.js app. The overhead, however, is completely constrained to these routes, and will not slow down or affect Payload outside when not in use.
</Banner>
Finally, the `custom.scss` file is where you can add or override globally-oriented styles in the Admin Panel, such as modify the color palette. Customizing the look and feel through CSS alone is a powerful feature of the Admin Panel, [more on that here](./customizing-css).
@@ -94,7 +94,6 @@ The following options are available:
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| **`disable`** | If set to `true`, the entire Admin Panel will be disabled. |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`meta`** | Base metadata to use for the Admin Panel. [More details](./metadata). |
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
@@ -103,7 +102,7 @@ The following options are available:
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Admin Options](./collections) and [Global Admin Options](./globals) through their respective `admin` keys.
</Banner>
@@ -123,8 +122,8 @@ const config = buildConfig({
```
<Banner type="warning">
<strong>Important:</strong>
<br />
**Important:**
The Admin Panel can only be used by a single auth-enabled Collection. To enable authentication for a Collection, simply set `auth: true` in the Collection's configuration. See [Authentication](../authentication/overview) for more information.
</Banner>
@@ -177,7 +176,7 @@ The following options are available:
| `graphQLPlayground` | `/graphql-playground` | The GraphQL Playground. |
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
You can easily add _new_ routes to the Admin Panel through [Custom Endpoints](../rest-api/overview#custom-endpoints) and [Custom Views](./views).
</Banner>
@@ -195,7 +194,7 @@ app/
```
<Banner type="warning">
<strong>Note:</strong>
**Note:**
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>
@@ -232,7 +231,7 @@ The following options are available:
| `unauthorized` | `/unauthorized` | The unauthorized page. |
<Banner type="success">
<strong>Note:</strong>
**Note:**
You can also swap out entire _views_ out for your own, using the `admin.views` property of the Payload Config. See [Custom Views](./views) for more information.
</Banner>

View File

@@ -16,8 +16,8 @@ Out of the box, Payload handles the persistence of your users' preferences in a
1. The last-known state of the `Nav` component, etc.
<Banner type="warning">
<strong>Important:</strong>
<br />
**Important:**
All preferences are stored on an individual user basis. Payload automatically recognizes the user
that is reading or setting a preference via all provided authentication methods.
</Banner>

View File

@@ -21,7 +21,7 @@ To swap in your own Custom View, first consult the list of available components,
Root Views are the main views of the [Admin Panel](./overview). These are views that are scoped directly under the `/admin` route, such as the Dashboard or Account views.
To swap Root Views with your own, or to [create entirely new ones](#adding-new-root-views), use the `admin.components.views` property of your root [Payload Config](../configuration/overview):
To swap Root Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views` property of your root [Payload Config](../configuration/overview):
```ts
import { buildConfig } from 'payload'
@@ -68,7 +68,7 @@ export const MyCustomView: React.FC<AdminViewProps> = ({
>
<Gutter>
<h1>Custom Default Root View</h1>
<br />
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
@@ -89,14 +89,14 @@ For more granular control, pass a configuration object instead. Payload exposes
| Property | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`Component`** \* | Pass in the component path that should be rendered when a user navigates to this route. |
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`Component`** * | Pass in the component path that should be rendered when a user navigates to this route. |
| **`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.|
| **`meta`** | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
### Adding New Views
@@ -125,8 +125,8 @@ const config = buildConfig({
The above example shows how to add a new [Root View](#root-views), but the pattern is the same for [Collection Views](#collection-views), [Global Views](#global-views), and [Document Views](#document-views). For help on how to build your own Custom Views, see [Building Custom Views](#building-custom-views).
<Banner type="warning">
<strong>Note:</strong>
<br />
**Note:**
Routes are cascading, so unless explicitly given the `exact` property, they will
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
routes in your application. Alternatively, define your nested route _before_ your parent
@@ -134,8 +134,8 @@ The above example shows how to add a new [Root View](#root-views), but the patte
</Banner>
<Banner type="warning">
<strong>Custom views are public</strong>
<br />
**Custom views are public**
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>
@@ -178,7 +178,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
**Note:**
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
@@ -190,7 +190,7 @@ The following options are available:
| **`list`** | The List View is used to show a list of documents for any given Collection. |
<Banner type="success">
<strong>Note:</strong>
**Note:**
You can also add _new_ Collection Views to the config by adding a new key to the `views` object with at least a `path` and `Component` property. See [Adding New Views](#adding-new-views) for more information.
</Banner>
@@ -198,7 +198,7 @@ The following options are available:
Global Views are views that are scoped under the `/globals` route, such as the Document Edit View.
To swap out Global Views with your own or [create entirely new ones](#adding-new-views), use the `admin.components.views` property in your [Global Config](../globals/overview):
To swap out Global Views with your own or [create entirely new ones](#adding-new-views), use the `admin.components.views` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
@@ -229,7 +229,7 @@ export const MyGlobalConfig: SanitizedGlobalConfig = {
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
**Note:**
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
@@ -240,7 +240,7 @@ The following options are available:
| **`edit`** | The Edit View is used to edit a single document for any given Global. [More details](#document-views). |
<Banner type="success">
<strong>Note:</strong>
**Note:**
You can also add _new_ Global Views to the config by adding a new key to the `views` object with at least a `path` and `Component` property. See [Adding New Views](#adding-new-views) for more information.
</Banner>
@@ -248,7 +248,7 @@ The following options are available:
Document Views are views that are scoped under the `/collections/:collectionSlug/:id` or the `/globals/:globalSlug` route, such as the Edit View or the API View. All Document Views keep their overall structure across navigation changes, such as their title and tabs, and replace only the content below.
To swap out Document Views with your own, or to [create entirely new ones](#adding-new-document-views), use the `admin.components.views.Edit[key]` property in your [Collection Config](../collections/overview) or [Global Config](../globals/overview):
To swap out Document Views with your own, or to [create entirely new ones](#adding-new-views), use the `admin.components.views.Edit[key]` property in your [Collection Config](../collections/overview) or [Global Config](../configuration/globals):
```ts
import type { SanitizedCollectionConfig } from 'payload'
@@ -272,20 +272,20 @@ export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
**Note:**
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `root` key. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
</Banner>
The following options are available:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **`root`** | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. |
| **`default`** | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. |
| **`versions`** | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions). |
| **`version`** | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions). |
| **`api`** | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview). |
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`root`** | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. |
| **`default`** | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. |
| **`versions`** | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions/overview). |
| **`version`** | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions/overview). |
| **`api`** | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview/overview). |
### Document Tabs
@@ -325,7 +325,7 @@ export const MyCollection: SanitizedCollectionConfig = {
```
<Banner type="warning">
<strong>Note:</strong>
**Note:**
This applies to _both_ Collections _and_ Globals.
</Banner>
@@ -354,22 +354,22 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`initPageResult`** | An object containing `req`, `payload`, `permissions`, etc. |
| **`clientConfig`** | The Client Config object. [More details](../components#accessing-the-payload-config). |
| **`importMap`** | The import map object. |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| **`doc`** | The document being edited. Only available in Document Views. [More details](#document-views). |
| Prop | Description |
| ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
| **`initPageResult`** | An object containing `req`, `payload`, `permissions`, etc. |
| **`clientConfig`** | The Client Config object. [More details](../admin/components#accessing-the-payload-config). |
| **`importMap`** | The import map object. |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| **`doc`** | The document being edited. Only available in Document Views. [More details](#document-views). |
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
All [Custom Server Components](./components) receive `payload` and `i18n` by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
<Banner type="warning">
<strong>Important:</strong>
**Important:**
It's up to you to secure your custom views. 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>

View File

@@ -14,8 +14,8 @@ For example, if you have a third-party service or external app that needs to be
1. Generate a non-expiring API key for that user to request with.
<Banner type="success">
<strong>Tip:</strong>
<br/>
**Tip:**
This is particularly useful as you can create a "user" that reflects an integration with a specific external service and assign a "role" or specific access only needed by that service/integration.
</Banner>
@@ -39,9 +39,9 @@ User API keys are encrypted within the database, meaning that if your database i
your API keys will not be.
<Banner type="warning">
<strong>Important:</strong>
**Important:**
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
<br />
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will
no longer be valid.
</Banner>

View File

@@ -9,7 +9,7 @@ keywords: authentication, config, configuration, documentation, Content Manageme
Payload offers the ability to [Authenticate](./overview) via HTTP-only cookies. These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
@@ -34,7 +34,7 @@ const pages = await response.json()
For more about including cookies in requests from your app to your Payload API, [read the MDN docs](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Sending_a_request_with_credentials_included).
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
To make sure you have a Payload cookie set properly in your browser after logging in, you can use
the browsers Developer Tools > Application > Cookies > [your-domain-here]. The Developer tools
will still show HTTP-only cookies.
@@ -44,7 +44,7 @@ For more about including cookies in requests from your app to your Payload API,
CSRF (cross-site request forgery) attacks are common and dangerous. By using an HTTP-only cookie, Payload removes many XSS vulnerabilities, however, CSRF attacks can still be possible.
For example, let's say you have a popular app `https://payload-finances.com` that allows users to manage finances, send and receive money. As Payload is using HTTP-only cookies, that means that browsers automatically will include cookies when sending requests to your domain - <strong>no matter what page created the request</strong>.
For example, let's say you have a popular app `https://payload-finances.com` that allows users to manage finances, send and receive money. As Payload is using HTTP-only cookies, that means that browsers automatically will include cookies when sending requests to your domain - **no matter what page created the request**.
So, if a user of `https://payload-finances.com` is logged in and is browsing around on the internet, they might stumble onto a page with malicious intent. Let's look at an example:
@@ -126,6 +126,6 @@ If you're configuring [cors](../production/preventing-abuse#cross-origin-resourc
<Banner type="success">
<strong>Good to know:</strong>
Setting up <code>secure: true</code> will not work if you're developing on <code>http://localhost</code> or any non-https domain. For local development you should conditionally set this to <code>false</code> based on the environment.
**Good to know:**
Setting up `secure: true` will not work if you're developing on `http://localhost` or any non-https domain. For local development you should conditionally set this to `false` based on the environment.
</Banner>

View File

@@ -19,15 +19,15 @@ A strategy is made up of the following:
| Parameter | Description |
| --------------------------- | ------------------------------------------------------------------------- |
| **`name`** \* | The name of your strategy |
| **`authenticate`**&nbsp;\* | A function that takes in the parameters below and returns a user or null. |
| **`name`** * | The name of your strategy |
| **`authenticate`** * | A function that takes in the parameters below and returns a user or null. |
The `authenticate` function is passed the following arguments:
| Argument | Description |
| ------------------- | ------------------------------------------------------------------------------------------------- |
| **`headers`** \* | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
| **`payload`** \* | The Payload class. Useful for authenticating the identifiable information against Payload. |
| **`headers`** * | The headers on the incoming request. Useful for retrieving identifiable information on a request. |
| **`payload`** * | The Payload class. Useful for authenticating the identifiable information against Payload. |
| **`isGraphQL`** | Whether or not the request was made from a GraphQL endpoint. Default is `false`. |

View File

@@ -26,15 +26,15 @@ export const Customers: CollectionConfig = {
```
<Banner type="info">
<strong>Tip:</strong>
Verification emails are fully customizable. [More details](#generateEmailHTML).
**Tip:**
Verification emails are fully customizable. [More details](#generateemailhtml).
</Banner>
The following options are available:
| Option | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users indicating how to validate their account. [More details](#generateemailhtml). |
| Option | Description |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users indicating how to validate their account. [More details](#generateemailhtml). |
| **`generateEmailSubject`** | Allows for overriding the subject of the email that is sent to users indicating how to validate their account. [More details](#generateemailsubject). |
#### generateEmailHTML
@@ -62,7 +62,7 @@ export const Customers: CollectionConfig = {
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
@@ -152,7 +152,7 @@ export const Customers: CollectionConfig = {
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
@@ -160,7 +160,7 @@ export const Customers: CollectionConfig = {
</Banner>
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are

View File

@@ -9,7 +9,7 @@ keywords: authentication, config, configuration, documentation, Content Manageme
Payload offers the ability to [Authenticate](./overview) via JSON Web Tokens (JWT). These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
@@ -45,7 +45,7 @@ import type { CollectionConfig } from 'payload'
export const UsersWithoutJWTs: CollectionConfig = {
slug: 'users-without-jwts',
auth: {
removeTokenFromRepsonse: true, // highlight-line
removeTokenFromResponse: true, // highlight-line
},
}
```

View File

@@ -269,6 +269,10 @@ const result = await payload.verifyEmail({
})
```
**Note:** the token you need to pass to the `verifyEmail` function is unique to verification and is not the same as the token that you can retrieve from the `forgotPassword` operation. It can be found on the user document, as a hidden `_verificationToken` field. If you'd like to retrieve this token, you can use the Local API's `find` or `findByID` methods, setting `showHiddenFields: true`.
**Note:** if you do not have a `config.serverURL` set, Payload will attempt to create one for you if the user was created via REST or GraphQL by looking at the incoming `req`. But this is not supported if you are creating the user via the Local API's `payload.create()` method. If this applies to you, and you do not have a `serverURL` set, you may want to override your `verify.generateEmailHTML` function to provide a full URL to link the user to a proper verification page.
## Unlock
If a user locks themselves out and you wish to deliberately unlock them, you can utilize the Unlock operation. The [Admin Panel](../admin/overview) features an Unlock control automatically for all collections that feature max login attempts, but you can programmatically unlock users as well by using the Unlock operation.
@@ -344,9 +348,11 @@ const token = await payload.forgotPassword({
})
```
**Note:** if you do not have a `config.serverURL` set, Payload will attempt to create one for you if the `forgot-password` operation was triggered via REST or GraphQL by looking at the incoming `req`. But this is not supported if you are calling `payload.forgotPassword()` via the Local API. If you do not have a `serverURL` set, you may want to override your `auth.forgotPassword.generateEmailHTML` function to provide a full URL to link the user to a proper reset-password page.
<Banner type="success">
<strong>Tip:</strong>
<br />
**Tip:**
You can stop the reset-password email from being sent via using the local API. This is helpful if
you need to create user accounts programmatically, but not set their password for them. This
effectively generates a reset password token which you can then use to send to a page you create,

View File

@@ -41,7 +41,7 @@ _Admin Panel screenshot depicting an Admins Collection with Auth enabled_
Any [Collection](../configuration/collections) can opt-in to supporting Authentication. Once enabled, each Document that is created within the Collection can be thought of as a "user". This enables a complete authentication workflow on your Collection, such as logging in and out, resetting their password, and more.
<Banner type="warning">
<strong>Note:</strong>
**Note:**
By default, Payload provides an auth-enabled `User` Collection which is used to access the Admin Panel. [More details](../admin/overview#the-admin-user-collection).
</Banner>
@@ -65,12 +65,12 @@ export const Admins: CollectionConfig = {
```
<Banner type="info">
<strong>Tip:</strong>
**Tip:**
For default auth behavior, set `auth: true`. This is a good starting point for most applications.
</Banner>
<Banner type="warning">
<strong>Note:</strong>
**Note:**
Auth-enabled Collections with be automatically injected with the `hash`, `salt`, and `email` fields. [More details](../fields/overview#field-names).
</Banner>
@@ -153,7 +153,7 @@ export default buildConfig({
```
<Banner type="warning">
<strong>Warning:</strong>
**Warning:**
The recommended way to use this feature is behind an [Environment Variable](../configuration/environment-vars). This will ensure it is _disabled_ in production.
</Banner>
@@ -182,7 +182,7 @@ Each of these strategies can work together or independently. You can also create
### HTTP-Only Cookies
[HTTP-only cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and <strong>cannot be read by JavaScript in the browser</strong>, unlike JWT's. [More details](./cookies).
[HTTP-only cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and **cannot be read by JavaScript in the browser**, unlike JWT's. [More details](./cookies).
### JSON Web Tokens

View File

@@ -70,8 +70,8 @@ export const Users: CollectionConfig = {
```
<Banner type="success">
<strong>Tip:</strong>
<br/>
**Tip:**
If you wish to use a different key other than the field `name`, you can define `saveToJWT` as a string.
</Banner>

View File

@@ -54,7 +54,7 @@ Any of the features in Payload Cloud that require environment variables will aut
Payment methods can be set per project and can be updated any time. You can use teams default payment method, or add a new one. Modify your payment methods in your Project settings / Team settings.
<Banner type="success">
<strong>Note:</strong> All Payload Cloud teams that deploy a project require a card on file. This
**Note:** All Payload Cloud teams that deploy a project require a card on file. This
helps us prevent fraud and abuse on our platform. If you select a plan with a free trial, you will
not be charged until your trial period is over. Well remind you 7 days before your trial ends and
you can cancel anytime.

View File

@@ -31,7 +31,7 @@ Next, select your `GitHub Scope`. If you belong to multiple organizations, they
After selecting your scope, create a unique `repository name` and select whether you want your repository to be public or private on GitHub.
<Banner type="warning">
<strong>Note:</strong> Public repositories can be accessed by anyone online, while private
**Note:** Public repositories can be accessed by anyone online, while private
repositories grant access only to you and anyone you explicitly authorize.
</Banner>
@@ -45,7 +45,7 @@ Payload Cloud works for any Node.js + MongoDB app. From the New Project page, se
_Creating a new project from an existing repository._
<Banner type="warning">
<strong>Note:</strong> In order to make use of the features of Payload Cloud in your own codebase,
**Note:** In order to make use of the features of Payload Cloud in your own codebase,
you will need to add the [Cloud Plugin](https://github.com/payloadcms/payload/tree/main/packages/payload-cloud) to your
Payload app.
</Banner>

View File

@@ -26,7 +26,7 @@ export default buildConfig({
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
If your Collection is only ever meant to contain a single Document, consider using a [Global](./globals) instead.
</Banner>
@@ -51,7 +51,7 @@ export const Posts: CollectionConfig = {
```
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
For more complex examples, see the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
@@ -67,19 +67,19 @@ The following options are available:
| **`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. |
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | Manage GraphQL-related properties for this collection. [More](#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. |
| **`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). |
| **`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._
_* An asterisk denotes that a property is required._
### Fields
@@ -97,6 +97,19 @@ Fields define the schema of the Documents within a Collection. To learn more, go
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis. To learn more, go to the [Collection Admin Options](../admin/collections) documentation.
## GraphQL
You can completely disable GraphQL for this collection by passing `graphQL: false` to your collection config. This will completely disable all queries, mutations, and types from appearing in your GraphQL schema.
You can also pass an object to the collection's `graphQL` property, which allows you to define the following properties:
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------- |
| **`singularName`** | Override the "singular" name that will be used in GraphQL schema generation. |
| **`pluralName`** | Override the "plural" name that will be used in GraphQL schema generation. |
| **`disableQueries`** | Disable all GraphQL queries that correspond to this collection by passing `true`. |
| **`disableMutations`** | Disable all GraphQL mutations that correspond to this collection by passing `true`. |
## TypeScript
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizeCollectionConfig`.

View File

@@ -45,7 +45,7 @@ For security and safety reasons, the [Admin Panel](../admin/overview) does **not
If you are building a [Custom Component](../admin/components) and need to access Environment Variables from the client-side, you can do so by prefixing them with `NEXT_PUBLIC_`.
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Be careful about what variables you provide to your client-side code. Analyze every single one to make sure that you're not accidentally leaking sensitive information. Only ever include keys that are safe for the public to read in plain text.
</Banner>
@@ -95,7 +95,7 @@ export default buildConfig({
```
<Banner type="warning">
<strong>Tip:</strong>
**Tip:**
Be sure that `dotenv` can find your `.env` file. By default, it will look for a file named `.env` in the root of your project. If you need to specify a different file, pass the path into the config options.
</Banner>

View File

@@ -24,7 +24,7 @@ export default buildConfig({
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
If you have more than one Global that share the same structure, consider using a [Collection](../configuration/collections) instead.
</Banner>
@@ -59,7 +59,7 @@ export const Nav: GlobalConfig = {
```
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
For more complex examples, see the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
@@ -73,16 +73,16 @@ The following options are available:
| **`dbName`** | Custom table or collection name for this Global depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`description`** | Text or React component to display below the Global header to give editors more information. |
| **`endpoints`** | Add custom routes to the REST API. [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 Global. [More details](../fields/overview). |
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Global. [More details](../fields/overview). |
| **`graphQL`** | Manage GraphQL-related properties related to this global. [More details](#graphql) |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#global-hooks). |
| **`label`** | Text for the name in the Admin Panel or an object with keys for each language. 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 Global. |
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Global. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#globals-config). |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
### Fields
@@ -100,6 +100,18 @@ Fields define the schema of the Global. To learn more, go to the [Fields](../fie
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis. To learn more, go to the [Global Admin Options](../admin/globals) documentation.
## GraphQL
You can completely disable GraphQL for this global by passing `graphQL: false` to your global config. This will completely disable all queries, mutations, and types from appearing in your GraphQL schema.
You can also pass an object to the global's `graphQL` property, which allows you to define the following properties:
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------- |
| **`name`** | Override the name that will be used in GraphQL schema generation. |
| **`disableQueries`** | Disable all GraphQL queries that correspond to this global by passing `true`. |
| **`disableMutations`** | Disable all GraphQL mutations that correspond to this global by passing `true`. |
## TypeScript
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizeGlobalConfig`.

View File

@@ -24,7 +24,7 @@ export default buildConfig({
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
If there is a language that Payload does not yet support, we accept [code contributions](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md).
</Banner>
@@ -75,7 +75,7 @@ export default buildConfig({
```
<Banner type="warning">
<strong>Tip:</strong>
**Tip:**
It's best to only support the languages that you need so that the bundled JavaScript is kept to a minimum for your project.
</Banner>

View File

@@ -71,7 +71,7 @@ export default buildConfig({
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
Localization works very well alongside [I18n](/docs/configuration/i18n).
</Banner>
@@ -93,12 +93,12 @@ The locale codes do not need to be in any specific format. It's up to you to def
| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
| **`code`** * | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
| **`fallbackLocale`** | The code for this language to fallback to when properties of a document are not present. |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Field Localization
@@ -121,7 +121,7 @@ With the above configuration, the `title` field will now be saved in the databas
All field types with a `name` property support the `localized` property—even the more complex field types like `array`s and `block`s.
<Banner type="info">
<strong>Note:</strong>
**Note:**
Enabling Localization for field types that support nested fields will automatically create
localized "sets" of all fields contained within the field. For example, if you have a page layout
using a blocks field type, you have the choice of either localizing the full layout, by enabling
@@ -129,7 +129,7 @@ All field types with a `name` property support the `localized` property—even t
</Banner>
<Banner type="warning">
<strong>Important:</strong>
**Important:**
When converting an existing field to or from `localized: true` the data structure in the document
will change for this field and so existing data for this field will be lost. Before changing the
Localization setting on fields with existing data, you may need to consider a field migration
@@ -205,8 +205,8 @@ const posts = await payload.find({
```
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
The REST and Local APIs can return all Localization data in one request by passing 'all' or '*' as
the <strong>locale</strong> parameter. The response will be structured so that field values come
the **locale** parameter. The response will be structured so that field values come
back as the full objects keyed for each locale instead of the single, translated value.
</Banner>

View File

@@ -23,7 +23,7 @@ export default buildConfig({
The Payload Config is strongly typed and ties directly into Payload's TypeScript codebase. This means your IDE (such as VSCode) will provide helpful information like type-ahead suggestions while you write your config.
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
The location of your Payload Config can be customized. [More details](#customizing--automating-config-location-detection).
</Banner>
@@ -57,56 +57,55 @@ export default buildConfig({
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
For more complex examples, see the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
The following options are available:
| Option | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
| Option | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** * | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cross-origin-resource-sharing-cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
| **`loggingLevels`** | An object to override the level to use in the logger for Payload's errors. |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/cookies#csrf-attacks). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** * | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Note:</strong>
**Note:**
Some properties are removed from the client-side bundle. [More details](../admin/components#accessing-the-payload-config).
</Banner>
### Typescript Config
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](../configuration/collections) and [Globals](../configuration/globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
@@ -140,10 +139,10 @@ For Payload command-line scripts, we need to be able to locate your Payload Conf
1. The `compilerOptions` in your `tsconfig`*
1. The `dist` directory*
_\* Config location detection is different between development and production environments. See below for more details._
_* Config location detection is different between development and production environments. See below for more details._
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Ensure your `tsconfig.json` is properly configured for Payload to auto-detect your config location. If if does not exist, or does not specify the proper `compilerOptions`, Payload will default to the current working directory.
</Banner>
@@ -195,7 +194,7 @@ To use a custom config location, set the `PAYLOAD_CONFIG_PATH` environment varia
```
<Banner type="info">
<strong>Tip:</strong>
**Tip:**
`PAYLOAD_CONFIG_PATH` can be either an absolute path, or path relative to your current working directory.
</Banner>
@@ -205,7 +204,7 @@ Payload collects **completely anonymous** telemetry data about general usage. Th
For more information about what we track, take a look at our [privacy policy](/privacy).
## Cross-origin resource sharing (CORS)
## Cross-origin resource sharing (CORS)#cors
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or a object with the following properties:

View File

@@ -189,7 +189,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](./postgres#prototyping-in-dev-mode).
For more information about push mode and prototyping in development, [click here](./postgres#prototyping-in-development-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

@@ -30,14 +30,15 @@ export default buildConfig({
## Options
| Option | Description |
| -------------------- | ----------- |
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
| `migrationDir` | Customize the directory that migrations are stored. |
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. |
| `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). |
| Option | Description |
| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
| `connectOptions` | Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose. |
| `collectionsSchemaOptions` | Customize Mongoose schema options for collections. |
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
| `migrationDir` | Customize the directory that migrations are stored. |
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. |
| `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). |
## Access to Mongoose models

View File

@@ -31,7 +31,7 @@ export default buildConfig({
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
The Database Adapter is an external dependency and must be installed in your project separately from Payload. You can find the installation instructions for each Database Adapter in their respective documentation.
</Banner>

View File

@@ -50,31 +50,48 @@ export default buildConfig({
})
```
<Banner type="info">
**Note:**
If when using `vercelPostgresAdapter` your `process.env.POSTGRES_URL` or `pool.connectionString` points to a local database (e.g hostname has `localhost` or `127.0.0.1`) we use the `pg` module for pooling instead of `@vercel/postgres`. This is because `@vercel/postgres` doesn't work with local databases, if you want to disable that behavior, you can pass `forceUseVercelPostgres: true` to adapter's 'args and follow [Vercel guide](https://vercel.com/docs/storage/vercel-postgres/local-development#option-2:-local-postgres-instance-with-docker) for a Docker Neon DB setup.
</Banner>
## Options
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pool` \* | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres` or to `@vercel/postgres` |
| `pool` * | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres` or to `@vercel/postgres` |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `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 disable auto database creation if it doesn't exist. Defaults to `false`. |
| `disableCreateDatabase` | Pass `true` to disable 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'. |
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
## Access to Drizzle
After Payload is initialized, this adapter will expose the full power of Drizzle to you for use if you need it.
You can access Drizzle as follows:
To ensure type-safety, you need to generate Drizzle schema first with:
```sh
npx payload generate:db-schema
```
```text
payload.db.drizzle
Then, you can access Drizzle as follows:
```ts
import { posts } from './payload-generated-schema'
// To avoid installing Drizzle, you can import everything that drizzle has from our re-export path.
import { eq, sql, and } from '@payloadcms/db-postgres/drizzle'
// Drizzle's Querying API: https://orm.drizzle.team/docs/rqb
const posts = await payload.db.drizzle.query.posts.findMany()
// Drizzle's Select API https://orm.drizzle.team/docs/select
const result = await payload.db.drizzle.select().from(posts).where(and(eq(posts.id, 50), sql`lower(${posts.title}) = 'example post title'`))
```
## Tables, relations, and enums
@@ -109,7 +126,7 @@ Runs before the schema is built. You can use this hook to extend your database s
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { integer, pgTable, serial } from 'drizzle-orm/pg-core'
import { integer, pgTable, serial } from '@payloadcms/db-postgres/drizzle/pg-core'
postgresAdapter({
beforeSchemaInit: [
@@ -178,7 +195,7 @@ postgresAdapter({
})
```
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
### afterSchemaInit
@@ -189,7 +206,7 @@ The following example adds the `extra_integer_column` column and a composite ind
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { index, integer } from 'drizzle-orm/pg-core'
import { index, integer } from '@payloadcms/db-postgres/drizzle/pg-core'
import { buildConfig } from 'payload'
export default buildConfig({
@@ -231,3 +248,45 @@ export default buildConfig({
})
```
### Note for generated schema:
Columns and tables, added in schema hooks won't be added to the generated via `payload generate:db-schema` Drizzle schema.
If you want them to be there, you either have to edit this file manually or mutate the internal Payload "raw" SQL schema in the `beforeSchemaInit`:
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
postgresAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
// Add a new table
adapter.rawTables.myTable = {
name: 'my_table',
columns: {
my_id: {
name: 'my_id',
type: 'serial',
primaryKey: true
}
}
}
// Add a new column to generated by Payload table:
adapter.rawTables.posts.columns.customColumn = {
name: 'custom_column',
// Note that Payload SQL doesn't support everything that Drizzle does.
type: 'integer',
notNull: true
}
// Add a new index to generated by Payload table:
adapter.rawTables.posts.indexes.customColumnIdx = {
name: 'custom_column_idx',
unique: true,
on: ['custom_column']
}
return schema
},
],
})
```

View File

@@ -34,27 +34,42 @@ export default buildConfig({
## Options
| Option | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client` \* | [Client connection options](https://orm.drizzle.team/docs/get-started-sqlite#turso) that will be passed to `createClient` from `@libsql/client`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
| `transactionOptions` | A SQLiteTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
| `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'. |
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
| Option | Description |
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client` * | [Client connection options](https://orm.drizzle.team/docs/get-started-sqlite#turso) that will be passed to `createClient` from `@libsql/client`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
| `idType` | A string of 'number', or 'uuid' that is used for the data type given to id columns. |
| `transactionOptions` | A SQLiteTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
| `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'. |
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
| `generateSchemaOutputFile` | Override generated schema from `payload generate:db-schema` file path. Defaults to `{CWD}/src/payload-generated.schema.ts` |
| `autoIncrement` | Pass `true` to enable SQLite [AUTOINCREMENT](https://www.sqlite.org/autoinc.html) for primary keys to ensure the same ID cannot be reused from deleted rows |
## Access to Drizzle
After Payload is initialized, this adapter will expose the full power of Drizzle to you for use if you need it.
You can access Drizzle as follows:
To ensure type-safety, you need to generate Drizzle schema first with:
```sh
npx payload generate:db-schema
```
```text
payload.db.drizzle
Then, you can access Drizzle as follows:
```ts
// Import table from the generated file
import { posts } from './payload-generated-schema'
// To avoid installing Drizzle, you can import everything that drizzle has from our re-export path.
import { eq, sql, and } from '@payloadcms/db-sqlite/drizzle'
// Drizzle's Querying API: https://orm.drizzle.team/docs/rqb
const posts = await payload.db.drizzle.query.posts.findMany()
// Drizzle's Select API https://orm.drizzle.team/docs/select
const result = await payload.db.drizzle.select().from(posts).where(and(eq(posts.id, 50), sql`lower(${posts.title}) = 'example post title'`))
```
## Tables and relations
@@ -88,7 +103,7 @@ Runs before the schema is built. You can use this hook to extend your database s
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { integer, sqliteTable } from 'drizzle-orm/sqlite-core'
import { integer, sqliteTable } from '@payloadcms/db-sqlite/drizzle/sqlite-core'
sqliteAdapter({
beforeSchemaInit: [
@@ -157,7 +172,7 @@ sqliteAdapter({
})
```
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
### afterSchemaInit
@@ -168,7 +183,7 @@ The following example adds the `extra_integer_column` column and a composite ind
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { index, integer } from 'drizzle-orm/sqlite-core'
import { index, integer } from '@payloadcms/db-sqlite/drizzle/sqlite-core'
import { buildConfig } from 'payload'
export default buildConfig({
@@ -210,3 +225,45 @@ export default buildConfig({
})
```
### Note for generated schema:
Columns and tables, added in schema hooks won't be added to the generated via `payload generate:db-schema` Drizzle schema.
If you want them to be there, you either have to edit this file manually or mutate the internal Payload "raw" SQL schema in the `beforeSchemaInit`:
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
sqliteAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
// Add a new table
adapter.rawTables.myTable = {
name: 'my_table',
columns: {
my_id: {
name: 'my_id',
type: 'integer',
primaryKey: true
}
}
}
// Add a new column to generated by Payload table:
adapter.rawTables.posts.columns.customColumn = {
name: 'custom_column',
// Note that Payload SQL doesn't support everything that Drizzle does.
type: 'integer',
notNull: true
}
// Add a new index to generated by Payload table:
adapter.rawTables.posts.indexes.customColumnIdx = {
name: 'custom_column_idx',
unique: true,
on: ['custom_column']
}
return schema
},
],
})
```

View File

@@ -11,14 +11,14 @@ Database transactions allow your application to make a series of database change
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>
<br />
**Note:**
MongoDB requires a connection to a replicaset in order to make use of transactions.
</Banner>
<Banner type="info">
<strong>Note:</strong>
<br />
**Note:**
Transactions in SQLite are disabled by default. You need to pass `transactionOptions: {}` to enable them.
</Banner>

View File

@@ -24,8 +24,8 @@ An email adapter will require at least the following fields:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |
| **`defaultFromName`** \* | The name part of the From field that will be seen on the delivered email |
| **`defaultFromAddress`** \* | The email address part of the From field that will be used when delivering email |
| **`defaultFromName`** * | The name part of the From field that will be seen on the delivered email |
| **`defaultFromAddress`** * | The email address part of the From field that will be used when delivering email |
### Official Email Adapters

View File

@@ -16,7 +16,12 @@ Payload provides a vast array of examples to help you get started with your proj
- [Live Preview](https://github.com/payloadcms/payload/tree/main/examples/live-preview)
- [Multi-tenant](https://github.com/payloadcms/payload/tree/main/examples/multi-tenant)
- [Tailwind / Shadcn-ui](https://github.com/payloadcms/payload/tree/main/examples/tailwind-shadcn-ui)
- [Tests](https://github.com/payloadcms/payload/tree/main/examples/testing)
- [White-label Admin UI](https://github.com/payloadcms/payload/tree/main/examples/whitelabel)
If you'd like to run the examples, you can use `create-payload-app` to create a project from one:
```sh
npx create-payload-app --example example_name
```
We are adding new examples every day, so if your particular use case is not demonstrated in any existing example, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.

View File

@@ -41,9 +41,9 @@ export const MyArrayField: Field = {
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as the heading in the [Admin Panel](../admin/overview) or an object with keys for each language. Auto-generated from name if not defined. |
| **`fields`** \* | Array of field types to correspond to each row of the Array. |
| **`fields`** * | Array of field types to correspond to each row of the Array. |
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
@@ -62,7 +62,7 @@ export const MyArrayField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -6,7 +6,7 @@ desc: The Blocks Field is a great layout build and can be used to construct any
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Blocks Field is <strong>incredibly powerful</strong>, storing an array of objects based on the fields that your define, where each item in the array is a "block" with its own unique schema.
The Blocks Field is **incredibly powerful** storing an array of objects based on the fields that your define, where each item in the array is a "block" with its own unique schema.
Blocks are a great way to create a flexible content model that can be used to build a wide variety of content types, including:
@@ -41,9 +41,9 @@ export const MyBlocksField: Field = {
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as the heading in the Admin Panel or an object with keys for each language. Auto-generated from name if not defined. |
| **`blocks`** \* | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
| **`blocks`** * | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
@@ -60,7 +60,7 @@ export const MyBlocksField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options
@@ -86,7 +86,7 @@ The Blocks Field inherits all of the default options from the base [Field Admin
#### Customizing the way your block is rendered in Lexical
If you're using this block within the [Lexical editor](/docs/lexical/overview), you can also customize how the block is rendered in the Lexical editor itself by specifying custom components.
If you're using this block within the [Lexical editor](/docs/rich-text/overview), you can also customize how the block is rendered in the Lexical editor itself by specifying custom components.
- `admin.components.Label` - pass a custom React component here to customize the way that the label is rendered for this block
- `admin.components.Block` - pass a component here to completely override the way the block is rendered in Lexical with your own component
@@ -96,28 +96,28 @@ This is super handy if you'd like to present your editors with a very deliberate
For example, if you have a `gallery` block, you might want to actually render the gallery of images directly in your Lexical block. With the `admin.components.Block` property, you can do exactly that!
<Banner type="success">
<strong>Tip:</strong><br/>
**Tip:**<br/>
If you customize the way your block is rendered in Lexical, you can import utility components to easily edit / remove your block - so that you don't have to build all of this yourself.
</Banner>
To import these utility components for one of your custom blocks, you can import the following:
```ts
import {
import {
// Edit block buttons (choose the one that corresponds to your usage)
// When clicked, this will open a drawer with your block's fields
// so your editors can edit them
InlineBlockEditButton,
BlockEditButton,
// Buttons that will remove this block from Lexical
// Buttons that will remove this block from Lexical
// (choose the one that corresponds to your usage)
InlineBlockRemoveButton,
BlockRemoveButton,
// The label that should be rendered for an inline block
InlineBlockLabel,
// The default "container" that is rendered for an inline block
// if you want to re-use it
InlineBlockContainer,
@@ -125,7 +125,7 @@ import {
// The default "collapsible" UI that is rendered for a regular block
// if you want to re-use it
BlockCollapsible,
} from '@payloadcms/richtext-lexical/client'
```
@@ -134,8 +134,8 @@ import {
Blocks are defined as separate configs of their own.
<Banner type="success">
<strong>Tip:</strong>
<br />
**Tip:**
Best practice is to define each block config in its own file, and then import them into your
Blocks field as necessary. This way each block config can be easily shared between fields. For
instance, using the "layout builder" example, you might want to feature a few of the same blocks
@@ -145,14 +145,14 @@ Blocks are defined as separate configs of their own.
| Option | Description |
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`slug`** \* | Identifier for this block type. Will be saved on each block as the `blockType` property. |
| **`fields`** \* | Array of fields to be stored in this block. |
| **`slug`** * | Identifier for this block type. Will be saved on each block as the `blockType` property. |
| **`fields`** * | Array of fields to be stored in this block. |
| **`labels`** | Customize the block labels that appear in the Admin dashboard. Auto-generated from slug if not defined. |
| **`imageURL`** | Provide a custom image thumbnail to help editors identify this block in the Admin UI. |
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
| **`dbName`** | Custom table name for this block type when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
| **`dbName`** | Custom table name for this block type when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
### Auto-generated data per block

View File

@@ -30,7 +30,7 @@ export const MyCheckboxField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
@@ -46,7 +46,7 @@ export const MyCheckboxField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Example

View File

@@ -31,10 +31,10 @@ export const MyBlocksField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`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. |
| **`index`** | Build an [index](/docs/database#overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
@@ -50,7 +50,7 @@ export const MyBlocksField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -35,12 +35,12 @@ export const MyCollapsibleField: Field = {
| Option | Description |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`label`** \* | A label to render within the header of the collapsible component. This can be a string, function or react component. Function/components receive `({ data, path })` as args. |
| **`fields`** \* | Array of field types to nest within this Collapsible. |
| **`label`** * | A label to render within the header of the collapsible component. This can be a string, function or react component. Function/components receive `({ data, path })` as args. |
| **`fields`** * | Array of field types to nest within this Collapsible. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -30,7 +30,7 @@ export const MyDateField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
@@ -46,7 +46,7 @@ export const MyDateField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options
@@ -70,23 +70,23 @@ The Date Field inherits all of the default options from the base [Field Admin Co
| **`placeholder`** | Placeholder text for the field. |
| **`date`** | Pass options to customize date field appearance. |
| **`date.displayFormat`** | Format date to be shown in field **cell**. |
| **`date.pickerAppearance`** \* | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. |
| **`date.monthsToShow`** \* | Number of months to display max is 2. Defaults to 1. |
| **`date.minDate`** \* | Min date value to allow. |
| **`date.maxDate`** \* | Max date value to allow. |
| **`date.minTime`** \* | Min time value to allow. |
| **`date.maxTime`** \* | Max date value to allow. |
| **`date.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
| **`date.pickerAppearance`** * | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. |
| **`date.monthsToShow`** * | Number of months to display max is 2. Defaults to 1. |
| **`date.minDate`** * | Min date value to allow. |
| **`date.maxDate`** * | Max date value to allow. |
| **`date.minTime`** * | Min time value to allow. |
| **`date.maxTime`** * | Max date value to allow. |
| **`date.overrides`** * | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
| **`date.timeIntervals`** * | Time intervals to display. Defaults to 30 minutes. |
| **`date.timeFormat`** * | Determines time format. Defaults to `'h:mm aa'`. |
_\* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). ._
_* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md)._
### Display Format and Picker Appearance
These properties only affect how the date is displayed in the UI. The full date is always stored in the format `YYYY-MM-DDTHH:mm:ss.SSSZ` (e.g. `1999-01-01T8:00:00.000+05:00`).
`displayFormat` determines how the date is presented in the field **cell**, you can pass any valid (unicode date format)[https://date-fns.org/v4.1.0/docs/format].
`displayFormat` determines how the date is presented in the field **cell**, you can pass any valid [unicode date format](https://date-fns.org/v4.1.0/docs/format).
`pickerAppearance` sets the appearance of the **react datepicker**, the options available are `dayAndTime`, `dayOnly`, `timeOnly`, and `monthOnly`. By default, the datepicker will display `dayOnly`.

View File

@@ -30,7 +30,7 @@ export const MyEmailField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`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. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
@@ -47,7 +47,7 @@ export const MyEmailField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -35,8 +35,8 @@ export const MyGroupField: Field = {
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`fields`** \* | Array of field types to nest within this Group. |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`fields`** * | Array of field types to nest within this Group. |
| **`label`** | Used as a heading in the Admin Panel and to name the generated GraphQL type. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
@@ -51,7 +51,7 @@ export const MyGroupField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -15,7 +15,7 @@ APIs.
The Join field is useful in scenarios including:
- To surface `Order`s for a given `Product`
- To surface `Orders` 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
@@ -59,7 +59,7 @@ are related to the Category are populated for you. This is extremely powerful an
of relationship types in an easy manner.
<Banner type="success">
The Join field is extremely performant and does not add additional query overhead to your API responses until you add depth of 1 or above. It works in all database adapters. In MongoDB, we use <strong>aggregations</strong> to automatically join in related documents, and in relational databases, we use joins.
The Join field is extremely performant and does not add additional query overhead to your API responses until you add depth of 1 or above. It works in all database adapters. In MongoDB, we use **aggregations** to automatically join in related documents, and in relational databases, we use joins.
</Banner>
### Schema advice
@@ -123,10 +123,10 @@ powerful Admin UI.
| 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. |
| **`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). |
@@ -138,17 +138,18 @@ powerful Admin UI.
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
_\* An asterisk denotes that a property is required._
_* 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](../admin/fields#label) |
| Option | Description |
|------------------------|---------------------------------------------------------------------------------------------------------------------------|
| **`defaultColumns`** | Array of field names that correspond to which columns to show in the relationship table. Default is the collection config. |
| **`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](../admin/fields#label) |
## Join Field Data

View File

@@ -31,7 +31,7 @@ export const MyJSONField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`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. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
@@ -49,7 +49,7 @@ export const MyJSONField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -30,7 +30,7 @@ export const MyNumberField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`min`** | Minimum value accepted. Used in the default `validation` function. |
| **`max`** | Maximum value accepted. Used in the default `validation` function. |
@@ -52,7 +52,7 @@ export const MyNumberField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -50,7 +50,7 @@ export const Page: CollectionConfig = {
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
Each field is an object with at least the `type` property. This matches the field to its corresponding Field Type. [More details](#field-options).
</Banner>
@@ -99,7 +99,7 @@ Here are the available Presentational Fields:
- [UI](/docs/fields/ui) - blank field for custom UI components
<Banner type="warning">
<strong>Tip:</strong>
**Tip:**
Don't see a Field Type that fits your needs? You can build your own using a [Custom Field Component](../admin/fields#field).
</Banner>
@@ -212,6 +212,7 @@ Functions can be written to make use of the following argument properties:
- `user` - the authenticated user object
- `locale` - the currently selected locale string
- `req` - the `PayloadRequest` object
Here is an example of a `defaultValue` function:
@@ -227,15 +228,15 @@ export const myField: Field = {
name: 'attribution',
type: 'text',
// highlight-start
defaultValue: ({ user, locale }) =>
defaultValue: ({ user, locale, req }) =>
`${translation[locale]} ${user.name}`,
// highlight-end
}
```
<Banner type="success">
<strong>Tip:</strong>
You can use async `defaultValue` functions to fill fields with data from API requests.
**Tip:**
You can use async `defaultValue` functions to fill fields with data from API requests or Local API using `req.payload`.
</Banner>
### Validation
@@ -377,7 +378,7 @@ export const MyCollection: CollectionConfig = {
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
The Custom ID Fields can only be of type [`Number`](./number) or [`Text`](./text).
Custom ID fields with type `text` must not contain `/` or `.` characters.

View File

@@ -27,7 +27,7 @@ export const MyPointField: Field = {
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
The Point Field currently is not supported in SQLite.
</Banner>
@@ -35,7 +35,7 @@ export const MyPointField: Field = {
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Used as a field label in the Admin Panel and to name the generated GraphQL type. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
@@ -52,7 +52,7 @@ export const MyPointField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Example

View File

@@ -35,8 +35,8 @@ export const MyRadioField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** * | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
@@ -53,11 +53,11 @@ export const MyRadioField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Important:</strong>
<br />
**Important:**
Option values should be strings that do not contain hyphens or special characters due to GraphQL
enumeration naming constraints. Underscores are allowed. If you determine you need your option
values to be non-strings or contain special characters, they will be formatted accordingly before

View File

@@ -39,13 +39,13 @@ export const MyRelationshipField: Field = {
| 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 one or many collection `slug`s to be able to assign relationships to. |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`relationTo`** * | Provide one or many collection `slug`s to be able to assign relationships to. |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-relationship-options). |
| **`hasMany`** | Boolean when, 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 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) |
| **`maxDepth`** | Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/queries/depth#max-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. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
@@ -63,10 +63,10 @@ export const MyRelationshipField: Field = {
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
The [Depth](../queries/depth) parameter can be used to automatically populate related documents that are returned by the API.
</Banner>
@@ -87,12 +87,12 @@ export const MyRelationshipField: Field = {
The Relationship Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| Property | Description |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------- |
| **`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) |
| **`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](#sort-options) |
### Sort Options
@@ -120,15 +120,9 @@ Example:
```ts
sortOptions: {
"pages"
:
"fieldName1",
"posts"
:
"-fieldName2",
"categories"
:
"fieldName3"
"pages": "fieldName1",
"posts": "-fieldName2",
"categories": "fieldName3"
}
```
@@ -156,6 +150,7 @@ called with an argument object with the following properties:
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
| `user` | An object containing the currently authenticated user |
| `req` | The Payload Request, which contains references to `payload`, `user`, `locale`, and more. |
## Example
@@ -191,12 +186,12 @@ export const ExampleCollection: CollectionConfig = {
You can learn more about writing queries [here](/docs/queries/overview).
<Banner type="warning">
<strong>Note:</strong>
<br />
When a relationship field has both <strong>filterOptions</strong> and a custom{' '}
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
**Note:**
When a relationship field has both **filterOptions** and a custom{' '}
**validate** function, the api will not validate **filterOptions**{' '}
unless you call the default relationship field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
**payload/shared** in your validate function.
</Banner>
## Bi-directional relationships
@@ -219,9 +214,7 @@ of collection.
```ts
{
slug: 'example-collection',
fields
:
[
fields: [
{
name: 'owner', // required
type: 'relationship', // required
@@ -253,9 +246,7 @@ tells Payload which Collections are valid to reference.
```ts
{
slug: 'example-collection',
fields
:
[
fields: [
{
name: 'owner', // required
type: 'relationship', // required
@@ -294,9 +285,7 @@ The `hasMany` tells Payload that there may be more than one collection saved to
```ts
{
slug: 'example-collection',
fields
:
[
fields: [
{
name: 'owners', // required
type: 'relationship', // required
@@ -324,9 +313,7 @@ When querying documents, the format does not change for arrays:
```ts
{
slug: 'example-collection',
fields
:
[
fields: [
{
name: 'owners', // required
type: 'relationship', // required
@@ -381,8 +368,8 @@ However, you **cannot** query on any field values within the related document.
Since we are referencing multiple collections, the field you are querying on may not exist and break the query.
<Banner type="warning">
<strong>Note:</strong>
<br />
You <strong>cannot</strong> query on a field within a polymorphic relationship as you would with a
**Note:**
You **cannot** query on a field within a polymorphic relationship as you would with a
non-polymorphic relationship.
</Banner>

View File

@@ -1,51 +1,44 @@
---
title: Rich Text Field
description: The Rich Text field allows dynamic content to be written through the Admin Panel. Learn how to use Rich Text fields, see examples and options.
keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
label: Rich Text
order: 140
desc: The Rich Text field allows dynamic content to be written through the Admin Panel. Learn how to use Rich Text fields, see examples and options.
keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
title: Rich Text Field
---
The Rich Text Field lets editors write and format dynamic content in a familiar interface.
The content is saved as JSON in the database and can be converted to HTML or any other format needed.
The Rich Text Field lets editors write and format dynamic content in a familiar interface. The content is saved as JSON in the database and can be converted to HTML or any other format needed.
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 Payload rich text editor.
Instead, you can invest your time and effort into learning the underlying open-source tools that will allow
you to apply your learnings elsewhere as well.
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 Payload rich text editor.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/richtext.png"
srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png"
alt="Shows a Rich Text field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Rich Text field"
/>
Instead, you can invest your time and effort into learning the underlying open-source tools that will allow you to apply your learnings elsewhere as well.
<LightDarkImage alt="Shows a Rich Text field in the Payload Admin Panel" caption="Admin Panel screenshot of a Rich Text field" srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png" srcLight="https://payloadcms.com/images/docs/fields/richtext.png"/>
## 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) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`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). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`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. [More details](#admin-options). |
| **`editor`** | Customize or override the rich text editor. [More details](/docs/rich-text/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
| Option | Description |
| --- | --- |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](../fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](../fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](../authentication/overview), include its data in the user JWT. |
| **`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). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](../fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](../configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`editor`** | Customize or override the rich text editor. [More details](../rich-text/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
** An asterisk denotes that a property is required.*
## Admin Options
The customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
To customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option. The Rich Text Field inherits all the default options from the base [Field Admin Config](../admin/fields#admin-options).
```ts
import type { Field } from 'payload'
@@ -58,15 +51,9 @@ export const MyRichTextField: Field = {
}
```
The Rich Text Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string for the field. |
| **`hideGutter`** | Set this property to `true` to hide this field's gutter within the Admin Panel. |
| **`rtl`** | Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction. |
Further customization can be done with editor-specific options.
## Editor-specific Options
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor,
take a look at the [rich text editor documentation](/docs/rich-text/overview).
take a look at the [rich text editor documentation](../rich-text/overview).

View File

@@ -35,11 +35,11 @@ export const MyRowField: Field = {
| Option | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`fields`** \* | Array of field types to nest within this Row. |
| **`fields`** * | Array of field types to nest within this Row. |
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Example

View File

@@ -35,8 +35,8 @@ export const MySelectField: Field = {
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** * | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
| **`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. |
@@ -56,10 +56,10 @@ export const MySelectField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Option values should be strings that do not contain hyphens or special characters due to GraphQL
enumeration naming constraints. Underscores are allowed. If you determine you need your option
values to be non-strings or contain special characters, they will be formatted accordingly before
@@ -204,4 +204,4 @@ If you are looking to create a dynamic select field, the following tutorial will
drawerTitle="How to Create a Custom Select Field: A Step-by-Step Guide"
/>
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/components#field) docs.
If you want to learn more about custom components check out the [Admin > Custom Component](/docs/admin/fields) docs.

View File

@@ -35,7 +35,7 @@ export const MyTabsField: Field = {
| Option | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **`tabs`** \* | Array of tabs to render within this Tabs field. |
| **`tabs`** * | Array of tabs to render within this Tabs field. |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
@@ -47,12 +47,12 @@ Each tab must have either a `name` or `label` and the required `fields` array. Y
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`name`** | Groups field data into an object when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | The label to render on the tab itself. Required when name is undefined, defaults to name converted to words. |
| **`fields`** \* | The fields to render within this tab. |
| **`fields`** * | The fields to render within this tab. |
| **`description`** | Optionally render a description within this tab to describe the contents of the tab itself. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). (`name` must be present) |
| **`virtual`** | Provide `true` to disable field in the database (`name` must be present). See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Example

View File

@@ -30,7 +30,7 @@ export const MyTextField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`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. |
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
@@ -52,7 +52,7 @@ export const MyTextField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options

View File

@@ -30,7 +30,7 @@ export const MyTextareaField: Field = {
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`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. |
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
@@ -49,7 +49,7 @@ export const MyTextareaField: Field = {
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Admin Options
@@ -68,11 +68,12 @@ export const MyTextareaField: Field = {
The Textarea Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string in the textarea. |
| **`autoComplete`** | Set this property to a string that will be used for browser autocomplete. |
| **`rtl`** | Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction. |
| Option | Description |
| ------------------ | --------------------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string in the textarea. |
| **`autoComplete`** | Set this property to a string that will be used for browser autocomplete. |
| **`rows`** | Set the number of visible text rows in the textarea. Defaults to `2` if not specified. |
| **`rtl`** | Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction. |
## Example

View File

@@ -30,14 +30,14 @@ export const MyUIField: Field = {
| Option | Description |
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | A unique identifier for this field. |
| **`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) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/components/#field) |
| **`admin.components.Field`** * | React component to be rendered for this field within the Edit View. [More](../admin/fields#field) |
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](../admin/fields#cell) |
| **`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._
_* An asterisk denotes that a property is required._
## Example

View File

@@ -37,7 +37,7 @@ export const MyUploadField: Field = {
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
To use the Upload Field, you must have a [Collection](../configuration/collections) configured to allow [Uploads](../upload/overview).
</Banner>
@@ -45,8 +45,8 @@ export const MyUploadField: Field = {
| 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> |
| **`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. **Note: the related collection must be configured to support Uploads.** |
| **`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. |
@@ -70,7 +70,7 @@ export const MyUploadField: Field = {
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
| **`graphQL`** | Custom graphQL configuration for the field. [More details](/docs/graphql/overview#field-complexity) |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Example
@@ -108,6 +108,7 @@ called with an argument object with the following properties:
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
| `user` | An object containing the currently authenticated user |
| `req` | The Payload Request, which contains references to `payload`, `user`, `locale`, and more. |
### Example#filter-options-example
@@ -125,12 +126,12 @@ const uploadField = {
You can learn more about writing queries [here](/docs/queries/overview).
<Banner type="warning">
<strong>Note:</strong>
<br />
When an upload field has both <strong>filterOptions</strong> and a custom{' '}
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
**Note:**
When an upload field has both **filterOptions** and a custom{' '}
**validate** function, the api will not validate **filterOptions**{' '}
unless you call the default upload field validation function imported from{' '}
<strong>payload/shared</strong> in your validate function.
**payload/shared** in your validate function.
</Banner>
## Bi-directional relationships

View File

@@ -53,7 +53,7 @@ Everything Payload does (create, read, update, delete, login, logout, etc.) is e
- [GraphQL](#graphql) - A full GraphQL API with a GraphQL Playground
<Banner type="success">
<strong>Note:</strong>
**Note:**
All of these APIs share the exact same query language. [More details](../queries/overview).
</Banner>
@@ -127,7 +127,7 @@ You can use any GraphQL client with Payload's GraphQL endpoint. Here are a few p
Payload is abstracted into a set of dedicated packages to keep the core `payload` package as lightweight as possible. This allows you to only install the parts of Payload based on your unique project requirements.
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Version numbers of all official Payload packages are always published in sync. You should make sure that you always use matching versions for all official Payload packages.
</Banner>
@@ -166,6 +166,6 @@ You can choose which Database Adapter you'd like to use for your project, and no
Payload's Rich Text functionality is abstracted into separate packages and if you want to enable Rich Text in your project, you'll need to install one of these packages. We recommend Lexical for all new projects, and this is where Payload will focus its efforts on from this point, but Slate is still supported if you have already built with it.
<Banner type="info">
<strong>Note:</strong>
**Note:**
Rich Text is entirely optional and you may not need it for your project.
</Banner>

View File

@@ -15,7 +15,7 @@ Payload requires the following software:
- Any [compatible database](/docs/database/overview) (MongoDB, Postgres or SQLite)
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Before proceeding any further, please ensure that you have the above requirements met.
</Banner>
@@ -36,7 +36,7 @@ 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.
**Note:** Next.js version 15 or higher is required for Payload.
</Banner>
#### 1. Install the relevant packages
@@ -48,7 +48,7 @@ pnpm i payload @payloadcms/next @payloadcms/richtext-lexical sharp graphql
```
<Banner type="warning">
<strong>Note:</strong>
**Note:**
Swap out `pnpm` for your package manager. If you are using npm, you might need to install using legacy peer deps: `npm i --legacy-peer-deps`.
</Banner>
@@ -67,7 +67,7 @@ To install a Database Adapter, you can run **one** of the following commands:
```
<Banner type="success">
<strong>Note:</strong>
**Note:**
New [Database Adapters](/docs/database/overview) are becoming available every day. Check the docs for the most up-to-date list of what's available.
</Banner>
@@ -116,7 +116,7 @@ export default withPayload(nextConfig) // highlight-line
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Payload is a fully ESM project, and that means the `withPayload` function is an ECMAScript module.
</Banner>

View File

@@ -65,8 +65,8 @@ The above example outputs all your definitions to a file relative from your payl
### Adding an npm script
<Banner type="warning">
<strong>Important</strong>
<br />
**Important**
Payload needs to be able to find your config to generate your GraphQL schema.
</Banner>

View File

@@ -43,8 +43,8 @@ export const PublicUser: CollectionConfig = {
**Payload will automatically open up the following queries:**
| Query Name | Operation |
| ------------------ | ------------------- |
| Query Name | Operation |
| ------------------- | ------------------- |
| `PublicUser` | `findByID` |
| `PublicUsers` | `find` |
| `countPublicUsers` | `count` |
@@ -116,8 +116,8 @@ GraphQL Playground is enabled by default for development purposes, but disabled
You can even log in using the `login[collection-singular-label-here]` mutation to use the Playground as an authenticated user.
<Banner type="success">
<strong>Tip:</strong>
<br />
**Tip:**
To see more regarding how the above queries and mutations are used, visit your GraphQL playground
(by default at
[`${SERVER_URL}/api/graphql-playground`](http://localhost:3000/api/graphql-playground))
@@ -153,7 +153,7 @@ const NoProductionIntrospection: GraphQL.ValidationRule = (context) => ({
{ nodes: [node] }
)
);
}
}
}
}
})

View File

@@ -22,7 +22,7 @@ export const CollectionWithHooks: CollectionConfig = {
```
<Banner type="info">
<strong>Tip:</strong>
**Tip:**
You can also set hooks on the field-level to isolate hook logic to specific fields. [More details](./fields).
</Banner>
@@ -186,13 +186,13 @@ const beforeReadHook: CollectionBeforeReadHook = async ({
The following arguments are provided to the `beforeRead` hook:
| Option | Description |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request.
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
| Option | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request. |
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
### afterRead
@@ -210,13 +210,13 @@ const afterReadHook: CollectionAfterReadHook = async ({
The following arguments are provided to the `afterRead` hook:
| Option | Description |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request.
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
| Option | Description |
| ---------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`collection`** | The [Collection](../configuration/collections) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request. |
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
### beforeDelete

View File

@@ -72,8 +72,8 @@ const Customer: CollectionConfig = {
slug: 'customers',
hooks: {
afterChange: [
async ({ doc }) => {
await payload.update({
async ({ doc, req }) => {
await req.payload.update({
// DANGER: updating the same slug as the collection in an afterChange will create an infinite loop!
collection: 'customers',
id: doc.id,
@@ -101,12 +101,12 @@ const MyCollection: CollectionConfig = {
slug: 'slug',
hooks: {
afterChange: [
async ({ context, doc }) => {
async ({ context, doc, req }) => {
// return if flag was previously set
if (context.triggerAfterChange === false) {
return
}
await payload.update({
await req.payload.update({
collection: contextHooksSlug,
id: doc.id,
data: {

View File

@@ -26,7 +26,7 @@ export const FieldWithHooks: Field = {
All Field Hooks accept an array of synchronous or asynchronous functions. These functions can optionally modify the return value of the field before the operation continues. All Field Hooks are formatted to accept the same arguments, although some arguments may be `undefined` based the specific hook type.
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Due to GraphQL's typed nature, changing the type of data that you return from a field will produce errors in the [GraphQL API](../graphql/overview). If you need to change the shape or type of data, consider [Collection Hooks](./collections) or [Global Hooks](./hooks) instead.
</Banner>
@@ -74,7 +74,7 @@ The following arguments are provided to all Field Hooks:
| **`value`** | The value of the [Field](../fields/overview). |
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
It's a good idea to conditionally scope your logic based on which operation is executing. For example, if you are writing a `beforeChange` hook, you may want to perform different logic based on if the current `operation` is `create` or `update`.
</Banner>

View File

@@ -22,7 +22,7 @@ export const GlobalWithHooks: GlobalConfig = {
```
<Banner type="info">
<strong>Tip:</strong>
**Tip:**
You can also set hooks on the field-level to isolate hook logic to specific fields. [More details](./fields).
</Banner>
@@ -163,14 +163,14 @@ const afterReadHook: GlobalAfterReadHook = async ({
The following arguments are provided to the `beforeRead` hook:
| Option | Description |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`findMany`** | Boolean to denote if this hook is running against finding one, or finding many (useful in versions). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request.
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
| Option | Description |
| -------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`global`** | The [Global](../configuration/globals) in which this Hook is running against. |
| **`context`** | Custom context passed between hooks. [More details](./context). |
| **`findMany`** | Boolean to denote if this hook is running against finding one, or finding many (useful in versions). |
| **`doc`** | The resulting Document after changes are applied. |
| **`query`** | The [Query](../queries/overview) of the request. |
| **`req`** | The [Web Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object. This is mocked for [Local API](../local-api/overview) operations. |
## TypeScript

View File

@@ -26,7 +26,7 @@ There are four main types of Hooks in Payload:
- [Field Hooks](/docs/hooks/fields)
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
Payload also ships a set of _React_ hooks that you can use in your frontend application. Although they share a common name, these are very different things and should not be confused. [More details](../admin/hooks).
</Banner>
@@ -34,7 +34,7 @@ There are four main types of Hooks in Payload:
Root Hooks are not associated with any specific Collection, Global, or Field. They are useful for globally-oriented side effects, such as when an error occurs at the application level.
To add Root Hooks, use the `hooks` property in your [Payload Config](/docs/configuration/config):
To add Root Hooks, use the `hooks` property in your [Payload Config](/docs/configuration/overview):
```ts
import { buildConfig } from 'payload'

View File

@@ -9,7 +9,7 @@ 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.
Whereas you define Workflows and Tasks, which control your business logic, a **Job** 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.

View File

@@ -9,7 +9,7 @@ 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.
A **Queue** 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.
@@ -25,7 +25,33 @@ Then, you could configure two different runner strategies:
## 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:
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 four ways:
#### Cron jobs
You can use the jobs.autoRun property to configure cron jobs:
```ts
export default buildConfig({
// Other configurations...
jobs: {
tasks: [
// your tasks here
],
// autoRun can optionally be a function that receives payload as an argument
autoRun: [
{
cron: '0 * * * *', // every hour at minute 0
limit: 100, // limit jobs to process each run
queue: 'hourly', // name of the queue
},
// add as many cron jobs as you want
],
},
})
```
<Banner type="warning">autoRun is intended for use with a dedicated server that is always running, and should not be used on serverless platforms like Vercel.</Banner>
#### Endpoint

View File

@@ -7,7 +7,7 @@ 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.
A **"Task"** 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/jobs-queue/jobs) or [Workflows](/docs/jobs-queue/workflows) that use them. Think of Tasks like tidy, isolated "functions that do one specific thing".
@@ -141,3 +141,111 @@ export const createPostHandler: TaskHandler<'createPost'> = async ({ input, job,
}
}
```
### Configuring task restoration
By default, if a task has passed previously and a workflow is re-run, the task will not be re-run. Instead, the output from the previous task run will be returned. This is to prevent unnecessary re-runs of tasks that have already passed.
You can configure this behavior through the `retries.shouldRestore` property. This property accepts a boolean or a function.
If `shouldRestore` is set to true, the task will only be re-run if it previously failed. This is the default behavior.
If `shouldRestore` this is set to false, the task will be re-run even if it previously succeeded, ignoring the maximum number of retries.
If `shouldRestore` is a function, the return value of the function will determine whether the task should be re-run. This can be used for more complex restore logic, e.g you may want to re-run a task up to X amount of times and then restore it for consecutive runs, or only re-run a task if the input has changed.
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
{
slug: 'myTask',
retries: {
shouldRestore: false,
}
// ...
} as TaskConfig<'myTask'>,
]
}
})
```
Example - determine whether a task should be restored based on the input data:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
{
slug: 'myTask',
inputSchema: [
{
name: 'someDate',
type: 'date',
required: true,
},
],
retries: {
shouldRestore: ({ input }) => {
if(new Date(input.someDate) > new Date()) {
return false
}
return true
},
}
// ...
} as TaskConfig<'myTask'>,
]
}
})
```
## Nested tasks
You can run sub-tasks within an existing task, by using the `tasks` or `ìnlineTask` arguments passed to the task `handler` function:
```ts
export default buildConfig({
// ...
jobs: {
// It is recommended to set `addParentToTaskLog` to `true` when using nested tasks, so that the parent task is included in the task log
// This allows for better observability and debugging of the task execution
addParentToTaskLog: true,
tasks: [
{
slug: 'parentTask',
inputSchema: [
{
name: 'text',
type: 'text'
},
],
handler: async ({ input, req, tasks, inlineTask }) => {
await inlineTask('Sub Task 1', {
task: () => {
// Do something
return {
output: {},
}
},
})
await tasks.CreateSimple('Sub Task 2', {
input: { message: 'hello' },
})
return {
output: {},
}
}
} as TaskConfig<'parentTask'>,
]
}
})
```

View File

@@ -7,7 +7,7 @@ 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.
A **"Workflow"** is an optional way to *combine multiple tasks together* 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.

View File

@@ -18,12 +18,12 @@ By default, all hooks accept the following args:
| Path | Description |
| ------------------ | -------------------------------------------------------------------------------------- |
| **`serverURL`** \* | The URL of your Payload server. |
| **`serverURL`** * | The URL of your Payload server. |
| **`initialData`** | The initial data of the document. The live data will be merged in as changes are made. |
| **`depth`** | The depth of the relationships to fetch. Defaults to `0`. |
| **`apiRoute`** | The path of your API route as defined in `routes.api`. Defaults to `/api`. |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
And return the following values:
@@ -89,7 +89,7 @@ export const PageClient: React.FC<{
```
<Banner type="warning">
<strong>Reminder:</strong>
**Reminder:**
If you are using [React Server Components](https://react.dev/reference/rsc/server-components), we strongly suggest setting up [server-side Live Preview](./server) instead.
</Banner>
@@ -151,8 +151,8 @@ The `subscribe` function takes the following args:
| Path | Description |
| ------------------ | ------------------------------------------------------------------------------------------- |
| **`callback`** \* | A callback function that is called with `data` every time a change is made to the document. |
| **`serverURL`** \* | The URL of your Payload server. |
| **`callback`** * | A callback function that is called with `data` every time a change is made to the document. |
| **`serverURL`** * | The URL of your Payload server. |
| **`initialData`** | The initial data of the document. The live data will be merged in as changes are made. |
| **`depth`** | The depth of the relationships to fetch. Defaults to `0`. |
@@ -239,7 +239,7 @@ export const useLivePreview = <T extends any>(props: {
## Example
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview/payload). There you will find examples of various front-end frameworks and how to integrate each one of them, including:
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview). There you will find examples of various front-end frameworks and how to integrate each one of them, including:
- [Next.js App Router](https://github.com/payloadcms/payload/tree/main/examples/live-preview/next-app)
- [Next.js Pages Router](https://github.com/payloadcms/payload/tree/main/examples/live-preview/next-pages)

View File

@@ -29,8 +29,8 @@ const config = buildConfig({
})
```
<Banner type="warning">
<strong>Reminder:</strong>
Alternatively, you can define the <code>admin.livePreview</code> property on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). Settings defined here will be merged into the top-level as overrides.
**Reminder:**
Alternatively, you can define the `admin.livePreview` property on individual [Collection Admin Configs](../admin/collections) and [Global Admin Configs](../admin/globals). Settings defined here will be merged into the top-level as overrides.
</Banner>
{/* IMAGE OF LIVE PREVIEW HERE */}
@@ -43,12 +43,12 @@ The following options are available:
| Path | Description |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`url`** \* | String, or function that returns a string, pointing to your front-end application. This value is used as the iframe `src`. [More details](#url). |
| **`url`** * | String, or function that returns a string, pointing to your front-end application. This value is used as the iframe `src`. [More details](#url). |
| **`breakpoints`** | Array of breakpoints to be used as “device sizes” in the preview window. Each item appears as an option in the toolbar. [More details](#breakpoints). |
| **`collections`** | Array of collection slugs to enable Live Preview on. |
| **`globals`** | Array of global slugs to enable Live Preview on. |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
### URL
@@ -88,10 +88,10 @@ const config = buildConfig({
// highlight-start
url: ({
data,
documentInfo,
collectionConfig,
locale
}) => `${data.tenant.url}${ // Multi-tenant top-level domain
documentInfo.slug === 'posts' ? `/posts/${data.slug}` : `${data.slug !== 'home' : `/${data.slug}` : ''}`
collectionConfig.slug === 'posts' ? `/posts/${data.slug}` : `${data.slug !== 'home' : `/${data.slug}` : ''}`
}${locale ? `?locale=${locale?.code}` : ''}`, // Localization query param
collections: ['pages'],
},
@@ -150,14 +150,12 @@ The following options are available for each breakpoint:
| Path | Description |
| --------------- | --------------------------------------------------------------------------- |
| **`label`** \* | The label to display in the drop-down. This is what the user will see. |
| **`name`** \* | The name of the breakpoint. |
| **`width`** \* | The width of the breakpoint. This is used to set the width of the iframe. |
| **`height`** \* | The height of the breakpoint. This is used to set the height of the iframe. |
| **`label`** * | The label to display in the drop-down. This is what the user will see. |
| **`name`** * | The name of the breakpoint. |
| **`width`** * | The width of the breakpoint. This is used to set the width of the iframe. |
| **`height`** * | The height of the breakpoint. This is used to set the height of the iframe. |
_\* An asterisk denotes that a property is required._
{/* IMAGE OF TOOLBAR HERE */}
_* An asterisk denotes that a property is required._
The "Responsive" option is always available in the drop-down and requires no additional configuration. This is the default breakpoint that will be used on initial load. This option styles the iframe with a width and height of `100%` so that it fills the screen at its maximum size and automatically resizes as the window changes size.
@@ -167,4 +165,4 @@ If you prefer to freely resize the Live Preview without the use of breakpoints,
## Example
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview/payload).
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview).

View File

@@ -160,7 +160,7 @@ export const RefreshRouteOnSave: React.FC<{
## Example
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview/payload). There you will find a fully working example of how to implement Live Preview in your Next.js App Router application.
For a working demonstration of this, check out the official [Live Preview Example](https://github.com/payloadcms/payload/tree/main/examples/live-preview). There you will find a fully working example of how to implement Live Preview in your Next.js App Router application.
## Troubleshooting

View File

@@ -9,8 +9,8 @@ keywords: local api, config, configuration, documentation, Content Management Sy
Payload can be used completely outside of Next.js which is helpful in cases like running scripts, using Payload in a separate backend service, or using Payload's Local API to fetch your data directly from your database in other frontend frameworks like SvelteKit, Remix, Nuxt, and similar.
<Banner>
<strong>Note:</strong>
<br/>
**Note:**
Payload and all of its official packages are fully ESM. If you want to use Payload within your own projects, make sure you are writing your scripts in ESM format or dynamically importing the Payload Config.
</Banner>

View File

@@ -9,8 +9,8 @@ keywords: local api, config, configuration, documentation, Content Management Sy
The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL within Node, directly on your server. Here, you don't need to deal with server latency or network speed whatsoever and can interact directly with your database.
<Banner type="success">
<strong>Tip:</strong>
<br />
**Tip:**
The Local API is incredibly powerful when used in React Server Components and other similar server-side contexts. With other headless CMS, you need to request your data from third-party servers via an HTTP layer, which can add significant loading time to your server-rendered pages. With Payload, you don't have to leave your server to gather the data you need. It can be incredibly fast and is definitely a game changer.
</Banner>
@@ -27,7 +27,7 @@ You can gain access to the currently running `payload` object via two ways:
#### Accessing from args or `req`
In most places within Payload itself, you can access `payload` directly from the arguments of [Hooks](../hooks/overview), [Access Control](../access-control/overview), [Validation](../fields/overview#validations) functions, and similar. This is the simplest way to access Payload in most cases. Most config functions take the `req` (Request) object, which has Payload bound to it (`req.payload`).
In most places within Payload itself, you can access `payload` directly from the arguments of [Hooks](../hooks/overview), [Access Control](../access-control/overview), [Validation](../fields/overview#validation) functions, and similar. This is the simplest way to access Payload in most cases. Most config functions take the `req` (Request) object, which has Payload bound to it (`req.payload`).
Example:
@@ -92,8 +92,8 @@ const post = await payload.find({
```
<Banner type="warning">
<strong>Note:</strong>
<br />
**Note:**
By default, all access control checks are disabled in the Local API, but you can re-enable them if
you'd like, as well as pass a specific user to run the operation with.
</Banner>

View File

@@ -770,8 +770,8 @@ For more details, see the [Documentation](https://payloadcms.com/docs/getting-st
```diff
// collections/Posts.ts
import type { CollectionConfig } from 'payload'
+ import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
+ import { addLocalesToRequest } from '@payloadcms/next/utilities'
+ import { addDataAndFileToRequest } from 'payload'
+ import { addLocalesToRequest } from 'payload'
export const PostsCollection: CollectionConfig = {
slug: 'posts',

View File

@@ -9,9 +9,8 @@ keywords: plugins, template, config, configuration, extensions, custom, document
Building your own [Payload Plugin](./overview) is easy, and if you&apos;re already familiar with Payload then you&apos;ll have everything you need to get started. You can either start from scratch or use the [Plugin Template](#plugin-template) to get up and running quickly.
<Banner type="success">
To use the template, run `npx create-payload-app@latest -t plugin -n my-new-plugin` directly in
your terminal or [clone the template directly from
GitHub](https://github.com/payloadcms/payload-plugin-template).
To use the template, run `npx create-payload-app@latest --template plugin` directly in
your terminal.
</Banner>
Our plugin template includes everything you need to build a full life-cycle plugin:
@@ -57,7 +56,7 @@ The initialization process goes in the following order:
## Plugin Template
In the [Payload Plugin Template](https://github.com/payloadcms/payload-plugin-template), you will see a common file structure that is used across plugins:
In the [Payload Plugin Template](https://github.com/payloadcms/payload/tree/main/templates/plugin), you will see a common file structure that is used across plugins:
1. `/` root folder - general configuration
2. `/src` folder - everything related to the plugin

View File

@@ -248,7 +248,7 @@ formBuilderPlugin({
Each field represents a form input. To override default settings pass either a boolean value or a partial [Payload Block](https://payloadcms.com/docs/fields/blocks) _keyed to the block's slug_. See [Field Overrides](#field-overrides) for more details on how to do this.
<Banner type="info">
<strong>Note:</strong>
**Note:**
"Fields" here is in reference to the _fields to build forms with_, not to be confused with the _fields
of a collection_ which are set via `formOverrides.fields`.
</Banner>
@@ -458,13 +458,13 @@ Below are some common troubleshooting tips. To help other developers, please con
![screenshot 1](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-1.jpg?raw=true)
<br />
![screenshot 2](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-2.jpg?raw=true)
<br />
![screenshot 3](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-3.jpg?raw=true)
<br />
![screenshot 4](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-4.jpg?raw=true)
<br />
![screenshot 5](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-5.jpg?raw=true)
<br />
![screenshot 6](https://github.com/payloadcms/plugin-form-builder/blob/main/images/screenshot-6.jpg?raw=true)

View File

@@ -163,8 +163,8 @@ When defined, the `breadcrumbs` field will not be provided for you, and instead,
own `breadcrumbs` field to each collection manually. Set this property to the `name` of your custom field.
<Banner type="info">
<strong>Note:</strong>
<br />
**Note:**
If you opt out of automatically being provided a `parent` or `breadcrumbs` field, you need to make
sure that both fields are placed at the top-level of your document. They cannot exist within any
nested data structures like a `group`, `array`, or `blocks`.
@@ -196,7 +196,7 @@ const examplePageConfig: CollectionConfig = {
},
// Note: if you override the `filterOptions` of the `parent` field,
// be sure to continue to prevent the document from referencing itself as the parent like this:
// filterOptions: ({ id }) => ({ id: {not_equals: id }})`
// filterOptions: ({ id }) => ({ id: {not_equals: id }})
},
),
createBreadcrumbsField(
@@ -215,8 +215,8 @@ const examplePageConfig: CollectionConfig = {
```
<Banner type="warning">
<strong>Note:</strong>
<br />
**Note:**
If overriding the `name` of either `breadcrumbs` or `parent` fields, you must specify the
`breadcrumbsFieldSlug` or `parentFieldSlug` respectively.
</Banner>

View File

@@ -147,6 +147,6 @@ export const addLastModified: Plugin = (incomingConfig: Config): Config => {
```
<Banner type="success">
<strong>Reminder:</strong>
**Reminder:**
See [how to build your own plugin](./build-your-own) for a more in-depth explication on how create your own Payload Plugin.
</Banner>

View File

@@ -1,26 +1,21 @@
---
title: SEO Plugin
description: Manage SEO metadata from your Payload admin
keywords: plugins, seo, meta, search, engine, ranking, google
label: SEO
order: 30
desc: Manage SEO metadata from your Payload admin
keywords: plugins, seo, meta, search, engine, ranking, google
title: SEO Plugin
---
[![npm](https://img.shields.io/npm/v/@payloadcms/plugin-seo)](https://www.npmjs.com/package/@payloadcms/plugin-seo)
![https://www.npmjs.com/package/@payloadcms/plugin-seo](https://img.shields.io/npm/v/@payloadcms/plugin-seo)
This plugin allows you to easily manage SEO metadata for your application from within your [Admin Panel](../admin/overview). When enabled on your [Collections](../configuration/collections) and [Globals](../configuration/globals), it adds a new `meta` field group containing `title`, `description`, and `image` by default. Your front-end application can then use this data to render meta tags however your application requires. For example, you would inject a `title` tag into the `<head>` of your page using `meta.title` as its content.
As users are editing documents within the Admin Panel, they have the option to "auto-generate" these fields. When clicked, this plugin will execute your own custom functions that re-generate the title, description, and image. This way you can build your own SEO writing assistance directly into your application. For example, you could append your site name onto the page title, or use the document's excerpt field as the description, or even integrate with some third-party API to generate the image using AI.
To help you visualize what your page might look like in a search engine, a preview is rendered on page just beneath the meta fields. This preview is updated in real-time as you edit your metadata. There are also visual indicators to help you write effective meta, such as a character counter for the title and description fields. You can even inject your own custom fields into the `meta` field group as your application requires, like `og:title` or `json-ld`. If you've ever used something like Yoast SEO, this plugin might feel very familiar.
To help you visualize what your page might look like in a search engine, a preview is rendered on the page just beneath the meta fields. This preview is updated in real-time as you edit your metadata. There are also visual indicators to help you write effective meta, such as a character counter for the title and description fields. You can even inject your own custom fields into the `meta` field group as your application requires, like `og:title` or `json-ld`. If you've ever used something like Yoast SEO, this plugin might feel very familiar.
<Banner type="info">
This plugin is completely open-source and the [source code can be found
here](https://github.com/payloadcms/payload/tree/main/packages/plugin-seo). If you need help,
check out our [Community Help](https://payloadcms.com/community-help). If you think you've found a
bug, please [open a new
issue](https://github.com/payloadcms/payload/issues/new?assignees=&labels=plugin%3A%20seo&template=bug_report.md&title=plugin-seo%3A)
with as much detail as possible.
This plugin is completely open-source and the [source code can be found here](https://github.com/payloadcms/payload/tree/main/packages/plugin-seo). If you need help, check out our [Community Help](https://payloadcms.com/community-help). If you think you've found a bug, please [open a new issue](https://github.com/payloadcms/payload/issues/new?assignees=&labels=plugin%3A%20seo&template=bug_report.md&title=plugin-seo%3A) with as much detail as possible.
</Banner>
## Core features
@@ -42,7 +37,7 @@ Install the plugin using any JavaScript package manager like [pnpm](https://pnpm
## Basic Usage
In the `plugins` array of your [Payload Config](https://payloadcms.com/docs/configuration/overview), call the plugin with [options](#options):
In the `plugins` array of your [Payload Config](../configuration/overview), call the plugin with [options](#options):
```ts
import { buildConfig } from 'payload';
@@ -113,17 +108,15 @@ Set the `uploadsCollection` to your application's upload-enabled collection slug
##### `tabbedUI`
When the `tabbedUI` property is `true`, it appends an `SEO` tab onto your config using Payload's [Tabs Field](https://payloadcms.com/docs/fields/tabs). If your collection is not already tab-enabled, meaning the first field in your config is not of type `tabs`, then one will be created for you called `Content`. Defaults to `false`.
When the `tabbedUI` property is `true`, it appends an `SEO` tab onto your config using Payload's [Tabs Field](../fields/tabs). If your collection is not already tab-enabled, meaning the first field in your config is not of type `tabs`, then one will be created for you called `Content`. Defaults to `false`.
<Banner type="info">
If you wish to continue to use top-level or sidebar fields with `tabbedUI`, you must not let the
default `Content` tab get created for you (see the note above). Instead, you must define the first
field of your config with type `tabs` and place all other fields adjacent to this one.
If you wish to continue to use top-level or sidebar fields with `tabbedUI`, you must not let the default `Content` tab get created for you (see the note above). Instead, you must define the first field of your config with type `tabs` and place all other fields adjacent to this one.
</Banner>
##### `generateTitle`
A function that allows you to return any meta title, including from document's content.
A function that allows you to return any meta title, including from the document's content.
```ts
// payload.config.ts
@@ -137,29 +130,29 @@ A function that allows you to return any meta title, including from document's c
All "generate" functions receive the following arguments:
| Argument | Description |
| Argument | Description |
| --- | --- |
| **`collectionConfig`** | The configuration of the collection. |
| **`collectionSlug`** | The slug of the collection. |
| **`doc`** | The data of the current document. |
| **`docPermissions`** | The permissions of the document. |
| **`globalConfig`** | The configuration of the global. |
| **`globalSlug`** | The slug of the global. |
| **`hasPublishPermission`** | Whether the user has permission to publish the document. |
| **`hasSavePermission`** | Whether the user has permission to save the document. |
| **`id`** | The ID of the document. |
| **`initialData`** | The initial data of the document. |
| **`initialState`** | The initial state of the document. |
| **`locale`** | The locale of the document. |
| **`preferencesKey`** | The preferences key of the document. |
| **`publishedDoc`** | The published document. |
| **`req`** | The Payload request object containing `user`, `payload`, `i18n`, etc. |
| **`title`** | The title of the document. |
| **`versionsCount`** | The number of versions of the document. |
| **`collectionConfig`** | The configuration of the collection. |
| **`collectionSlug`** | The slug of the collection. |
| **`doc`** | The data of the current document. |
| **`docPermissions`** | The permissions of the document. |
| **`globalConfig`** | The configuration of the global. |
| **`globalSlug`** | The slug of the global. |
| **`hasPublishPermission`** | Whether the user has permission to publish the document. |
| **`hasSavePermission`** | Whether the user has permission to save the document. |
| **`id`** | The ID of the document. |
| **`initialData`** | The initial data of the document. |
| **`initialState`** | The initial state of the document. |
| **`locale`** | The locale of the document. |
| **`preferencesKey`** | The preferences key of the document. |
| **`publishedDoc`** | The published document. |
| **`req`** | The Payload request object containing `user`, `payload`, `i18n`, etc. |
| **`title`** | The title of the document. |
| **`versionsCount`** | The number of versions of the document. |
##### `generateDescription`
A function that allows you to return any meta description, including from document's content.
A function that allows you to return any meta description, including from the document's content.
```ts
// payload.config.ts
@@ -175,7 +168,7 @@ For a full list of arguments, see the [`generateTitle`](#generatetitle) function
##### `generateImage`
A function that allows you to return any meta image, including from document's content.
A function that allows you to return any meta image, including from the document's content.
```ts
// payload.config.ts
@@ -225,8 +218,7 @@ Rename the meta group interface name that is generated for TypeScript and GraphQ
There is the option to directly import any of the fields from the plugin so that you can include them anywhere as needed.
<Banner type="info">
You will still need to configure the plugin in the Payload Config in order to configure the generation functions.
Since these fields are imported and used directly, they don't have access to the plugin config so they may need additional arguments to work the same way.
You will still need to configure the plugin in the Payload Config in order to configure the generation functions. Since these fields are imported and used directly, they don't have access to the plugin config so they may need additional arguments to work the same way.
</Banner>
```ts
@@ -269,7 +261,7 @@ OverviewField({
```
<Banner type="info">
Tip: You can override the length rules by changing the minLength and maxLength props on the fields. In the case of the OverviewField you can use `titleOverrides` and `descriptionOverrides` to override the length rules.
Tip: You can override the length rules by changing the minLength and maxLength props on the fields. In the case of the OverviewField you can use `titleOverrides` and `descriptionOverrides` to override the length rules.
</Banner>
## TypeScript
@@ -303,4 +295,4 @@ The [Templates Directory](https://github.com/payloadcms/payload/tree/main/templa
## Screenshots
![image](https://user-images.githubusercontent.com/70709113/163850633-f3da5f8e-2527-4688-bc79-17233307a883.png)
![image](https://user-images.githubusercontent.com/70709113/163850633-f3da5f8e-2527-4688-bc79-17233307a883.png)

View File

@@ -65,14 +65,14 @@ export default config
| Option | Type | Default | Description |
| ------------------------------ | ------------------ | ----------- | ------------------------------------------------------------------------------------------------------------------------ |
| `stripeSecretKey` \* | string | `undefined` | Your Stripe secret key |
| `stripeSecretKey` * | string | `undefined` | Your Stripe secret key |
| `stripeWebhooksEndpointSecret` | string | `undefined` | Your Stripe webhook endpoint secret |
| `rest` | boolean | `false` | When `true`, opens the `/api/stripe/rest` endpoint |
| `webhooks` | object \| function | `undefined` | Either a function to handle all webhooks events, or an object of Stripe webhook handlers, keyed to the name of the event |
| `webhooks` | object or function | `undefined` | Either a function to handle all webhooks events, or an object of Stripe webhook handlers, keyed to the name of the event |
| `sync` | array | `undefined` | An array of sync configs |
| `logs` | boolean | `false` | When `true`, logs sync events to the console as they happen |
_\* An asterisk denotes that a property is required._
_* An asterisk denotes that a property is required._
## Endpoints
@@ -109,15 +109,15 @@ const res = await fetch(`/api/stripe/rest`, {
If you need to proxy the API server-side, use the [stripeProxy](#node) function.
<Banner type="info">
<strong>Note:</strong>
<br />
**Note:**
The `/api` part of these routes may be different based on the settings defined in your Payload
config.
</Banner>
<Banner type="warning">
<strong>Warning:</strong>
<br />
**Warning:**
Opening the REST proxy endpoint in production is a potential security risk. Authenticated users will have open access to the Stripe REST API. In production, open your own endpoint and use the [stripeProxy](#node) function to proxy the Stripe API server-side.
</Banner>
@@ -232,8 +232,8 @@ export const MyFunction = async () => {
This option will setup a basic sync between Payload collections and Stripe resources for you automatically. It will create all the necessary hooks and webhooks handlers, so the only thing you have to do is map your Payload fields to their corresponding Stripe properties. As documents are created, updated, and deleted from either Stripe or Payload, the changes are reflected on either side.
<Banner type="info">
<strong>Note:</strong>
<br />
**Note:**
If you wish to enable a _two-way_ sync, be sure to setup [`webhooks`](#webhooks) and pass the
`stripeWebhooksEndpointSecret` through your config.
</Banner>
@@ -268,8 +268,8 @@ export default config
```
<Banner type="warning">
<strong>Note:</strong>
<br />
**Note:**
Due to limitations in the Stripe API, this currently only works with top-level fields. This is
because every Stripe object is a separate entity, making it difficult to abstract into a simple
reusable library. In the future, we may find a pattern around this. But for now, cases like that

View File

@@ -8,7 +8,7 @@ keywords: deployment, production, config, configuration, documentation, Content
<Banner type="success">
So you've developed a Payload app, it's fully tested, and running great locally. Now it's time to
launch. <strong>Awesome! Great work!</strong> Now, what's next?
launch. **Awesome! Great work!** Now, what's next?
</Banner>
There are many ways to deploy Payload to a production environment. When evaluating how you will deploy Payload, you need
@@ -55,17 +55,17 @@ Because _**you**_ are in complete control of who can do what with your data, you
wield that power responsibly before deploying to Production.
<Banner type="error">
<strong>
**
By default, all Access Control functions require that a user is successfully logged in to
Payload to create, read, update, or delete data.
</strong>
**
But, if you allow public user registration, for example, you will want to make sure that your
access control functions are more strict - permitting
{' '}
<strong>
**
only appropriate users
</strong>
{' '}
**
to perform appropriate actions.
</Banner>
@@ -133,9 +133,9 @@ perpetually.
- Many other more traditional web hosts
<Banner type="error">
<strong>Warning:</strong>
<br />
If you rely on Payload's <strong>Upload</strong> functionality, make sure you either use a host
**Warning:**
If you rely on Payload's **Upload** functionality, make sure you either use a host
with a persistent filesystem or have an integration with a third-party file host like Amazon S3.
</Banner>

View File

@@ -20,7 +20,7 @@ Querying a collection and automatically including related documents via `depth`
## Cross-Site Request Forgery (CSRF)
CSRF prevention will verify the authenticity of each request to your API to prevent a malicious action from another site from authorized users. See how to configure CSRF [here](/docs/authentication/overview#csrf-protection).
CSRF prevention will verify the authenticity of each request to your API to prevent a malicious action from another site from authorized users. See how to configure CSRF [here](/docs/authentication/cookies#csrf-attacks).
## Cross Origin Resource Sharing (CORS)
@@ -38,7 +38,7 @@ If you do not need GraphQL it is advised that you disable it altogether with the
Payload does not execute uploaded files on the server, but depending on your setup it may be used to transmit and store potentially dangerous files. If your configuration allows file uploads there is the potential that a bad actor uploads a malicious file that is then served to other users. Consider the following ways to mitigate the risks.
First, enable email [verification](/docs/authentication/overview#email-verification) when users are allowed to register new accounts and add other bot prevention services.
First, enable email [verification](/docs/authentication/email#email-verification) when users are allowed to register new accounts and add other bot prevention services.
Review that `create` and `update` access on file upload collections are as restrictive as your application needs allow. Consider limiting `read` access of uploaded user's files and how you might limit user uploaded files from being served outside of Payload.

View File

@@ -34,7 +34,7 @@ But with a `depth` of `1`, the response might look like this:
```
<Banner type="warning">
<strong>Important:</strong>
**Important:**
Depth has no effect in the [GraphQL API](../graphql/overview), because there, depth is based on the shape of your queries.
</Banner>
@@ -56,7 +56,7 @@ const getPosts = async (payload: Payload) => {
```
<Banner type="info">
<strong>Reminder:</strong>
**Reminder:**
This is the same for [Globals](../configuration/globals) using the `findGlobal` operation.
</Banner>
@@ -71,7 +71,7 @@ fetch('https://localhost:3000/api/posts?depth=2') // highlight-line
```
<Banner type="info">
<strong>Reminder:</strong>
**Reminder:**
This is the same for [Globals](../configuration/globals) using the `/api/globals` endpoint.
</Banner>

View File

@@ -31,7 +31,7 @@ const query: Where = {
_The exact query syntax will depend on the API you are using, but the concepts are the same across all APIs. [More details](#writing-queries)._
<Banner>
<strong>Tip:</strong>
**Tip:**
You can also use queries within [Access Control](../access-control/overview) functions.
</Banner>
@@ -58,7 +58,7 @@ The following operators are available for use in queries:
| `intersects` | For [Point Fields](../fields/point) to filter documents based on whether points intersect with the given area defined in GeoJSON. [Example](../fields/point#querying-intersects) |
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
If you know your users will be querying on certain fields a lot, add `index: true` to the Field Config. This will speed up searches using that field immensely.
</Banner>

View File

@@ -10,18 +10,18 @@ All collection `find` queries are paginated automatically. Responses are returne
**`Find` response properties:**
| Property | Description |
| ------------- | --------------------------------------------------------- |
| docs | Array of documents in the collection |
| totalDocs | Total available documents within the collection |
| limit | Limit query parameter - defaults to `10` |
| totalPages | Total pages available, based upon the `limit` queried for |
| page | Current page number |
| pagingCounter | `number` of the first doc on the current page |
| hasPrevPage | `true/false` if previous page exists |
| hasNextPage | `true/false` if next page exists |
| prevPage | `number` of previous page, `null` if it doesn't exist |
| nextPage | `number` of next page, `null` if it doesn't exist |
| Property | Description |
| --------------- | --------------------------------------------------------- |
| `docs` | Array of documents in the collection |
| `totalDocs` | Total available documents within the collection |
| `limit` | Limit query parameter - defaults to `10` |
| `totalPages` | Total pages available, based upon the `limit` queried for |
| `page` | Current page number |
| `pagingCounter` | `number` of the first doc on the current page |
| `hasPrevPage` | `true/false` if previous page exists |
| `hasNextPage` | `true/false` if next page exists |
| `prevPage` | `number` of previous page, `null` if it doesn't exist |
| `nextPage` | `number` of next page, `null` if it doesn't exist |
**Example response:**

View File

@@ -54,7 +54,7 @@ const getPosts = async (payload: Payload) => {
<Banner type="warning">
<strong>Important:</strong>
**Important:**
To perform querying with `select` efficiently, Payload implements your `select` query on the database level. Because of that, your `beforeRead` and `afterRead` hooks may not receive the full `doc`.
</Banner>
@@ -100,7 +100,7 @@ const getPosts = async () => {
```
<Banner type="info">
<strong>Reminder:</strong>
**Reminder:**
This is the same for [Globals](../configuration/globals) using the `/api/globals` endpoint.
</Banner>
@@ -137,6 +137,11 @@ export const Pages: CollectionConfig<'pages'> = {
}
```
<Banner type="warning">
<strong>Important:</strong>
When using `defaultPopulate` on a collection with [Uploads](/docs/fields/upload) enabled and you want to select the `url` field, it is important to specify `filename: true` as well, otherwise Payload will not be able to construct the correct file URL, instead returning `url: null`.
</Banner>
## populate
Setting `defaultPopulate` will enforce that each time Payload performs a "population" of a related document, only the fields specified will be queried and returned. However, you can override `defaultPopulate` with the `populate` property in the Local and REST API:

View File

@@ -11,7 +11,7 @@ Documents in Payload can be easily sorted by a specific [Field](../fields/overvi
Because sorting is handled by the database, the field cannot be a [Virtual Field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges). It must be stored in the database to be searchable.
<Banner type="success">
<strong>Tip:</strong>
**Tip:**
For performance reasons, it is recommended to enable `index: true` for the fields that will be sorted upon. [More details](../fields/overview).
</Banner>

View File

@@ -50,29 +50,16 @@ Note: Collection slugs must be formatted in kebab-case
updatedAt: "2023-04-27T11:27:32.419Z",
},
},
drawerContent: (
<>
<h6>Additional <code>find</code> query parameters</h6>
The <code>find</code> endpoint supports the following additional query parameters:
<ul>
<li>
<a href="/docs/queries/overview#sort">sort</a> - sort by field
</li>
<li>
<a href="/docs/queries/overview">where</a> - pass a where query to constrain returned
documents
</li>
<li>
<a href="/docs/queries/pagination#pagination-controls">limit</a> - limit the returned
documents to a certain number
</li>
<li>
<a href="/docs/queries/pagination#pagination-controls">page</a> - get a specific page of
documents
</li>
</ul>
</>
),
drawerContent: `
#### Additional \`find\` query parameters
The \`find\` endpoint supports the following additional query parameters:
- [sort](/docs/queries/overview#sort) - sort by field
- [where](/docs/queries/overview) - pass a where query to constrain returned documents
- [limit](/docs/queries/pagination#pagination-controls) - limit the returned documents to a certain number
- [page](/docs/queries/pagination#pagination-controls) - get a specific page of documents
`
},
},
{
@@ -659,7 +646,7 @@ export const Orders: CollectionConfig = {
```
<Banner>
<strong>Note:</strong>
**Note:**
**req** will have the **payload** object and can be used inside your endpoint handlers for making calls like req.payload.find() that will make use of [Access Control](../access-control/overview) and [Hooks](../hooks/overview).
</Banner>
@@ -671,7 +658,7 @@ Data is not automatically appended to the request. You can read the body data by
Or you could use our helper function that mutates the request and appends data and file if found.
```ts
import { addDataAndFileToRequest } from '@payloadcms/next/utilities'
import { addDataAndFileToRequest } from 'payload'
// custom endpoint example
{

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