Compare commits

..

150 Commits

Author SHA1 Message Date
Elliot DeNolf
f878e35cc7 chore(release): v3.0.0-beta.126 [skip ci] 2024-11-06 16:23:57 -05:00
Dan Ribbens
f0f96e7558 fix: allow workflows to be empty or undefined (#9039)
### What?

- Makes `jobs.workflows` optional
- Dynamically include the `workflowSlugs` select field in the jobs
collection as needed

### Why?

When configuring jobs, it should be possible to define `job` with just
some simple tasks and not be forced to define workflows.

### How?

Workflows type was made optional and optional chaining is added where
needed. The workflowSlugs field is added to the jobs collection if
workflows are defined.

Fixes #

When using postgres, the workflowSlugs being an empty enum cause an
error when drizzle fails to detect the enum already exists. This results
in the error `"enum_payload_jobs_workflow_slug" already exists`. Drizzle
tries to make the enum as: `enum_payload_jobs_workflow_slug as enum();`
and the check for existing enums only works when it has values.
2024-11-06 15:50:17 -05:00
Javier
0165ab8930 fix: replace console.error with logger.errors (#9044)
## Problem
When `PayloadRequest` objects are logged using `console.log`, it creates
unstructured, multiline entries in logging services like DataDog and
Sentry. This circumvents the structured logging approach used throughout
the rest of the codebase.

## Solution
Replace `console.x` calls with the structured logging system when
logging `payload.logger.x` objects. This ensures consistent log
formatting and better integration with monitoring tools.

## Changes
- Replaced instances of `console.log` with structured logging methods
only in `@payloadcms/next`
- Maintains logging consistency across the codebase
- Improves log readability in DataDog, Sentry, and other monitoring
services

## First

<img width="914" alt="Screenshot 2024-11-06 at 09 53 44"
src="https://github.com/user-attachments/assets/019b6f4b-40ed-4e54-a92a-8d1b50baa303">

## Then

<img width="933" alt="Screenshot 2024-11-06 at 00 50 29"
src="https://github.com/user-attachments/assets/0a339db4-d706-4ff9-ba8c-80445bbef5d0">
2024-11-06 15:49:27 -05:00
Sasha
213b7c6fb6 feat: generate types for joins (#9054)
### What?
Generates types for `joins` property.
Example from our `joins` test, keys are type-safe:
<img width="708" alt="image"
src="https://github.com/user-attachments/assets/f1fbbb9d-7c39-49a2-8aa2-a4793ae4ad7e">

Output in `payload-types.ts`:
```ts
 collectionsJoins: {
    categories: {
      relatedPosts: 'posts';
      hasManyPosts: 'posts';
      hasManyPostsLocalized: 'posts';
      'group.relatedPosts': 'posts';
      'group.camelCasePosts': 'posts';
      filtered: 'posts';
      singulars: 'singular';
    };
  };
```
Additionally, we include type information about on which collection the
join is, it will help when we have types generation for `where` and
`sort`.

### Why?
It provides a better DX as you don't need to memoize your keys.

### How?
Modifies `configToJSONSchema` to generate the json schema for
`collectionsJoins`, uses that type within `JoinQuery`
2024-11-06 22:43:07 +02:00
Jessica Chowdhury
7dc52567f1 fix: publish locale with autosave enabled and close dropdown (#8719)
1. Fix publish specific locale option when no published versions exist
2. Close the publish locale dropdown on click
2024-11-06 14:36:28 -05:00
Sasha
a22c0e62fa feat: add populate property to Local / REST API (#8969)
### What?
Adds `populate` property to Local API and REST API operations that can
be used to specify `select` for a specific collection when it's
populated
```ts
const result = await payload.findByID({
  populate: {
   // type safe if you have generated types
    posts: {
      text: true,
    },
  },
  collection: 'pages',
  depth: 1,
  id: aboutPage.id,
})

result.relatedPost // only has text and id properties
``` 

```ts
fetch('https://localhost:3000/api/pages?populate[posts][text]=true') // highlight-line
  .then((res) => res.json())
  .then((data) => console.log(data))
```

It also overrides
[`defaultPopulate`](https://github.com/payloadcms/payload/pull/8934)

Ensures `defaultPopulate` doesn't affect GraphQL.

### How?
Implements the property for all operations that have the `depth`
argument.
2024-11-06 13:50:19 -05:00
Sasha
147d28e62c fix(db-postgres): handle special characters in createDatabase (#9022)
### What?
Handles database name with special characters. For example: `-` -
`my-awesome-app`.

### Why?
Previously, `my-awesome-app` led to this error:
```
Error: failed to create database my-awesome-app.
Details: syntax error at or near "-"
```
This can reproduced for example with `create-payload-app`, as the
generated db name is based on project's name.

### How?
Wraps the query variable to quotes, `create database "my-awesome-app"`
instead of `create database my-awesome-app`.
2024-11-06 13:29:57 -05:00
Sasha
f507305192 fix: handle bulk upload sequentially to prevent conflicts (#9052)
### What?
Uses sequential pattern for Bulk Upload instead of `Promise.all`.

### Why?
* Concurrent uploads led to filename conflicts for example when you have
`upload.png` and `upload(1).png` already and you try to upload
`upload.png`
* Potentially expensive for resources, especially with high amount of
files / sizes

### How?
Replaces `Promise.all` with `for` loop, adds indicator "Uploaded 2/20"
to the loading overlay.

---------

Co-authored-by: James <james@trbl.design>
2024-11-06 12:54:16 -05:00
Timothy Choi
d42529055a fix(richtext-slate, ui): use PointerEvents to show tooltips on enabled / disabled buttons (#9006)
Fixes #9005

Note: I did not replace all instances of `onMouseEnter`, just the ones
that can be disabled and have `tooltip` set.
2024-11-06 12:43:06 -05:00
Jacob Fletcher
4b4ecb386d fix(ui): dedupes custom id fields (#9050)
Setting a custom `id` field within unnamed fields causes duplicative ID
fields to be appear in the client config. When a top-level `id` field is
detected in your config, Payload uses that instead of injecting its
default field. But when nested within unnamed fields, such as an unnamed
tab, these custom `id` fields were not being found, causing the default
field to be duplicately rendered into tables columns, etc.
2024-11-06 12:19:19 -05:00
Andreas Bernhard
becf56d582 fix(ui): edit many modal draft action button order and style (#9047)
PR adjusts "draft" action button order and style on the edit-many-modal
to be consistent with default collection edit view action buttons.

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

Makes it possible to filter join documents using a `where` added
directly in the config.


### Why?

It makes the join field more powerful for adding contextual meaning to
the documents being returned. For example, maybe you have a
`requiresAction` field that you set and you can have a join that
automatically filters the documents to those that need attention.

### How?

In the database adapter, we merge the requested `where` to the `where`
defined on the field.
On the frontend the results are filtered using the `filterOptions`
property in the component.

Fixes
https://github.com/payloadcms/payload/discussions/8936
https://github.com/payloadcms/payload/discussions/8937

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-11-06 10:06:25 -05:00
Elliot DeNolf
cdcefa88f2 fix(cpa): remove lock file on project creation 2024-11-06 10:02:29 -05:00
Elliot DeNolf
5c049f7c9c ci(triage): adjust tag condition 2024-11-05 23:03:27 -05:00
Elliot DeNolf
ae6fb4dd1b ci(triage): add granularity in actions to be performed, enable comments 2024-11-05 22:58:33 -05:00
Sasha
9ce2ba6a3f fix: custom endpoints with method: 'put' (#9037)
### What?
Fixes support for custom endpoints with `method: 'put'`.
Previously, this didn't work:
```ts
export default buildConfigWithDefaults({
  collections: [ ],
  endpoints: [
    {
      method: 'put',
      handler: () => new Response(),
      path: '/put',
    },
  ],
})
```

### Why?
We supported this in 2.0 and docs are saying that we can use `'put'` as
`method`
https://payloadcms.com/docs/beta/rest-api/overview#custom-endpoints

### How?
Implements the `REST_PUT` export for `@payloadcms/next/routes`, updates
all templates. Additionally, adds tests to ensure root/collection level
custom endpoints with all necessary methods execute properly.

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

-->
2024-11-05 23:14:34 +02:00
Sasha
f52b7c45c0 fix: type augmentation of RequestContext (#9035)
### What?

Makes this to actually work
```ts
import type { RequestContext as OriginalRequestContext } from 'payload'

declare module 'payload' {
  // Create a new interface that merges your additional fields with the original one
  export interface RequestContext extends OriginalRequestContext {
    myObject?: string
    // ...
  }
}
```
<img width="502" alt="image"
src="https://github.com/user-attachments/assets/38570d3c-e8a8-48aa-a57d-6d11e79394f5">


### Why?
This is described in our docs
https://payloadcms.com/docs/beta/hooks/context#typescript therefore it
should work.

### How?
In order to get the declaration work, we need to reuse the type from the
root file `payload/src/index.js`. Additionally, removes `RequestContext`
type duplication in both `payload/src/types/index.js` and
`payload/src/index.js`.

Fixes https://github.com/payloadcms/payload/issues/8851
2024-11-05 23:14:04 +02:00
Elliot DeNolf
2eeed4a8ae chore(templates): add lock file to with-payload-cloud 2024-11-05 15:55:57 -05:00
Elliot DeNolf
c0335aa49e chore(templates): add lock files 2024-11-05 15:27:27 -05:00
Paul
3ca203e08c fix(ui): json fields can now take a maxHeight in admin props and there's a mininum height of 3 lines (#9018)
JSON fields are now 3 lines minimum in height like so:

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


This helps fix an issue where long content is wrapped:

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

Previously it would show like this:

![image](https://github.com/user-attachments/assets/7f321220-ffa2-40ff-bc4b-2b26d21d4911)
2024-11-05 13:43:51 -06:00
James Mikrut
50f3ca93ee docs: improves jobs queue (#9038)
improves docs for jobs queue
2024-11-05 19:25:14 +00:00
Friggo
4652e8d56e feat(plugin-seo): add czech translation (#8998)
Adds Czech translation to SEO plugin.
2024-11-05 18:28:12 +00:00
Patrik
2175e5cdfb fix(ui): ensure upload field updates reflect in edit popup changes (#9034)
### What?

Any changes inside edit popup for the field with type `upload` and the
`relationTo` collection does nothing in context of the field, it has
affect only to collection.

I.e. when you make an edit to an uploads field in the edit drawer -
after saving and existing the drawer, your new changes are not present
until a refresh of the page.

### Why?

Previously, we were not performing a reload of the document fetch upon
saving of the doc in the edit drawer.

### How?

Now, we perform a reload (fetch) for updated docs on save within the
edit drawer.

Fixes #8837
2024-11-05 13:03:12 -05:00
Paul
201d68663e feat(templates): website template now has configured image sizes, updated readme and simplified env vars for setting up (#9036) 2024-11-05 17:59:29 +00:00
Patrik
ebd3c025b7 fix(ui): updatedAt field in locked-docs collection able to be updated by non-owner (#9026)
### What?

If you have a custom field that sets the value of the field using the
`useField` hook on entry into a document - the `updatedAt` field would
be updated even when a non-owner tries to enter a locked document.

### Why?

When a field is updated in the edit view - we perform an update in
`form-state` to keep the doc in `payload-locked-documents` up to date
with the current editing status. The above scenario would hit this
update operation even on non-owner users because it was previously only
checking for `updateLastEdited` (which would get hit by the `setValue`
in the `useField` hook) so we also need to check to make sure the
current user entering a locked doc is also the owner of the document.

### How?

When performing an update to `payload-locked-documents` in
`buildFormState` - only perform the update if the current user is also
the owner of the locked document otherwise skip the `update` operation.

Fixes #8781
2024-11-05 12:39:48 -05:00
Paul
ddc9d9731a feat: adds x-powered-by Payload header in next config (#9027)
Adds the `x-powered-by` header to include Payload alongside Next.js

End result looks like this
```
x-powered-by:
Next.js, Payload
```

It also respects the nextConfig `poweredBy: false` to completely disable
it
2024-11-04 18:11:51 -06:00
Jesper We
3e31b7aec9 feat(plugin-seo): add Swedish translations (#9007)
### What?

Swedish text translations

### Why?

There was no Swedish before
2024-11-04 21:25:08 +00:00
Elliot DeNolf
e390835711 chore(release): v3.0.0-beta.124 [skip ci] 2024-11-04 14:47:38 -05:00
James Mikrut
35b107a103 fix: prefetch causing stale data (#9020)
Potentially fixes #9012 by disabling prefetch for all Next.js `Link`
component usage.

With prefetch left as the default and _on_, there were cases where the
prefetch could fetch stale data for Edit routes. Then, when navigating
to the Edit route, the data could be stale.

In addition, I think there is some strangeness happening on the Next.js
side where prefetched data might still come from the router cache even
though router cache is disabled.

This fix should be done regardless, but I suspect it will solve for a
lot of stale data issues.
2024-11-04 19:24:28 +00:00
Paul
6b9f178fcb fix: graphql missing options route resulting in failed cors preflight checks in production (#8987)
GraphQL currently doesn't pass CORS checks as we don't expose an OPTIONS
endpoint which is used for browser preflights.

Should also fix situations like this
https://github.com/payloadcms/payload/issues/8974
2024-11-04 14:20:09 -05:00
vahacreative
cca6746e1e feat(plugin-seo): add Turkish translation v3 (#8993) 2024-11-04 11:54:57 -06:00
Sasha
4349b78a2b fix: invalid select type with strictNullChecks: true (#8991)
### What?
Fixes type for the `select` property when having `strictNullChecks:
true` or `strict: true` in tsconfig.

### Why?
`select` should provide autocompletion for users, at this point it
doesn't work with this condtiion

### How?
Makes `collectionsSelect` and `globalsSelect` properties required in
`configToJSONSchema.ts`.

Fixes
https://github.com/payloadcms/payload/pull/8550#issuecomment-2452669237
2024-11-04 19:16:37 +02:00
Sasha
5b97ac1a67 fix: querying relationships by id path with REST (#9013)
### What?
Fixes the issue with querying by `id` from REST / `overrideAccess:
false`.
For example, this didn't work:

`/api/loans?where[book.bibliography.id][equals]=67224d74257b3f2acddc75f4`
```
QueryError: The following path cannot be queried: id
```

### Why?
We support this syntax within the Local API.

### How?
Now, for simplicity we sanitize everything like
`relation.otherRelation.id` to `relation.otherRelation`

Fixes https://github.com/payloadcms/payload/issues/9008
2024-11-04 17:57:41 +02:00
Patrik
f10a160462 docs: improves clarity for better readability of document-locking docs (#9010) 2024-11-04 09:26:08 -05:00
Elliot DeNolf
59ff8c18f5 chore: add project id source (#8983)
Add `projectIDSource` to analytics event.
2024-11-01 09:46:44 -04:00
Elliot DeNolf
10d5a8f9ae ci: force add triage action 2024-11-01 09:00:05 -04:00
Said Akhrarov
48d2ac1fce docs: include hasMany in upload field config options (#8978)
### What?
Includes `hasMany`, `minRows`, and `maxRows` in Upload field config
options table.

### Why?
To be inline with the type definitions.

### How?
Changes to `docs/fields/upload.mdx`
2024-11-01 05:40:04 -04:00
Elliot DeNolf
c33791d1f8 chore(release): v3.0.0-beta.123 [skip ci] 2024-10-31 16:10:52 -04:00
Paul
9eb79c1b5f fix(templates): website template error inside the populateAuthors hook (#8972) 2024-10-31 17:51:23 +00:00
Germán Jabloñski
4246b36e06 docs: improve docs about beforeSync in searchPlugin (#8946)
This clarification was made to prevent anyone from wasting time on this
again:

https://github.com/payloadcms/payload/issues/5173
2024-10-31 12:14:04 -04:00
Sasha
3175541c80 fix: select with unnamed tabs (#8966)
### What?
Fixes `select` handling for properties inside of unnamed tabs using the
mongodb adapter.
Additionally, refactors `traverseFields` in drizzle to reuse logic from
groups / collapsible or rows if unnamed.

### Why?
`select` must work for any fields.

### How?
Fixes the `'tab'` case in `buildProjectionFromSelect` to handle when the
field is an unnamed tab.
Adds extra tests for named tabs / unnamed.
2024-10-31 12:06:05 -04:00
Patrik
090831c92c fix(next): overly large width on document locked modal content (#8967) 2024-10-31 11:02:17 -04:00
Patrik
55ce8e68fc fix: locked documents with read access for users (#8950)
### What?

When read access is restricted on the `users` collection - restricted
users would not have access to other users complete user data object
only their IDs when accessing `user.value`.

### Why?

This is problematic when determining the lock status of a document from
a restricted users perspective as `user.id` would not exist - the user
data would not be an object in this case but instead a `string` or
`number` value for user ID

### How?

This PR properly handles both cases now and checks if the incoming user
data is an object or just a `string` / `number`.
2024-10-31 09:23:18 -04:00
Paul
b417c1f61a feat(plugin-seo)!: support overriding default fields via a function instead and fixes bugs regarding localized labels (#8958)
## The SEO plugin now takes in a function to override or add in new
fields
- `fieldOverrides` has been removed
- `fields` is now a function that takes in `defaultFields` and expects
an array of fields in return

This makes it a lot easier for end users to override and extend existing
fields and add new ones. This change also brings this plugin inline with
the pattern that we use in our other plugins.

```ts
// before
seoPlugin({
  fieldOverrides: {
    title: {
      required: true,
    },
  },
  fields: [
    {
      name: 'customField',
      type: 'text',
    }
  ]
})

// after
seoPlugin({
  fields: ({ defaultFields }) => {
    const modifiedFields = defaultFields.map((field) => {
     // Override existing fields
      if ('name' in field && field.name === 'title') {
        return {
          ...field,
          required: true,
        }
      }
      return field
    })

    return [
      ...modifiedFields,

     // Add a new field
      {
        name: 'ogTitle',
        type: 'text',
        label: 'og:title',
      },
    ]
  },
})
```



## Also fixes
- Localization labels not showing up on default fields
- The inability to add before and after inputs to default fields
https://github.com/payloadcms/payload/issues/8893
2024-10-31 06:03:39 +00:00
Elliot DeNolf
2c6635fe20 ci: port all templates, actions, and workflows from main (#8949)
Port all templates, actions, and workflows from `main` in preparation
for making `beta` the default branch.
2024-10-30 21:36:51 -04:00
Sasha
c0397c35a2 fix(ui): increase z-index of ReactSelect (#8735)
Fixes https://github.com/payloadcms/payload/issues/8728

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





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

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

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

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

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

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

### What?

### Why?

### How?

Fixes #

-->

### What?
`auth` enabled collections show "Password" fields whenever a GraphQL
query is performed or the GraphQL playground is opened (see #8032)

You can reproduce this behavior by spinning up the `admin` test with
PostgreSQL:
```bash
pnpm dev:postgres admin
```

Open the admin UI and navigate to the `dev@payloadcms.com` document in
the `Users` collection (see screenshot below)
<img width="915" alt="image"
src="https://github.com/user-attachments/assets/40624a8f-80b7-412b-b851-5e3643ffcae1">

Open the [GraphQL
playground](http://localhost:3000/api/graphql-playground)
Open the admin UI and select the user again. The password field appears
multiple times.
Subsequent GraphQL playground page refreshes lead to even more password
fields in the admin UI.

<img width="1086" alt="image"
src="https://github.com/user-attachments/assets/009264bd-b153-4bf7-8fc9-8e465fc27247">

The current behavior has an impact during development and even on
production. Since the password field is added to the collection, payload
tries to add this field to the database as well (at least I could
observe at in my own project)

### Why?
In the `packages/graphql/src/schema/initCollections.ts` file, the
`initCollections` function mutates the config object by adding the
password field for the GraphQL schema (line 128). This mutation adds the
field multiple times, depending how often you open the playground. In
addition, this added field is also shown in the UI since the config
object is shared (see screenshot above).

### How?
By creating a deep copy of the object, the mutation of the configuration
does not leak additional fields to the UI or other parts of the code.
2024-10-31 00:45:07 +00:00
Gregor Gabrič
3918c09013 feat(translations): added sl to exported date locales (#8817)
added sl to exported date locales
2024-10-30 18:26:12 -06:00
Konsequanzheng
bf989e6041 docs: fix copy paste oversights in storage-adapters.mdx (#8919)
### What?
S3, Azure Blob, and Google Cloud storage sections were referring to
Vercel Blob Storage (presumably because of copy pasting)
2024-10-30 18:15:25 -06:00
Paul
57fba36257 fix(ui): overly large width on stay logged in modal content (#8952) 2024-10-31 00:01:58 +00:00
Sasha
df4661a388 docs: fix defaultPopulate docs formatting (#8951)
### What?
Fixes this
[here](https://payloadcms.com/docs/beta/queries/select#rest-api)
<img width="535" alt="image"
src="https://github.com/user-attachments/assets/a9fec4a7-c1c2-43f3-ba36-a07505deb012">
2024-10-31 00:37:45 +02:00
James Mikrut
03e5ae8095 fix: bulk upload mimetype wildcard file selection (#8954)
Fixes an issue where using wildcards in upload-enabled collection
mimeType restrictions would prevent files from being selected in the
bulk upload file selector.
2024-10-30 16:26:36 -06:00
Elliot DeNolf
d89db00295 chore(release): v3.0.0-beta.121 [skip ci] 2024-10-30 14:25:34 -04:00
James Mikrut
8970c6b3a6 feat: adds jobs queue (#8228)
Adds a jobs queue to Payload.

- [x] Docs, w/ examples for Vercel Cron, additional services
- [x] Type the `job` using GeneratedTypes in `JobRunnerArgs`
(@AlessioGr)
- [x] Write the `runJobs` function 
- [x] Allow for some type of `payload.runTask` 
- [x] Open up a new bin script for running jobs
- [x] Determine strategy for runner endpoint to either await jobs
successfully or return early and stay open until job work completes
(serverless ramifications here)
- [x] Allow for job runner to accept how many jobs to run in one
invocation
- [x] Make a Payload local API method for creating a new job easily
(payload.createJob) or similar which is strongly typed (@AlessioGr)
- [x] Make `payload.runJobs` or similar  (@AlessioGr)
- [x] Write tests for retrying up to max retries for a given step
- [x] Write tests for dynamic import of a runner

The shape of the config should permit the definition of steps separate
from the job workflows themselves.

```js
const config = {
  // Not sure if we need this property anymore
  queues: {
  },
  // A job is an instance of a workflow, stored in DB
  // and triggered by something at some point
  jobs: {
    // Be able to override the jobs collection
    collectionOverrides: () => {},

    // Workflows are groups of tasks that handle
    // the flow from task to task.
    // When defined on the config, they are considered as predefined workflows
    // BUT - in the future, we'll allow for UI-based workflow definition as well.
    workflows: [
      {
        slug: 'job-name',
        // Temporary name for this
        // should be able to pass function 
        // or path to it for Node to dynamically import
        controlFlowInJS: '/my-runner.js',

        // Temporary name as well
        // should be able to eventually define workflows
        // in UI (meaning they need to be serialized in JSON)
        // Should not be able to define both control flows
        controlFlowInJSON: [
          {
            task: 'myTask',
            next: {
              // etc
            }
          }
        ],

        // Workflows take input
        // which are a group of fields
        input: [
          {
            name: 'post',
            type: 'relationship',
            relationTo: 'posts',
            maxDepth: 0,
            required: true,
          },
          {
            name: 'message',
            type: 'text',
            required: true,
          },
        ],
      },
    ],

    // Tasks are defined separately as isolated functions
    // that can be retried on fail
    tasks: [
      {
        slug: 'myTask',
        retries: 2,
        // Each task takes input
        // Used to auto-type the task func args
        input: [
          {
            name: 'post',
            type: 'relationship',
            relationTo: 'posts',
            maxDepth: 0,
            required: true,
          },
          {
            name: 'message',
            type: 'text',
            required: true,
          },
        ],
        // Each task takes output
        // Used to auto-type the function signature
        output: [
          {
            name: 'success',
            type: 'checkbox',
          }
        ],
        onSuccess: () => {},
        onFail: () => {},
        run: myRunner,
      },
    ]
  }
}
```

### `payload.createJob`

This function should allow for the creation of jobs based on either a
workflow (group of tasks) or an individual task.

To create a job using a workflow:

```js
const job = await payload.createJob({
  // Accept the `name` of a workflow so we can match to either a 
  // code-based workflow OR a workflow defined in the DB
  // Should auto-type the input
  workflowName: 'myWorkflow',
  input: {
    // typed to the args of the workflow by name
  }
})
```

To create a job using a task:

```js
const job = await payload.createJob({
  // Accept the `name` of a task
  task: 'myTask',
  input: {
    // typed to the args of the task by name
  }
})
```

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-10-30 17:56:50 +00:00
Said Akhrarov
0574155e59 docs: fix docs-wide spelling errors and formatting issues (#8942)
### What?
I noticed a spelling error in the banner of the beta docs and decided I
could save everyone some time by *running the entirety of the beta docs*
through a spellchecker.

### Why?
To fix many spelling and formatting mistakes at once.

### How?
By enabling `edit mode` in my browser and letting the built-in
spellchecker perform its magic (and changing _only_ where it made
sense).

~~Ironically, the original spelling mistake that inspired me to do this
remains unchanged as that is a part of the website repo. [PR for that is
here](https://github.com/payloadcms/website/pull/388).~~
2024-10-30 11:54:44 -06:00
Paul
03331de2ac fix(ui): perf improvements in bulk upload (#8944) 2024-10-30 13:44:09 -04:00
Sasha
d64946c2e2 fix(db-mongodb): ensure relationships are stored in ObjectID (#8932)
### What?
Since the join field, we do store relationship fields values in
`ObjectID`. This wasn't true if the field is nested to an array /
blocks.

### Why?
All relationship fields values should be stored in `ObjectID`.

### How?
Fixes arrays / blocks handling in the `traverseFields.ts` function.
Before it didn't run for them.
2024-10-30 13:42:07 -04:00
Sasha
c41ef65a2b feat: add defaultPopulate property to collection config (#8934)
### What?
Adds `defaultPopulate` property to collection config that allows to
specify which fields to select when the collection is populated from
another document.
```ts
import type { CollectionConfig } from 'payload'

// The TSlug generic can be passed to have type safety for `defaultPopulate`.
// If avoided, the `defaultPopulate` type resolves to `SelectType`.
export const Pages: CollectionConfig<'pages'> = {
  slug: 'pages',
  // I need only slug, NOT the WHOLE CONTENT!
  defaultPopulate: {
    slug: true,
  },
  fields: [
    {
      name: 'slug',
      type: 'text',
      required: true,
    },
  ],
}
```

### Why?
This is essential for example in case of links. You don't need the whole
document, which can contain large data but only the `slug`.

### How?
Implements `defaultPopulate` when populating relationships, including
inside of lexical / slate rich text fields.
2024-10-30 13:41:34 -04:00
Paul
d38d7b8932 fix(ui): broken buttons in the bulk upload drawer (#8926)
Fixes the mobile bottom interface and the arrow buttons in the actions
at the top.

Before:

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


After:

![image](https://github.com/user-attachments/assets/7837684c-37a7-4b2e-a875-47972cf1671f)
2024-10-30 11:29:58 -06:00
Paul
01ccbd48b0 feat!: custom views are now public by default and fixed some issues with notFound page (#8820)
This PR aims to fix a few issues with the notFound page and custom views
so it matches v2 behaviour:
- Non authorised users should always be redirected to the login page
regardless if not found or valid URL
- Previously notFound would render for non users too potentially
exposing valid but protected routes and creating a confusing workflow as
the UI was being rendered as well
- Custom views are now public by default
- in our `admin` test suite, the `/admin/public-custom-view` is
accessible to non users but
`/admin/public-custom-view/protected-nested-view` is not unless the
checkbox is true in the Settings global, there's e2e coverage for this
- Fixes https://github.com/payloadcms/payload/issues/8716
2024-10-30 11:29:29 -06:00
Kendell Joseph
61b4f2efd7 chore: updates payload cloud plugin docs (#8943)
Documentation updated to match current implementation.

Original Doc:
```ts
import { payloadCloud } from '@payloadcms/payload-cloud'
```

Current:
```ts
import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
```

---

References in docs have been updated.
2024-10-30 12:52:56 -04:00
Sasha
f4041ce6e2 fix(db-mongodb): joins with singular collection name (#8933)
### What?
Properly specifies `$lookup.from` when the collection name is singular.

### Why?
MongoDB can pluralize the collection name and so can be different for
singular ones.

### How?
Uses the collection name from the driver directly
`adapter.collections[slug].collection.name` instead of just `slug`.
2024-10-30 12:06:03 -04:00
James Mikrut
123125185c fix!: plugin-search with localization enabled (#8938)
The search plugin was incorrectly retrieving all locales, when it should
just be retrieving the locale of the parent document that was actively
being updated.

## BREAKING CHANGES:

If you have a localized Payload config, and you are using the `plugin-search`, we will now automatically localize the `title` field that is injected by the search plugin and this may lead to data loss. To opt out of this new behavior, you can pass `localize: false` to the plugin options.
2024-10-30 11:49:54 -04:00
Kendell Joseph
04bd502d37 chore: uses custom live preview component if one is provided (#8930)
Issue: https://github.com/payloadcms/payload/issues/8273
2024-10-30 11:37:01 -04:00
Sasha
dae832c288 feat: select fields (#8550)
Adds `select` which is used to specify the field projection for local
and rest API calls. This is available as an optimization to reduce the
payload's of requests and make the database queries more efficient.

Includes:
- [x] generate types for the `select` property
- [x] infer the return type by `select` with 2 modes - include (`field:
true`) and exclude (`field: false`)
- [x] lots of integration tests, including deep fields / localization
etc
- [x] implement the property in db adapters
- [x] implement the property in the local api for most operations
- [x] implement the property in the rest api 
- [x] docs

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-10-29 21:47:18 +00:00
Dan Ribbens
6cdf141380 feat: prevent create new for joins (#8929)
### What?

Adds a way to prevent creating new documents from the admin UI in a join
field.

### Why?

There are two reasons: 
1. You want to disable this any time as a feature of your admin user
experience
2. When creating a new document it is not yet possible to create the
relationship, preventing create is necessary for the workflow to make
sense.

### How?

join field has a new admin property called `allowCreate`, can be set to
false. By default the UI will never allow create when the current
document being edited does not yet have an `id`.

Fixes #

#8892

### Before

Even though the document doesn't have an ID yet, the create buttons are
shown which doesn't actually work.

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

### After

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

Prevented using `allowCreate: false`
![Screenshot 2024-10-29
130409](https://github.com/user-attachments/assets/69c3f601-fab3-4f5a-9df5-93fd133682ca)
2024-10-29 16:49:27 -04:00
Kendell Joseph
29704428bd chore: corrects package import paths for live preview test (#8925)
Corrects package import paths for live preview test.

- This would cause a import glitch when trying to run the live-preview
test due to incorrect file paths.
2024-10-29 16:12:45 -04:00
Sasha
6c341b5661 fix(ui): sanitize limit for preferences (#8913)
### What?
Fixes the issue with passing a string `limit` value from user
preferences to the mongodb `.aggregate` function.

To reproduce:

- click the list view for a collection that has a join field
- set "show per page" to 100
- reload, see this:

<img width="1001" alt="image"
src="https://github.com/user-attachments/assets/86c644d1-d183-48e6-bf34-0ccac23cb114">

### Why?
When using `.aggregate`, MongoDB doesn't cast a value for the `$limit`
stage to a number automatically as it's not handled by Mongoose. It's
also more convenient to store this value as a number.

### How?
Stores `limit` inside of preferences in number.
2024-10-29 16:03:31 -04:00
Kendell Joseph
9c530e47bb chore: changes admin API key field visuals based on read and update permissions (#8923)
Issue: https://github.com/payloadcms/payload/issues/8785
2024-10-29 18:56:29 +00:00
Elliot DeNolf
7ba19e03d6 ci: add payload-cloud as valid pr scope 2024-10-29 13:47:37 -04:00
Paul
c0aa96f59a fix(ui): missing localization label on text area fields (#8927) 2024-10-29 17:19:38 +00:00
Patrik
c7bde52aba chore: adds additional locked documents e2e tests (#8921)
Additional tests for global locked documents
2024-10-29 10:03:09 -04:00
Paul
915a3ce3f5 docs: fix dead link for local API (#8917) 2024-10-29 05:56:05 +00:00
Said Akhrarov
b6867f222b docs: form builder number field table unformatted (#8915)
### What?
This PR aims to fix an issue in the form-builder plugin page - in the
`number` field table, where an issue with one of the columns makes the
whole table unformatted. [See issue
here](https://payloadcms.com/docs/beta/plugins/form-builder#number).

### Why?
As it stands, the whole table is being rendered without any formatting,
making understanding it very difficult.

### How?
Changes to `docs/plugins/form-builder.mdx`
2024-10-28 23:29:21 -06:00
Elliot DeNolf
43fcccab93 chore(release): v3.0.0-beta.120 [skip ci] 2024-10-28 22:08:50 -04:00
Patrik
e74906f555 fix(next, ui): exclude expired locks for globals (#8914)
Continued PR off of https://github.com/payloadcms/payload/pull/8899
2024-10-28 21:49:50 -04:00
Patrik
1e002acce9 fix(next, ui): only show locked docs that are not expired (#8899)
`Issue`:

Previously, documents that were locked but expired would still show in
the list view / render the `DocumentLocked` modal upon other users
entering the document.

The expected outcome should be having expired locked documents seen as
unlocked to other users.

I.e:

- Removing the lock icon from expired locks in the list view.
- Prevent the `DocumentLocked` modal from appearing for other users -
requiring a take over.

`Fix`:

- Only query for locked documents that are not expired, aka their
`updatedAt` dates are greater than the the current time minus the lock
duration.
- Performs a `deleteMany` on expired documents when any user edits any
other document in the same collection.

Fixes #8778 

`TODO`: Add tests
2024-10-28 20:05:26 -04:00
Sasha
7a7a2f3918 fix(db-mongodb): query 'in' with a comma-delimited value (#8910)
### What?
Fixes the issue with `in` querying when the collection has a join field.

### Why?
When using `.aggregate`, MongoDB doesn't cast a comma delimited value
for the `$in` operator to an array automatically as it's not handled by
Mongoose.

### How?
Sanitizes the incoming value to an array if it should.

Fixes https://github.com/payloadcms/payload/issues/8901
2024-10-28 19:41:28 -04:00
Dan Ribbens
f0edbb79f9 feat: join field defaultLimit and defaultSort (#8908)
### What?

Allow specifying the defaultSort and defaultLimit to use for populating
a join field

### Why?

It is much easier to set defaults rather than be forced to always call
the join query using the query pattern ("?joins[categories][limit]=0").

### How?

See docs and type changes
2024-10-28 17:52:37 -04:00
Said Akhrarov
3605da1e3f docs: update metadata icons example to use url and fix images type in table (#8898)
<!--

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

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

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

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

### What?

### Why?

### How?

Fixes #

-->
### What?
Updates the examples in the
[admin/metadata#root-metadata](https://payloadcms.com/docs/beta/admin/metadata#root-metadata)
and
[admin/metadata#icons](https://payloadcms.com/docs/beta/admin/metadata#icons)
sections from using `href` to `url` and fixes the way that the `images`
Type excludes the description due to `|` being parsed as column
separator

### Why?
As of right now, the examples are incorrect and the `images` type bleeds
into the description and omits it entirely

See image of table issue at `images`:

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

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

Fixes #8887

Credit to @thgh for the `href` to `url` find
2024-10-28 17:02:06 -04:00
Brandon Kocur
7127c5507c docs: update database adpater installation commands to use beta version (#8895)
While following the "Adding to an existing app" instructions for the
**beta** docs, I noticed that the pnpm installation commands for the
database adapters were missing the `@beta` tag, which will result in
errors in the project.
2024-10-28 17:00:38 -04:00
James Mikrut
00ed66b4ee fix: autosave potentially losing latest: true w/ race condition (#8894)
Fixes a potential race condition where versions could lose `latest:
true` and potentially also introduce a conflict with the `parent` field.

We now explicitly define these as we update versions in the
`saveVersion` function.
2024-10-28 16:28:57 -04:00
James Mikrut
44e52b0305 fix: #8903, form-builder payment static value field (#8905)
Fixes #8903
2024-10-28 16:28:41 -04:00
Sasha
aea1b41f90 fix(cpa): write POSTGRES_URL to .env for vercel postgres (#8743)
Fixes https://github.com/payloadcms/payload/issues/8877
Current behaviour:
`pnpx create-payload-app@beta`, select "Vercel Postgres",

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

`payload.config.ts`:
```ts
db: vercelPostgresAdapter({
  pool: {
    connectionString: process.env.POSTGRES_URL || '',
  },
}),
```
2024-10-28 17:34:58 +00:00
Alessio Gravili
a8569b9e78 fix(richtext-lexical): ensure editor cursor / selection state is preserved when working with drawers (#8872)
Previously, when opening e.g. a link drawer, clicking within the drawer,
and then closing it, the cursor / selection of the lexical editor will
reset to the beginning of the editor.

Now, we have dedicated logic to storing, preserving and restoring the
lexical selection when working with drawers.

This will work with all drawers. Links, uploads, relationships etc.


https://github.com/user-attachments/assets/ab3858b1-0f52-4ee5-813f-02b848355998
2024-10-27 22:32:31 +00:00
Elliot DeNolf
07a8a37fbd chore(templates): use payload cloud (#8871)
Update templates to use `@payloadcms/payload-cloud`. 

**NOTE:** This should not be merged until beta.119 is released.
2024-10-25 16:20:58 -04:00
Elliot DeNolf
6c2eecc47e chore(release): v3.0.0-beta.119 [skip ci] 2024-10-25 16:11:53 -04:00
Paul
4f88fb046f chore: update docs mention on payload cloud plugin (#8869) 2024-10-25 13:09:35 -06:00
Elliot DeNolf
1b1dc82cfb feat!: rename @payloadcms/plugin-cloud (#8828)
BREAKING CHANGE: Rename `@payloadcms/plugin-cloud` to
`@payloadcms/payload-cloud`. Anyone using the existing plugin will need
to switch to using the new package.

## Why?

Since v3 will be using _fixed versioning_, all versions of `^3` must be
available. Unfortunately, the `@payloadcms/plugin-cloud` version has
already breached that version number. Renaming will allow it to be on
the same version as other monorepo packages.

Additionally, the name `plugin-cloud` is quite ambiguous and sometimes
is confused with `plugin-cloud-storage`, so using `payload-cloud` feels
like a good move to make this more evident.
2024-10-24 21:19:15 -04:00
Paul
2df8f94a75 fix(plugin-search): issues with overriding the search collection slug consistently across hooks (#8847)
Fixes https://github.com/payloadcms/payload/issues/8842
2024-10-25 00:29:39 +00:00
Paul
e72e81c3da fix(ui): upload buttons being hidden at mobile screen widths (#8860) 2024-10-24 22:29:29 +00:00
Elliot DeNolf
b1b571d53e ci: do not run pr-title on synchronize event 2024-10-24 16:48:05 -04:00
Paul
085e127217 fix(ui): leave without saving when changing /account theme (#8724)
Fixes an annoying instance where on the /account page if you change your
theme then navigate away the Leaving without save popup is triggered
even though you don't need to submit a form or trigger a save in order
to change your admin theme.
2024-10-24 16:46:19 -04:00
Anders Semb Hermansen
4d44c378ed feat: sort by multiple fields (#8799)
This change adds support for sort with multiple fields in local API and
REST API. Related discussion #2089

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-10-24 15:46:30 -04:00
Sasha
6e919cc83a perf: index globals versions timestamps by default (#8821) 2024-10-24 14:58:59 -04:00
Elliot DeNolf
1a15425b59 fix(cpa): properly detect if pnpm exists on windows (#8855)
Use `where <command>` if using windows when detecting package manager
2024-10-24 14:53:11 -04:00
Sasha
9069bd3fac fix(db-postgres): sort by localized fields (#8839)
### What?
Fixes https://github.com/payloadcms/payload/issues/5152 issue related to
sorting by a localized field with SQLite / Postgres database adapters.

### Why?
It was an incorrect behaviour.


### How?
Modifies the `getTableColumnFromPath` file to have correct join
conditions. Previously if you had this structure in the _locales table
_locale title parent
en          A    1
es          B     1
we sorted by everything that's here, but we need to sort only by the
passed locale.

Additionally fixes a typescript error in `dev.ts` that I added here
https://github.com/payloadcms/payload/pull/8834

Also, removes the condition with `joins.length` in `countDistinct`. It
was there as for this issue
https://github.com/payloadcms/payload/issues/4889 because sorting by a
localized property caused duplication. This can simnifically improve
performance for `.find` with nested querying/sorting on large data sets,
because `count(*)` is faster than `count(DISTINCT id)`
2024-10-24 14:47:58 -04:00
Hristiyan Dodov
2e11068f49 feat(richtext-slate): add useElement hook to richtext-slate client exports (#8856)
I'm extending the Slate editor with a custom component and everything
works great, except I have to import `useElement()` like this:

```tsx
import { useElement } from 'node_modules/.pnpm/@payloadcms+richtext-slate@3.0.0-beta.113_monaco-editor@0.51.0_next@15.0.0-canary.191_@babel+_qmdxs6s5hpzjhuopohgawpvl6i/node_modules/@payloadcms/richtext-slate/dist/field/providers/ElementProvider.js'

export function Element() {
	const { attributes, children } = useElement()
	return (
		<p {...attributes} className="rich-text-preheading">
			{children}
		</p>
	)
}
```

That's because it's not in the `@payloadcms/richtext-slate/client`
module. This PR fixes this and would allow me to do:

```tsx
import { useElement } from '@payloadcms/richtext-slate/client'
```
2024-10-24 11:50:09 -06:00
Elliot DeNolf
749a7d9131 chore(cpa): remove beta from postgres selection 2024-10-24 13:07:38 -04:00
Elliot DeNolf
b482da63c6 chore(release): v3.0.0-beta.118 [skip ci] 2024-10-23 22:07:05 -04:00
MotorcycleEnjoyer
0fcbce3a01 feat(templates): add a copy button to website template code blocks (#8794)
## WHAT
- Adds a copy code button to the Code Blocks in V3 Beta Website
Template.
- Uses the existing button from `@/components/ui/button`
- SVG from this website: https://uxwing.com/copy-icon/


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

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

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


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

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

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

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

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

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

instead of

> 4 FAILED

example of the previous behaviour

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

![image](https://github.com/user-attachments/assets/7f261ac3-17dd-474d-87a3-47ad6cbacd68)
2024-10-22 23:22:20 +03:00
Sasha
52b1d332db chore: fixes dev server doesn't drop the database (#8834)
Apparently, `nextDev` seems to run in a different process and has its
own env variables, we can run the dev server the same way we run it for
E2Es instead via `createServer`.
2024-10-22 23:19:48 +03:00
Sasha
5ea8d2c196 docs: append the beta tag to plugins installation commands (#8831)
Example:
```sh
pnpm add @payloadcms/plugin-sentry
```

to:

```sh
pnpm add @payloadcms/plugin-sentry@beta
```

Because of this, people can be confused with the wrong installed
version. We'll change it back on stable
2024-10-22 19:50:48 +03:00
Sasha
8af00f2deb fix: join field works on collections with versions enabled (#8715)
- Fixes errors with drizzle when building the schema
https://github.com/payloadcms/payload/issues/8680
- Adds `joins` to `db.queryDrafts` to have them when doing `.find` with
`draft: true`
2024-10-22 11:05:55 -04:00
Sasha
4c396c720e fix(db-postgres): alias already in use in this query (#8823)
Fixes https://github.com/payloadcms/payload/issues/8517

Reuses existing joins instead of adding new, duplicate ones which
causes:
```
Error: Alias "" is already used in this query.
```
2024-10-22 10:14:38 -04:00
Elliot DeNolf
69125504af chore(release): v3.0.0-beta.117 [skip ci] 2024-10-22 09:33:50 -04:00
Elliot DeNolf
74266bdd9a feat!: bump next.js to 15.0.0 (#8825)
Bump Next.js to 15.0.0
2024-10-21 23:12:22 -04:00
Elliot DeNolf
9fb86655a9 fix: drizzle init args (#8818)
Adjust drizzle init for changes in drizzle 0.35.0
https://github.com/drizzle-team/drizzle-orm/releases/tag/0.35.0

The pool/connection should now be passed as the `client` arg when
initializing drizzle.

```ts
this.drizzle = drizzle({
  client: this.poolOptions ? new VercelPool(this.poolOptions) : sql,
  logger,
  schema: this.schema,
})
```

This was causing an issue where running `payload migrate` on Vercel was
causing drizzle to attempt to `127.0.0.1:5432` instead of the specified
environment variable in the adapter 🤔
2024-10-21 21:39:37 -04:00
Patrik
2908c9adde fix(next, ui): ensures selectAll in the list view ignores locked documents (#8813)
Fixes #8783
2024-10-21 16:18:34 -04:00
Sasha
fe25b54fff fix(ui): unique ids for nested rows on row duplicate to prevent errors with postgres (#8790)
Fixes https://github.com/payloadcms/payload/issues/8784

This works for any deep level, both arrays and blocks.
2024-10-21 08:51:26 -04:00
Anders Semb Hermansen
ef8a5b1f3e perf: replace jsonwebtoken with jose (#8217)
The jose package has 0 dependencies and is tree shakable ESM.
So we get lower bundle size and get rid of 10 dependencies.
2024-10-18 10:04:37 -06:00
Sasha
197e3bc010 docs: corrects old imports (#8769)
1
`import type { Field } from 'payload/types'`
to
`import type { Field } from 'payload'`
2
`import { buildConfig } from 'payload/config'`
to
`import { buildConfig } from 'payload'`

3
```
import { SelectInput, useField } from 'payload/components/forms';
import { useAuth } from 'payload/components/utilities';
```
to
`import { SelectInput, useAuth, useField } from '@payloadcms/ui'`

4
uses `import type` for `import type { CollectionConfig } from 'payload'`
2024-10-18 10:47:47 +03:00
Because789
36acfee288 docs: fix missing TextField import (#8688)
Fixes a missing import in field prop example in
docs/beta/admin/fields.mdx.

<!--

For external contributors, please include:

- A summary of the pull request and any related issues it fixes.
- Reasoning for the changes made or any additional context that may be
useful.

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

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

22 dependencies, 2MB total size

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

AFTER:

12 dependencies, 1MB total size

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


https://github.com/user-attachments/assets/cf78082d-9054-4324-90cd-c81219a4f26d
2024-10-18 05:38:48 +00:00
Germán Jabloñski
fa49215078 chore: add internationalization guidelines to CONTRIBUTING.md (#8755) 2024-10-18 03:50:31 +00:00
Alessio Gravili
aedf3c8a76 fix(richtext-*): ensure admin panel doesn't freeze with some field configurations consisting of 2+ richtext fields (#8773)
See comments in code for proper explanation. In some cases, where 2
richtext `editor`s referencing the same `editor` are used, the admin
panel will hang. That's because the server will send their client props
that have the same object reference down to the client twice.

Next.js sometimes does not like this and, ever since one of the v15
canaries, started to hang
2024-10-18 03:22:05 +00:00
Sasha
9056b9fe9b fix(db-mongodb): virtual fields within row / collapsible / tabs (#8733)
Fixes https://github.com/payloadcms/payload/issues/8674
2024-10-17 16:23:45 -04:00
Paul
82f278931b fix(ui): padding on relationship fields when no options or loading text is displayed (#8767) 2024-10-17 19:46:28 +00:00
Germán Jabloñski
a7895560a6 fix(richtext-lexical): fix CLS on collapsed/expanded state of Lexical blocks (#8029)
## Description

The goal is to reduce CLS on collapsed/expanded state of Lexical blocks.
That state is stored as "preferences" and is different for each user.
As Payload has been working so far, if the state of a Lexical block was
"collapsed", it was rendered expanded, and when the correct state was
obtained from the server, it was collapsed producing a CLS with a poor
UX.

My original idea was to get the correct state on the first render.
Talking to @AlessioGr and @jmikrut, we saw that this can be a bit
difficult or challenging, since the feature on the server does not have
access to the Payload object, nor to the user who is making the request.

I was instructed to mimic the behavior of blocks not in Lexial
(`\ui\src\fields\Collapsible\index.tsx`). There the blocks are rendered
after the collapse/expand state is obtained in a useEffect.

In the following video, the case where the first block is collapsed is
shown, rendering everything with a "fast 4G" connection throttle.


https://github.com/user-attachments/assets/078e37c7-6540-4183-a266-bd751cc9d78e

Yes, it's a slight improvement over current behavior. But it could be
much better. There are request waterfalls several levels deep, and
plenty of CLS still.

Unless there is some very big tradeoff that I'm not aware of, I think
it's worth exposing the Payload object and the user to the server in
order to get the correct state on the first render.

And if that's not possible and the request has to be made on the client,
I think initializing the state as collapsed and then expanding it is
better than not showing it at all.

Another observation that is evident from the video, is that there are
several sources or causes of CLS besides the expanded/collapsed state of
the blocks.

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

## Type of change

- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-10-17 19:36:14 +00:00
Paul
1f0d8da182 fix(plugin-seo): description and title fields now respect given minLength and maxLength rules for passing validation (#8765)
Previously minLength or maxLength was not being respected and the
components would use default values only.
2024-10-17 19:28:54 +00:00
Said Akhrarov
c91f21bb78 docs: fix incorrect link for outside-nextjs in local-api importing it section (#8764)
Currently in the `beta` docs at the bottom of [Local API Overview Import
It
section](https://payloadcms.com/docs/beta/local-api/overview#importing-it)
there is a link for _Outside Nextjs_ which incorrectly sends you to
`/docs/beta/beta/local-api/outside-nextjs` instead of
`docs/beta/local-api/outside-nextjs`.

Interestingly enough, a `Not Found` component/message is not rendered
and instead you see a blank screen.

---------

Co-authored-by: Sasha <64744993+r1tsuu@users.noreply.github.com>
2024-10-17 13:13:37 -06:00
Elliot DeNolf
7136515f8d chore(release): v3.0.0-beta.116 [skip ci] 2024-10-17 09:05:45 -04:00
Sasha
73102e97fe fix(drizzle): bump drizzle-orm in drizzle package to 0.35.1 (#8759)
Fixes https://github.com/payloadcms/payload/issues/8757. Other packages
have `drizzle-orm` `0.35.1`, but this does not (`0.34.1-1f15bfd`).
2024-10-17 07:14:02 -04:00
Sasha
f37e476758 fix(db-postgres): esm compatible import of pg (#8758)
Fixes this error that doesn't occur in our monorepo but on users
projects.
<img width="1040" alt="image"
src="https://github.com/user-attachments/assets/6b410959-9108-4022-ae0a-64bc4be6de67">
2024-10-17 10:02:30 +00:00
Sasha
90bca15f52 fix(drizzle): enforce uniqueness on index names (#8754)
Fixes https://github.com/payloadcms/payload/issues/8752

Previously, trying to define a config like this:
```ts
{
  type: 'text',
  name: 'someText',
  index: true,
},
{
  type: 'array',
  name: 'some',
  index: true,
  fields: [
    {
      type: 'text',
      name: 'text',
      index: true,
    },
  ],
}
```

Lead to the error:
```
Warning  We've found duplicated index name across public schema. Please rename your index in either the demonstration table or the table with the duplicated index name
```

Now, if we encounter duplicates, we increment the name like this:
`collection_some_text_idx`
`collection_some_text_1_idx`

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-10-17 02:05:27 +00:00
Sasha
872b205acc fix(drizzle): select hasMany nested to array + tab/group (#8737)
Fixes https://github.com/payloadcms/payload/issues/8732
2024-10-16 21:52:48 -04:00
Jarrod Flesch
99b4359e89 fix: pg where filters not respected in policy generation (#8753)
Fixes https://github.com/payloadcms/payload/issues/8224

Fixes an issue with PG `where` filters not being respected when
generating doc policies/permissions by utilizing the combineQueries
function in getEntityPolicies function.
2024-10-16 16:54:23 -04:00
Dan Ribbens
b269d33278 chore: bump drizzle-kit 0.26.2 (#8750) 2024-10-16 16:32:54 -04:00
Patrik
c63b7bc606 fix: disables document locking of payload-locked-documents, preferences, & migrations collections (#8744)
Fixes #8589 

### Issue: 
There were problems with updating documents in
`payload-locked-documents` collection i.e when "taking over" a document
- a `patch` request is sent to `payload-locked-documents` to update the
user (owner).

However, as a result, this `update` operation would lock that
corresponding doc in `payload-locked-documents` and therefore error on
the `patch` request.

### Fix:
Disable document locking entirely from `payload-locked-documents` &
`preferences` & `migrations` collections
2024-10-16 14:46:39 -04:00
Elliot DeNolf
0fb92d3a0a chore(release): v3.0.0-beta.115 [skip ci] 2024-10-16 14:20:27 -04:00
Jarrod Flesch
99228b62ce chore: improves getLatestCollectionVersion where constraints (#8746) 2024-10-16 14:12:43 -04:00
Dan Ribbens
7019f22aad chore: bump drizzle-orm 0.35.1 (#8742) 2024-10-16 15:14:20 +00:00
Said Akhrarov
c4fa885e84 fix(ui): restrict file picking via upload config mimetypes (#8710)
Fixes #8673

This PR restricts inputs with `type="file"` to only those mimetypes
specified in collection upload configs. This also works for the input in
`bulkUpload` and drag-and-drop capabilities by omitting dropped files if
they do not conform to the upload config mimetypes. This PR also assumes
that an upload config with an empty mimetype array should accept all
files since the negation of that statement makes an upload collection
redundant.
2024-10-16 09:24:21 -04:00
Jarrod Flesch
a9c6a91c1c chore(examples): correct where path comes from in multi-tenant (#8698) 2024-10-16 08:28:28 -04:00
Jarrod Flesch
a19e8d382d fix: corrects schemaPath passing (#8726)
Fixes https://github.com/payloadcms/payload/issues/8690

Fixes an issue where unrelated schema paths were being joined and passed
into nested sanitizeFields function calls.
2024-10-16 06:59:37 -04:00
Paul
e6a1ca5049 fix(ui): add missing styles under the payload-default css layer (#8723) 2024-10-16 01:58:50 +00:00
Dan Ribbens
6d0676ab09 chore: bump drizzle-kit 0.26.1 (#8721) 2024-10-15 21:12:40 +00:00
Dan Ribbens
93545f3103 fix(db-postgres, db-sqlite)!: bump drizzle-kit drizzle-orm @libsql/client (#8617)
Inheriting all the fixes from drizzle moving to latest versions

## BREAKING CHANGES
If you have a prior version of @libsql/client installed in your project,
you must upgrade to 0.14.0
2024-10-15 20:20:50 +00:00
Patrik
8d10737b2f fix(ui): removes overflow: hidden style from actions wrapper (#8717)
`Before`:
![Screenshot 2024-10-15 at 2 55
22 PM](https://github.com/user-attachments/assets/39b261c4-bb72-4497-ab47-01d430255773)

`After`:
![Screenshot 2024-10-15 at 2 55
07 PM](https://github.com/user-attachments/assets/8913479a-9e0b-4edf-baa1-130dc179af34)
2024-10-15 15:58:36 -04:00
Paul
303a224072 fix(templates): website template issue with previewing drafts (#8714)
Fixes https://github.com/payloadcms/payload/issues/8708
2024-10-15 15:10:34 +00:00
Elliot DeNolf
2315719c28 chore(deps): bump turbo 2024-10-15 09:58:28 -04:00
724 changed files with 88294 additions and 4125 deletions

View File

@@ -0,0 +1,76 @@
name: Functionality Bug
description: '[REPRODUCTION REQUIRED] - Create a bug report'
labels: ['status: needs-triage', 'v3', 'validate-reproduction']
body:
- type: textarea
attributes:
label: Describe the Bug
validations:
required: true
- type: input
id: reproduction-link
attributes:
label: Link to the code that reproduces this issue
description: >-
_REQUIRED_: Please provide a link to your reproduction. Note, if the URL is invalid (404 or a private repository), we may close the issue.
Either use `npx create-payload-app@beta -t blank` then push to a repo or follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
validations:
required: true
- type: textarea
attributes:
label: Reproduction Steps
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required: true
- type: dropdown
attributes:
label: Which area(s) are affected? (Select all that apply)
multiple: true
options:
- 'Not sure'
- 'area: core'
- 'area: docs'
- 'area: templates'
- 'area: ui'
- 'db-mongodb'
- 'db-postgres'
- 'db-sqlite'
- 'db-vercel-postgres'
- 'plugin: cloud'
- 'plugin: cloud-storage'
- 'plugin: form-builder'
- 'plugin: nested-docs'
- 'plugin: richtext-lexical'
- 'plugin: richtext-slate'
- 'plugin: search'
- 'plugin: sentry'
- 'plugin: seo'
- 'plugin: stripe'
- 'plugin: other'
validations:
required: true
- type: textarea
attributes:
label: Environment Info
description: Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
render: text
placeholder: |
Payload:
Node.js:
Next.js:
validations:
required: true
- type: markdown
attributes:
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: markdown
attributes:
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!

View File

@@ -0,0 +1,40 @@
name: Design Issue
description: '[SCREENSHOT REQUIRED] - Create a design issue report'
labels: ['status: needs-triage', 'v3', 'area: ui']
body:
- type: textarea
attributes:
label: Describe the Bug.
description: >-
_REQUIRED:_ Please a screenshot/video of the issue along with a detailed description of the problem.
validations:
required: true
- type: textarea
attributes:
label: Reproduction Steps
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
validations:
required: true
- type: textarea
attributes:
label: Environment Info
description: Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
render: text
placeholder: |
Payload:
Node.js:
Next.js:
validations:
required: true
- type: markdown
attributes:
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
- type: markdown
attributes:
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
- type: markdown
attributes:
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!

View File

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

View File

@@ -1,23 +1,23 @@
## Description
<!--
<!-- Please include a summary of the pull request and any related issues it fixes. Please also include relevant motivation and context. -->
Thank you for the PR! Please go through the checklist below and make sure you've completed all the steps.
- [ ] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
Please review the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository if you haven't already.
## Type of change
The following items will ensure that your PR is handled as smoothly as possible:
<!-- Please delete options that are not relevant. -->
- PR Title must follow conventional commits format. For example, `feat: my new feature`, `fix(plugin-seo): my fix`.
- Minimal description explained as if explained to someone not immediately familiar with the code.
- Provide before/after screenshots or code diffs if applicable.
- Link any related issues/discussions from GitHub or Discord.
- Add review comments if necessary to explain to the reviewer the logic behind a change
- [ ] Chore (non-breaking change which does not add functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Change to the [templates](https://github.com/payloadcms/payload/tree/main/templates) directory (does not affect core functionality)
- [ ] Change to the [examples](https://github.com/payloadcms/payload/tree/main/examples) directory (does not affect core functionality)
- [ ] This change requires a documentation update
### What?
## Checklist:
### Why?
- [ ] I have added tests that prove my fix is effective or that my feature works
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
### How?
Fixes #
-->

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

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

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

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

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

@@ -0,0 +1,40 @@
name: Triage
description: Initial triage for issues
inputs:
reproduction-comment:
description: 'Either a string or a path to a .md file inside the repository. Example: ".github/invalid-reproduction.md"'
default: '.github/invalid-reproduction.md'
reproduction-hosts:
description: 'Comma-separated list of hostnames that are allowed for reproductions. Example: "github.com,codesandbox.io"'
default: github.com
reproduction-invalid-label:
description: 'Label to apply to issues without a valid reproduction. Example: "invalid-reproduction"'
default: 'invalid-reproduction'
reproduction-issue-labels:
description: 'Comma-separated list of issue labels. If configured, only verify reproduction URLs of issues with one of these labels present. Adding a comma at the end will handle non-labeled issues as invalid. Example: "bug,", will consider issues with the label "bug" or no label.'
default: ''
reproduction-link-section:
description: 'A regular expression string with "(.*)" matching a valid URL in the issue body. The result is trimmed. Example: "### Link to reproduction(.*)### To reproduce"'
default: '### Link to reproduction(.*)### To reproduce'
actions-to-perform:
description: 'Comma-separated list of actions to perform on the issue. Example: "tag,comment,close"'
default: 'tag,comment,close'
runs:
using: 'composite'
steps:
- name: Checkout code
if: ${{ github.event_name != 'pull_request' }}
uses: actions/checkout@v4
- name: Run action
run: node ${{ github.action_path }}/dist/index.js
shell: sh
# https://github.com/actions/runner/issues/665#issuecomment-676581170
env:
'INPUT_REPRODUCTION_COMMENT': ${{inputs.reproduction-comment}}
'INPUT_REPRODUCTION_HOSTS': ${{inputs.reproduction-hosts}}
'INPUT_REPRODUCTION_INVALID_LABEL': ${{inputs.reproduction-invalid-label}}
'INPUT_REPRODUCTION_ISSUE_LABELS': ${{inputs.reproduction-issue-labels}}
'INPUT_REPRODUCTION_LINK_SECTION': ${{inputs.reproduction-link-section}}
'INPUT_ACTIONS_TO_PERFORM': ${{inputs.actions-to-perform}}

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

File diff suppressed because one or more lines are too long

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

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

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

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

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

File diff suppressed because it is too large Load Diff

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

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

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

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

View File

@@ -0,0 +1,20 @@
**Please add a reproduction in order for us to be able to investigate.**
Depending on the quality of reproduction steps, this issue may be closed if no reproduction is provided.
### Why was this issue marked with the `invalid-reproduction` label?
To be able to investigate, we need access to a reproduction to identify what triggered the issue. We prefer a link to a public GitHub repository created with `create-payload-app@beta -t blank` or a forked/branched version of this repository with tests added (more info in the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md)).
To make sure the issue is resolved as quickly as possible, please make sure that the reproduction is as **minimal** as possible. This means that you should **remove unnecessary code, files, and dependencies** that do not contribute to the issue. Ensure your reproduction does not depend on secrets, 3rd party registries, private dependencies, or any other data that cannot be made public. Avoid a reproduction including a whole monorepo (unless relevant to the issue). The easier it is to reproduce the issue, the quicker we can help.
Please test your reproduction against the latest version of Payload to make sure your issue has not already been fixed.
### I added a link, why was it still marked?
Ensure the link is pointing to a codebase that is accessible (e.g. not a private repository). "[example.com](http://example.com/)", "n/a", "will add later", etc. are not acceptable links -- we need to see a public codebase. See the above section for accepted links.
### Useful Resources
- [Reproduction Guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md)
- [Contributing to Payload](https://www.youtube.com/watch?v=08Qa3ggR9rw)

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

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

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

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

View File

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

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

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

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

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

View File

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

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

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

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

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

View File

@@ -122,3 +122,19 @@ This is how you can preview changes you made locally to the docs:
4. Add a `DOCS_DIR` environment variable to the `.env` file which points to the absolute path of your modified docs folder. For example `DOCS_DIR=/Users/yourname/Documents/GitHub/payload/docs`
5. Run `yarn run fetchDocs:local`. If this was successful, you should see no error messages and the following output: _Docs successfully written to /.../website/src/app/docs.json_. There could be error messages if you have incorrect markdown in your local docs folder. In this case, it will tell you how you can fix it
6. You're done! Now you can start the website locally using `yarn run dev` and preview the docs under [http://localhost:3000/docs/](http://localhost:3000/docs/)
## Internationalization (i18n)
If your PR adds a string to the UI, we need to make sure to translate it into all the languages that Payload supports. To do that:
- Find the appropriate internationalization file for your package. These are typically located in `packages/translations/src/languages`, although some packages (e.g., richtext-lexical) have separate i18n files for each feature.
- Add the string to the English locale "en".
- Translate it to other languages. You can use the `translateNewKeys` script if you have an OpenAI API key in your `.env` (under `OPENAI_KEY`), or you can use ChatGPT or Google translate - whatever is easier for you. For payload core translations (in packages/translations) you can run the `translateNewKeys` script using `cd packages/translations && pnpm translateNewKeys`. For lexical translations, you can run it using `cd packages/richtext-lexical && pnpm translateNewKeys`. External contributors can skip this step and leave it to us.
To display translation strings in the UI, make sure to use the `t` utility of the `useTranslation` hook:
```ts
const { t } = useTranslation()
// ...
t('yourStringKey')
```

View File

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

View File

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

View File

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

View File

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

View File

@@ -11,7 +11,7 @@ The behavior of [Collections](../configuration/collections) within the [Admin Pa
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
@@ -89,7 +89,7 @@ It is possible to display a Preview Button within the Edit View of the Admin Pan
To configure the Preview Button, set the `admin.preview` property to a function in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
@@ -126,7 +126,7 @@ All Collections receive their own List View which displays a paginated list of d
To configure pagination options, use the `admin.pagination` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
@@ -155,7 +155,7 @@ In the List View, there is a "search" box that allows you to quickly find a docu
To define which fields should be searched, use the `admin.listSearchableFields` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...

View File

@@ -8,7 +8,7 @@ keywords: admin, components, custom, documentation, Content Management System, c
The Payload [Admin Panel](./overview) is designed to be as minimal and straightforward as possible to allow for both easy customization and full control over the UI. In order for Payload to support this level of customization, Payload provides a pattern for you to supply your own React components through your [Payload Config](../configuration/overview).
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api/overview) directly on the front-end. Custom Components are available for nearly every part of the Admin Panel for extreme granularity and control.
<Banner type="success">
<strong>Note:</strong>
@@ -145,7 +145,7 @@ Instead, we utilize component paths to reference React Components. This method e
When constructing the `ClientConfig`, Payload uses the component paths as keys to fetch the corresponding React Component imports from the Import Map. It then substitutes the `PayloadComponent` with a `MappedComponent`. A `MappedComponent` includes the React Component and additional metadata, such as whether it's a server or a client component and which props it should receive. These components are then rendered through the `<RenderComponent />` component within the Payload Admin Panel.
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](/docs/beta/local-api/outside-nextjs#troubleshooting) section.
Import maps are regenerated whenever you modify any element related to component paths. This regeneration occurs at startup and whenever Hot Module Replacement (HMR) runs. If the import maps fail to regenerate during HMR, you can restart your application and execute the `payload generate:importmap` command to manually create a new import map. If you encounter any errors running this command, see the [Troubleshooting](../local-api/outside-nextjs#troubleshooting) section.
### Component paths in external packages
@@ -329,7 +329,7 @@ export const useMyCustomContext = () => useContext(MyCustomContext)
## Building Custom Components
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api) directly on the front-end, among other things.
All Custom Components in Payload are [React Server Components](https://react.dev/reference/rsc/server-components) by default, with the exception of [Custom Providers](#custom-providers). This enables the use of the [Local API](../local-api/overview) directly on the front-end, among other things.
To make building Custom Components as easy as possible, Payload automatically provides common props, such as the [`payload`](../local-api/overview) class and the [`i18n`](../configuration/i18n) object. This means that when building Custom Components within the Admin Panel, you do not have to get these yourself.

View File

@@ -217,6 +217,7 @@ Client Component:
'use client'
import React from 'react'
import type { TextFieldClientComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
export const MyTextField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />

View File

@@ -760,7 +760,7 @@ const LinkFromCategoryToPosts: React.FC = () => {
## useLocale
In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale`gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example:
In any Custom Component you can get the selected locale object with the `useLocale` hook. `useLocale` gives you the full locale object, consisting of a `label`, `rtl`(right-to-left) property, and then `code`. Here is a simple example:
```tsx
'use client'

View File

@@ -2,7 +2,7 @@
title: Document Locking
label: Document Locking
order: 90
desc: Ensure your documents are locked while being edited, preventing concurrent edits from multiple users and preserving data integrity.
desc: Ensure your documents are locked during editing to prevent concurrent changes from multiple users and maintain data integrity.
keywords: locking, document locking, edit locking, document, concurrency, Payload, headless, Content Management System, cms, javascript, react, node, nextjs
---
@@ -12,24 +12,24 @@ The lock is automatically triggered when a user begins editing a document within
## How it works
When a user starts editing a document, Payload locks the document for that user. If another user tries to access the same document, they will be notified that it is currently being edited and can choose one of the following options:
When a user starts editing a document, Payload locks it for that user. If another user attempts to access the same document, they will be notified that it is currently being edited. They can then choose one of the following options:
- View in Read-Only Mode: View the document without making any changes.
- Take Over Editing: Take over editing from the current user, which locks the document for the new editor and notifies the original user.
- View in Read-Only: View the document without the ability to make any changes.
- Take Over: Take over editing from the current user, which locks the document for the new editor and notifies the original user.
- Return to Dashboard: Navigate away from the locked document and continue with other tasks.
The lock will automatically expire after a set period of inactivity, configurable using the duration property in the lockDocuments configuration, after which others can resume editing.
The lock will automatically expire after a set period of inactivity, configurable using the `duration` property in the `lockDocuments` configuration, after which others can resume editing.
<Banner type="info"> <strong>Note:</strong> If your application does not require document locking, you can disable this feature for any collection by setting the <code>lockDocuments</code> property to <code>false</code>. </Banner>
<Banner type="info"> <strong>Note:</strong> If your application does not require document locking, you can disable this feature for any collection or global by setting the <code>lockDocuments</code> property to <code>false</code>. </Banner>
### Config Options
The lockDocuments property exists on both the Collection Config and the Global Config. By default, document locking is enabled for all collections and globals, but you can customize the lock duration or disable the feature entirely.
The `lockDocuments` property exists on both the Collection Config and the Global Config. Document locking is enabled by default, but you can customize the lock duration or turn off the feature for any collection or global.
Heres an example configuration for document locking:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
@@ -55,13 +55,13 @@ export const Posts: CollectionConfig = {
### Impact on APIs
Document locking affects both the Local API and the REST API, ensuring that if a document is locked, concurrent users will not be able to perform updates or deletes on that document (including globals). If a user attempts to update or delete a locked document, they will receive an error.
Document locking affects both the Local and REST APIs, ensuring that if a document is locked, concurrent users will not be able to perform updates or deletes on that document (including globals). If a user attempts to update or delete a locked document, they will receive an error.
Once the document is unlocked or the lock duration has expired, other users can proceed with updates or deletes as normal.
#### Overriding Locks
For operations like update and delete, Payload includes an `overrideLock` option. This boolean flag, when set to `false`, enforces document locks, ensuring that the operation will not proceed if another user currently holds the lock.
For operations like `update` and `delete`, Payload includes an `overrideLock` option. This boolean flag, when set to `false`, enforces document locks, ensuring that the operation will not proceed if another user currently holds the lock.
By default, `overrideLock` is set to `true`, which means that document locks are ignored, and the operation will proceed even if the document is locked. To enforce locks and prevent updates or deletes on locked documents, set `overrideLock: false`.

View File

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

View File

@@ -93,7 +93,7 @@ For more granular control, pass a configuration object instead. Payload exposes
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| **`sensitive`** | When true, will match if the path is case sensitive.
| **`sensitive`** | When true, will match if the path is case sensitive.|
| **`meta`** | Page metadata overrides to apply to this view within the Admin Panel. [More details](./metadata). |
_\* An asterisk denotes that a property is required._
@@ -133,6 +133,12 @@ The above example shows how to add a new [Root View](#root-views), but the patte
route.
</Banner>
<Banner type="warning">
<strong>Custom views are public</strong>
<br />
Custom views are public by default. If your view requires a user to be logged in or to have certain access rights, you should handle that within your view component yourself.
</Banner>
## Collection Views
Collection Views are views that are scoped under the `/collections` route, such as the Collection List and Document Edit views.

View File

@@ -97,7 +97,7 @@ Cookies can cross subdomains without being considered third party cookies, for e
##### 2. Configure cookies
If option 1 isn't possible, then you can get around this limitation by [configuring your cookies](https://payloadcms.com/docs/beta/authentication/overview#config-options) on your authentication collection to achieve the following setup:
If option 1 isn't possible, then you can get around this limitation by [configuring your cookies](./overview#config-options) on your authentication collection to achieve the following setup:
```
SameSite: None // allows the cookie to cross domains
@@ -122,7 +122,7 @@ Configuration example:
},
```
If you're configuring [cors](https://payloadcms.com/docs/beta/production/preventing-abuse#cross-origin-resource-sharing-cors) in your Payload config, you won't be able to use a wildcard anymore, you'll need to specify the list of allowed domains.
If you're configuring [cors](../production/preventing-abuse#cross-origin-resource-sharing-cors) in your Payload config, you won't be able to use a wildcard anymore, you'll need to specify the list of allowed domains.
<Banner type="success">

View File

@@ -38,7 +38,7 @@ At its core a strategy simply takes information from the incoming request and re
Your `authenticate` method should return an object containing a Payload user document and any optional headers that you'd like Payload to set for you when we return a response.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
slug: 'users',

View File

@@ -15,7 +15,7 @@ Email Verification forces users to prove they have access to the email address t
To enable Email Verification, use the `auth.verify` property on your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -42,7 +42,7 @@ The following options are available:
Function that accepts one argument, containing `{ req, token, user }`, that allows for overriding the HTML within emails that are sent to users indicating how to validate their account. The function should return a string that supports HTML, which can optionally be a full HTML email.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -74,7 +74,7 @@ export const Customers: CollectionConfig = {
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -95,7 +95,7 @@ export const Customers: CollectionConfig = {
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -119,7 +119,7 @@ The following options are available:
This function allows for overriding the HTML within emails that are sent to users attempting to reset their password. The function should return a string that supports HTML, which can be a full HTML email.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
@@ -179,7 +179,7 @@ The following arguments are passed to the `generateEmailHTML` function:
Similarly to the above `generateEmailHTML`, you can also customize the subject of the email. The function argument are the same but you can only return a string - not HTML.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...

View File

@@ -25,7 +25,7 @@ When Authentication is enabled on a [Collection](../configuration/collections),
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collection#auth):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
// ...
@@ -48,7 +48,7 @@ Any [Collection](../configuration/collections) can opt-in to supporting Authenti
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Admins: CollectionConfig = {
// ...
@@ -86,7 +86,7 @@ The following options are available:
| **`loginWithUsername`** | Ability to allow users to login with username/password. [More](/docs/authentication/overview#login-with-username) |
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
| **`removeTokenFromResponses`** | Set to true if you want to remove the token from the returned authentication API responses such as login or refresh. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`strategies`** | Advanced - an array of custom authentication strategies to extend this collection's authentication with. [More details](./custom-strategies). |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More details](./api-keys). |
| **`verify`** | Set to `true` or pass an object with verification options to require users to verify by email before they are allowed to log into your app. [More details](./email#email-verification). |

View File

@@ -6,7 +6,7 @@ desc: Storing data for read on the request object.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appeneded to the request for you.
During the lifecycle of a request you will be able to access the data you have configured to be stored in the JWT by accessing `req.user`. The user object is automatically appended to the request for you.
### Definining Token Data

View File

@@ -84,7 +84,7 @@ export default buildConfig({
## Email
Powered by [Resend](https://resend.com), Payload Cloud comes with integrated email support out of the box. No configuration is needed, and you can use `payload.sendEmail()` to send email right from your Payload app. To learn more about sending email with Payload, checkout the [Email Configuration](https://payloadcms.com/docs/email/overview) overview.
Powered by [Resend](https://resend.com), Payload Cloud comes with integrated email support out of the box. No configuration is needed, and you can use `payload.sendEmail()` to send email right from your Payload app. To learn more about sending email with Payload, checkout the [Email Configuration](../email/overview) overview.
If you are on the Pro or Enterprise plan, you can add your own custom Email domain name. From the Email page of your projects Settings, add the domain you wish to use for email delivery. This will generate a set of DNS records. Add these records to your DNS provider and click verify to check that your records are resolving properly. Once verified, your emails will now be sent from your custom domain name.
@@ -98,14 +98,14 @@ From there, you are ready to make updates to your project. When you are ready to
Projects generated from a template will come pre-configured with the official Cloud Plugin, but if you are using your own repository you will need to add this into your project. To do so, add the plugin to your Payload Config:
`yarn add @payloadcms/plugin-cloud`
`yarn add @payloadcms/payload-cloud`
```js
import { payloadCloud } from '@payloadcms/plugin-cloud'
import { payloadCloudPlugin } from '@payloadcms/payload-cloud'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [payloadCloud()],
plugins: [payloadCloudPlugin()],
// rest of config
})
```
@@ -115,6 +115,11 @@ export default buildConfig({
over Payload Cloud's email service.
</Banner>
<Banner type="info">
Good to know: the Payload Cloud Plugin was previously named `@payloadcms/plugin-cloud`. If you are
using this plugin, you should update to the new package name.
</Banner>
#### **Optional configuration**
If you wish to opt-out of any Payload cloud features, the plugin also accepts options to do so.

View File

@@ -37,7 +37,7 @@ It's often best practice to write your Collections in separate files and then im
Here is what a simple Collection Config might look like:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
@@ -57,26 +57,27 @@ export const Posts: CollectionConfig = {
The following options are available:
| Option | Description |
|------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. |
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/collections). |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. [More details](../authentication/overview). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`disableDuplicate`** | When true, do not show the "Duplicate" button while editing documents within this Collection and prevent `duplicate` from all APIs. |
| **`defaultSort`** | Pass a top-level field to sort by default in the Collection List View. Prefix the name of the field with a minus symbol ("-") to sort in descending order. Multiple fields can be specified by using a string array. |
| **`dbName`** | Custom table or Collection name depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`endpoints`** | Add custom routes to the REST API. Set to `false` to disable routes. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [More details](../fields/overview). |
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#collection-hooks). |
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. |
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](../upload/overview) documentation. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#collection-config). |
| **`defaultPopulate`** | Specify which fields to select when this Collection is populated from another document. [More Details](../queries/select#defaultpopulate-collection-config-property). |
_\* An asterisk denotes that a property is required._

View File

@@ -117,7 +117,7 @@ While Payload's built-in features come fully translated, you may also want to tr
To do this, provide the translations wherever applicable, keyed to the language code:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Articles: CollectionConfig = {
slug: 'articles',

View File

@@ -163,7 +163,7 @@ In development mode, if the configuration file is not found at the root, Payload
**Production Mode**
In production mode, Payload will first attempt to find the config file in the `outDir` of your `tsconfig.json`, and if not found, will fallback to the `rootDor` directory:
In production mode, Payload will first attempt to find the config file in the `outDir` of your `tsconfig.json`, and if not found, will fallback to the `rootDir` directory:
```json
{
@@ -216,7 +216,7 @@ Cross-origin resource sharing (CORS) can be configured with either a whitelist a
Here's an example showing how to allow incoming requests from any domain:
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
// ...
@@ -227,7 +227,7 @@ export default buildConfig({
Here's an example showing how to append a new header (`x-custom-header`) in `Access-Control-Allow-Headers`:
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
// ...

View File

@@ -157,7 +157,7 @@ You can disable this setting and solely use migrations to manage your local deve
For this reason, we suggest that you leave `push` as its default setting and treat your local dev database as a sandbox.
For more information about push mode and prototyping in development, [click here](/docs/beta/database/postgres#prototyping-in-dev-mode).
For more information about push mode and prototyping in development, [click here](./postgres#prototyping-in-dev-mode).
The typical workflow in Payload is to build out your Payload configs, install plugins, and make progress in development mode - allowing Drizzle to push your changes to your local database for you. Once you're finished, you can create a migration.

View File

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

View File

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

View File

@@ -126,6 +126,6 @@ await payload.update({
where: {
slug: { equals: 'my-slug' }
},
req: { disableTransaction: true },
disableTransaction: true,
})
```

View File

@@ -24,7 +24,7 @@ Arrays are useful for many different types of content from simple to complex, su
To create an Array Field, set the `type` to `array` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyArrayField: Field = {
// ...
@@ -69,7 +69,7 @@ _\* An asterisk denotes that a property is required._
To customize the appearance and behavior of the Array Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyArrayField: Field = {
// ...
@@ -92,7 +92,7 @@ The Array Field inherits all of the default options from the base [Field Admin C
In this example, we have an Array Field called `slider` that contains a set of fields for a simple image slider. Each row in the array has a `title`, `image`, and `caption`. We also customize the row label to display the title if it exists, or a default label if it doesn't.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,8 +6,10 @@ desc: The Join field provides the ability to work on related documents. Learn ho
keywords: join, relationship, junction, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can edit and view collections
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is stored on the collection with a Join
The Join Field is used to make Relationship and Upload fields available in the opposite direction. With a Join you can
edit and view collections
having reference to a specific collection document. The field itself acts as a virtual field, in that no new data is
stored on the collection with a Join
field. Instead, the Admin UI surfaces the related documents for a better editing experience and is surfaced by Payload's
APIs.
@@ -19,10 +21,10 @@ The Join field is useful in scenarios including:
- Displaying where a document or upload is used in other documents
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/join.png"
srcDark="https://payloadcms.com/images/docs/fields/join-dark.png"
alt="Shows Join field in the Payload Admin Panel"
caption="Admin Panel screenshot of Join field"
srcLight="https://payloadcms.com/images/docs/fields/join.png"
srcDark="https://payloadcms.com/images/docs/fields/join-dark.png"
alt="Shows Join field in the Payload Admin Panel"
caption="Admin Panel screenshot of Join field"
/>
For the Join field to work, you must have an existing [relationship](./relationship) or [upload](./upload) field in the
@@ -30,7 +32,7 @@ collection you are joining. This will reference the collection and path of the f
To add a Relationship Field, set the `type` to `join` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyJoinField: Field = {
// highlight-start
@@ -111,29 +113,42 @@ related docs from a new pseudo-junction collection called `categories_posts`. No
third junction collection, and can be surfaced on both Posts and Categories. But, importantly, you could add
additional "context" fields to this shared junction collection.
For example, on this `categories_posts` collection, in addition to having the `category` and `post` fields, we could add custom "context" fields like `featured` or `spotlight`,
For example, on this `categories_posts` collection, in addition to having the `category` and `post` fields, we could add
custom "context" fields like `featured` or `spotlight`,
which would allow you to store additional information directly on relationships.
The `join` field gives you complete control over any type of relational architecture in Payload, all wrapped up in a powerful Admin UI.
The `join` field gives you complete control over any type of relational architecture in Payload, all wrapped up in a
powerful Admin UI.
## Config Options
| Option | Description |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| Option | Description |
|------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The name of the relationship or upload field that relates to the collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`where`** \* | A `Where` query to hide related documents from appearing. Will be merged with any `where` specified in the request. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth). |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`defaultLimit`** | The number of documents to return. Set to 0 to return all related documents. |
| **`defaultSort`** | The field name used to specify the order the joined documents are returned. |
| **`admin`** | Admin-specific configuration. [More details](#admin-config-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema. |
_\* An asterisk denotes that a property is required._
## Admin Config Options
You can control the user experience of the join field using the `admin` config properties. The following options are supported:
| Option | Description |
|------------------------|----------------------------------------------------------------------------------------|
| **`allowCreate`** | Set to `false` to remove the controls for making new related documents from this field. |
| **`components.Label`** | Override the default Label of the Field Component. [More details](#the-label-component). |
## Join Field Data
When a document is returned that for a Join field is populated with related documents. The structure returned is an
@@ -150,12 +165,12 @@ object with:
{
"id": "66e3431a3f23e684075aaeb9",
// other fields...
"category": "66e3431a3f23e684075aae9c",
},
"category": "66e3431a3f23e684075aae9c"
}
// { ... }
],
"hasNextPage": false
},
}
// other fields...
}
```
@@ -168,11 +183,11 @@ returning. This is useful for performance reasons when you don't need the relate
The following query options are supported:
| Property | Description |
|-------------|--------------------------------------------------------------|
| **`limit`** | The maximum related documents to be returned, default is 10. |
| **`where`** | An optional `Where` query to filter joined documents. |
| **`sort`** | A string used to order related results |
| Property | Description |
|-------------|-----------------------------------------------------------------------------------------------------|
| **`limit`** | The maximum related documents to be returned, default is 10. |
| **`where`** | An optional `Where` query to filter joined documents. Will be merged with the field `where` object. |
| **`sort`** | A string used to order related results |
These can be applied to the local API, GraphQL, and REST API.
@@ -213,7 +228,8 @@ You can specify as many `joins` parameters as needed for the same or different j
### GraphQL
The GraphQL API supports the same query options as the local and REST APIs. You can specify the query options for each join field in your query.
The GraphQL API supports the same query options as the local and REST APIs. You can specify the query options for each
join field in your query.
Example:
@@ -226,9 +242,9 @@ query {
limit: 5
where: {
author: {
equals: "66e3431a3f23e684075aaeb9"
}
equals: "66e3431a3f23e684075aaeb9"
}
}
) {
docs {
title

View File

@@ -19,7 +19,7 @@ The JSON Field saves actual JSON in the database, which differs from the Code fi
To add a JSON Field, set the `type` to `json` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyJSONField: Field = {
// ...
@@ -56,7 +56,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the JSON Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyJSONField: Field = {
// ...
@@ -77,7 +77,7 @@ The JSON Field inherits all of the default options from the base [Field Admin Co
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -102,7 +102,7 @@ If you only provide a URL to a schema, Payload will fetch the desired schema if
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -135,7 +135,7 @@ export const ExampleCollection: CollectionConfig = {
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

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

View File

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

View File

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

View File

@@ -24,7 +24,7 @@ The Relationship field is used in a variety of ways, including:
To add a Relationship Field, set the `type` to `relationship` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRelationshipField: Field = {
// ...
@@ -74,7 +74,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Relationship Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRelationshipField: Field = {
// ...
@@ -159,7 +159,7 @@ called with an argument object with the following properties:
## Example
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -25,11 +25,7 @@ Right now, Payload is officially supporting two rich text editors:
<Banner type="success">
<strong>
Consistent with Payload's goal of making you learn as little of Payload as possible, customizing
and using the Rich Text Editor does not involve learning how to develop for a
{' '}
<em>Payload</em>
{' '}
rich text editor.
and using the Rich Text Editor does not involve learning how to develop for a{' '}<em>Payload</em>{' '}rich text editor.
</strong>
Instead, you can invest your time and effort into learning the underlying open-source tools that
@@ -63,7 +59,7 @@ _\* An asterisk denotes that a property is required._
The customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyRichTextField: Field = {
// ...

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,7 @@ With the UI Field, you can:
To add a UI Field, set the `type` to `ui` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyUIField: Field = {
// ...
@@ -44,7 +44,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -25,7 +25,7 @@ caption="Admin Panel screenshot of an Upload field"
To create an Upload Field, set the `type` to `upload` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
import type { Field } from 'payload'
export const MyUploadField: Field = {
// ...
@@ -46,8 +46,11 @@ 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> |
| **`relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
| **`hasMany`** | Boolean which, if set to true, allows this field to have many relations instead of only one. |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. Used with hasMany. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. Used with hasMany. |
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](../queries/depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
@@ -73,7 +76,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -54,12 +54,12 @@ To install a Database Adapter, you can run **one** of the following commands:
- To install the [MongoDB Adapter](../database/mongodb), run:
```bash
pnpm i @payloadcms/db-mongodb
pnpm i @payloadcms/db-mongodb@beta
```
- To install the [Postgres Adapter](../database/postgres), run:
```bash
pnpm i @payloadcms/db-postgres
pnpm i @payloadcms/db-postgres@beta
```
<Banner type="success">

View File

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

View File

@@ -139,4 +139,4 @@ declare module 'payload' {
}
```
This will add a the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.
This will add the property `myObject` with a type of string to every context object. Make sure to follow this example correctly, as type augmentation can mess up your types if you do it wrong.

View File

@@ -0,0 +1,463 @@
---
title: Jobs Queue
label: Overview
order: 10
desc: Payload provides all you need to run job queues, which are helpful to offload long-running processes into separate workers.
keywords: jobs queue, application framework, typescript, node, react, nextjs
---
Payload's Jobs Queue gives you a simple, yet powerful way to offload large or future tasks to separate compute resources.
For example, when building applications with Payload, you might run into a case where you need to perform some complex logic in a Payload [Hook](/docs/hooks/overview) but you don't want that hook to "block" or slow down the response returned from the Payload API.
Instead of running long or expensive logic in a Hook, you can instead create a Job and add it to a Queue. It can then be picked up by a separate worker which periodically checks the queue for new jobs, and then executes each job accordingly. This way, your Payload API responses can remain as fast as possible, and you can still perform logic as necessary without blocking or affecting your users' experience.
Jobs are also handy for delegating certain actions to take place in the future, such as scheduling a post to be published at a later date. In this example, you could create a Job that will automatically publish a post at a certain time.
#### How it works
There are a few concepts that you should become familiarized with before using Payload's Jobs Queue - [Tasks](#tasks), [Workflows](#workflows), [Jobs](#jobs), and finally [Queues](#queues).
## Tasks
<Banner type="default">
A <strong>"Task"<strong> is a function definition that performs business logic and whose input and output are both strongly typed.
</Banner>
You can register Tasks on the Payload config, and then create Jobs or Workflows that use them. Think of Tasks like tidy, isolated "functions that do one specific thing".
Payload Tasks can be configured to automatically retried if they fail, which makes them valuable for "durable" workflows like AI applications where LLMs can return non-deterministic results, and might need to be retried.
Tasks can either be defined within the `jobs.tasks` array in your payload config, or they can be defined inline within a workflow.
### Defining tasks in the config
Simply add a task to the `jobs.tasks` array in your Payload config. A task consists of the following fields:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |
| `slug` | Define a slug-based name for this job. This slug needs to be unique among both tasks and workflows.|
| `handler` | The function that should be responsible for running the job. You can either pass a string-based path to the job function file, or the job function itself. If you are using large dependencies within your job, you might prefer to pass the string path because that will avoid bundling large dependencies in your Next.js app. |
| `inputSchema` | Define the input field schema - payload will generate a type for this schema. |
| `interfaceName` | You can use interfaceName to change the name of the interface that is generated for this task. By default, this is "Task" + the capitalized task slug. |
| `outputSchema` | Define the output field schema - payload will generate a type for this schema. |
| `label` | Define a human-friendly label for this task. |
| `onFail` | Function to be executed if the task fails. |
| `onSuccess` | Function to be executed if the task fails. |
| `retries` | Specify the number of times that this step should be retried if it fails. |
The logic for the Task is defined in the `handler` - which can be defined as a function, or a path to a function. The `handler` will run once a worker picks picks up a Job that includes this task.
It should return an object with an `output` key, which should contain the output of the task as you've defined.
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
{
// Configure this task to automatically retry
// up to two times
retries: 2,
// This is a unique identifier for the task
slug: 'createPost',
// These are the arguments that your Task will accept
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
// These are the properties that the function should output
outputSchema: [
{
name: 'postID',
type: 'text',
required: true,
},
],
// This is the function that is run when the task is invoked
handler: async ({ input, job, req }) => {
const newPost = await req.payload.create({
collection: 'post',
req,
data: {
title: input.title,
},
})
return {
output: {
postID: newPost.id,
},
}
},
} as TaskConfig<'createPost'>,
]
}
})
```
In addition to defining handlers as functions directly provided to your Payload config, you can also pass an _absolute path_ to where the handler is defined. If your task has large dependencies, and you are planning on executing your jobs in a separate process that has access to the filesystem, this could be a handy way to make sure that your Payload + Next.js app remains quick to compile and has minimal dependencies.
In general, this is an advanced use case. Here's how this would look:
`payload.config.ts:`
```ts
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
export default buildConfig({
jobs: {
tasks: [
{
// ...
// The #createPostHandler is a named export within the `createPost.ts` file
handler: path.resolve(dirname, 'src/tasks/createPost.ts') + '#createPostHandler',
}
]
}
})
```
Then, the `createPost` file itself:
`src/tasks/createPost.ts:`
```ts
import type { TaskHandler } from 'payload'
export const createPostHandler: TaskHandler<'createPost'> = async ({ input, job, req }) => {
const newPost = await req.payload.create({
collection: 'post',
req,
data: {
title: input.title,
},
})
return {
output: {
postID: newPost.id,
},
}
}
```
## Workflows
<Banner type="default">
A <strong>"Workflow"<strong> is an optional way to <em>combine multiple tasks together</em> in a way that can be gracefully retried from the point of failure.
</Banner>
They're most helpful when you have multiple tasks in a row, and you want to configure each task to be able to be retried if they fail.
If a task within a workflow fails, the Workflow will automatically "pick back up" on the task where it failed and **not re-execute any prior tasks that have already been executed**.
#### Defining a workflow
The most important aspect of a Workflow is the `handler`, where you can declare when and how the tasks should run by simply calling the `runTask` function. If any task within the workflow, fails, the entire `handler` function will re-run.
However, importantly, tasks that have successfully been completed will simply re-return the cached and saved output without running again. The Workflow will pick back up where it failed and only task from the failure point onward will be re-executed.
To define a JS-based workflow, simply add a workflow to the `jobs.wokflows` array in your Payload config. A workflow consists of the following fields:
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------- |
| `slug` | Define a slug-based name for this workflow. This slug needs to be unique among both tasks and workflows.|
| `handler` | The function that should be responsible for running the workflow. You can either pass a string-based path to the workflow function file, or workflow job function itself. If you are using large dependencies within your workflow, you might prefer to pass the string path because that will avoid bundling large dependencies in your Next.js app. |
| `inputSchema` | Define the input field schema - payload will generate a type for this schema. |
| `interfaceName` | You can use interfaceName to change the name of the interface that is generated for this workflow. By default, this is "Workflow" + the capitalized workflow slug. |
| `label` | Define a human-friendly label for this workflow. |
| `queue` | Optionally, define the queue name that this workflow should be tied to. Defaults to "default". |
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
// ...
]
workflows: [
{
slug: 'createPostAndUpdate',
// The arguments that the workflow will accept
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
// The handler that defines the "control flow" of the workflow
// Notice how it calls `runTask` to execute tasks
handler: async ({ job, runTask }) => {
// This workflow first runs a task called `createPost`
const output = await runTask({
task: 'createPost',
// You need to define a unique ID for this task invocation
// that will always be the same if this workflow fails
// and is re-executed in the future
id: '1',
input: {
title: job.input.title,
},
})
// Once the prior task completes, it will run a task
// called `updatePost`
await runTask({
task: 'updatePost',
id: '2',
input: {
post: job.taskStatus.createPost['1'].output.postID, // or output.postID
title: job.input.title + '2',
},
})
},
} as WorkflowConfig<'updatePost'>
]
}
})
```
#### Running tasks inline
In the above example, our workflow was executing tasks that we already had defined in our Payload config. But, you can also run tasks without predefining them.
To do this, you can use the `runTaskInline` function.
The drawbacks of this approach are that tasks cannot be re-used across workflows as easily, and the **task data stored in the job** will not be typed. In the following example, the inline task data will be stored on the job under `job.taskStatus.inline['2']` but completely untyped, as types for dynamic tasks like these cannot be generated beforehand.
Example:
```ts
export default buildConfig({
// ...
jobs: {
tasks: [
// ...
]
workflows: [
{
slug: 'createPostAndUpdate',
inputSchema: [
{
name: 'title',
type: 'text',
required: true,
},
],
handler: async ({ job, runTask }) => {
// Here, we run a predefined task.
// The `createPost` handler arguments and return type
// are both strongly typed
const output = await runTask({
task: 'createPost',
id: '1',
input: {
title: job.input.title,
},
})
// Here, this task is not defined in the Payload config
// and is "inline". Its output will be stored on the Job in the database
// however its arguments will be untyped.
const { newPost } = await runTaskInline({
task: async ({ req }) => {
const newPost = await req.payload.update({
collection: 'post',
id: '2',
req,
retries: 3,
data: {
title: 'updated!',
},
})
return {
output: {
newPost
},
}
},
id: '2',
})
},
} as WorkflowConfig<'updatePost'>
]
}
})
```
## Jobs
Now that we have covered Tasks and Workflows, we can tie them together with a concept called a Job.
<Banner type="default">
Whereas you define Workflows and Tasks, which control your business logic, a <strong>Job</strong> is an individual instance of either a Task or a Workflow which contains many tasks.
</Banner>
For example, let's say we have a Workflow or Task that describes the logic to sync information from Payload to a third-party system. This is how you'd declare how to sync that info, but it wouldn't do anything on its own. In order to run that task or workflow, you'd create a Job that references the corresponding Task or Workflow.
Jobs are stored in the Payload database in the `payload-jobs` collection, and you can decide to keep a running list of all jobs, or configure Payload to delete the job when it has been successfully executed.
#### Queuing a new job
In order to queue a job, you can use the `payload.jobs.queue` function.
Here's how you'd queue a new Job, which will run a `createPostAndUpdate` workflow:
```ts
const createdJob = await payload.jobs.queue({
// Pass the name of the workflow
workflow: 'createPostAndUpdate',
// The input type will be automatically typed
// according to the input you've defined for this workflow
input: {
title: 'my title',
},
})
```
In addition to being able to queue new Jobs based on Workflows, you can also queue a job for a single Task:
```ts
const createdJob = await payload.jobs.queue({
task: 'createPost',
input: {
title: 'my title',
},
})
```
## Queues
Now let's talk about how to _run these jobs_. Right now, all we've covered is how to queue up jobs to run, but so far, we aren't actually running any jobs. This is the final piece of the puzzle.
<Banner type="default">
A <strong>Queue</strong> is a list of jobs that should be executed in order of when they were added.
</Banner>
When you go to run jobs, Payload will query for any jobs that are added to the queue and then run them. By default, all queued jobs are added to the `default` queue.
**But, imagine if you wanted to have some jobs that run nightly, and other jobs which should run every five minutes.**
By specifying the `queue` name when you queue a new job using `payload.jobs.queue()`, you can queue certain jobs with `queue: 'nightly'`, and other jobs can be left as the default queue.
Then, you could configure two different runner strategies:
1. A `cron` that runs nightly, querying for jobs added to the `nightly` queue
2. Another that runs any jobs that were added to the `default` queue every ~5 minutes or so
## Executing jobs
As mentioned above, you can queue jobs, but the jobs won't run unless a worker picks up your jobs and runs them. This can be done in two ways:
#### Endpoint
You can execute jobs by making a fetch request to the `/api/payload-jobs/run` endpoint:
```ts
// Here, we're saying we want to run only 100 jobs for this invocation
// and we want to pull jobs from the `nightly` queue:
await fetch('/api/payload-jobs/run?limit=100&queue=nightly', {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`,
},
});
```
This endpoint is automatically mounted for you and is helpful in conjunction with serverless platforms like Vercel, where you might want to use Vercel Cron to invoke a serverless function that executes your jobs.
**Vercel Cron Example**
If you're deploying on Vercel, you can add a `vercel.json` file in the root of your project that configures Vercel Cron to invoke the `run` endpoint on a cron schedule.
Here's an example of what this file will look like:
```json
{
"crons": [
{
"path": "/api/payload-jobs/run",
"schedule": "*/5 * * * *"
}
]
}
```
The configuration above schedules the endpoint `/api/payload-jobs/run` to be invoked every 5 minutes.
The last step will be to secure your `run` endpoint so that only the proper users can invoke the runner.
To do this, you can set an environment variable on your Vercel project called `CRON_SECRET`, which should be a random string—ideally 16 characters or longer.
Then, you can modify the `access` function for running jobs by ensuring that only Vercel can invoke your runner.
```ts
export default buildConfig({
// Other configurations...
jobs: {
access: {
run: ({ req }: { req: PayloadRequest }): boolean => {
// Allow logged in users to execute this endpoint (default)
if (req.user) return true
// If there is no logged in user, then check
// for the Vercel Cron secret to be present as an
// Authorization header:
const authHeader = req.headers.get('authorization');
return authHeader === `Bearer ${process.env.CRON_SECRET}`;
},
},
// Other job configurations...
}
})
```
This works because Vercel automatically makes the `CRON_SECRET` environment variable available to the endpoint as the `Authorization` header when triggered by the Vercel Cron, ensuring that the jobs can be run securely.
After the project is deployed to Vercel, the Vercel Cron job will automatically trigger the `/api/payload-jobs/run` endpoint in the specified schedule, running the queued jobs in the background.
#### Local API
If you want to process jobs programmatically from your server-side code, you can use the Local API:
```ts
const results = await payload.jobs.run()
// You can customize the queue name and limit by passing them as arguments:
await payload.jobs.run({ queue: 'nightly', limit: 100 })
```
#### Bin script
Finally, you can process jobs via the bin script that comes with Payload out of the box.
```sh
npx payload jobs:run --queue default --limit 10
```
In addition, the bin script allows you to pass a `--cron` flag to the `jobs:run` command to run the jobs on a scheduled, cron basis:
```sh
npx payload jobs:run --cron "*/5 * * * *"
```

View File

@@ -52,7 +52,7 @@ const Pages: CollectionConfig = {
}
```
and done! Now, everytime this lexical editor is initialized, it converts the slate date to lexical on-the-fly. If the data is already in lexical format, it will just pass it through.
and done! Now, every time this lexical editor is initialized, it converts the slate date to lexical on-the-fly. If the data is already in lexical format, it will just pass it through.
This is by far the easiest way to migrate from Slate to Lexical, although it does come with a few caveats:

View File

@@ -71,27 +71,29 @@ import config from '@payload-config'
const payload = await getPayload({ config })
```
Both options function in exactly the same way outside of one having HMR support and the other not. For more information about using Payload outside of Next.js, [click here](/docs/beta/local-api/outside-nextjs).
Both options function in exactly the same way outside of one having HMR support and the other not. For more information about using Payload outside of Next.js, [click here](./outside-nextjs).
## Local options available
You can specify more options within the Local API vs. REST or GraphQL due to the server-only context that they are executed in.
| Local Option | Description |
|-----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
| `data` | The data to use within the operation. Required for `create`, `update`. |
| `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. |
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
| `overrideLock` | By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](../admin/locked-documents). |
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
| `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. |
| `disableErrors` | When set to `true`, errors will not be thrown. Instead, the `findByID` operation will return `null`, and the `find` operation will return an empty documents array. |
| `disableTransaction` | When set to `true`, a [database transactions](../database/transactions) will not be initialized. |
| Local Option | Description |
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
| `data` | The data to use within the operation. Required for `create`, `update`. |
| `depth` | [Control auto-population](../queries/depth) of nested relationship and upload fields. |
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
| `select` | Specify [select](../queries/select) to control which fields to include to the result. |
| `populate` | Specify [populate](../queries/select#populate) to control which fields to include to the result from populated documents. |
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
| `overrideLock` | By default, document locks are ignored (`true`). Set to `false` to enforce locks and prevent operations when a document is locked by another user. [More details](../admin/locked-documents). |
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
| `context` | [Context](/docs/hooks/context), which will then be passed to `context` and `req.context`, which can be read by hooks. Useful if you want to pass additional information to the hooks which shouldn't be necessarily part of the document, for example a `triggerBeforeChange` option which can be read by the BeforeChange hook to determine if it should run or not. |
| `disableErrors` | When set to `true`, errors will not be thrown. Instead, the `findByID` operation will return `null`, and the `find` operation will return an empty documents array. |
| `disableTransaction` | When set to `true`, a [database transactions](../database/transactions) will not be initialized. |
_There are more options available on an operation by operation basis outlined below._

View File

@@ -36,7 +36,7 @@ Forms can be as simple or complex as you need, from a basic contact form, to a m
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-form-builder
pnpm add @payloadcms/plugin-form-builder@beta
```
## Basic Usage
@@ -138,7 +138,7 @@ const beforeEmail: BeforeEmail<FormSubmission> = (emailsToSend, beforeChangePara
### `defaultToEmail`
Provide a fallback for the email address to send form submissions to. If the email in form configuration does not have a to email set, this email address will be used. If this is not provided then it falls back to the `defaultFromAddress` in your [email configuration](https://payloadcms.com/docs/beta/email/overview).
Provide a fallback for the email address to send form submissions to. If the email in form configuration does not have a to email set, this email address will be used. If this is not provided then it falls back to the `defaultFromAddress` in your [email configuration](../email/overview).
```ts
// payload.config.ts
@@ -343,12 +343,12 @@ Maps to a `checkbox` input on your front-end. Used to collect a boolean value.
Maps to a `number` input on your front-end. Used to collect a number.
| Property | Type | Description |
| -------------- | -------- | ---------------------------------------------------- | --- | -------------- | ------ | ------------------------------- |
| -------------- | -------- | ---------------------------------------------------- |
| `name` | string | The name of the field. |
| `label` | string | The label of the field. |
| `defaultValue` | string | The default value of the field. |
| `defaultValue` | number | The default value of the field. |
| `width` | string | The width of the field on the front-end. |
| `required` | checkbox | Whether or not the field is required when submitted. | | `defaultValue` | number | The default value of the field. |
| `required` | checkbox | Whether or not the field is required when submitted. |
### Message
@@ -412,11 +412,11 @@ formBuilder({
## Email
This plugin relies on the [email configuration](https://payloadcms.com/docs/beta/email/overview) defined in your payload configuration. It will read from your config and attempt to send your emails using the credentials provided.
This plugin relies on the [email configuration](../email/overview) defined in your payload configuration. It will read from your config and attempt to send your emails using the credentials provided.
### Email formatting
The email contents supports rich text which will be serialised to HTML on the server before being sent. By default it reads the global configuration of your rich text editor.
The email contents supports rich text which will be serialized to HTML on the server before being sent. By default it reads the global configuration of your rich text editor.
The email subject and body supports inserting dynamic fields from the form submission data using the `{{field_name}}` syntax. For example, if you have a field called `name` in your form, you can include this in the email body like so:

View File

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

View File

@@ -32,7 +32,7 @@ For example, if you have a page at `/about` and you want to change it to `/about
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-redirects
pnpm add @payloadcms/plugin-redirects@beta
```
## Basic Usage

View File

@@ -39,7 +39,7 @@ This plugin is a great way to implement a fast, immersive search experience such
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-search
pnpm add @payloadcms/plugin-search@beta
```
## Basic Usage
@@ -81,6 +81,10 @@ export default config
The `collections` property is an array of collection slugs to enable syncing to search. Enabled collections receive a `beforeChange` and `afterDelete` hook that creates, updates, and deletes its respective search record as it changes over time.
### `localize`
By default, the search plugin will add `localization: true` to the `title` field of the newly added `search` collection if you have localization enabled. If you would like to disable this behavior, you can set this to `false`.
#### `defaultPriorities`
This plugin automatically adds a `priority` field to the `search` collection that can be used as the `?sort=` parameter in your queries. For example, you may want to list blog posts before pages. Or you may want one specific post to always take appear first.
@@ -139,7 +143,8 @@ Before creating or updating a search record, the `beforeSync` function runs. Thi
searchPlugin({
beforeSync: ({ originalDoc, searchDoc }) => ({
...searchDoc,
// Modify your docs in any way here, this can be async
// - Modify your docs in any way here, this can be async
// - You also need to add the `excerpt` field in the `searchOverrides` config
excerpt: originalDoc?.excerpt || 'This is a fallback excerpt',
}),
}),

View File

@@ -39,7 +39,7 @@ This multi-faceted software offers a range of features that will help you manage
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-sentry
pnpm add @payloadcms/plugin-sentry@beta
```
## Sentry for Next.js setup

View File

@@ -37,7 +37,7 @@ To help you visualize what your page might look like in a search engine, a previ
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-seo
pnpm add @payloadcms/plugin-seo@beta
```
## Basic Usage
@@ -89,12 +89,23 @@ An array of global slugs to enable SEO. Enabled globals receive a `meta` field w
##### `fields`
An array of fields that allows you to inject your own custom fields onto the `meta` field group. The following fields are provided by default:
A function that takes in the default fields via an object and expects an array of fields in return. You can use this to modify existing fields or add new ones.
- `title`: text
- `description`: textarea
- `image`: upload (if an `uploadsCollection` is provided)
- `preview`: ui
```ts
// payload.config.ts
{
// ...
seoPlugin({
fields: ({ defaultFields }) => [
...defaultFields,
{
name: 'customField',
type: 'text',
}
]
})
}
```
##### `uploadsCollection`
@@ -209,25 +220,6 @@ Rename the meta group interface name that is generated for TypeScript and GraphQ
}
```
#### `fieldOverrides`
Pass any valid field props to the base fields: Title, Description or Image.
```ts
// payload.config.ts
seoPlugin({
// ...
fieldOverrides: {
title: {
required: true,
},
description: {
localized: true,
},
},
})
```
## Direct use of fields
There is the option to directly import any of the fields from the plugin so that you can include them anywhere as needed.
@@ -276,6 +268,10 @@ OverviewField({
})
```
<Banner type="info">
Tip: You can override the length rules by changing the minLength and maxLength props on the fields. In the case of the OverviewField you can use `titleOverrides` and `descriptionOverrides` to override the length rules.
</Banner>
## TypeScript
All types can be directly imported:

View File

@@ -39,7 +39,7 @@ The beauty of this plugin is the entirety of your application's content and busi
Install the plugin using any JavaScript package manager like [Yarn](https://yarnpkg.com), [NPM](https://npmjs.com), or [PNPM](https://pnpm.io):
```bash
pnpm add @payloadcms/plugin-stripe
pnpm add @payloadcms/plugin-stripe@beta
```
## Basic Usage

158
docs/queries/select.mdx Normal file
View File

@@ -0,0 +1,158 @@
---
title: Select
label: Select
order: 30
desc: Payload select determines which fields are selected to the result.
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You may not need the full data from your Local API / REST queries, but only some specific fields. The select fields API can help you to optimize those cases.
## Local API
To specify select in the [Local API](../local-api/overview), you can use the `select` option in your query:
```ts
// Include mode
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
select: {
text: true,
// select a specific field from group
group: {
number: true
},
// select all fields from array
array: true,
}, // highlight-line
})
return posts
}
// Exclude mode
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
// Select everything except for array and group.number
select: {
array: false,
group: {
number: false
}
}, // highlight-line
})
return posts
}
```
<Banner type="warning">
<strong>Important:</strong>
To perform querying with `select` efficiently, it works on the database level. Because of that, your `beforeRead` and `afterRead` hooks may not receive the full `doc`.
</Banner>
## REST API
To specify select in the [REST API](../rest-api/overview), you can use the `select` parameter in your query:
```ts
fetch('https://localhost:3000/api/posts?select[color]=true&select[group][number]=true') // highlight-line
.then((res) => res.json())
.then((data) => console.log(data))
```
To understand the syntax, you need to understand that complex URL search strings are parsed into a JSON object. This one isn't too bad, but more complex queries get unavoidably more difficult to write.
For this reason, we recommend to use the extremely helpful and ubiquitous [`qs`](https://www.npmjs.com/package/qs) package to parse your JSON / object-formatted queries into query strings:
```ts
import { stringify } from 'qs-esm'
const select = {
text: true,
group: {
number: true
}
// This query could be much more complex
// and QS would handle it beautifully
}
const getPosts = async () => {
const stringifiedQuery = stringify(
{
select, // ensure that `qs` adds the `select` property, too!
},
{ addQueryPrefix: true },
)
const response = await fetch(`http://localhost:3000/api/posts${stringifiedQuery}`)
// Continue to handle the response below...
}
```
<Banner type="info">
<strong>Reminder:</strong>
This is the same for [Globals](../configuration/globals) using the `/api/globals` endpoint.
</Banner>
## `defaultPopulate` collection config property
The `defaultPopulate` property allows you specify which fields to select when populating the collection from another document.
This is especially useful for links where only the `slug` is needed instead of the entire document.
```ts
import type { CollectionConfig } from 'payload'
import { lexicalEditor, LinkFeature } from '@payloadcms/richtext-lexical'
import { slateEditor } from '@payloadcms/richtext-slate'
// The TSlug generic can be passed to have type safety for `defaultPopulate`.
// If avoided, the `defaultPopulate` type resolves to `SelectType`.
export const Pages: CollectionConfig<'pages'> = {
slug: 'pages',
// Specify `select`.
defaultPopulate: {
slug: true,
},
fields: [
{
name: 'slug',
type: 'text',
required: true,
},
],
}
```
## `populate`
You can override `defaultPopulate` with the `populate` property in the Local and REST API
Local API:
```ts
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
populate: {
// Select only `text` from populated docs in the "pages" collection
pages: {
text: true,
}, // highlight-line
},
})
return posts
}
```
REST API:
```ts
fetch('https://localhost:3000/api/posts?populate[pages][text]=true') // highlight-line
.then((res) => res.json())
.then((data) => console.log(data))
```

View File

@@ -6,7 +6,7 @@ desc: Payload sort allows you to order your documents by a field in ascending or
keywords: query, documents, pagination, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order.
Documents in Payload can be easily sorted by a specific [Field](../fields/overview). When querying Documents, you can pass the name of any top-level field, and the response will sort the Documents by that field in _ascending_ order. If prefixed with a minus symbol ("-"), they will be sorted in _descending_ order. In Local API multiple fields can be specified by using an array of strings. In REST API multiple fields can be specified by separating fields with comma. The minus symbol can be in front of individual fields.
Because sorting is handled by the database, the field cannot be a [Virtual Field](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges). It must be stored in the database to be searchable.
@@ -30,6 +30,19 @@ const getPosts = async () => {
}
```
To sort by multiple fields, you can use the `sort` option with fields in an array:
```ts
const getPosts = async () => {
const posts = await payload.find({
collection: 'posts',
sort: ['priority', '-createdAt'], // highlight-line
})
return posts
}
```
## REST API
To sort in the [REST API](../rest-api/overview), you can use the `sort` parameter in your query:
@@ -40,6 +53,14 @@ fetch('https://localhost:3000/api/posts?sort=-createdAt') // highlight-line
.then((data) => console.log(data))
```
To sort by multiple fields, you can use the `sort` parameter with fields separated by comma:
```ts
fetch('https://localhost:3000/api/posts?sort=priority,-createdAt') // highlight-line
.then((response) => response.json())
.then((data) => console.log(data))
```
## GraphQL API
To sort in the [GraphQL API](../graphql/overview), you can use the `sort` parameter in your query:

View File

@@ -18,6 +18,8 @@ All Payload API routes are mounted and prefixed to your config's `routes.api` UR
- [depth](../queries/depth) - automatically populates relationships and uploads
- [locale](/docs/configuration/localization#retrieving-localized-docs) - retrieves document(s) in a specific locale
- [fallback-locale](/docs/configuration/localization#retrieving-localized-docs) - specifies a fallback locale if no locale value exists
- [select](../queries/select) - specifies which fields to include to the result
- [populate](../queries/select#populate) - specifies which fields to include to the result from populated documents
## Collections
@@ -591,7 +593,7 @@ Each endpoint object needs to have:
Example:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
// a collection of 'orders' with an additional route for tracking details, reachable at /api/orders/:id/tracking
export const Orders: CollectionConfig = {

View File

@@ -34,7 +34,7 @@ export default buildConfig({
And here's an example for how to install the Slate editor on a field-by-field basis, while customizing its options:
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
import { slateEditor } from '@payloadcms/richtext-slate'
export const Pages: CollectionConfig = {

View File

@@ -43,7 +43,7 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
</Banner>
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
@@ -98,7 +98,7 @@ _An asterisk denotes that an option is required._
| **`displayPreview`** | Enable displaying preview of the uploaded file in Upload fields related to this Collection. Can be locally overridden by `displayPreview` option in Upload field. [More](/docs/fields/upload#config-options). |
| **`externalFileHeaderFilter`** | Accepts existing headers and returns the headers after filtering or modifying. |
| **`filesRequiredOnCreate`** | Mandate file data on creation, default is true. |
| **`filenameCompoundIndex`** | Field slugs to use for a compount index instead of the default filename index.
| **`filenameCompoundIndex`** | Field slugs to use for a compound index instead of the default filename index.
| **`focalPoint`** | Set to `false` to disable the focal point selection tool in the [Admin Panel](../admin/overview). The focal point selector is only available when `imageSizes` or `resizeOptions` are defined. [More](#crop-and-focal-point-selector) |
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
| **`handlers`** | Array of Request handlers to execute when fetching a file, if a handler returns a Response it will be sent to the client. Otherwise Payload will retrieve and send back the file. |
@@ -144,7 +144,7 @@ export default buildConfig({
If you specify an array of `imageSizes` to your `upload` config, Payload will automatically crop and resize your uploads to fit each of the sizes specified by your config.
The [Admin Panel](../admin/overview) will also automatically display all available files, including width, height, and filesize, for each of your uploaded files.
The [Admin Panel](../admin/overview) will also automatically display all available files, including width, height, and file size, for each of your uploaded files.
Behind the scenes, Payload relies on [`sharp`](https://sharp.pixelplumbing.com/api-resize#resize) to perform its image resizing. You can specify additional options for `sharp` to use while resizing your images.
@@ -217,7 +217,7 @@ You can specify how Payload retrieves admin thumbnails for your upload-enabled C
1. `adminThumbnail` as a **string**, equal to one of your provided image size names.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
@@ -246,7 +246,7 @@ export const Media: CollectionConfig = {
2. `adminThumbnail` as a **function** that takes the document's data and sends back a full URL to load the thumbnail.
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',
@@ -267,7 +267,7 @@ Some example values are: `image/*`, `audio/*`, `video/*`, `image/png`, `applicat
**Example mimeTypes usage:**
```ts
import { CollectionConfig } from 'payload'
import type { CollectionConfig } from 'payload'
export const Media: CollectionConfig = {
slug: 'media',

View File

@@ -22,7 +22,7 @@ Payload offers additional storage adapters to handle file uploads. These adapter
### Installation
```sh
pnpm add @payloadcms/storage-vercel-blob
pnpm add @payloadcms/storage-vercel-blob@beta
```
### Usage
@@ -71,12 +71,12 @@ export default buildConfig({
### Installation
```sh
pnpm add @payloadcms/storage-s3
pnpm add @payloadcms/storage-s3@beta
```
### Usage
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the S3 Storage adapter. The slug _must_ match one of your existing collection slugs.
- The `config` object can be any [`S3ClientConfig`](https://docs.aws.amazon.com/AWSJavaScriptSDK/v3/latest/client/s3) object (from [`@aws-sdk/client-s3`](https://github.com/aws/aws-sdk-js-v3)). _This is highly dependent on your AWS setup_. Check the AWS documentation for more information.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
@@ -119,12 +119,12 @@ See the the [AWS SDK Package](https://github.com/aws/aws-sdk-js-v3) and [`S3Clie
### Installation
```sh
pnpm add @payloadcms/storage-azure
pnpm add @payloadcms/storage-azure@beta
```
### Usage
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the Azure Blob adapter. The slug _must_ match one of your existing collection slugs.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
```ts
@@ -168,12 +168,12 @@ export default buildConfig({
### Installation
```sh
pnpm add @payloadcms/storage-gcs
pnpm add @payloadcms/storage-gcs@beta
```
### Usage
- Configure the `collections` object to specify which collections should use the Vercel Blob adapter. The slug _must_ match one of your existing collection slugs.
- Configure the `collections` object to specify which collections should use the Google Cloud Storage adapter. The slug _must_ match one of your existing collection slugs.
- When enabled, this package will automatically set `disableLocalStorage` to `true` for each collection.
```ts
@@ -218,7 +218,7 @@ export default buildConfig({
### Installation
```sh
pnpm add @payloadcms/storage-uploadthing
pnpm add @payloadcms/storage-uploadthing@beta
```
### Usage
@@ -261,7 +261,7 @@ If you need to create a custom storage adapter, you can use the [`@payloadcms/pl
### Installation
`pnpm add @payloadcms/plugin-cloud-storage`
`pnpm add @payloadcms/plugin-cloud-storage@beta`
### Usage
@@ -310,7 +310,7 @@ This plugin is configurable to work across many different Payload collections. A
| Option | Type | Description |
| ---------------- | ----------------------------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| `collections` \* | `Record<string, CollectionOptions>` | Object with keys set to the slug of collections you want to enable the plugin for, and values set to collection-specific options. |
| `enabled` | | `boolean` to conditionally enable/disable plugin. Default: true. |
| `enabled` | `boolean` | To conditionally enable/disable plugin. Default: `true`. |
## Collection-specific options

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,13 +1,13 @@
'use client'
import { RelationshipField, useField } from '@payloadcms/ui'
import { RelationshipField, useField, useFieldProps } from '@payloadcms/ui'
import React from 'react'
type Props = {
initialValue?: string
path: string
readOnly: boolean
}
export function TenantFieldComponentClient({ initialValue, path, readOnly }: Props) {
export function TenantFieldComponentClient({ initialValue, readOnly }: Props) {
const { path } = useFieldProps()
const { formInitializing, setValue, value } = useField({ path })
const hasSetInitialValue = React.useRef(false)

View File

@@ -6,7 +6,6 @@ import React from 'react'
import { TenantFieldComponentClient } from './Field.client'
export const TenantFieldComponent: React.FC<{
path: string
payload: Payload
readOnly: boolean
}> = async (args) => {
@@ -22,7 +21,6 @@ export const TenantFieldComponent: React.FC<{
return (
<TenantFieldComponentClient
initialValue={cookies.get('payload-tenant')?.value || undefined}
path={args.path}
readOnly={args.readOnly}
/>
)

View File

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

View File

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

View File

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

View File

@@ -1,6 +1,6 @@
{
"name": "payload-monorepo",
"version": "3.0.0-beta.114",
"version": "3.0.0-beta.126",
"private": true,
"type": "module",
"scripts": {
@@ -29,7 +29,7 @@
"build:live-preview-vue": "turbo build --filter \"@payloadcms/live-preview-vue\"",
"build:next": "turbo build --filter \"@payloadcms/next\"",
"build:payload": "turbo build --filter payload",
"build:plugin-cloud": "turbo build --filter \"@payloadcms/plugin-cloud\"",
"build:payload-cloud": "turbo build --filter \"@payloadcms/payload-cloud\"",
"build:plugin-cloud-storage": "turbo build --filter \"@payloadcms/plugin-cloud-storage\"",
"build:plugin-form-builder": "turbo build --filter \"@payloadcms/plugin-form-builder\"",
"build:plugin-nested-docs": "turbo build --filter \"@payloadcms/plugin-nested-docs\"",
@@ -104,13 +104,13 @@
},
"devDependencies": {
"@jest/globals": "29.7.0",
"@libsql/client": "0.6.2",
"@next/bundle-analyzer": "15.0.0-canary.173",
"@libsql/client": "0.14.0",
"@next/bundle-analyzer": "15.0.0",
"@payloadcms/db-postgres": "workspace:*",
"@payloadcms/eslint-config": "workspace:*",
"@payloadcms/eslint-plugin": "workspace:*",
"@payloadcms/live-preview-react": "workspace:*",
"@playwright/test": "1.46.0",
"@playwright/test": "1.48.1",
"@sentry/nextjs": "^8.33.1",
"@sentry/node": "^8.33.1",
"@swc-node/register": "1.10.9",
@@ -132,8 +132,8 @@
"create-payload-app": "workspace:*",
"cross-env": "7.0.3",
"dotenv": "16.4.5",
"drizzle-kit": "0.23.2-df9e596",
"drizzle-orm": "0.32.1",
"drizzle-kit": "0.26.2",
"drizzle-orm": "0.35.1",
"escape-html": "^1.0.3",
"execa": "5.1.1",
"form-data": "3.0.1",
@@ -145,15 +145,15 @@
"lint-staged": "15.2.7",
"minimist": "1.2.8",
"mongodb-memory-server": "^9.0",
"next": "15.0.0-canary.173",
"next": "15.0.0",
"open": "^10.1.0",
"p-limit": "^5.0.0",
"playwright": "1.46.0",
"playwright-core": "1.46.0",
"playwright": "1.48.1",
"playwright-core": "1.48.1",
"prettier": "3.3.3",
"prompts": "2.4.2",
"react": "19.0.0-rc-3edc000d-20240926",
"react-dom": "19.0.0-rc-3edc000d-20240926",
"react": "19.0.0-rc-65a56d0e-20241020",
"react-dom": "19.0.0-rc-65a56d0e-20241020",
"rimraf": "3.0.2",
"semver": "^7.5.4",
"sharp": "0.32.6",
@@ -163,12 +163,12 @@
"swc-plugin-transform-remove-imports": "1.15.0",
"tempy": "1.0.1",
"tsx": "4.19.1",
"turbo": "^2.1.2",
"typescript": "5.6.2"
"turbo": "^2.1.3",
"typescript": "5.6.3"
},
"peerDependencies": {
"react": "^19.0.0 || ^19.0.0-rc-3edc000d-20240926",
"react-dom": "^19.0.0 || ^19.0.0-rc-3edc000d-20240926"
"react": "^19.0.0 || ^19.0.0-rc-65a56d0e-20241020",
"react-dom": "^19.0.0 || ^19.0.0-rc-65a56d0e-20241020"
},
"packageManager": "pnpm@9.7.1",
"engines": {

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