Compare commits

...

613 Commits

Author SHA1 Message Date
Elliot DeNolf
e900e8974b chore(release): v3.0.0-beta.109 [skip ci] 2024-09-26 14:00:43 -04:00
Dan Ribbens
adc9bb5cbd fix(db-mongodb): docs duplicated in list view with drafts (#8435)
fixes #8430
2024-09-26 13:57:07 -04:00
Germán Jabloñski
a09811f5d4 fix(richtext-lexical): add max-width to tables (temporary fix for overflow). (#8431)
This is a half-baked and temporary solution to
https://github.com/payloadcms/payload/issues/8036

As I said there:
- ideally tables would have a horizontal scroll independent of the rest
of the document, just like Notion does.
- the solution in this PR can make the experience of resizing columns
frustrating

However, despite that drawback, it is arguably a better behavior than
the current one where they can have overflow over the editor container.

Until the ideal solution is implemented, let's default to this behavior.

## Before


![image](https://github.com/user-attachments/assets/b2856a3f-4b43-45f0-a7db-00c53fe5c980)


## After

![image](https://github.com/user-attachments/assets/2f60d186-d614-4c72-968c-137820812e11)
2024-09-26 14:37:25 -03:00
Paul
c73f6c74b3 fix(ui): autosave and preventLeaveWithoutSaving interfering with fetching form-state reliably (#8434)
Removes the setModified call from Autosave logic and updates the
`preventLeaveWithoutSaving` logic in Document info to actually disable
if autosave is enabled (previously it always resolved to true)

Fixes https://github.com/payloadcms/payload/issues/8072
2024-09-26 11:22:36 -06:00
Paul
5c2e39ef0c fix(ui): number field not being able to clear out the field's value (#8425)
Fixes #7780 

Fixes a bug where the number field won't save data if it's being removed
entirely (should be null) instead of changed to another value.

---------

Co-authored-by: PatrikKozak <patrik@payloadcms.com>
2024-09-26 08:37:23 -06:00
Riley Pearce
84d2026330 feat: preselected theme (#8354)
This PR implements the ability to attempt to force the use of light/dark
theme in the admin panel. While I am a big advocate for the benefits
that dark mode can bring to UX, it does not always suit a clients
branding needs.

Open to discussion on whether we consider this a suitable feature for
the platform. Please feel free to add to this PR as needed.

TODO:

- [x] Implement tests (I'm open to guidance on this from the Payload
team as currently it doesn't look like it's possible to adjust the
payload config file on the fly - meaning it can't be easily placed in
the admin folder tests).

---------

Co-authored-by: Germán Jabloñski <43938777+GermanJablo@users.noreply.github.com>
2024-09-26 11:09:29 -03:00
Paul
4b0351fcca fix(ui): align to the top fields inside row field (#8421) 2024-09-25 22:39:30 +00:00
Jessica Chowdhury
fa97d95675 chore: add join field image to docs (#8420)
Add screenshot of join field to docs.
2024-09-25 16:03:06 -04:00
Paul
95231daf14 fix(ui): versions in documentInfo and status component reverse latest true changes (#8417) 2024-09-25 19:36:58 +00:00
Sasha
8acbda078e feat(drizzle): customize schema with before / after init hooks (#8196)
Adds abillity to customize the generated Drizzle schema with
`beforeSchemaInit` and `afterSchemaInit`. Could be useful if you want to
preserve the existing database schema / override the generated one with
features that aren't supported from the Payload config.

## Docs:

### beforeSchemaInit

Runs before the schema is built. You can use this hook to extend your
database structure with tables that won't be managed by Payload.

```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { integer, pgTable, serial } from 'drizzle-orm/pg-core'

postgresAdapter({
  beforeSchemaInit: [
    ({ schema, adapter }) => {
      return {
        ...schema,
        tables: {
          ...schema.tables,
          addedTable: pgTable('added_table', {
            id: serial('id').notNull(),
          }),
        },
      }
    },
  ],
})
```

One use case is preserving your existing database structure when
migrating to Payload. By default, Payload drops the current database
schema, which may not be desirable in this scenario.
To quickly generate the Drizzle schema from your database you can use
[Drizzle
Introspection](https://orm.drizzle.team/kit-docs/commands#introspect--pull)
You should get the `schema.ts` file which may look like this:

```ts
import { pgTable, uniqueIndex, serial, varchar, text } from 'drizzle-orm/pg-core'

export const users = pgTable('users', {
  id: serial('id').primaryKey(),
  fullName: text('full_name'),
  phone: varchar('phone', { length: 256 }),
})

export const countries = pgTable(
  'countries',
  {
    id: serial('id').primaryKey(),
    name: varchar('name', { length: 256 }),
  },
  (countries) => {
    return {
      nameIndex: uniqueIndex('name_idx').on(countries.name),
    }
  },
)

```

You can import them into your config and append to the schema with the
`beforeSchemaInit` hook like this:

```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { users, countries } from '../drizzle/schema'

postgresAdapter({
  beforeSchemaInit: [
    ({ schema, adapter }) => {
      return {
        ...schema,
        tables: {
          ...schema.tables,
          users,
          countries
        },
      }
    },
  ],
})
```

Make sure Payload doesn't overlap table names with its collections. For
example, if you already have a collection with slug "users", you should
either change the slug or `dbName` to change the table name for this
collection.


### afterSchemaInit

Runs after the Drizzle schema is built. You can use this hook to modify
the schema with features that aren't supported by Payload, or if you
want to add a column that you don't want to be in the Payload config.
To extend a table, Payload exposes `extendTable` utillity to the args.
You can refer to the [Drizzle
documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
The following example adds the `extra_integer_column` column and a
composite index on `country` and `city` columns.

```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { index, integer } from 'drizzle-orm/pg-core'
import { buildConfig } from 'payload'

export default buildConfig({
  collections: [
    {
      slug: 'places',
      fields: [
        {
          name: 'country',
          type: 'text',
        },
        {
          name: 'city',
          type: 'text',
        },
      ],
    },
  ],
  db: postgresAdapter({
    afterSchemaInit: [
      ({ schema, extendTable, adapter }) => {
        extendTable({
          table: schema.tables.places,
          columns: {
            extraIntegerColumn: integer('extra_integer_column'),
          },
          extraConfig: (table) => ({
            country_city_composite_index: index('country_city_composite_index').on(
              table.country,
              table.city,
            ),
          }),
        })

        return schema
      },
    ],
  }),
})

```



<!--

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-09-25 15:14:03 -04:00
Dan Ribbens
b10f61cb25 fix(db-mongodb): add req to migration templates for transactions (#8407)
- Add `req` to MigrateUpArgs and MigrateDownArgs for mongodb
- Improve docs for transactions and migrations
2024-09-25 12:58:48 -04:00
Sasha
87360f23ac fix: make field property of FieldLabel optional and partial (#8409)
Fixes https://github.com/payloadcms/payload/issues/8366
2024-09-25 11:46:33 -04:00
Paul
8fadc3391b fix(plugin-seo): titles being displayed twice (#8310) 2024-09-25 11:05:18 -04:00
Paul
c6519aba8a fix(drizzle): migrate args no longer partial payload request (#8375)
The arguments for migration up or down is now the full PayloadRequest instead of partial
2024-09-25 09:29:37 -04:00
Dan Ribbens
82ba1930e5 feat: add upsert to database interface and adapters (#8397)
- Adds the upsert method to the database interface
- Adds a mongodb specific option to extend the updateOne to accept
mongoDB Query Options (to pass `upsert: true`)
- Added upsert method to all database adapters
- Uses db.upsert in the payload preferences update operation

Includes a test using payload-preferences
2024-09-25 09:23:54 -04:00
Paul
06ea67a184 fix: client function error on forgot password view (#8374) 2024-09-24 18:00:41 -06:00
Sasha
775e6e413a fix(drizzle): use alias for localized field sorting (#8396)
Fixes https://github.com/payloadcms/payload/issues/7015
2024-09-24 16:39:00 -04:00
Patrik
57f93c97a1 fix: lock documents using the live-preview view (#8343)
Updates:
- Exports `handleGoBack`, `handleBackToDashboard`, & `handleTakeOver`
functions to consolidate logic in default edit view & live-preview edit
view.

- Only unlock document on navigation away from edit view entirely (aka
do not unlock document if switching between tabs like `edit` -->
`live-preview` --> `versions` --> `api`
2024-09-24 16:38:11 -04:00
Elliot DeNolf
32c8d2821b ci: add missing gh usernames for label-author 2024-09-24 16:03:48 -04:00
Paul
a37abd16ac fix(ui): published, draft and changed labels should now be correctly displayed (#8382)
Fixes the issue where the published or changed document is always shown
as "Changed" instead of "Published" or "Draft"


![image](https://github.com/user-attachments/assets/05581b73-0e17-4b41-96a8-007c8b6161f2)


Statuses:
- Published - when the current version is also the published version
- Changed - when the current version is a draft version but a published
version exists
- Draft - when the current version is a draft and no published versions
exist

---------

Co-authored-by: Jessica Chowdhury <jessica@trbl.design>
2024-09-24 19:48:21 +00:00
Elliot DeNolf
a033cfe1c4 ci: handle labeling CONTRIBUTOR and COLLABORATOR author associations 2024-09-24 13:47:41 -04:00
Sasha
28ea0c59e8 feat!: improve afterError hook to accept array of functions, change to object args (#8389)
Changes the `afterError` hook structure, adds tests / more docs.
Ensures that the `req.responseHeaders` property is respected in the
error handler.

**Breaking**
`afterError` now accepts an array of functions instead of a single
function:
```diff
- afterError: () => {...}
+ afterError: [() => {...}]
```

The args are changed to accept an object with the following properties:
| Argument | Description |
| ------------------- |
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
| **`error`** | The error that occurred. |
| **`context`** | Custom context passed between Hooks. [More
details](./context). |
| **`graphqlResult`** | The GraphQL result object, available if the hook
is executed within a GraphQL context. |
| **`req`** | The
[Request](https://developer.mozilla.org/en-US/docs/Web/API/Request)
object containing the currently authenticated `user` |
| **`collection`** | The [Collection](../configuration/collections) in
which this Hook is running against. This will be `undefined` if the hook
is executed from a non-collection endpoint or GraphQL. |
| **`result`** | The formatted error result object, available if the
hook is executed from a REST context. |
2024-09-24 13:29:53 -04:00
Elliot DeNolf
6da4f06205 fix(db-vercel-postgres): include needed pg dependency (#8393)
`pg` appears to be a needed dependency in order for drizzle /
@vercel/postgres to build successfully.
2024-09-24 13:10:25 -04:00
Elliot DeNolf
50da2125a5 fix(templates): proper migration file import source for vercel-postgres (#8394)
- Add `ci` npm script properly for postgres templates
- Fix import source for migration files when using
`@payloadcms/db-vercel-postgres`
2024-09-24 12:24:59 -04:00
Elliot DeNolf
7f3d935b4d ci: add db-vercel-postgres as valid scope 2024-09-24 12:15:22 -04:00
Elliot DeNolf
e72f12af97 feat: templates update (#8391)
Run generate templates script
2024-09-24 11:20:35 -04:00
Alessio Gravili
a80f5b65ec fix: safely access user in auth operations (#8381) 2024-09-23 20:46:43 +00:00
Dan Ribbens
dc69e2c0f6 fix(db-mongodb): db.find default limit to 0 (#8376)
Fixes an error anytime a `db.find` is called on documents with joins
without a set `limit` by defaulting the limit to 0.
2024-09-23 16:31:50 -04:00
Germán Jabloñski
19e2f10f4b fix(richtext-lexical): regression in lexical blocks (#8378)
Fix https://github.com/payloadcms/payload/issues/8371
2024-09-23 19:58:27 +00:00
Germán Jabloñski
bd41b4d7d2 fix(richtext-lexical): table dropdown menu dark mode color (#8368)
This PR supports dark mode for the tables dropdown menu (currently only
available in light mode).

I copied the colors from
[slash-menu-popup](https://github.com/payloadcms/payload/blob/beta/packages/richtext-lexical/src/lexical/plugins/SlashMenu/index.scss)
to keep things consistent.

Below are screenshots of the change. I also show the slash-menu-popup to
compare color consistency, and the light mode to verify that it's not
broken.

## Before


![image](https://github.com/user-attachments/assets/a709bf8c-1dc2-47ac-8310-5cd1776cb268)


## After


![image](https://github.com/user-attachments/assets/e6df6693-793d-4afb-8dcc-2ead5ac62ca9)

![image](https://github.com/user-attachments/assets/7604fdcd-34d0-4801-96c2-ae5ca92357d9)

![image](https://github.com/user-attachments/assets/3bd2c877-2567-44dd-89fe-cc565988f72a)

![image](https://github.com/user-attachments/assets/813693ea-ddbe-45f5-8f98-5c9c8c58c082)
2024-09-23 14:03:14 -04:00
Sasha
fbc395b692 fix: optional sortOptions type for SingleRelationshipFieldClient (#8340)
Fixes the typescript error when using `RelationshipField` and passing
`admin` options without `sortOptions`.
2024-09-23 11:40:42 -04:00
Sasha
30eb1d522e fix(next): set the user data after first user registration (#8360)
Fixes https://github.com/payloadcms/payload/issues/8353 by analogy with
https://github.com/payloadcms/payload/pull/8135
2024-09-23 11:39:36 -04:00
Sasha
dedcff0448 fix(drizzle): sanitize query value uuid / number id NaN (#8369)
Fixes https://github.com/payloadcms/payload/issues/8347 (additionally
for UUID search as well)
2024-09-23 11:35:07 -04:00
Sasha
338c93a229 fix(drizzle): array/relationship/select hasMany in localized field (#8355)
This PR addresses these issues with localized groups / tabs with
Postgres / SQLite:

- Array fields inside of localized groups. Fixes
https://github.com/payloadcms/payload/issues/8322
- Select fields with `hasMany: true` inside of localized groups. Related
to 1, but still needed its own additional logic.
- Relationship (non-polymorphic / non has-many) inside of localized
groups. Previously, even just trying to define them in the config led to
a crash. Fixes https://github.com/payloadcms/payload/issues/8308

Ensures test coverage for localized groups.
2024-09-23 11:34:02 -04:00
Elliot DeNolf
36ba6d47b4 ci: unused debug log in post-release 2024-09-22 10:39:54 -04:00
Dan Ribbens
c696728f64 fix: cannot use join on relationships in unnamed fields (#8359)
fixes #8356
2024-09-22 08:29:58 -04:00
Tylan Davis
3583c45b67 fix(ui): inconsistent arrow dropdown on buttons, popover missing caret (#8341)
Fixes the style of the Publish and Restore buttons' dropdown triggers,
using the button's size for consistent padding of the trigger's button.
Closes #8284

| Before | After |
| :--- | :--- |
| ![Screenshot 2024-09-20 at 2 32
51 PM](https://github.com/user-attachments/assets/ae8a5788-dfd3-43d1-a066-d99722592aee)
| ![Screenshot 2024-09-20 at 2 34
27 PM](https://github.com/user-attachments/assets/16dbdfa9-9db8-4ce5-a210-bc308727b39e)
|
| ![Screenshot 2024-09-20 at 2 34
56 PM](https://github.com/user-attachments/assets/f0edc8aa-08f4-46a2-a64d-1ff2ff95abd2)
| ![Screenshot 2024-09-20 at 2 35
12 PM](https://github.com/user-attachments/assets/31e8db78-5687-43ab-82a6-c6d1db5fec5a)
|
2024-09-21 16:13:42 -04:00
Elliot DeNolf
c3bc2ba4a4 chore: bold the scope in release notes 2024-09-20 23:00:03 -04:00
Elliot DeNolf
040c2a2fbb chore(eslint): FlatConfig type deprecated, set to Config 2024-09-20 22:46:40 -04:00
Elliot DeNolf
b1173dc6ad ci: add uploadthing scope [skip ci] 2024-09-20 22:07:36 -04:00
Elliot DeNolf
7faa6253fc chore(release): v3.0.0-beta.108 [skip ci] 2024-09-20 15:58:38 -04:00
Germán Jabloñski
7d2022f28b feat(richtext-lexical)!: dropdown menu disabled status (#8177)
**Breaking change**: ToolbarDropdown no longer receives
`groupKey={group.key}` and `items={group.items}` as props, but instead
`group={group}`

___

Similar to #8159, but in this case it allows you to disable an entire
dropdown menu, not just individual items in the dropdown.

This adds a new property to `ToolbarGroup` when used with `type:
'dropdown'`.

For example, if you add `isEnabled: () => false,` inside
`packages/richtext-lexical/src/features/shared/toolbar/textDropdownGroup.ts`
and run `pnpm dev fields`, this is what you'll see in the Lexical
editor:


![image](https://github.com/user-attachments/assets/4efe2e92-2e78-473f-8c97-0995e3d44671)
2024-09-20 15:55:34 -04:00
Patrik
493b121ae8 fix(ui): hide dot menu in read-only mode for locked documents (#8342) 2024-09-20 15:48:57 -04:00
Elliot DeNolf
55afbe589c chore(cpa): prefer pnpm if exists (#8345)
Prefer pnpm if it exists.
2024-09-20 15:35:30 -04:00
Patrik
e916512fa7 fix(db-mongodb): treat empty strings as null / undefined for exists queries (#8337)
v2 PR [here](https://github.com/payloadcms/payload/pull/8336)
2024-09-20 15:27:07 -04:00
Germán Jabloñski
81a972d966 chore(richtext-lexical): add strictNullChecks to the richtext-lexical package (#8295)
This PR addresses around 500 TypeScript errors by enabling
strictNullChecks in the richtext-lexical package. In the process,
several bugs were identified and fixed.

In some cases, I applied non-null assertions where necessary, although
there may be room for further type refinement in the future. The focus
of this PR is to resolve the immediate issues without introducing
additional technical debt, rather than aiming for perfect type
definitions at this stage.

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-09-20 18:42:30 +00:00
Paul
1f7d47a361 fix(ui): client side error when passing labels as functions for custom view tabs (#8339) 2024-09-20 17:32:46 +00:00
Louis Ba
afb8805a9b fix: add logger to serverOnlyConfigProperties (#8325)
## Description

Add `logger` field to `serverOnlyConfigProperties` to prevent it being
passed to client components, which could cause issues.

### Reproduction Steps
``` typescript
// payload.config.ts

export default buildConfig({
  // ...
  logger: pino({
    name: 'test',
  }),
  // ...
})
```


![image](https://github.com/user-attachments/assets/21d155b7-3d13-4a78-9ba6-036475a6633f)

- [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

<!-- Please delete options that are not relevant. -->

- [ ] Chore (non-breaking change which does not add functionality)
- [x] 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

## Checklist:

- [ ] 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
2024-09-20 13:00:24 -04:00
Paul
0789f4d0d4 fix(plugin-form-builder)!: emails array field has read access by authenticated users only by default now (#8338) 2024-09-20 16:54:33 +00:00
Alessio Gravili
cb831362c7 chore: add re-usable run against prod command (#8333) 2024-09-20 16:10:06 +00:00
Alessio Gravili
1afcaa30ed feat!: upgrade next, react and react-dom, move react/next dependency checker from payload to next package (#8323)
Fixes https://github.com/payloadcms/payload/issues/8013

**BREAKING:**
- Upgrades minimum supported @types/react version from
npm:types-react@19.0.0-rc.0 to npm:types-react@19.0.0-rc.1
- Upgrades minimum supported @types/react-dom version from
npm:types-react-dom@19.0.0-rc.0 to npm:types-react-dom@19.0.0-rc.1
- Upgrades minimum supported react and react-dom version from
19.0.0-rc-06d0b89e-20240801 to 19.0.0-rc-5dcb0097-20240918
- Upgrades minimum supported Next.js version from 15.0.0-canary.104 to
15.0.0-canary.160

---------

Co-authored-by: PatrikKozak <patrik@payloadcms.com>
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
2024-09-20 12:09:42 -04:00
Alessio Gravili
d3b982f38d chore(templates): remove now unnecessary ts-ignore from lexical serializer (#8332) 2024-09-20 15:21:43 +00:00
Sasha
265d7fa0e2 fix(drizzle): equals polymorphic querying with object notation (#8316)
Previously, this wasn't valid in Postgres / SQLite:
```ts
const res = await payload.find({
  collection: 'polymorphic-relationships',
  where: {
    polymorphic: {
      equals: {
        relationTo: 'movies',
        value: movie.id,
      },
    },
  },
})
```

Now it works and actually in more performant way than this:
```ts
const res = await payload.find({
  collection: 'polymorphic-relationships',
  where: {
    and: [
      {
        'polymorphic.relationTo': {
          equals: 'movies',
        },
      },
      {
        'polymorphic.value': {
          equals: 'movies',
        },
      },
    ],
  },
})
``` 

Why? Because with the object notation, the output SQL is: `movies_id =
1` - checks exactly 1 column in the `*_rels` table, while with the
separate query by `relationTo` and `value` we need to check against
_each_ possible relationship collection with OR.
2024-09-20 11:18:13 -04:00
Sasha
2596b85027 fix(drizzle): nested arrays with localized items and versions (#8331)
Fixes https://github.com/payloadcms/payload/issues/7695

Previosuly, trying to append a new item to an array that contains
another array with localized items and enabled versions led to a unique
`_locale` and `_parent_id` error
```ts
{
  name: 'nestedArrayLocalized',
  type: 'array',
  fields: [
    {
      type: 'array',
      name: 'array',
      fields: [
        {
          name: 'text',
          type: 'text',
          localized: true,
        },
      ],
    },
  ],
}
```
2024-09-20 11:16:14 -04:00
Dan Ribbens
6ef2bdea15 feat!: join field (#7518)
## Description

- Adds a new "join" field type to Payload and is supported by all database adapters
- The UI uses a table view for the new field
- `db-mongodb` changes relationships to be stored as ObjectIDs instead of strings (for now querying works using both types internally to the DB so no data migration should be necessary unless you're querying directly, see breaking changes for details
- Adds a reusable traverseFields utility to Payload to make it easier to work with nested fields, used internally and for plugin maintainers

```ts
export const Categories: CollectionConfig = {
    slug: 'categories',
    fields: [
        {
            name: 'relatedPosts',
            type: 'join',
            collection: 'posts',
            on: 'category',
        }
    ]
}
```

BREAKING CHANGES:
All mongodb relationship and upload values will be stored as MongoDB ObjectIDs instead of strings going forward. If you have existing data and you are querying data directly, outside of Payload's APIs, you get different results. For example, a `contains` query will no longer works given a partial ID of a relationship since the ObjectID requires the whole identifier to work. 

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-09-20 11:10:16 -04:00
Tylan Davis
b51d2bcb39 fix(ui): adjust list view table alignment (#8330)
### Description
- Fixes checkbox alignment issues within the collection list view table.
(Closes #8307)
- Aligns table cells to top for better readability across rows.

**Before:**
![Screenshot 2024-09-20 at 10 01
43 AM](https://github.com/user-attachments/assets/c35804d9-941b-4b52-a37d-0fac5734312e)

**After:**
![Screenshot 2024-09-20 at 9 10
35 AM](https://github.com/user-attachments/assets/52bb8405-b1ca-4083-a76d-30e7468bdad5)
2024-09-20 10:58:18 -04:00
Alessio Gravili
0cdd5b628c perf: disable router cache refresh that occurs after every page transition or page load (#8318)
This speeds up all page loads and reduces the amount of requests

## Example

### Clientside transition from dashboard => ui-fields list view

#### Router cache disabled
 GET /admin/collections/ui-fields 200 in 33ms
 POST /api/form-state 200 in 9ms
 POST /api/form-state 200 in 10ms
 GET /api/payload-preferences/ui-fields-list 200 in 11ms
 GET /admin/collections/ui-fields?limit=10&sort=id 200 in 42ms
 
#### Router cache enabled
 GET /admin/collections/ui-fields 200 in 33ms
 POST /api/form-state 200 in 11ms
 POST /api/form-state 200 in 12ms
 GET /api/payload-preferences/ui-fields-list 200 in 15ms
 GET /admin/collections/ui-fields?limit=10&sort=id 200 in 42ms
**GET /admin/collections/ui-fields?limit=10&sort=id 200 in 82ms** <==
this is gone
2024-09-20 09:57:09 -04:00
Elliot DeNolf
63b446c82b ci: bring back node setup action 2024-09-20 09:13:52 -04:00
Dan Ribbens
dbdc7d9308 chore: use updatedAt instead of editedAt for locked documents (#8324)
- Removes locked documents `editedAt` as it was redundant with the
`updatedAt` timestamp
- Adjust stale lock tests to configure the duration down to 1 second and
await it to not lose any test coverage
- DB performance changes: 
1. Switch to payload.db.find instead of payload.find for
checkDocumentLockStatus to avoid populating the user and other payload
find overhead
   2. Add maxDepth: 1 to user relationship
   3. Add index to global slug
2024-09-20 09:08:58 -04:00
Alessio Gravili
79c117c664 chore: fix lingering jest and next-server processes in monorepo (#8320) 2024-09-20 01:15:20 +00:00
Paul
faaa1188f4 chore: add warning in documentation about custom endpoints and authentication (#8321) 2024-09-20 01:03:30 +00:00
James Mikrut
c6a7ad2817 perf: optimizes admin ui loading by using react cache to memoize req / auth (#8315)
Uses React `cache` to memoize a lot of the work that the Payload Admin
UI had to perform in parallel, in multiple places.

Specifically, we were running `auth` in three places:

1. `not-found.tsx` - for some reason this renders even if not used
2. `initPage.ts`
3. `RootLayout`

Now, a lot of expensive calculations only happen once and are memoized
per-request. 🎉
2024-09-19 21:58:34 +00:00
Patrik
9c3f863ad2 feat: adds overrideLock flag to update & delete operations (#8294)
- Adds `overrideLock` flag to `update` & `delete` operations

- Instead of throwing an `APIError` (500) when trying to update / delete
a locked document - now throw a `Locked` (423) error status
2024-09-19 17:07:02 -04:00
Patrik
879f690161 feat(ui): hides lock icon when locked by current user (#8309) 2024-09-19 14:13:14 -04:00
Sasha
405a6c3447 feat(ui): threads collectionSlugs through useListDrawer (#8292)
Exposes `collectionSlugs` state from the `useListDrawer` hook to control
it outside of the hook. We can't use `collectionSlug` from the hook
props because it's memoized inside of the hook state.

```ts
const [
  ListDrawer,
  ListDrawerToggler,
  { collectionSlugs, setCollectionSlugs },
] = useListDrawer({
});
```
2024-09-19 12:16:18 -04:00
gervickas.js
a94e40f762 feat(storage-vercel-blob): threads cacheControlMaxAge through static handler (#8065)
## Description
I'm facing a issue while trying to set a cache age for vercel blob
storage plugin, this way I changed to accept and set as response the
cache control.

### Before changes

![image](https://github.com/user-attachments/assets/b67ee1a0-f4af-4f1f-942a-2063ec2fa5a2)

![image](https://github.com/user-attachments/assets/a3a7bce7-70be-4c06-ade6-3708f47d524c)


### After changes


![image](https://github.com/user-attachments/assets/9085193a-ef2d-4fa0-9aae-6817fe97aae0)


![image](https://github.com/user-attachments/assets/69a44948-402d-423b-873b-026be39c7501)

### Using plugin
```
vercelBlobStorage({
      enabled: true, // Optional, defaults to true
      // dev: Specify which collections should use Vercel Blob
      collections: {
        [Media.slug]: true,
      },
      // dev:Token provided by Vercel once Blob storage is added to your Vercel project
      token: process.env.BLOB_READ_WRITE_TOKEN!,
      cacheControlMaxAge: 31536000, /// the same we see
    }),
```

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [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

<!-- Please delete options that are not relevant. -->

- [ ] Chore (non-breaking change which does not add functionality)
- [x] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-19 08:51:03 -06:00
Jessica Chowdhury
2d29b7e254 fix: only add snapshot to versions query when localization is enabled (#8293)
Versions list view should not query `snapshot` unless localization is
enabled.

Closes https://github.com/payloadcms/payload/issues/8289
2024-09-19 10:40:47 -04:00
Paul
7b907a8701 chore: add best practices for authenticating with cookies cross domains in documentation (#8301) 2024-09-18 21:08:34 -06:00
Sasha
72995fccf5 feat(ui): useTableColumns add abillity to reset columns state (#8296)
Fixes https://github.com/payloadcms/payload/issues/8205

Adds `resetColumnsState` method to `useTableColumns` return
Example of a `BeforeList` component for column state reset:
```ts
'use client'

import { Pill, useTableColumns } from '@payloadcms/ui'

function ResetDefaultColumnsButton() {
  const { resetColumnsState } = useTableColumns()

  return <Pill onClick={resetColumnsState}>Reset to default columns</Pill>
}

export { ResetDefaultColumnsButton }

```

Additionally, fixes that `setActiveColumns` didn't respect the passed
order of columns and didn't update the UI immediately
2024-09-18 20:35:03 -06:00
Frank Omondi
a095a6f891 docs: correct grammatical mistake (#8287) 2024-09-18 19:28:07 +00:00
Sasha
37e1adfa5c fix: findByID adjust type to null if disableErrors: true is passed (#8282)
Fixes https://github.com/payloadcms/payload/issues/8280

Now, the result type of this operation:
```ts
const post = await payload.findByID({
  collection: "posts",
  id,
  disableErrors: true
})
```
is `Post | null` instead of `Post` when `disableErrors: true` is passed

Adds test for the `disableErrors` property and docs.
2024-09-18 16:39:58 +00:00
Paul
9821aeb67a feat(plugin-form-builder): new wildcards {{*}} and {{*:table}} are now supported in email bodies and emails fall back to a global configuration value in addition to base email configuration (#8271)
Email bodies in the plugin form builder now support wildcards `{{*}}`
and `{{*:table}}` to export all the form submission data in key:value
pairs with the latter formatted as a table.

Emails also fallback to a global plugin configuration item and then to
the `defaultFromAddress` address in email transport config.
2024-09-18 00:28:52 +00:00
Paul
dd96f9a058 fix(richtext-slate): fix issue with richText field cell not being a link when used as a useAsTitle (#8272) 2024-09-18 00:00:00 +00:00
Patrik
023c650e03 chore: cleans up locked-documents (#8269)
Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-09-17 18:19:18 -04:00
Germán Jabloñski
4d54cc6e02 fix(templates): optional chaining bug (#8268)
Another one that ts non-strict mode is not catching 🙃🫠


https://github.com/user-attachments/assets/7cf78db9-4181-4a2d-9a8e-cdf3dd4f1951
2024-09-17 14:11:09 -06:00
Germán Jabloñski
f011e4fa26 fix(ui): code field adjusts its height to its content dynamically. Scrolling over the container is not prevented. (#8209)
Closes #8051.

- The scrolling problem reported in the issue is solved with Monaco's
`alwaysConsumeMouseWheel` property.
- In addition to that, it is necessary to dynamically adjust the height
of the editor so that it fits its content and does not require
scrolling.
- Additionally, I disabled the `overviewRuler` which is the indicator
strip on the side (above the scrollbar) that makes no sense when there
is no scroll.

**Gotchas**

- Unfortunately, there is a bit of CLS since the editor doesn't know the
height of its content before rendering. In Lexical these things are
possible since it has a lifecycle that allows interaction before or
after rendering, but this is not the case with Monaco.
- I've noticed that sometimes when I press enter the letters in the
editor flicker or move with a small, rapid shake. Maybe it has to do
with the new height being calculated as an effect.


## Before


https://github.com/user-attachments/assets/0747f79d-a3ac-42ae-8454-0bf46dc43f34


## After


https://github.com/user-attachments/assets/976ab97c-9d20-4e93-afb5-023083a6608b
2024-09-17 15:55:09 -04:00
Jacob Fletcher
c0aad3cccb fix: strongly types field validation args (#8263)
Continuation of #8243. Strongly types the `value` argument within
`field.validate` functions:

- Uses existing internal validation types for field `validate` property
- Exports additional validation types to cover `hasMany` fields
- Includes `null` and `undefined` values
2024-09-17 15:14:10 -04:00
Paul
110fda7533 fix(ui): mobile menu button sizing (#8264) 2024-09-17 18:14:40 +00:00
Patrik
f98d032617 feat: lock documents while being edited (#7970)
## Description

Adds a new property to `collection` / `global` configs called
`lockDocuments`.

Set to `true` by default - the lock is automatically triggered when a
user begins editing a document within the Admin Panel and remains in
place until the user exits the editing view or the lock expires due to
inactivity.

Set to `false` to disable document locking entirely - i.e.
`lockDocuments: false`

You can pass an object to this property to configure the `duration` in
seconds, which defines how long the document remains locked without user
interaction. If no edits are made within the specified time (default:
300 seconds), the lock expires, allowing other users to edit / update or
delete the document.

```
lockDocuments: {
  duration: 180, // 180 seconds or 3 minutes
}
```

- [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] New feature (non-breaking change which adds functionality)

## 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-09-17 14:04:48 -04:00
Because789
05a3cc47a6 docs: fixes link to ecommerce template in nested-docs.mdx (#8237) 2024-09-17 17:44:19 +00:00
Thành Trang
89601f18f5 feat(plugin-seo): add vietnamese translation (#8179) 2024-09-17 17:25:57 +00:00
Sasha
31ffc57366 fix(drizzle): in query on polymorphic relations across ID types (#8240)
Fixes querying using `in` operator by polymorphic relationship value.
The previous PR https://github.com/payloadcms/payload/pull/8191 didn't
handle the case when the incoming query value is an array and therefore
each item of the array can have a different type.
Ensures test coverage
2024-09-17 12:57:00 -04:00
Germán Jabloñski
9035467998 fix(ui): filter collection crashes when navigating away (#8260)
Fix https://github.com/payloadcms/payload/issues/8198

Caused by not having ts in strict mode.
2024-09-17 16:45:28 +00:00
Jacob Fletcher
029eba57b2 fix: properly infers field validation args (#8243)
Field validation functions currently do not type their `value` arg. This
is because the underlying `FieldBase` type breaks the type inferences
for these functions. The fix is to `Omit` the `validate` property from
this type before overriding it with our own, typed version for each
field.

Here's an example of the problem:

<img width="373" alt="Screenshot 2024-09-16 at 2 50 10 PM"
src="https://github.com/user-attachments/assets/a99e32fb-5645-4df6-82f2-0efab26b9831">

Here's an example of the fix:

<img width="363" alt="Screenshot 2024-09-16 at 3 59 42 PM"
src="https://github.com/user-attachments/assets/f83909bc-2169-4378-b5a7-5cca78b6ad64">

This PR also fixes the `hasMany` type inferences (shown above), where
the `value` type changes to an array when this property is set. Here's a
minimal example of the solution:

```ts
export type NumberField = {
  type: 'number'
} & (
  | {
      hasMany: true
      validate?: Validate<number[], unknown, unknown, NumberField>
    }
  | {
      hasMany?: false | undefined
      validate?: Validate<number, unknown, unknown, NumberField>
    }
)
```

```ts
{
  type: 'text',
  validate: (value) => '' // value is `string`
},
{
  type: 'text',
  hasMany: true,
  validate: (value) => '' // value is `string[]`
}
```

Disclaimer: in order for these types to properly infer their values,
`strictNullChecks: true` must be set in your `tsconfig.json`. This is
_not_ currently set in the Payload Monorepo, but consuming apps _should_
have this defined in order properly infer these types.
 
This PR also adds stronger types for misc. untyped values such as the
`point` field, etc.
2024-09-17 16:29:38 +00:00
Germán Jabloñski
67cd3b3cf8 fix(richtext-lexical): dropdown item disabled status (#8159)
## Description

It is possible to disable arbitrary items from a toolbar dropdown menu
with the `isEnabled` property. In order to illustrate the changes in
this PR, I have introduced the following lines in the
`HeadingFeatureClient` located at
`packages/richtext-lexical/src/features/heading/client/index.tsx`.

```ts
          isEnabled: () => {
            return headingSize === 'h2'
          },
```
**Before this PR**

![Screenshot 2024-09-10 at 4 50
08 PM](https://github.com/user-attachments/assets/bffe93db-9bb1-4ddd-8ca4-2cd9e37b7811)
![Screenshot 2024-09-10 at 4 50
40 PM](https://github.com/user-attachments/assets/a63d316d-bb28-4072-95c1-96b66bcdb519)

**After this PR**

![image](https://github.com/user-attachments/assets/427b2fa5-b015-4542-a632-aee094dd881b)

![image](https://github.com/user-attachments/assets/d5123d1b-c0cd-468f-a94b-bb5910dff1e9)


packages/richtext-lexical/src/features/heading/client/index.tsx


- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-09-17 10:55:50 -04:00
Sasha
bf48af411d feat: add virtual property to the fields config (#7621)
## Description

Adds `virtual` property to the fields config. Providing `true`
completely disables the field in the DB, which is useful for [Virtual
Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges)
Disables abillity to query by a field with `virtual: true`.
Currently, they bloat the DB with unused tables / columns, which may as
well introduce additional joins.
Discussion https://github.com/payloadcms/payload/discussions/6270
Prev PR (this one contains only this feature):
https://github.com/payloadcms/payload/pull/6983

- [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

<!-- Please delete options that are not relevant. -->

- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## 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-09-17 10:40:54 -04:00
Because789
a7e8828e5e docs: fixes link to i18n in components.mdx (#8253) 2024-09-17 08:12:23 -04:00
Paul
a06458d70d fix(ui): pass label as prop through to the textarea input (#8248) 2024-09-16 22:58:22 +00:00
Paul
149b7cb26c fix(ui): field alignment when labels overflow inside rows (#8246) 2024-09-16 22:42:01 +00:00
Paul
ccd0b1ef48 fix(ui): draft docs are now correctly provided in preview URL (#8245) 2024-09-16 22:30:28 +00:00
Paul
d2eafdfaf8 fix: error on forgot-password route (#8244) 2024-09-16 20:41:57 +00:00
Paul
a68f0cec4a fix(ui): nav button height being stretched and navWrapper border on RTL (#8242) 2024-09-16 20:35:25 +00:00
Sasha
8520fd9570 fix(drizzle): optimize count querying when no joins (#7749)
Closes https://github.com/payloadcms/payload/issues/6321


To run benchmark:
`git checkout b840222` - from r1tsuu/payload
b840222784
`pnpm dev:postgres _community`

Benchmark results: (Before / After)
Postgres 400 000 rows:

![image](https://github.com/user-attachments/assets/cd7c478f-2057-4c7c-adec-5dbf0b05ec7b)
Postgres 2 000 000 rows:

![image](https://github.com/user-attachments/assets/04224f95-77eb-42ab-9591-887b197c597a)

SQLite 400 000 rows:

![image](https://github.com/user-attachments/assets/ba7482c2-30f1-4498-892d-59710639a7b3)
SQLite 2 000 000 rows:

![image](https://github.com/user-attachments/assets/c0a889f8-8e21-4b98-ac92-65ac735b8b32)



## Description

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [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

<!-- Please delete options that are not relevant. -->


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

## Checklist:

- [x] Existing test suite passes locally with my changes - See
https://github.com/payloadcms/payload/pull/7749#issuecomment-2295763721
2024-09-16 16:21:06 -04:00
Jessica Chowdhury
b7a0b15786 feat: add publish specific locale (#7669)
## Description

1. Adds ability to publish a specific individual locale (collections and
globals)
2. Shows published locale in versions list and version comparison
3. Adds new int tests to `versions` test suite

- [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] New feature (non-breaking change which adds functionality)
- [ ] This change requires a documentation update

## 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
- [ ] I have made corresponding changes to the documentation

---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-09-16 16:15:29 -04:00
Jacob Fletcher
aee76cb793 fix(plugin-seo): threads entity slug and document config through generation fn args (#8238)
The `generateTitle`, `generateDescription`, `generateURL`, and
`generateImage` functions in the SEO Plugin do not currently receive any
args representing the document's entity. This means that within these
functions, it is currently not possible to discern the _type_ of
document you are working with, i.e. a collection or global. The
underlying problem here was that the request made to execute these
functions was threading through `slug` as `undefined`. This is because
the `DocumentInfoProvider` was failing to thread this prop through
context as the types suggest. Now, these functions receive their
respective `collectionConfig` and `globalConfig`.

```ts
import type { GenerateTitle } from '@payloadcms/plugin-seo/types'
import type { Page } from '@/payload-types'

const generateTitle: GenerateTitle<Page> = ({
  doc,
  collectionConfig,
  globalConfig,
}) => {
  return `Website.com — ${doc?.title}`
}
```
2024-09-16 19:27:39 +00:00
Sasha
b7db53cef4 fix(drizzle)!: localized fields uniqueness per locale (#8230)
Previously, this worked with MongoDB but failed with Postgres / SQLite
when the `slug` field has both `localized: true` and `unique: true`.

```ts
await payload.create({
  collection: "posts",
  locale: "en",
  data: {
    slug: "my-post"
  }
})

await payload.create({
  collection: "posts",
  locale: "de",
  data: {
    slug: "my-post"
  }
})
```

Now, we build unique constraints and indexes in combination with the
_locale column. This should also improve query performance for fields
with both index: true and localized: true.

### Migration steps (Postgres/SQLite only)
This change updates the database schema and requires a migration (if you
have any localized fields). To apply it, run the following commands:

```sh
pnpm payload migration:create locale_unique_indexes
pnpm payload migrate
```

Note that if you use `db.push: true` which is a default, you don't have
to run `pnpm payload migrate` in the development mode, only in the
production, as Payload automatically pushes the schema to your DB with
it.
2024-09-16 14:47:13 -04:00
Dan Ribbens
f72fd8543b chore: gitignore test/databaseAdapter (#8235) 2024-09-16 17:02:08 +00:00
Elliot DeNolf
d046e0d18f chore(deps): bump turbo 2024-09-16 11:57:02 -04:00
Elliot DeNolf
a198fe0be5 chore(release): v3.0.0-beta.107 [skip ci] 2024-09-16 11:50:44 -04:00
James Mikrut
c460868e52 fix: duplication with localized arrays in unnamed tabs (#8236)
Fixes a case where in relational DBs, you can't duplicate documents if
you have localized arrays within unnamed tabs.

The `beforeDuplicate` hooks were not being run for fields within unnamed
tabs.
2024-09-16 11:43:36 -04:00
Sasha
a0a1e20193 fix(drizzle): polymorphic querying of different ID types (#8191)
This PR fixes querying by a relationship field that has custom IDs in
`relationTo` with different types.
Now, in this case, we do cast the ID value in the database.

Example of the config / int test that reproduced the issue:

```ts
{
  slug: 'posts-a',
  fields: [],
},
{
  slug: 'posts-b',
  fields: [],
},
{
  slug: 'posts-custom-id',
  fields: [{ name: 'id', type: 'text' }],
},
{
  slug: 'roots',
  fields: [
    {
      name: 'rel',
      relationTo: ['posts-a', 'posts-b', 'posts-custom-id'],
      type: 'relationship',
    },
  ],
},
```

```ts
const postA = await payload.create({ collection: 'posts-a', data: {} })
const postB = await payload.create({ collection: 'posts-b', data: {} })
const postC = await payload.create({
  collection: 'posts-custom-id',
  data: { id: crypto.randomUUID() },
})

const root_1 = await payload.create({
  collection: 'roots',
  data: {
    rel: {
      value: postC.id,
      relationTo: 'posts-custom-id',
    },
  },
})

const res_1 = await payload.find({
  collection: 'roots',
  where: {
    'rel.value': { equals: postC.id },
  },
})

// COALESCE types integer and character varying cannot be matched

expect(res_1.totalDocs).toBe(1)
```

<!--

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-09-16 10:39:55 -04:00
Jessica Chowdhury
3b59416298 feat: add new option for admin.components.header (#7647)
## Description

Adds `admin.components.header` option to allow users to insert custom
components in the page header / top of page.

[Related
discussion](https://github.com/payloadcms/payload/discussions/7584)

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [X] 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)
- [x] This change requires a documentation update

## Checklist:

- [x] I have added tests that prove my fix is effective or that my
feature works - will add
- [X] Existing test suite passes locally with my changes
2024-09-16 10:05:15 -04:00
Elliot DeNolf
7c8272b467 feat(cpa): add node engines (#8234) 2024-09-16 09:36:16 -04:00
Jacob Fletcher
06e5db6529 chore(examples): updates custom components example to latest payload (#8186) 2024-09-16 09:03:10 -04:00
Elliot DeNolf
8448e65b73 ci: release commenter (#8226)
In order to have beta releases properly trigger GitHub Actions'
`published` event in our `post-release` workflow, this job must exist on
the branch the release is on.
2024-09-15 13:41:09 -04:00
Alessio Gravili
6d1a287dd1 perf: remove find-up dependency, upgrade file-type dependency (#8195)
Fixes https://github.com/payloadcms/payload/issues/8111 and
https://github.com/payloadcms/payload/issues/8113

Before: 132 dependencies
After: 123 dependencies

This PR also contains a small performance optimization during telemetry
startup: By using the async `fs.promises.readFile` instead of
`readFileSync` we're not blocking the entire thread anymore and are
allowing other stuff to happen while the file is being read.
Also, in our dependency checker, this moves some variables out of loops,
to the module scope, as they only need to be calculated once.

We have to pin file-type to 19.3.0 and cannot upgrade it further (latest
is 19.5.0). See reasoning in
https://github.com/payloadcms/payload/issues/8111#issuecomment-2348119533
2024-09-15 16:53:53 +00:00
Elliot DeNolf
bb2dd5f4d2 chore(release): v3.0.0-beta.106 [skip ci] 2024-09-14 23:15:44 -04:00
James Mikrut
5873a3db06 fix: duplicating localized nested arrays (#8220)
Fixes an issue where duplicating documents in Postgres / SQLite would
crash because of a foreign key constraint / unique ID issue when you
have nested arrays / blocks within localized arrays / blocks.

We now run `beforeDuplicate` against all locales prior to
`beforeValidate` and `beforeChange` hooks.

This PR also fixes a series of issues in Postgres / SQLite where you
have localized groups / named tabs, and then arrays / blocks within the
localized groups / named tabs.
2024-09-15 02:51:31 +00:00
Elliot DeNolf
8fc2c43190 chore(release): v3.0.0-beta.105 [skip ci] 2024-09-14 22:40:24 -04:00
Jacob Fletcher
64f2395c58 fix(plugin-seo): removes duplicative json translations (#8206)
The SEO Plugin defines duplicative translations in both TS and JSON,
even though JSON translations are no longer in use. Translations were
still being maintained in JSON, despite this fact. This PR removes all
JSON files, replacing them with TS, and improving file organization and
overall types.
2024-09-14 20:19:12 -04:00
Paul
ff1c1e0c59 fix: error when viewing versions if plural label is set as a function (#8213) 2024-09-13 23:55:31 +00:00
Paul
d0bb1c9e60 fix(richtext-lexical): default Cell not being a link when used as the primary column in lists (#8212) 2024-09-13 21:17:44 +00:00
Paul
1608150a25 fix(ui): field type being overridden when providing a Cell component (#8211) 2024-09-13 20:16:28 +00:00
Alessio Gravili
fbc28b0249 perf: upgrade ajv, and upgrade typescript to 5.6.2 in monorepo (#8204)
Ajv 8.14.0 => 8.17.1

- Bundle size: 119.6kB => 111kB
- Dependencies: 5 => 4
- Gets rid of dependency on `punycode`. Will help with the annoying
deprecated module console warning spam

This also upgrades TypeScript to 5.6.2 in our monorepo. The most
type-relevant packages are updated as well, e.g. ts-essentials and
@types/node
2024-09-13 17:48:53 +00:00
Alessio Gravili
ec624bd1f2 perf: upgrade jsonwebtoken from 9.0.1 to 9.0.2 (#8202)
The bundle size of the `jsonwebtoken` package has been reduced in this
release. See
https://github.com/auth0/node-jsonwebtoken/blob/master/CHANGELOG.md
2024-09-13 16:33:03 +00:00
Sasha
43a9109b53 fix(db-postgres): preserve parent createdAt when creating a new version (#8160)
## Description

Fixes https://github.com/payloadcms/payload/issues/7915
- [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
2024-09-13 18:41:39 +03:00
Germán Jabloñski
334f940e0c fix(richtext-lexical): unnecessary isEnabled computations on toolbar items (#8176)
Fixes #8170 

- wrapped onActiveChange in useCallback
- removed an unnecessary mouseUp event

Note: I put the console.log for debugging in the useCallback called
updateStates inside
packages/richtext-lexical/src/features/toolbars/shared/ToolbarDropdown/index.tsx.

## Before


https://github.com/user-attachments/assets/07d715d4-f6c7-4a4a-91ab-5de418c909d6

## After


https://github.com/user-attachments/assets/2d404d1c-d1a7-46fd-a5b6-7d01c5c16959
2024-09-13 12:29:10 -03:00
Jarrod Flesch
dd5a9acb60 chore: prevent leave without saving from appearing when not needed (#8200) 2024-09-13 10:48:47 -04:00
Elliot DeNolf
9548961ec9 ci: post-release workflow, comment on releases 2024-09-12 22:43:37 -04:00
Elliot DeNolf
66082d5127 ci: initialize post-release workflow 2024-09-12 22:39:38 -04:00
Victor Winberg
db29e1ec98 fix(graphql): id field non null (#8169)
Resolves #8172

## Summary

This PR addresses an issue where the`id` field in the GraphQL schema is
incorrectly marked as `nullable`. The change ensures that the `id` field
is set to non-nullable, which aligns with the expectation that every
resource should have a non-nullable ID, especially when using UUIDs as
primary keys.

### Changes
- Fix: Set the `id` field type to `GraphQLNonNull` for consistency in
the GraphQL schema.
2024-09-12 17:34:12 -06:00
Paul
d28d40ced3 fix(ui)!: bulk selection and useSelection hook losing types of the IDs its returning (#8194)
This PR changes the type of `selected` returned from the `useSelection`
hook from the `SelectionProvider` from an object to a Map.

This fixes a bug where in some situations we lose the type of the ID
which can break data entry when using postgres, due to keys being cast
to strings inside of objects which doesn't happen when using a Map.

This PR also fixes a CSS bug with the checkbox when it should be
partially selected.

```ts
// before
selected: Record<number | string, boolean>

// after
selected: Map<number | string, boolean>
```

This means you now need to read the data differently than before.

```ts
// before
Object.entries(selected).forEach(([key, value]) => {
  // do something
})

// after
for (const [key, value] of selected) {
  // do something
}
```
2024-09-12 16:58:54 -06:00
Jacob Fletcher
a6f13f7330 fix(ui): properly extracts label from field in FieldLabel component (#8190)
Although the `<FieldLabel />` component receives a `field` prop, it does
not use this prop to extract the `label` from the field. This is
currently only an issue when rendering this component directly, such as
within `admin.components.Label`. The label simply won't appear unless
explicitly provided, despite it being passed as `field.label`. This is
not an issue when rendering field components themselves, because they
properly thread this value through as a top-level prop.

Here's an example of the issue:

```tsx
import type { TextFieldLabelServerComponent } from 'payload'

import { FieldLabel } from '@payloadcms/ui'
import React from 'react'

export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => {
  return (
    <FieldLabel
      field={clientField}
      label={clientField.label} // this should not be needed!
    />
  )
}
```

Here is the end result:

```tsx
import type { TextFieldLabelServerComponent } from 'payload'

import { FieldLabel } from '@payloadcms/ui'
import React from 'react'

export const MyCustomLabelComponent: TextFieldLabelServerComponent = ({ clientField }) => {
  return <FieldLabel field={clientField} />
}
```
2024-09-12 14:45:17 -04:00
Florian Quiblier
532e4b52fe docs: removes type keyword from useFormFields import (#8091) 2024-09-12 16:38:14 +00:00
Christoffer Hasselberg
59b6107e2d docs: fixes getPayloadHMR import path (#8180) 2024-09-12 12:33:22 -04:00
Jacob Fletcher
c28618b19c fix: requires client field prop in server field components (#8188)
Fixes a type error when using server components for field labels,
descriptions, and errors. The `clientField` prop will always exist, so
the types just need to be reflective of this. Here's an example:

```tsx
import type { TextFieldServerLabelComponent } from 'payload'

import { FieldLabel } from '@payloadcms/ui'
import React from 'react'

export const MyServerFieldLabelComponent: TextFieldServerLabelComponent = ({ clientField }) => {
  return <FieldLabel field={clientField} /> // `TextFieldClientWithoutType | undefined` is not assignable to type `ClientFieldWithoutType`
}
```
2024-09-12 12:15:26 -04:00
Elliot DeNolf
945d9192a1 chore(deps): bump turbo 2024-09-12 09:11:50 -04:00
Elliot DeNolf
dbf2301a61 chore(release): v3.0.0-beta.104 [skip ci] 2024-09-12 09:05:20 -04:00
Dan Ribbens
c34401dc4b test: uploads return correct content type headers (#8182) 2024-09-12 11:21:10 +00:00
Patrik
6e94884d18 fix(ui): properly retrieves singular labels for array field rows (#8171)
## Description

`singular` labels were not being used for array rows - this PR updates
the array field to properly retrieve the correct label

- [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
2024-09-11 15:58:05 -04:00
Jacob Fletcher
8b307012f3 feat: passes client field config to server components (#8166)
## Description

### TL;DR:

It's currently not possible to render our field components from a server
component because their `field` prop is the original field config, not
the _client_ config which our components require. Currently, the `field`
prop passed into custom fields changes type depending on whether it's a
server or client component, leaving server components without any access
to the client field config or mechanism to acquire it.

This PR passes the client config to all server field components through
a new `clientField` prop. This allows the following in a server
component, which is very similar to how client field components
currently work:

Server component:

```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'

export const MyCustomServerField: TextFieldServerComponent = ({ clientField }) => {
  return <TextField field={clientField} />
}
```

Client component:

```tsx
'use client'
import { TextField } from '@payloadcms/ui'
import type { TextFieldClientComponent } from 'payload'

export const MyCustomClientField: TextFieldClientComponent = ({ field }) => {
  return <TextField field={field} />
}
```

### Full Background

If you have a custom field component, and it's a server component, there
is currently no way to pass the field prop into Payload's client-side
field components.

Here's an example of the problem:

```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'

import React from 'react'

export const MyServerComponent: TextFieldServerComponent = (props) => {
  const { field } = props

  return (
    <TextField field={field} /> // This is not possible
  )
}
```

The config needs to be transformed into a client config, however,
because of the sheer number of hard-to-find arguments that the
`createClientField` requires, we cannot use it in its raw form.

Here is another example of the problem:

```tsx
import { TextField } from '@payloadcms/ui'
import { createClientField } from '@payloadcms/ui/utilities/createClientField'
import type { TextFieldServerComponent } from 'payload'

import React from 'react'

export const MyServerComponent: TextFieldServerComponent = ({ createClientField }) => {
  const clientField = createClientField({...}) // Not a good option bc it requires many hard-to-find args

  return (
    <TextField field={clientField} />
  )
}
```

Theoretically, we could preformat a `createFieldConfig` function so it
can simply be called without arguments:

```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'

import React from 'react'

export const MyServerComponent: TextFieldServerComponent = ({ createClientField }) => {
  return <TextField field={createClientField()} />
}
```

But this means the field config would be evaluated twice unnecessarily,
including label functions, etc.

The right way to fix this is to simply pass the client config to server
components through a new `clientField` prop:

```tsx
import { TextField } from '@payloadcms/ui'
import type { TextFieldServerComponent } from 'payload'

import React from 'react'

export const MyServerComponent: TextFieldServerComponent = ({ clientField }) => {
  return <TextField field={clientField} />
}
```

- [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] New feature (non-breaking change which adds functionality)

## Checklist:

- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-09-11 15:47:56 -04:00
Paul
9561aa3f79 fix(templates): website media staticDir to public folder (#8175) 2024-09-11 18:37:55 +00:00
Jacob Fletcher
51bc8b4416 feat: document drawer controls (#7679)
## Description

Currently, you cannot create, delete, or duplicate documents within the
document drawer directly. To create a document within a relationship
field, for example, you must first navigate to the parent field and open
the "create new" drawer. Similarly (but worse), to duplicate or delete a
document, you must _navigate to the parent document to perform these
actions_ which is incredibly disruptive to the content editing workflow.
This becomes especially apparent within the relationship field where you
can edit documents inline, but cannot duplicate or delete them. This PR
supports all document-level actions within the document drawer so that
these actions can be performed on-the-fly without navigating away.

Inline duplication flow on a polymorphic "hasOne" relationship:


https://github.com/user-attachments/assets/bb80404a-079d-44a1-b9bc-14eb2ab49a46

Inline deletion flow on a polymorphic "hasOne" relationship:


https://github.com/user-attachments/assets/10f3587f-f70a-4cca-83ee-5dbcad32f063

- [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] New feature (non-breaking change which adds functionality)

## 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
2024-09-11 14:34:03 -04:00
Paul
ec3730722b feat(drizzle): add support for in and not_in operators on json field (#8148)
Closes https://github.com/payloadcms/payload/issues/7952

Adds support for `in` and `not_in` operator against JSON field filters.

The following queries are now valid in postgres as well, previously it
only worked in mongo

```ts
await payload.find({
  collection: 'posts',
  where: {
    'data.value': {
      in: ['12', '13', '14'],
    },
  },
  context: {
    disable: true,
  },
})


await payload.find({
  collection: 'posts',
  where: {
    'data.value': {
      not_in: ['12', '13', '14'],
    },
  },
  context: {
    disable: true,
  },
})
```
2024-09-11 11:11:13 -06:00
Jacob Fletcher
465e47a219 fix!: properly names BlocksField and related types (#8174)
The `BlockField` type is not representative of the underlying "blocks"
field type, which is plural, i.e. `BlocksField`. This is a semantic
change that will better align the type with the field.

## Breaking Changes

Types related to the `blocks` field have change names. If you were using
the `BlockField` or related types in your own applications, simply
change the import name to be plural and instead of singular.

Old (singular):

```ts
import type {
  BlockField,
  BlockFieldClient,
  BlockFieldValidation,
  BlockFieldDescriptionClientComponent,
  BlockFieldDescriptionServerComponent,
  BlockFieldErrorClientComponent,
  BlocksFieldErrorServerComponent,
  BlockFieldLabelClientComponent,
  BlockFieldLabelServerComponent,
} from 'payload'
```

New (plural):

```ts
import type {
  BlocksField,
  BlocksFieldClient,
  BlocksFieldValidation,
  BlocksFieldDescriptionClientComponent,
  BlocksFieldDescriptionServerComponent,
  BlocksFieldErrorClientComponent,
  BlocksFieldErrorServerComponent,
  BlocksFieldLabelClientComponent,
  BlocksFieldLabelServerComponent,
} from 'payload'
```
2024-09-11 16:05:03 +00:00
Hampus Wallentin Olsen
043bf95a70 fix(cpa): match vercel postgres db type with package name (#8141)
## Description

Fixes the bug I reported in
https://github.com/payloadcms/payload/issues/8139 where the casing of
the defined value (camelCase) of Vercel's Postgres database adapter does
not match the casing of the package (kebab-case).
2024-09-11 09:47:09 -06:00
Germán Jabloñski
cd734b0f98 fix(ui): fix row width bug (#7940)
Closes https://github.com/payloadcms/payload/issues/7867

Problem: currently, setting an 

```ts
admin: {
   width: '30%'
}
```

does not work for fields inside a row or similar (group, array etc.)

Solution: when we render the field, we set a CSS variable
`--field-width` with the value of `admin.width`. This allows us to
calculate the correct width for a field in CSS by doing `flex: 0 1
var(--field-width);`

It also allows us to properly handle `gap` with `flex-wrap: wrap;`

Notes: added playwright tests to ensure widths are correctly rendered


![image](https://github.com/user-attachments/assets/0c0f11fc-2387-4f01-9298-a2613fceee22)
2024-09-11 12:36:54 -03:00
Elliot DeNolf
6e61431ca1 chore(release): v3.0.0-beta.103 [skip ci] 2024-09-11 09:04:49 -04:00
Paul
663e5119b2 fix: useAsTitle validation now accounts for default and base fields (#8165) 2024-09-11 03:52:52 +00:00
Jacob Fletcher
8fe6ffd39b feat(examples): adds custom components example (#8162) 2024-09-10 22:48:52 -04:00
Sasha
0118bce582 fix(next): set the user data before redirect after login (#8135)
## Description

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

- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-09-10 19:04:42 +00:00
Jarrod Flesch
46707e4c5e chore: update lexical docs links 2024-09-10 14:11:11 -04:00
Sasha
a234092b34 fix: upload.defParamCharset: utf8 by default (#8157)
## Description

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

This has been confusing for people from countries where characters
aren't latin, for example the Japanese file name:
フェニックス.png
Turns into:
 ãã§ããã¯ã¹.png  

Additionally, ensures type-safety for `DEFAULT_OPTIONS` and removes
unused `fileHandler` property from there, which isn't defined in the
`FetchAPIFileUploadOptions` type.

## Type of change

<!-- Please delete options that are not relevant. -->

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

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-10 17:40:44 +00:00
Germán Jabloñski
281c80d2c7 fix(richtext-lexical): hover style of the button to remove blocks (#8154)
## Description

Fix #8045

Before: hover with same color as background, as in the issue
description.

After (light):
![Screenshot 2024-09-10 at 9 36
21 AM](https://github.com/user-attachments/assets/260dbc69-a583-42f6-9b25-a81b8d8d4f70)

After (dark):
![Screenshot 2024-09-10 at 9 35
34 AM](https://github.com/user-attachments/assets/3606ee3c-24d6-43dd-8a0e-11d12e1fe779)


- [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] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-09-10 11:47:05 -03:00
Jacob Fletcher
12a30a0585 fix: extends server props onto field component types (#8155) 2024-09-10 10:42:22 -04:00
Sasha
0c563ebd73 fix(db-postgres): querying on array wtihin a relationship field (#8152)
## Description

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

- [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

<!-- Please delete options that are not relevant. -->

- [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
2024-09-10 08:44:38 -04:00
Bruno Crosier
82a684138a Merge branch 'beta' of https://github.com/payloadcms/payload into fix-row-field-width 2024-09-09 23:32:25 +01:00
Elliot DeNolf
df023a52fd chore(release): v3.0.0-beta.102 [skip ci] 2024-09-09 17:07:31 -04:00
Dan Ribbens
d267cad482 fix: beforeDuplicate localized blocks and arrays (#8144)
fixes #7988
2024-09-09 21:02:56 +00:00
Germán Jabloñski
fa38dfc16c fix(richtext-lexical): indent regression (#8138)
## Description

Fixes #8038, which was broken in #7817

I'm not entirely sure if this change violates the original intent of the
"base" utility, which from what I understand was introduced for
scalability reasons. Either way, I think it's a good idea to keep the
indent at 40px all the time.

The reason for this is that browsers use 40px as the indentation setting
for lists, and using that setting the indented paragraphs and headings
match the lists. See https://github.com/facebook/lexical/pull/4025

- [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-09-09 20:48:05 +00:00
Jacob Fletcher
8e1a5c8dba feat!: explicitly types field components (#8136)
## Description

Currently, there is no way of typing custom server field components.
This is because internally, all field components are client components,
and so these were never fully typed. For example, the docs currently
indicate for all custom fields to be typed in this way:

Old:
    
```tsx
export const MyClientTextFieldComponent: React.FC<TextFieldProps>
```

But if your component is a server component, you will never receive the
fully typed `field` prop, `payload` prop, etc. unless you've typed that
yourself using some of the underlying utilities. So to fix this, every
field now explicitly exports a type for each environment:

New:

- Client component:
    ```tsx
    'use client'
    export const MyClientTextFieldComponent: TextFieldClientComponent
    ```

- Server component:
    ```tsx
    export const MyServerTextFieldComponent: TextFieldServerComponent
    ```

This pattern applies to every field type, where the field name is
prepended onto the component type.

```ts
import type {
  TextFieldClientComponent,
  TextFieldServerComponent,
  TextFieldClientProps,
  TextFieldServerProps,
  TextareaFieldClientComponent,
  TextareaFieldServerComponent,
  TextareaFieldClientProps,
  TextareaFieldServerProps,
  // ...and so on for each field type
} from 'payload'
```

## BREAKING CHANGES

We are no longer exporting `TextFieldProps` etc. for each field type.
Instead, we now export props for each client/server environment
explicitly. If you were previously importing one of these types into
your custom component, simply change the import name to reflect your
environment.

Old:

```tsx
import type { TextFieldProps } from 'payload'
``` 

New:

```tsx
import type { TextFieldClientProps, TextFieldServerProps } from 'payload'
``` 

Related: #7754. 

- [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] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## Checklist:

- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-09-09 20:15:10 +00:00
Germán Jabloñski
67e1d6abc5 fix hover block remove button 2024-09-09 17:07:30 -03:00
Elliot DeNolf
a8c60c1c02 chore(release): v3.0.0-beta.101 [skip ci] 2024-09-09 16:04:45 -04:00
James Mikrut
d44fb2db37 fix: #6800, graphql parallel queries with different fallback locales (#8140)
## Description

Fixes #6800 where parallel GraphQL queries with different locales /
fallbackLocales do not return their data properly.
2024-09-09 16:01:58 -04:00
Bruno Crosier
3a61d8d656 fix 2024-09-09 20:01:49 +01:00
Bruno Crosier
d04f6ab2bf fix test 2024-09-09 19:42:23 +01:00
Dan Ribbens
852f9fc1fd fix!: multiple preferences for the same user and entry (#8100)
fixes #7762

This change mitigates having multiple preferences for one user but not
awaiting the change to a preference and reduces querying by skipping the
access control. In the event that a user has multiple preferences with
the same key, only the one with the latest updatedAt will be returned.

BREAKING CHANGES:
- payload/preferences/operations are no longer default exports

## Description

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [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

<!-- Please delete options that are not relevant. -->

- [ ] Chore (non-breaking change which does not add functionality)
- [x] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-09-09 14:00:51 -04:00
Bruno Crosier
552239b637 fix type errors 2024-09-09 18:53:14 +01:00
Bruno Crosier
37e181a38d pr comments 2024-09-09 18:42:19 +01:00
Dan Ribbens
e2d803800d fix: removes transactions wrapping auth strategies and login (#8137)
## Description

By default all api requests are creating transactions due to the
authentication stategy. This change removes transactions for auth and
login requests. This should only happen when the database needs to make
changes in which case the auth strategy or login lockout updates will
invoke their own transactions still.

This should improve performance without any sacrifice to database
consistency.

Fixes #8092 

- [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

<!-- Please delete options that are not relevant. -->

- [ ] 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

## Checklist:

- [ ] 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
2024-09-09 13:27:21 -04:00
Germán Jabloñski
7fa68d17f5 fix(ui): wrong block indication when an error occurred (#7963) 2024-09-09 10:20:03 -04:00
Paul
9ec431a5bd fix(ui): bulk select checkbox being selected by default when in drawer (#8126) 2024-09-09 06:47:35 +00:00
Paul
cadf815ef6 fix(ui): thumbnails when serverURL config is provided (#8124) 2024-09-09 06:16:43 +00:00
Paul
638382e7fd feat: add validation for useAsTitle to throw an error if it's an invalid or nested field (#8122) 2024-09-08 18:53:12 -06:00
Elliot DeNolf
08fdbcacc0 chore: proper error log format (#8105)
Fix some error log formatting to use `{ msg, err }` properly
2024-09-07 02:48:59 +00:00
Paul
b27e42c484 fix(ui): various issues around documents lists, listQuery provider and search params (#8081)
This PR fixes and improves:
- ListQuery provider is now the source of truth for searchParams instead
of having components use the `useSearchParams` hook
- Various issues with search params and filters sticking around when
navigating between collections
- Pagination and limits not working inside DocumentDrawer
- Searching and filtering causing a flash of overlay in DocumentDrawer,
this now only shows for the first load and on slow networks
- Preferences are now respected in DocumentDrawer
- Changing the limit now resets your page back to 1 in case the current
page no longer exists

Fixes https://github.com/payloadcms/payload/issues/7085
Fixes https://github.com/payloadcms/payload/pull/8081
Fixes https://github.com/payloadcms/payload/issues/8086
2024-09-06 15:51:09 -06:00
Tylan Davis
32cc1a5761 fix(ui): missing thumbnail for non-image files in bulk upload sidebar (#8102)
## Description

Uses the `Thumbnail` component used in other places for the bulk upload
file rows. Closes #8099

In the future, we should consider adding different thumbnail icons based
on the `mimeType` to better describe the files being uploaded.

Before:
![Screenshot 2024-09-06 at 4 51
56 PM](https://github.com/user-attachments/assets/35cd528c-5086-465e-8d3c-7bb66d7c35da)


After:
![Screenshot 2024-09-06 at 4 50
12 PM](https://github.com/user-attachments/assets/54d2b98d-ac11-481e-abe5-4be071c3c8f2)


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

- [ ] 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
2024-09-06 21:28:50 +00:00
Tylan Davis
38be69b7d3 fix(ui): better responsiveness for upload fields in sidebar (#8101)
## Description

Adjusts the styling for the Dropzone component for upload fields with
`admin.position: sidebar`.

Before:
![Screenshot 2024-09-06 at 4 10
28 PM](https://github.com/user-attachments/assets/221d43f9-f426-4a44-ba58-29123050c775)

After:
![Screenshot 2024-09-06 at 4 09
32 PM](https://github.com/user-attachments/assets/c4369a65-d842-4e65-9153-19244fcf5600)


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

- [ ] 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
2024-09-06 20:37:38 +00:00
Elliot DeNolf
6b82196f01 chore(release): v3.0.0-beta.100 [skip ci] 2024-09-06 15:25:41 -04:00
Tylan Davis
ead12c8a49 fix(ui, next): adjust modal alignment and padding (#7931)
## Description

Updates styling on modals and auth forms for more consistent spacing and
alignment.

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

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-06 14:54:39 -04:00
Jacob Fletcher
6253ec5d1a fix(ui): optimizes the relationship field by sharing a single document drawer across all values (#8094)
## Description

Currently, the relationship field's _value(s)_ each render and controls
its own document drawer. This has led to `hasMany` relationships
processing a potentially large number of drawers unnecessarily. But the
real problem is when attempting to perform side-effects as a result of a
drawer action. Currently, when you change the value of a relationship
field, all drawers within are (rightfully) unmounted because the
component representing the value was itself unmounted. This meant that
you could not update the title of a document, for example, then update
the underlying field's value, without also closing the document drawer
outright. This is needed in order to support things like creating and
duplicating documents within document drawers (#7679).

- [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] Existing test suite passes locally with my changes
2024-09-06 14:00:53 -04:00
Jacob Fletcher
f9ae56ec88 fix(ui): handles falsey relationship options on reset (#8095) 2024-09-06 12:55:09 -04:00
Sasha
0688c2b79d fix(db-postgres): sanitize tab/group path for table name (#8009)
## Description

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

Example of table structures that lead to the problem with camelCased
group / tab names.
`group_field_array_localized` - `groupField` -> `array` (has a localized
field inside)
`group_field_array_nested_array` - `groupField` -> `array` ->
`nestedArray`

<!-- Please include a summary of the pull request and any related issues
it fixes. Please also include relevant motivation and context. -->

- [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

<!-- Please delete options that are not relevant. -->

- [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
2024-09-06 11:43:47 -04:00
Sasha
c6246618ba fix(cpa): detect package manager from command execution environment (#8087)
Previously, on some machines this command:
`pnpx create-payload-app@beta app` created a project using `npm`,
instead of `pnpm`, the same with `yarn`.

Also, the way we detected the package manager was always prioritizing
`pnpm`, even if they executed the command with `yarn` / `npm`. Now we
are relying only on from which package manager user executed
`create-payload-app`.

The code for detection is grabbed from create-next-app
https://github.com/vercel/next.js/blob/canary/packages/create-next-app/helpers/get-pkg-manager.ts
2024-09-06 08:57:20 -04:00
Alexander
b69826a81e feat(cpa): add support for bun package manager in v3 installer (#7709)
Adds support for bun package manger in v3, enabled with `--use-bun`
flag.

Related: #6932 (for v2)
2024-09-05 23:50:03 -04:00
Paul
e80da7cb75 chore: add jsdocs for authentication types and add missing config to docs (#8082) 2024-09-06 00:04:13 +00:00
Francisco Lourenço
6f512b6ca8 docs: fix TextFieldProps in client field component example (#8080)
## Description

Without using `React.FC<>`, the type needs to be placed on the right
side of the props object.

- [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

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] ~I have added tests that prove my fix is effective or that my
feature works~
- [ ] ~Existing test suite passes locally with my changes~
- [x] I have made corresponding changes to the documentation
2024-09-05 15:41:48 -06:00
Elliot DeNolf
22ee8bf383 chore(release): v3.0.0-beta.99 [skip ci] 2024-09-05 12:38:08 -04:00
Jacob Fletcher
308fad8a7a fix(ui): significantly optimizes relationship field (#8063)
## Description

Reduces the number of client-side requests made by the relationship
field component, and fixes the visual "blink" of the field's value on
initial load. Does so through a new `useIgnoredEffect` hook that allows
this component's effects to be precisely triggered based on whether a
only _subset_ of its dependencies have changed, which looks something
like this:

```tsx
// ...
useIgnoredEffect(() => {
  // Do something
}, [deps], [ignoredDeps])
```

"Ignored deps" are still treated as normal dependencies of the
underlying `useEffect` hook, but they do not cause the provided function
to execute. This is useful if you have a list of dependencies that
change often, but need to scope your effect's logic to explicit
dependencies within that list. This is a typical pattern in React using
refs, just standardized within a reusable hook.

This significantly reduces the overall number of re-renders and
duplicative API requests within the relationship field because the
`useEffect` hooks that control the fetching of these related documents
were running unnecessarily often. In the future, we really ought to
leverage the `RelationshipProvider` used in the List View so that we can
also reduce the number of duplicative requests across _unrelated fields_
within the same document.

Before:


https://github.com/user-attachments/assets/ece7c85e-20fb-49f6-b393-c5e9d5176192

After:


https://github.com/user-attachments/assets/9f0a871e-f10f-4fd6-a58b-8146ece288c4

- [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
2024-09-04 21:37:00 -04:00
Jessica Chowdhury
6427b7eb29 fix: only show restore as draft option when drafts enabled (#8066)
## Description

In version comparison view, the `Restore as draft` button should only be
visible when `versions.drafts: true`.

Before:
<img width="1414" alt="Screenshot 2024-09-04 at 3 33 21 PM"
src="https://github.com/user-attachments/assets/1f96d804-46d7-443a-99ea-7b6481839b47">

After:
<img width="1307" alt="Screenshot 2024-09-04 at 3 38 42 PM"
src="https://github.com/user-attachments/assets/d2621ddd-2b14-4dab-936c-29a5521444de">


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

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-09-04 19:54:34 +00:00
Sasha
3a657847f2 fix(db-postgres): query hasMany text/number in array/blocks (#8003)
## Description

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

- [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
2024-09-04 11:53:43 -04:00
Elliot DeNolf
8212c0d65f chore(eslint): silence some warnings that always get auto-fixed 2024-09-04 11:26:36 -04:00
Elliot DeNolf
772f869cc6 chore(release): v3.0.0-beta.98 [skip ci] 2024-09-03 12:59:23 -04:00
Alessio Gravili
b6a8d1c461 perf(richtext-lexical)!: greatly simplify lexical loading and improve performance (#8041)
We noticed that we can bring functions down to the client directly
without having to wrap them in a component first. This greatly
simplifies the loading of all lexical client components

**BREAKING:**
- `createClientComponent` is no longer exported as it's not needed
anymore
- The exported `ClientComponentProps` type has been renamed to
`BaseClientFeatureProps`.
- The order of arguments in `sanitizeClientEditorConfig` has changed
2024-09-03 12:48:41 -04:00
Elliot DeNolf
11576eda13 ci: adjust label pr on open [skip ci] (#8043) 2024-09-03 11:38:21 -04:00
Elliot DeNolf
3c62e6c772 chore(eslint): lint entire codebase including db packages (#8042) 2024-09-03 11:22:41 -04:00
Alessio Gravili
5b74879c5e chore: add lint commit to .git-blame-ignore-revs 2024-09-03 11:20:26 -04:00
Alessio Gravili
7fd736ea5b chore: lint entire codebase including db packages 2024-09-03 11:19:19 -04:00
Germán Jabloñski
7a3507d597 fix(richtext-lexical): toolbar styles (#7936)
fix https://github.com/payloadcms/payload/issues/7925.

The `active` style was not effective due to a typo in the CSS (`them`
instead of `theme`).

I took the opportunity to improve a few things:
- Now the colors on hover, active, and hover+active are slightly
different.
- Added a missing gap to the fixed toolbar buttons.

Gap changes: Before:
![CleanShot 2024-09-03 at 00 02
52@2x](https://github.com/user-attachments/assets/2381468c-7bdd-43f6-93b6-5baa587dd0a6)

After:
![CleanShot 2024-09-03 at 00 01
22@2x](https://github.com/user-attachments/assets/53d0cac9-9718-4b97-a478-f249b10d416e)


Thanks @tylandavis for the help!
2024-09-03 00:04:12 -04:00
Bruno Crosier
ef6fe9ca9a review comments 2024-09-02 23:52:04 +01:00
Paul
9bcdf0dc81 fix(plugin-seo): meta image selection not working (#8024)
Fixes https://github.com/payloadcms/payload/issues/8016
2024-09-02 05:11:27 +00:00
Paul
8203fe86cd fix: padding on the right of the default padding when scrollbars are enabled in the browser (#8023) 2024-09-02 04:22:02 +00:00
Elliot DeNolf
39cd8283c8 chore(scripts): release notes emoji 2024-09-01 19:39:52 -04:00
Giuseppe Chiruzzi
1130a581c0 feat(plugin-seo): add Italian translations (#8020)
Added italian translation and updated index.ts
2024-09-01 23:03:12 +00:00
Riley Pearce
d9cccc7081 fix(richtext-lexical): incorrect error check in TableActionMenu (#7964)
Fixes #7961 and #8021
2024-09-01 18:29:02 -04:00
Bruno Crosier
053256d5ce more tests and better implementation 2024-08-31 23:58:20 +01:00
Elliot DeNolf
751803d4f4 chore(cpa): get templates using tar (#8006)
Remove `degit` in favor of tar files from codeload.

Degit is rather dated and has unfixed bugs such as #5402  and #7463 .
2024-08-30 22:51:32 -04:00
Paul
ee3d5856e3 fix: collection pagination limits being merged with defaults instead of overidden (#8004) 2024-08-30 23:29:20 +00:00
Paul
cf9e13aebb fix(ui): radio fields are now selectable as options in filtering in query builder (#8002) 2024-08-30 23:04:31 +00:00
Elliot DeNolf
9816787fbf chore: remove all unused imports (#7999)
Removes all unused imports.

Temporarily swapped in
https://github.com/sweepline/eslint-plugin-unused-imports to
differentiate between unused imports and unused vars. The default rule
does not differentiate.
2024-08-30 16:52:08 -04:00
Alessio Gravili
b5fb92530c chore(eslint): change no-empty-object-type to warn instead of error (#7998) 2024-08-30 20:29:06 +00:00
Elliot DeNolf
2c1c0dae70 chore(release): eslint/3.0.0-beta.97 2024-08-30 16:11:29 -04:00
Paul
9295a6130e chore(templates): bump versions to just beta instead of pinned (#7997) 2024-08-30 19:30:06 +00:00
Paul
91fc5fb31b chore(templates): update folder structure for seed script in website template (#7995) 2024-08-30 19:14:03 +00:00
Paul
e25730f95c fix(ui): list view crash when using a code field type (#7994) 2024-08-30 12:47:33 -06:00
Elliot DeNolf
7f6b0f087f chore(release): v3.0.0-beta.97 [skip ci] 2024-08-30 14:21:21 -04:00
Paul
c1533bfd3e fix(templates): add button to exit preview mode (#7991) 2024-08-30 17:44:11 +00:00
Elliot DeNolf
442d105841 fix: migrations exit code (#7989)
Migration command were not returning proper error codes on failure. This
caused issues with CI in particular.

Fixes #7031 for 3.0
2024-08-30 16:37:39 +00:00
Elliot DeNolf
c45ee0d26b ci: add drizzle as valid pr title scope [skip ci] 2024-08-30 12:25:24 -04:00
Jarrod Flesch
b97dcc33c7 chore: hoist selection provider (#7985) 2024-08-30 11:02:58 -04:00
Elliot DeNolf
8202c3dee8 feat: move logger configuration to Payload config (#7973)
Removes `loggerOptions` and `loggerDestination` from `initOptions`
(these were not able to be used anyway).

Creates new `logger` property on the Payload config.

```ts
// Logger options only
logger: {
   level: 'info',
}

// Logger options with destination stream
logger: {
   options: {
   level: 'info',
   },
   destination: process.stdout
},

// Logger instance
logger: pino({ name: 'my-logger' })
```
2024-08-30 09:37:51 -04:00
Paul
b6ae6890aa fix(ui): upload field not showing admin.description (#7978) 2024-08-30 04:22:43 +00:00
Elliot DeNolf
c14dbfba40 build: bump nodejs (#7935)
Bumped to 22.6.0
2024-08-29 23:46:06 -04:00
Elliot DeNolf
0a36529dc5 build(deps): bump node.js to 22.7.0 2024-08-29 23:29:40 -04:00
Paul
e033488db7 fix(nested-docs-plugin): throw an error to the UI if children are not passing validation (#7977) 2024-08-30 02:48:38 +00:00
Paul
90b3e83fc2 feat(templates): update website src directory structure (#7971) 2024-08-30 02:41:02 +00:00
Elliot DeNolf
76dda13ca1 chore: significantly improve test suite eslint performance, lint and prettier everything (#7975)
Linting test/admin beta: > 3 minutes (stopped counting after 3 min)
Linting test/admin after my PR: 8s

Linting ui beta: 18s
Linting ui after my PR:  18s
2024-08-29 22:13:05 -04:00
Paul
e071382a79 fix(ui): upload with has many bulk select not working with postgres (#7976)
Fixes https://github.com/payloadcms/payload/issues/7921
2024-08-30 02:01:38 +00:00
Alessio Gravili
131f2def3c chore: undo lint changes to db-* and drizzle 2024-08-29 22:01:37 -04:00
Alessio Gravili
d97cd2fd5d chore: add lint commit to .git-blame-ignore-revs 2024-08-29 21:36:33 -04:00
Alessio Gravili
86fdad0bb8 chore: significantly improve eslint performance, lint and prettier everything 2024-08-29 21:25:50 -04:00
Alessio Gravili
bc367ab73c chore(eslint): upgrade to typescript-eslint v8, upgrade all eslint packages (#7082) 2024-08-29 16:27:58 -04:00
Jacob Fletcher
c0728220ff fix(ui): propagates sort change events through list query provider (#7968) 2024-08-29 13:18:05 -04:00
Jacob Fletcher
6893f404ac chore: removes duplicative loop over column state to determine linked cells (#7958) 2024-08-29 12:35:51 -04:00
Elliot DeNolf
2a8bd4c775 chore(release): v3.0.0-beta.96 [skip ci] 2024-08-29 11:25:10 -04:00
James Mikrut
ac10bad723 fix(db-postgres): nested localized arrays (#7962)
## Description

Fixes a bug with nested arrays within either localized blocks or arrays.
2024-08-29 15:01:53 +00:00
Elliot DeNolf
142616e6ad chore(eslint): curly [skip-lint] (#7959)
Now enforcing curly brackets on all if statements. Includes auto-fixer.


```ts
//  Bad
if (foo) foo++;

//  Good
if (foo) {
  foo++;
}
```




Note: this did not lint the `drizzle` package or any `db-*` packages.
This will be done in the future.
2024-08-29 10:15:36 -04:00
Jarrod Flesch
dd3d985091 chore: upload field style fix (#7942) 2024-08-29 00:11:56 -04:00
Jarrod Flesch
de3d7c95e7 fix: prevents duplicate active nav indicators (#7943) 2024-08-29 00:11:42 -04:00
Elliot DeNolf
570422ff9a chore(db-mongodb): adjust default exports (#7945) 2024-08-29 04:09:44 +00:00
Elliot DeNolf
53c41bdfd8 chore(cpa): unused vars (#7944) 2024-08-29 03:59:44 +00:00
Elliot DeNolf
e5c34ead16 chore: plugin lint fixes (#7947) 2024-08-29 03:59:16 +00:00
Elliot DeNolf
6e561b11ca chore(graphql): adjust default exports (#7946) 2024-08-29 03:51:03 +00:00
Jarrod Flesch
f7146362df chore: brings back tests from has many PR (#7917) 2024-08-28 22:44:58 -04:00
Elliot DeNolf
ec9d1cda2d chore(eslint): lint:fix on all packages (#7941)
- Run `lint:fix` on all packages to fix anything that may have slipped
through without being autofixed
- A few manual fixes as well.
2024-08-29 02:35:17 +00:00
Elliot DeNolf
657326b528 chore(eslint): remove unused .eslintignore files [skip ci] 2024-08-28 22:12:19 -04:00
James Mikrut
538b7ee616 feat!: auto-removes localized property from localized fields within other localized fields (#7933)
## Description

Payload localization works on a field-by-field basis. As you can nest
fields within other fields, you could potentially nest a localized field
within a localized field—but this would be redundant and unnecessary.
There would be no reason to define a localized field within a localized
parent field, given that the entire data structure from the parent field
onward would be localized.

Up until this point, Payload would _allow_ you to nest a localized field
within another localized field, and this might have worked in MongoDB
but it will throw errors in Postgres.

Now, Payload will automatically remove the `localized: true` property
from sub-fields within `sanitizeFields` if a parent field is localized.

This could potentially be a breaking change if you have a configuration
with MongoDB that nests localized fields within localized fields.

## Migrating

You probably only need to migrate if you are using MongoDB, as there,
you may not have noticed any problems. But in Postgres or SQLite, this
would have caused issues so it's unlikely that you've made it too far
without experiencing issues due to a nested localized fields config.

In the event you would like to keep existing data in this fashion, we
have added a `compatibility.allowLocalizedWithinLocalized` flag to the
Payload config, which you can set to `true`, and Payload will then
disable this new sanitization step.

Set this compatibility flag to `true` only if you have an existing
Payload MongoDB database from pre-3.0, and you have nested localized
fields that you would like to maintain without migrating.
2024-08-29 01:56:17 +00:00
Elliot DeNolf
828f5d866d build(scripts): add lint scripts to all, turbo lint tasks [skip ci] 2024-08-28 21:55:51 -04:00
Bruno Crosier
efe17ff5e4 fix(row): set max-width for row 2024-08-29 02:23:54 +01:00
Alessio Gravili
e375f6e727 feat: significantly reduce payload install size by removing unnecessary monaco-editor dependency (#7939)
This reduces the total install size of `payload` from 115 MB to 34 MB. 

We never used monaco-editor within payload - we were only using
`@monaco-editor/react` which is a lot smaller.

Since we expose its types to the end user, we have to add it to our
`dependencies`, not `devDependencies`.

Before:
https://npmgraph.js.org/?q=payload@3.0.0-canary.1a675ae#select=exact%3Apayload%403.0.0-canary.1a675ae&zoom=w

After:
https://npmgraph.js.org/?q=payload%403.0.0-canary.cdb9474#zoom=h&select=exact%3Apayload%403.0.0-canary.cdb9474
2024-08-28 23:24:42 +00:00
Paul
cc9b877e88 fix: improve validation errors for unique fields (#7937) 2024-08-28 16:10:54 -06:00
Alessio Gravili
dc12047723 feat: reduce package size and amount of dependencies by upgrading json-schema-to-typescript (#7938)
Closes https://github.com/payloadcms/payload/issues/7934
2024-08-28 21:59:32 +00:00
Jarrod Flesch
12fb691e4f chore: upload dropzone style changes (#7932) 2024-08-28 15:49:14 -04:00
Alessio Gravili
0962850086 fix: incorrect config.upload types (#7874)
Fixes https://github.com/payloadcms/payload/issues/7698

Now exporting `FetchAPIFileUploadOptions` from payload, as that type is
now used in `config.upload`.
2024-08-28 15:39:51 -04:00
Elliot DeNolf
78c8bb81a1 chore(release): v3.0.0-beta.95 [skip ci] 2024-08-28 14:49:15 -04:00
Elliot DeNolf
419b274bb1 chore: move ui and translations into deps from peerDeps (#7929)
Move `ui` and `translations` from peerDeps into deps for a few packages.
Users should not have to install these directly unless they are making
customizations.
2024-08-28 14:47:02 -04:00
Alessio Gravili
ef818fd5c8 fix(ui): admin.dependencies components not added to client config (#7928) 2024-08-28 13:56:52 -04:00
Germán Jabloñski
0aaf3af1ea fix(richtext-lexical): enabledCollections and disabledCollections props in RelationshipFeature (#7926)
fixes https://github.com/payloadcms/payload/issues/7379

The enabledCollections and disabledCollections properties of the
RelationshipFeature were not being sent to the client and therefore did
not have the expected effect.

Now those 2 properties are sent to the client via the
`clientFeatureProps` property.
2024-08-28 13:45:10 -04:00
James Mikrut
18b0806b5b fix(db-postgres, db-sqlite): hasMany text, number, poly relationship, blocks, arrays within localized fields (#7900)
## Description

In Postgres, localized blocks or arrays that contain other array / block
/ relationship fields were not properly storing locales in the database.

Now they are! Need to check a few things yet:

- Ensure test coverage is sufficient
- Test localized array, with non-localized array inside of it
- Test localized block with relationship field within it
- Ensure `_rels` table gets the `locale` column added if a single
non-localized relationship exists within a localized array / block

Fixes step 6 as identified in #7805
2024-08-28 17:43:12 +00:00
Jacob Fletcher
3d9051ad34 test: extracts reorderColumns e2e util for reuse (#7923) 2024-08-28 12:20:47 -04:00
Jarrod Flesch
e4ef47b938 chore(examples): multi tenant single domain fixes (#7922) 2024-08-28 11:34:22 -04:00
Alessio Gravili
c7e7dc71d3 fix(richtext-lexical): ensure html converter text is escaped (#7919) 2024-08-28 14:31:06 +00:00
Jarrod Flesch
375671c162 fix: active nav item set incorrectly in child routes (#7918) 2024-08-28 10:00:13 -04:00
Elliot DeNolf
23b495b145 build: update turborepo npm scripts (#7899)
Updating all turborepo npm scripts for this rather inconvenient breaking
change: https://github.com/vercel/turborepo/pull/8137
2024-08-27 22:04:05 -04:00
Paul
27d743e2a8 fix: depth not being respected by upload has many (#7897) 2024-08-28 00:50:29 +00:00
Elliot DeNolf
8c9ff3d54b revert(scripts): publish script progress prefix 2024-08-27 19:53:15 -04:00
Elliot DeNolf
5c447252e7 chore(release): v3.0.0-beta.94 [skip ci] 2024-08-27 19:47:37 -04:00
Jarrod Flesch
a76be81368 fix: upload has many field updates (#7894)
## Description

Implements fixes and style changes for the upload field component.

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

![CleanShot 2024-08-27 at 16 22
33](https://github.com/user-attachments/assets/fa27251c-20b8-45ad-9109-55dee2e19e2f)

![CleanShot 2024-08-27 at 16 22
49](https://github.com/user-attachments/assets/de2d24f9-b2f5-4b72-abbe-24a6c56a4c21)


- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] 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

## Checklist:

- [ ] 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

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-08-27 19:07:18 -04:00
Paul
5d97d57e70 feat(templates): add new slug component to the website (#7895)
https://github.com/user-attachments/assets/1ba125d3-9c65-4bab-98df-fb80c70eeb71
2024-08-27 22:26:56 +00:00
Alessio Gravili
de7ff1f8c6 fix(richtext-lexical): html converters can populate relationships infinitely (#7890)
Fixes https://github.com/payloadcms/payload/issues/7743
2024-08-27 15:24:50 -04:00
James Mikrut
3d714d3e72 fix: locale selector + autosave race condition (#7891)
## Description

Fixes a race condition where you could switch locales and have autosave
trigger with old locale data.

By adding the `key` to the `Document` component, we will ensure that the
entire `Document` will be un-mounted and re-mounted between locale
switches.
2024-08-27 14:56:28 -04:00
Elliot DeNolf
2bbb02b9c0 chore(scripts): add package count to publish script [skip ci] 2024-08-27 14:41:47 -04:00
Elliot DeNolf
0533e7f5db chore(release): v3.0.0-beta.93 [skip ci] 2024-08-27 14:16:30 -04:00
Paul
23c5ef428d fix: bugs in versions UI with perPage, pagination and diffs not showing for tabs. publish button no longer double saves when using keyboard (#7889)
Fixes:
- issue with publish button double saving on keyboard command
- versions diffs not showing if fields are tabs
https://github.com/payloadcms/payload/issues/7860
- navigation on versions not working for perPage and pagination
2024-08-27 17:45:30 +00:00
Alessio Gravili
f046a04510 fix(richtext-lexical): dependency checker suggesting incorrect version (#7888)
Fixes this:
https://discord.com/channels/967097582721572934/1278031296970625190/1278031652089757818
2024-08-27 17:17:19 +00:00
Elliot DeNolf
4cda7d2363 chore(release): v3.0.0-beta.92 [skip ci] 2024-08-27 09:44:02 -04:00
Elliot DeNolf
ea48cfbfe9 feat: implement info command (#7882)
Implements `info` command similar to Next.js.

`pnpm payload info` will output info in this format:

```
Binaries:
  Node: 18.20.2
  npm: 10.5.0
  Yarn: 1.22.19
  pnpm: 9.7.0
Relevant Packages:
  payload: 3.0.0-beta.91
  next: 15.0.0-canary.104
  @payloadcms/db-mongodb: 3.0.0-beta.91
  @payloadcms/db-postgres: 3.0.0-beta.91
  @payloadcms/email-nodemailer: 3.0.0-beta.91
  @payloadcms/graphql: 3.0.0-beta.91
  @payloadcms/next/utilities: 3.0.0-beta.91
  @payloadcms/plugin-cloud: 3.0.0-beta.91
  @payloadcms/richtext-lexical: 3.0.0-beta.91
  @payloadcms/richtext-slate: 3.0.0-beta.91
  @payloadcms/translations: 3.0.0-beta.91
  @payloadcms/ui/shared: 3.0.0-beta.91
  react: 19.0.0-rc-06d0b89e-20240801
  react-dom: 19.0.0-rc-06d0b89e-20240801
Operating System:
  Platform: darwin
  Arch: arm64
  Version: Darwin Kernel Version 23.6.0: Mon Jul 29 21:13:04 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6020
  Available memory (MB): 32768
  Available CPU cores: 12
 ```
2024-08-27 01:41:39 +00:00
Paul
1aeb912762 fix(templates): website live preview and code block (#7881) 2024-08-26 23:42:45 +00:00
Paul
ce2cb35d71 fix(plugin-seo): remove dependency on import from payload/next package (#7879) 2024-08-26 22:40:38 +00:00
Paul
d3ec68ac2f fix: error when closing the live preview popup window (#7878) 2024-08-26 22:33:56 +00:00
Paul
05bf52aac3 fix(templates): website bug fixes for slug generation and form builder and adds support for strictNullChecks: true (#7877) 2024-08-26 22:10:09 +00:00
Jacob Fletcher
fed7f2fa5b fix: sanitizes modifyResponseHeaders from client config (#7876) 2024-08-26 21:50:29 +00:00
James Mikrut
686b0865b2 fix: exports richtext-slate useSlatePlugin (#7875)
## Description

exports `useSlatePlugin` for `richtext-slate`
2024-08-26 17:21:25 -04:00
Alessio Gravili
dfb4c8eb4c feat: add nextjs and react version checks to dependency checker (#7868) 2024-08-26 17:19:14 -04:00
Alessio Gravili
ad7a387e19 feat(richtext-lexical): more lenient url validation, URL-encode invalid urls on save (#7870)
Fixes https://github.com/payloadcms/payload/issues/7477

This simplifies validation to the point where it only errors on spaces.
Actual validation is then used in beforeChange, which then automatically
url encodes the input if it doesn't pass
2024-08-26 15:33:29 -04:00
Elliot DeNolf
d05be016ce ci(scripts): emoji release notes 2024-08-23 16:25:50 -04:00
Elliot DeNolf
ec3bb71e7c chore(release): v3.0.0-beta.91 [skip ci] 2024-08-23 16:13:30 -04:00
Elliot DeNolf
825d8b83d1 feat(templates): add vercel postgres template (#7841)
- docs: add db-vercel-postgres info
- feat: update template variations
2024-08-23 15:17:26 -04:00
Alessio Gravili
83022f6d55 feat: enable react compiler for @payloadcms/next package (#7839)
also upgrades esbuild and react compiler packages
2024-08-23 18:01:21 +00:00
Alessio Gravili
4bbc593dc5 chore: hide node deprecation warnings in monorepo (#7837) 2024-08-23 12:33:21 -04:00
Jacob Fletcher
03440f5eca fix(next): properly 404s not found documents (#7833) 2024-08-23 14:59:03 +00:00
Elliot DeNolf
0fa6611260 fix: trim down accepted args of getPayloadHMR (#7834)
`getPayloadHMR`'s arg type was accepting unnecessary args that did not
do anything. This was leading to confusion.

This PR trims down the accepted type.

Fixes #7832
2024-08-23 14:54:20 +00:00
Tylan Davis
a2d68f84e1 chore(richtext-*): improved rich text editor styles and interaction (#7817)
## Description

- Improves the standard typography styles of the rich text editors.
- Improve styles of Lexical relationship, inline-relationship, upload,
and blocks features.
- Improves drag and drop interaction for Lexical.
- Adds a dark mode style for Lexical inline toolbar, floating link editor,
and slash menu.

- [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

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] 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
2024-08-23 14:50:53 +00:00
Jarrod Flesch
49c0709fed fix: collapsible toggle hover stacking issue (#7812) 2024-08-23 08:51:10 -04:00
Elliot DeNolf
350a4a0718 build(deps): update turborepo (#7827)
Updates turbo to v2.
2024-08-23 03:00:21 +00:00
Alessio Gravili
6349cd42e9 feat(richtext-lexical): improve upload and relationship node types (#7822)
Fixes https://github.com/payloadcms/payload/issues/7808. The types are
now accurate. Previously, they would assume that upload and relationship
nodes are never populated
2024-08-22 22:05:45 +00:00
Alessio Gravili
c2b2f10676 fix: weaken JsonObject type to allow types from payload-types being assigned to it (#7815)
This fixes that type in the website template:
3d86bf1974/templates/website/src/app/components/RichText/serialize.tsx (L24)

Now, JsonObject still ensures that only objects can be passed, but it's
weak enough to allow non-dynamic types like the ones we generate in
payload-types.

The "JSON" part of this type has no meaning anymore, as it does allow
objects with functions now. However, we can still use it to signal to
the user that this should be JSON-serializable. It's more clear than
just using Record<string, unknown>
2024-08-22 20:24:58 +00:00
Paul
95ebead464 feat(ui): add styling for no docs and clear all on hasmany upload (#7816) 2024-08-22 18:54:35 +00:00
Jacob Fletcher
3eed8b11cb fix(ui): relationship field "add new" button styling (#7814) 2024-08-22 14:55:36 +00:00
Dan Ribbens
404008dc4e chore: fix dev importmap for windows (#7811) 2024-08-22 09:55:55 -04:00
Elliot DeNolf
c7c6fca537 chore(eslint): remove fixable from no-imports-from-self [skip ci] 2024-08-22 09:36:17 -04:00
Ritsu
9de3ffdcfe chore(ui): expose useCollapsible hook (#7807)
Exposes `useCollapsible` hook from `@payloadcms/ui`
2024-08-22 04:11:18 +00:00
Alessio Gravili
1eefb12070 fix(richtext-lexical): slate => lexical migrator improvements (#7802) 2024-08-22 00:09:43 -04:00
Elliot DeNolf
2d8b752ef2 chore(release): v3.0.0-beta.90 [skip ci] 2024-08-21 22:58:28 -04:00
Elliot DeNolf
3e5c31a024 chore(scripts): add db-vercel-postgres to publish list 2024-08-21 22:55:29 -04:00
Elliot DeNolf
631431e006 feat: @payloadcms/db-vercel-postgres adapter (#7806)
Dedicated adapter for Vercel Postgres

- Uses the `@vercel/postgres` package under the hood.
- No `pg` dependency, speeds up invocation
- Includes refactoring all base postgres functionality into a
`BasePostgresAdapter` type, which will ease implementation of [other
adapters supported by
drizzle-orm](https://orm.drizzle.team/docs/get-started-postgresql)

## Usage

```ts
import { buildConfig } from 'payload'
import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres'

export default buildConfig({
  db: vercelPostgresAdapter({
    pool: {
      connectionString: process.env.DATABASE_URI,
    },
  }),
  // ...rest of config
})
```

### Automatic Connection String Detection

Have Vercel automatically detect from environment variable (typically
`process.env.POSTGRES_URL`)

```ts
export default buildConfig({
  db: postgresAdapter(),
  // ...rest of config
})
```
2024-08-21 22:54:47 -04:00
Paul
492d920133 fix(ui): upload has many no rows error (#7804) 2024-08-21 22:52:20 -04:00
Elliot DeNolf
f754edc375 chore(release): v3.0.0-beta.89 [skip ci] 2024-08-21 20:54:18 -04:00
Paul
d2571e10d6 feat: upload hasmany (#7796)
Supports `hasMany` upload fields, similar to how `hasMany` works in
other fields, i.e.:

```ts
{
  type: 'upload',
  relationTo: 'media',
  hasMany: true
}
```

---------

Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-08-21 20:44:04 -04:00
Alessio Gravili
a687cb9c5b Merge PR: Lexical migration and validation improvements 2024-08-21 18:31:53 -04:00
Alessio Gravili
cf6634111f fix(richtext-lexical): ensure errors during slate => lexical migration are caught and do not halt migration progress 2024-08-21 17:52:45 -04:00
Jarrod Flesch
1ee19d3016 feat: bulk upload (#7800)
## Description

Adds bulk upload functionality to upload enabled configs.

You can disable the ability by defining `upload.bulkUpload: false` in
your upload enabled config.

- [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] New feature (non-breaking change which adds functionality)

## Checklist:

- [ ] 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
2024-08-21 17:44:34 -04:00
Alessio Gravili
9beaa281dc feat: log document id in ValidationError cause, if present 2024-08-21 17:31:31 -04:00
Alessio Gravili
5174c7092f fix(richtext-lexical): inaccurate detection of whether the editor is empty or not 2024-08-21 17:26:02 -04:00
Alessio Gravili
d894ac75f0 fix(richtext-lexical): migrate scripts not working due to migration hooks running during migrate script 2024-08-21 16:43:56 -04:00
Alessio Gravili
af0105ced5 fix: no longer handle disabling node deprecation warnings within bin script shebangs, as it errored on some systems (#7797)
Fixes https://github.com/payloadcms/payload/issues/7741

I have no idea why it broke and was not able to reproduce this at all.
But given the amount of people reporting this issue, it's not worth
keeping this around for the small benefit this brings
2024-08-21 17:01:57 +00:00
Tylan Davis
93e81314df fix(ui, richtext-lexical): corrects clickable areas on block headers (#7791)
## Description

Fixes an issue where Block component section titles were taking up the
entire clickable area of block headers.

- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-21 10:45:05 -04:00
Jarrod Flesch
163d1c85da chore: corrects icon color styles (#7792) 2024-08-21 10:28:01 -04:00
Jacob Fletcher
cb9b80aaf9 fix!: handles custom collection description components (#7789)
## Description

Closes #7784 by properly handling custom collection description
components via `admin.components.Description`. This component was
incorrectly added to the `admin.components.edit` key, and also was never
handled on the front-end. This was especially misleading because the
client-side config had a duplicative key in the proper position.

## Breaking Changes

This PR is only labeled as a breaking change because the key has changed
position within the config. If you were previously defining a custom
description component on a collection, simply move it into the correct
position:

Old:
```ts
{
  admin: {
    components: {
      edit: {
        Description: ''
      }
    }
  }
}
```

New:

```ts
{
  admin: {
    components: {
      Description: ''
    }
  }
}
```

- [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)
- [x] This change requires a documentation update

## 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-08-21 10:20:22 -04:00
Jarrod Flesch
cad1906725 feat: extends Button and extracts ListHeader components (#7777) 2024-08-21 09:37:11 -04:00
Elliot DeNolf
988c8848e9 chore(release): v3.0.0-beta.88 [skip ci] 2024-08-20 16:41:10 -04:00
Elliot DeNolf
95a8bb0d27 feat(ui): export Banner component (#7779)
Export `Banner` component
2024-08-20 20:07:03 +00:00
Paul
9c2ccbf61a fix(ui): on Table component crashing when looking for className on admin (#7776) 2024-08-20 19:03:18 +00:00
Paul
3ee0e842a5 fix(plugin-search): not being able to override labels (#7775)
Close https://github.com/payloadcms/payload/issues/7771
2024-08-20 18:54:30 +00:00
Tylan Davis
6ec982022e fix(ui): text clipping on document header title with Segoe UI font (#7774)
## Description

Fixes text clipping that occurs on the document header title when Segoe
UI font is used in the admin panel.

- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-20 17:35:06 +00:00
Elliot DeNolf
4f71df79fc ci: update codeowners file 2024-08-20 09:51:59 -04:00
Elliot DeNolf
227d2e0502 chore(release): v3.0.0-beta.87 [skip ci] 2024-08-20 09:10:00 -04:00
Jacob Fletcher
3a91deb0a4 feat: threads field config through components and strictly types props (#7754)
## Description

Threads the field config to all "field subcomponents" through props,
i.e. field label, description, error, etc. This way, the field config
that controls any particular component is easily accessible and strongly
typed, i.e. `props.field.maxLength`. This is true for both server and
client components, whose server-side props are now also contextually
typed. This behavior was temporarily removed in #7474 due to bloating
HTML, but has since been resolved in #7620. This PR also makes
significant improvements to component types by exporting explicit types
for _every component of every field_, each with its own client/server
variation. Now, a custom component can look something like this:

```tsx
import type { TextFieldLabelServerComponent } from 'payload'

import React from 'react'

export const CustomLabel: TextFieldLabelServerComponent = (props) => {
  return (
    <div>{`The max length of this field is: ${props?.field?.maxLength}`}</div>
  )
}
```

The following types are now available:

```ts
import type {
  TextFieldClientComponent,
  TextFieldServerComponent,
  TextFieldLabelClientComponent,
  TextFieldLabelServerComponent,
  TextFieldDescriptionClientComponent,
  TextFieldDescriptionServerComponent,
  TextFieldErrorClientComponent,
  TextFieldErrorServerComponent,
  // ...and so one for each field
} from 'payload'
```

BREAKING CHANGES:

In order to strictly type these components, a few breaking changes have
been made _solely to type definitions_. This only effects you if you are
heavily using custom components.

Old
```ts
import type { ErrorComponent, LabelComponent, DescriptionComponent } from 'payload'
```

New:
```ts
import type {
  FieldErrorClientComponent,
  FieldErrorServerComponent,
  FieldLabelClientComponent,
  FieldLabelServerComponent,
  FieldDescriptionClientComponent,
  FieldDescriptionServerComponent,
  // Note: these are the generic, underlying types of the more stricter types described above ^
  // For example, you should use the type that is explicit for your particular field and environment
  // i.e. `TextFieldLabelClientComponent` and not simply `FieldLabelClientComponent`
} from 'payload'
```

- [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
2024-08-20 04:25:10 +00:00
Jacob Fletcher
9e6e8357b8 docs: admin metadata (#7767) 2024-08-19 23:07:10 -04:00
Elliot DeNolf
0dd17e6347 chore(release): v3.0.0-beta.86 [skip ci] 2024-08-19 21:27:26 -04:00
James Mikrut
17312d9f90 Fix/postgres migrate args (#7766)
## Description

Replaces the export of `MigrateUpArgs` and `MigrateDownArgs` from
`db-postgres`
2024-08-20 01:00:13 +00:00
Paul
0c36cbde73 fix: type generation for block fields with no blocks (#7765) 2024-08-19 22:34:19 +00:00
Alessio Gravili
ebd43c7763 feat: pre-compile ui and richtext-lexical with react compiler (#7688)
This noticeably improves performance in the admin panel, for example
when there are multiple richtext editors on one page (& likely
performance in other areas too, though I mainly tested rich text).

The babel plugin currently only optimizes files with a 'use client'
directive at the top - thus we have to make sure to add use client
wherever possible, even if it's imported by a parent client component.

There's one single component that broke when it was compiled using the
React compiler (it stopped being reactive and failed one of our admin
e2e tests):
150808f608
opting out of it completely fixed that issue

Fixes https://github.com/payloadcms/payload/issues/7366
2024-08-19 17:31:36 -04:00
Jarrod Flesch
adf2f31178 fix: useField incorrect initialization of errorMessage on update (#7756) 2024-08-19 17:00:39 -04:00
Elliot DeNolf
beadc0158e chore(release): v3.0.0-beta.85 [skip ci] 2024-08-19 16:41:30 -04:00
Dan Ribbens
bb09da08c2 fix: migrate error on windows (#7759)
handle windows compatible file names when reading migrations

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-08-19 15:46:40 -04:00
Paul
ab09f2aff5 fix(ui): tabs preferences not being saved (#7761) 2024-08-19 19:25:31 +00:00
Alessio Gravili
2f3829083d fix(richtext-lexical): richtext editor features overriding other editor features props if multiple editors in one document (#7758)
Example: richText editor 1 and 2 both have UploadFeature. richText
editor 1 calls UploadFeature() with custom fields, richText editor 2
calls UploadFeature() with NO custom fields. Before this PR, richText
editor 1 would not have had any custom fields, as richText editor 2 will
override the feature object (specifically its props).
2024-08-19 12:01:31 -04:00
Jacob Fletcher
a526c7becd feat: custom view and document-level metadata (#7716) 2024-08-18 23:22:38 -04:00
Elliot DeNolf
2835e1d709 feat: abstract postgres base adapter (#7732)
Abstracts Postgres base adapter in order to allow future postgres-based
adapters.
2024-08-16 18:51:39 -04:00
Alessio Gravili
4808e31276 chore: fix dev:postgres command, disable dependency checker in core dev (#7733) 2024-08-16 19:46:49 +00:00
Elliot DeNolf
bd51fd1390 chore: re-enable husky pre-commit 2024-08-16 15:22:56 -04:00
Tylan Davis
b3b1cd2c23 fix: prevent vertical scrolling on tab fields (#7729)
## Description

Prevents tabs fields from displaying vertical scrollbars in certain
cases with different viewports/zoom levels.

- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-16 15:13:12 -04:00
Alessio Gravili
d67f674160 chore: update all templates (#7731)
Old blank templates had invalid pregenerated importMap. Would error for
fresh apps from create-payload-app. And website was on an old version
riddled with bugs
2024-08-16 18:59:58 +00:00
Alessio Gravili
6eb4438dc8 fix(ui): relationship cells in table from list drawer not shown (#7730)
Also a nice performance improvement. The list drawer was previously
fetching data with depth 1. This will cause the relationship cell to
break, as it expects the relationship data to be a string/number, not a
populated object with the id inside.

Now, it fetches using depth 0 - same as the normal list view
2024-08-16 18:44:59 +00:00
Elliot DeNolf
2d6e7f8a37 chore(release): v3.0.0-beta.84 [skip ci] 2024-08-16 13:56:50 -04:00
James Mikrut
3d37d74c6e fix: adds default drizzle package exports (#7728)
Default exports were missing for Drizzle package.
2024-08-16 13:40:41 -04:00
James Mikrut
de19822ed4 fix: ensures user is accurate in useAuth (#7727)
## Description

Fixes an issue where the `user` could be out of date after logging in.
2024-08-16 17:10:32 +00:00
Tylan Davis
2b2bcb5264 fix: corrects logout icon styling (#7726)
## Description

before: 
<img width="89" alt="Screenshot 2024-08-16 at 12 43 56 PM"
src="https://github.com/user-attachments/assets/1052cfdb-6dde-4b65-a4c0-e37a909dac34">

after:
<img width="48" alt="Screenshot 2024-08-16 at 12 43 35 PM"
src="https://github.com/user-attachments/assets/aa4d6aed-4a78-4b17-a209-df3618b273a1">

- [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

<!-- Please delete options that are not relevant. -->

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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-16 17:01:42 +00:00
Elliot DeNolf
e9b01e6d9f chore(release): v3.0.0-beta.83 [skip ci] 2024-08-16 12:36:30 -04:00
Alessio Gravili
b0a760193e fix: type RelationshipFieldClient typed incorrectly (#7725) 2024-08-16 12:35:05 -04:00
Jarrod Flesch
95569e44e4 fix: login with username server validations (#7719) 2024-08-16 12:07:53 -04:00
Paul
11816080a6 fix: bin script error when running on linux (#7721)
Fixes https://github.com/payloadcms/payload/issues/7717
2024-08-16 10:07:03 -06:00
Paul
3a86822f0a fix(ui): ensure that aborting Autosave always has a valid reason for the controller - fixes uncaught error (#7723) 2024-08-16 16:04:32 +00:00
Jarrod Flesch
6f8604e18c fix: ensures users cannot be created without confirming pw (#7583) 2024-08-16 11:44:27 -04:00
Tylan Davis
aec3f5e308 chore: admin panel style updates (#7720)
## Description

Minor admin panel style updates:
- Adjusts document header title spacing.
- Makes toast notifications more apparent.
- Adjusts alignment of create new button.
- Improves chevron icon.

- [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

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-16 15:23:08 +00:00
Jarrod Flesch
e0a5de6730 chore: extends dropzone and upload field (#7713)
## Description

Tweaks to Upload and Dropzone components, making them more extendable.

- Dropzone adds prop to allow multiple files
- Upload correctly sets url if state is initialized with a File

- [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] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] 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
2024-08-16 09:38:41 -04:00
Paul
5eee49da9a feat(plugin-seo): pass req through to generate functions (#7711)
Closes https://github.com/payloadcms/payload/issues/7708
2024-08-15 23:09:08 +00:00
dependabot[bot]
b7d01dec70 chore(deps): bump pnpm/action-setup from 3 to 4 in /.github/actions/setup in the github_actions group across 1 directory (#7687)
Bumps the github_actions group with 1 update in the
/.github/actions/setup directory:
[pnpm/action-setup](https://github.com/pnpm/action-setup).

Updates `pnpm/action-setup` from 3 to 4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pnpm/action-setup/releases">pnpm/action-setup's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<p>An error is thrown if one version of pnpm is specified in the
<code>packageManager</code> field of <code>package.json</code> and a
different version is specified in the action's settings <a
href="https://redirect.github.com/pnpm/action-setup/pull/122">#122</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fe02b34f77"><code>fe02b34</code></a>
docs: bump action-setup version in README</li>
<li><a
href="bee1f099e5"><code>bee1f09</code></a>
feat: throw error when multiple versions specified (<a
href="https://redirect.github.com/pnpm/action-setup/issues/122">#122</a>)</li>
<li><a
href="ce859e384f"><code>ce859e3</code></a>
refactor: replace <code>fs-extra</code> with Node.js built-in fs methods
(<a
href="https://redirect.github.com/pnpm/action-setup/issues/120">#120</a>)</li>
<li><a
href="2ab6dce4f5"><code>2ab6dce</code></a>
docs(README): fix link to LICENSE</li>
<li><a
href="e280758d01"><code>e280758</code></a>
docs(README): update dependency versions (<a
href="https://redirect.github.com/pnpm/action-setup/issues/117">#117</a>)</li>
<li><a
href="129abb77bf"><code>129abb7</code></a>
Bump undici from 5.28.2 to 5.28.3 (<a
href="https://redirect.github.com/pnpm/action-setup/issues/115">#115</a>)</li>
<li>See full diff in <a
href="https://github.com/pnpm/action-setup/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility
score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=pnpm/action-setup&package-manager=github_actions&previous-version=3&new-version=4)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-15 15:57:33 -04:00
Elliot DeNolf
0618130fe3 chore(release): v3.0.0-beta.82 [skip ci] 2024-08-15 15:46:12 -04:00
Jacob Fletcher
cd245793fc chore(ui): resolves self-referencing imports (#7707) 2024-08-15 14:27:19 -04:00
Dan Ribbens
3a6c75a1a3 fix: importMap windows paths (#7706)
Fix windows compatibility for importMap generation
2024-08-15 17:57:48 +00:00
Alessio Gravili
5a683b6947 chore: fix issues running postgres in our dev test suites (#7704) 2024-08-15 16:58:00 +00:00
Elliot DeNolf
9b27f03e61 feat(eslint): no-imports-from-self rule (#7691)
New rule to prevent a package from importing from itself.
2024-08-15 09:02:29 -04:00
Elliot DeNolf
89746ebe09 chore(eslint): update relative import regex to handle more scenarios (#7690)
Updates no-relative-monorepo-import regex to handle more scenarios:

 Scenarios that will violate the rule:
```ts
import { something } from '../../payload/src/utilities/some-util.js'
import { something } from '../../../packages/payload/src/utilities/some-util.js'
import { something } from 'packages/payload/src/utilities/some-util.js'
```
2024-08-14 23:57:22 -04:00
dependabot[bot]
eacf2030cd chore(deps): bump the github_actions group with 2 updates (#7686)
Bumps the github_actions group with 2 updates:
[pnpm/action-setup](https://github.com/pnpm/action-setup) and
[supercharge/mongodb-github-action](https://github.com/supercharge/mongodb-github-action).

Updates `pnpm/action-setup` from 3 to 4
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/pnpm/action-setup/releases">pnpm/action-setup's
releases</a>.</em></p>
<blockquote>
<h2>v4.0.0</h2>
<p>An error is thrown if one version of pnpm is specified in the
<code>packageManager</code> field of <code>package.json</code> and a
different version is specified in the action's settings <a
href="https://redirect.github.com/pnpm/action-setup/pull/122">#122</a></p>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="fe02b34f77"><code>fe02b34</code></a>
docs: bump action-setup version in README</li>
<li><a
href="bee1f099e5"><code>bee1f09</code></a>
feat: throw error when multiple versions specified (<a
href="https://redirect.github.com/pnpm/action-setup/issues/122">#122</a>)</li>
<li><a
href="ce859e384f"><code>ce859e3</code></a>
refactor: replace <code>fs-extra</code> with Node.js built-in fs methods
(<a
href="https://redirect.github.com/pnpm/action-setup/issues/120">#120</a>)</li>
<li><a
href="2ab6dce4f5"><code>2ab6dce</code></a>
docs(README): fix link to LICENSE</li>
<li><a
href="e280758d01"><code>e280758</code></a>
docs(README): update dependency versions (<a
href="https://redirect.github.com/pnpm/action-setup/issues/117">#117</a>)</li>
<li><a
href="129abb77bf"><code>129abb7</code></a>
Bump undici from 5.28.2 to 5.28.3 (<a
href="https://redirect.github.com/pnpm/action-setup/issues/115">#115</a>)</li>
<li>See full diff in <a
href="https://github.com/pnpm/action-setup/compare/v3...v4">compare
view</a></li>
</ul>
</details>
<br />

Updates `supercharge/mongodb-github-action` from 1.10.0 to 1.11.0
<details>
<summary>Release notes</summary>
<p><em>Sourced from <a
href="https://github.com/supercharge/mongodb-github-action/releases">supercharge/mongodb-github-action's
releases</a>.</em></p>
<blockquote>
<p>Release 1.11.0</p>
</blockquote>
</details>
<details>
<summary>Changelog</summary>
<p><em>Sourced from <a
href="https://github.com/supercharge/mongodb-github-action/blob/main/CHANGELOG.md">supercharge/mongodb-github-action's
changelog</a>.</em></p>
<blockquote>
<h2><a
href="https://github.com/superchargejs/mongodb-github-action/compare/v1.10.0...v1.11.0">1.11.0</a>
- 2024-05-22</h2>
<h3>Added</h3>
<ul>
<li>added <code>mongodb-container-name</code> input: this option allows
you to define the Docker container name</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>use the <code>mongo</code> command to interact with MongoDB versions
4.x or lower. Previously, we only checked for MongoDB 4 and would use
<code>mongosh</code> for MongoDB 3 (and lower). <a
href="https://redirect.github.com/supercharge/mongodb-github-action/pull/61">Thanks
to Aravind!</a></li>
</ul>
<h3>Updated</h3>
<ul>
<li>bump dependencies</li>
</ul>
</blockquote>
</details>
<details>
<summary>Commits</summary>
<ul>
<li><a
href="5a87bd81f8"><code>5a87bd8</code></a>
prepare changelog for 1.11.0</li>
<li><a
href="7c12fc679c"><code>7c12fc6</code></a>
update readme</li>
<li><a
href="ad73029553"><code>ad73029</code></a>
bump mongoose dependency</li>
<li><a
href="268fb2c93c"><code>268fb2c</code></a>
Merge pull request <a
href="https://redirect.github.com/supercharge/mongodb-github-action/issues/61">#61</a>
from aravindnc/main</li>
<li><a
href="12b898a9c8"><code>12b898a</code></a>
Fix to use mongo client if MongoDB verison is less than or equal to
4.</li>
<li><a
href="b8277548e0"><code>b827754</code></a>
wait 20 seconds</li>
<li><a
href="5f37c5fb42"><code>5f37c5f</code></a>
revert ESLint to 8.x</li>
<li><a
href="fcc7443a6b"><code>fcc7443</code></a>
bump verions</li>
<li><a
href="fde299bc70"><code>fde299b</code></a>
bump deps</li>
<li><a
href="9ceda80ede"><code>9ceda80</code></a>
bump versions of GitHub Actions</li>
<li>Additional commits viewable in <a
href="https://github.com/supercharge/mongodb-github-action/compare/1.10.0...1.11.0">compare
view</a></li>
</ul>
</details>
<br />


Dependabot will resolve any conflicts with this PR as long as you don't
alter it yourself. You can also trigger a rebase manually by commenting
`@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits
that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after
your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge
and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating
it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all
of the ignore conditions of the specified dependency
- `@dependabot ignore <dependency name> major version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's major version (unless you unignore this specific
dependency's major version or upgrade to it yourself)
- `@dependabot ignore <dependency name> minor version` will close this
group update PR and stop Dependabot creating any more for the specific
dependency's minor version (unless you unignore this specific
dependency's minor version or upgrade to it yourself)
- `@dependabot ignore <dependency name>` will close this group update PR
and stop Dependabot creating any more for the specific dependency
(unless you unignore this specific dependency or upgrade to it yourself)
- `@dependabot unignore <dependency name>` will remove all of the ignore
conditions of the specified dependency
- `@dependabot unignore <dependency name> <ignore condition>` will
remove the ignore condition of the specified dependency and ignore
conditions


</details>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-14 21:56:24 -04:00
Elliot DeNolf
86428539f5 chore: add packageManager property for dependabot 2024-08-14 21:30:53 -04:00
Elliot DeNolf
a7f519c53a chore(release): v3.0.0-beta.81 [skip ci] 2024-08-14 19:53:07 -04:00
Alessio Gravili
49a2d70fbb feat: allow passing false as PayloadComponent which signals that the component should not be rendered (#7682)
If it's undefined/null => Fallback Component may be rendered
If it's false => No component should be rendered - as if an empty
component was passed in

This ensures that the user does not have to install `@payloadcms/ui`
anymore, which previously exported an empty component to be used in
component paths
2024-08-14 22:31:58 +00:00
Alessio Gravili
cb7fa00a6f fix: use tsx instead of swc as default bin script transpiler, as swc errors when it encounters 'next/cache' (#7681)
Fixes https://github.com/payloadcms/payload/issues/7677

- Payload bin scripts were not properly working on windows
- Use tsx by default instead of swc, as swc does not handle next/cache
imports without the .js at the end
- Support other node runtimes through --disable-transpile flag
2024-08-14 16:40:31 -04:00
Jacob Fletcher
a212cdef3f fix(next): supports root document view overrides as separate from default edit view (#7673)
## Description

We've since lost the ability to override the document view at the
root-level. This was a feature that made it possible to override _the
entire document routing/view structure_, including the document
header/tabs and all nested routes within, i.e. the API route/view, the
Live Preview route/view, etc. This is distinct from the "default" edit
view, which _only_ targets the component rendered within the "edit" tab.
This regression was introduced when types were simplified down to better
support "component paths" here: #7620. The `default` key was incorrectly
used as the "root" view override. To continue to support stricter types
_and_ root view overrides, a new `root` key has been added to the
`views` config.

You were previously able to do this:

```tsx
import { MyComponent } from './MyComponent.js'

export const MyCollection = {
  // ...
  admin: {
    views: {
      Edit: MyComponent
    }
  }
}
```

This is now done like this:

```tsx
export const MyCollection = {
  // ...
  admin: {
    views: {
      edit: {
        root: {
          Component: './path-to-my-component.js'
        }
      }
    }
  }
}
```

Some of the documentation was also incorrect according to the new
component paths API.

- [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)
- [x] This change requires a documentation update

## Checklist:

- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-08-14 16:02:14 -04:00
Paul
4f323a3754 fix(ui): issue with checking for undefined json when autosave and validate is enabled (#7678) 2024-08-14 18:47:27 +00:00
Paul
f5e7578b41 chore: add command to run inside the importMap error (#7674) 2024-08-14 17:39:12 +00:00
Elliot DeNolf
0bf27b117a chore(release): v3.0.0-beta.80 [skip ci] 2024-08-14 13:14:57 -04:00
Patrik
806c22e6bd fix(next): properly closes leave-without-saving modal after navigating from Leave anyway button (#7661) 2024-08-14 13:05:26 -04:00
Alessio Gravili
39d7b717a9 fix: sidebar nav jumping around when loading page (#7574)
Fixes this:


https://github.com/user-attachments/assets/1c637bca-0c13-43f6-bcd7-6ca58da9ae77
2024-08-14 16:23:57 +00:00
Paul
9d1997e6a0 chore: update docs for redirects plugin for new redirect type feature (#7672) 2024-08-14 16:22:11 +00:00
Alessio Gravili
c65f5027d6 fix(ui): ensure field components safely access field.admin property (#7670) 2024-08-14 12:06:01 -04:00
Elliot DeNolf
dc496e4387 chore(release): v3.0.0-beta.79 [skip ci] 2024-08-14 09:21:24 -04:00
Alessio Gravili
3d86bf1974 chore: update website and blank templates to incorporate import map changes (#7664) 2024-08-14 09:10:40 -04:00
Alessio Gravili
96e7c95ebc chore: upgrade to pnpm v9, regenerate lockfile (#7369)
- regenerates the lockfile
- upgrades pnpm from v8 to v9.7.0 minimum
- ensures playwright does not import payload config. Even after our
importmap revamp that made the payload config server-only / node-safe, I
was getting these `Error: Invariant: AsyncLocalStorage accessed in
runtime where it is not available` errors in combination with pnpm v9
and lockfile regeneration.
This does not happen with pnpm v8, however I'm still blaming playwright
for this, as this does not happen in dev and we've had this specific
error with playwright in the past when we were importing the payload
config. Perhaps it's related to both playwright and the future Next.js
process importing the same config file, and not related to the config
file containing client-side React code.
Making sure playwright doesn't import the config fixed it (it was
importing it through the import map generation). The import map
generation is now run in a separate process, and playwright simply waits
for it
- One positive thing: this pr fixes a bunch of typescript errors with
react-select components. We got those errors because react-select types
are not compatible with react 19. lockfile regeneration fixed that (not
related to pnpm v9) - probably because we were installing mismatching
react versions (I saw both `fb9a90fa48-20240614` and `06d0b89e-20240801`
in our lockfile). I have thus removed the caret for react and react-dom
in our package.json - now it's consistent
2024-08-14 08:57:04 -04:00
Alessio Gravili
fca4ee995e fix(richtext-lexical): inline blocks and tables not functioning correctly if they are used in more than one editor on the same page (#7665)
Fixes https://github.com/payloadcms/payload/issues/7579

The problem was that multiple richtext editors shared the same drawer
slugs for the table and inline block drawers.
2024-08-13 21:46:23 -04:00
Elliot DeNolf
352ed0ebef ci: debug github.ref condition 2024-08-13 20:00:29 -04:00
Elliot DeNolf
bcf9b17321 ci: test github.ref 2024-08-13 19:40:37 -04:00
Alessio Gravili
a19263245f feat(richtext-lexical)!: move migration related features to /migrate subpath export in order to decrease module count when those are not used (#7660)
This lowers the module count by 31 modules

BREAKING: Migration-related lexical modules are now exported from
`@payloadcms/richtext-lexical/migrate` instead of
`@payloadcms/richtext-lexical`
2024-08-13 20:20:05 +00:00
Alessio Gravili
78e55d61be docs: move import map section from admin/overview to admin/components (#7659) 2024-08-13 19:17:14 +00:00
Alessio Gravili
cea272e189 docs: update ui field docs to use component paths (#7658) 2024-08-13 14:39:03 -04:00
Alessio Gravili
8b13dc64d1 docs: update docs with component path / client config changes (#7657) 2024-08-13 14:34:42 -04:00
Elliot DeNolf
5fc9f76406 feat: filename compound index (#7651)
Allow a compound index to be used for upload collections via a
`filenameCompoundIndex` field. Previously, `filename` was always treated
as unique.

Usage:

```ts
{
  slug: 'upload-field',
   upload: {
     // Slugs to include in compound index
     filenameCompoundIndex: ['filename', 'alt'],
  },
}
```
2024-08-13 13:55:10 -04:00
Alessio Gravili
6c0f99082b chore: install tsx in monorepo (#7656)
CI depends on it, and swc does not support the `p-limit` dependency used
in CI scripts
2024-08-13 17:32:46 +00:00
Alessio Gravili
90b7b20699 feat!: beta-next (#7620)
This PR makes three major changes to the codebase:

1. [Component Paths](#component-paths)
Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938

2. [Client Config](#client-config)
Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).

3. [Custom client component are no longer
server-rendered](#custom-client-components-are-no-longer-server-rendered)
Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.

## Component Paths

Instead of importing custom components into your config directly, they
are now defined as file paths and rendered only when needed. That way
the Payload config will be significantly more lightweight, and ensures
that the Payload config is 100% server-only and Node-safe. Related
discussion: https://github.com/payloadcms/payload/discussions/6938

In order to reference any custom components in the Payload config, you
now have to specify a string path to the component instead of importing
it.

Old:

```ts
import { MyComponent2} from './MyComponent2.js'

admin: {
  components: {
    Label: MyComponent2
  },
},
```

New:

```ts
admin: {
  components: {
    Label: '/collections/Posts/MyComponent2.js#MyComponent2', // <= has to be a relative path based on a baseDir configured in the Payload config - NOT relative based on the importing file
  },
},
```

### Local API within Next.js routes

Previously, if you used the Payload Local API within Next.js pages, all
the client-side modules are being added to the bundle for that specific
page, even if you only need server-side functionality.

This `/test` route, which uses the Payload local API, was previously 460
kb. It is now down to 91 kb and does not bundle the Payload client-side
admin panel anymore.

All tests done
[here](https://github.com/payloadcms/payload-3.0-demo/tree/feat/path-test)
with beta.67/PR, db-mongodb and default richtext-lexical:

**dev /admin before:**
![CleanShot 2024-07-29 at 22 49
12@2x](https://github.com/user-attachments/assets/4428e766-b368-4bcf-8c18-d0187ab64f3e)

**dev /admin after:**
![CleanShot 2024-07-29 at 22 50
49@2x](https://github.com/user-attachments/assets/f494c848-7247-4b02-a650-a3fab4000de6)

---

**dev /test before:**
![CleanShot 2024-07-29 at 22 56
18@2x](https://github.com/user-attachments/assets/1a7e9500-b859-4761-bf63-abbcdac6f8d6)

**dev /test after:**
![CleanShot 2024-07-29 at 22 47
45@2x](https://github.com/user-attachments/assets/f89aa76d-f2d5-4572-9753-2267f034a45a)

---

**build before:**
![CleanShot 2024-07-29 at 22 57
14@2x](https://github.com/user-attachments/assets/5f8f7281-2a4a-40a5-a788-c30ddcdd51b5)

**build after::**
![CleanShot 2024-07-29 at 22 56
39@2x](https://github.com/user-attachments/assets/ea8772fd-512f-4db0-9a81-4b014715a1b7)

### Usage of the Payload Local API / config outside of Next.js

This will make it a lot easier to use the Payload config / local API in
other, server-side contexts. Previously, you might encounter errors due
to client files (like .scss files) not being allowed to be imported.

## Client Config

Deprecates the component map by merging its logic into the client
config. The main goal of this change is for performance and
simplification. There was no need to deeply iterate over the Payload
config twice, once for the component map, and another for the client
config. Instead, we can do everything in the client config one time.
This has also dramatically simplified the client side prop drilling
through the UI library. Now, all components can share the same client
config which matches the exact shape of their Payload config (with the
exception of non-serializable props and mapped custom components).

This is breaking change. The `useComponentMap` hook no longer exists,
and most component props have changed (for the better):

```ts
const { componentMap } = useComponentMap() // old
const { config } = useConfig() // new
```

The `useConfig` hook has also changed in shape, `config` is now a
property _within_ the context obj:

```ts
const config = useConfig() // old
const { config } = useConfig() // new
```

## Custom Client Components are no longer server rendered

Previously, custom components would be server-rendered, no matter if
they are server or client components. Now, only server components are
rendered on the server. Client components are automatically detected,
and simply get passed through as `MappedComponent` to be rendered fully
client-side.

The benefit of this change:

Custom client components can now receive props. Previously, the only way
for them to receive dynamic props from a parent client component was to
use hooks, e.g. `useFieldProps()`. Now, we do have the option of passing
in props to the custom components directly, if they are client
components. This will be simpler than having to look for the correct
hook.

This makes rendering them on the client a little bit more complex, as
you now have to check if that component is a server component (=>
already has been rendered) or a client component (=> not rendered yet,
has to be rendered here). However, this added complexity has been
alleviated through the easy-to-use `<RenderMappedComponent />` helper.

This helper now also handles rendering arrays of custom components (e.g.
beforeList, beforeLogin ...), which actually makes rendering custom
components easier in some cases.

## Misc improvements

This PR includes misc, breaking changes. For example, we previously
allowed unions between components and config object for the same
property. E.g. for the custom view property, you were allowed to pass in
a custom component or an object with other properties, alongside a
custom component.

Those union types are now gone. You can now either pass an object, or a
component. The previous `{ View: MyViewComponent}` is now `{ View: {
Component: MyViewComponent} }` or `{ View: { Default: { Component:
MyViewComponent} } }`.

This dramatically simplifies the way we read & process those properties,
especially in buildComponentMap. We can now simply check for the
existence of one specific property, which always has to be a component,
instead of running cursed runtime checks on a shared union property
which could contain a component, but could also contain functions or
objects.

![CleanShot 2024-07-29 at 23 07
07@2x](https://github.com/user-attachments/assets/1e75aa4c-7a4c-419f-9070-216bb7b9a5e5)

![CleanShot 2024-07-29 at 23 09
40@2x](https://github.com/user-attachments/assets/b4c96450-6b7e-496c-a4f7-59126bfd0991)

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

---------

Co-authored-by: PatrikKozak <patrik@payloadcms.com>
Co-authored-by: Paul <paul@payloadcms.com>
Co-authored-by: Paul Popus <paul@nouance.io>
Co-authored-by: Jacob Fletcher <jacobsfletch@gmail.com>
Co-authored-by: James <james@trbl.design>
2024-08-13 12:54:33 -04:00
Patrik
9cb84c48b9 fix(live-preview): encode query string url (#7635)
## Description

Fixes #7529 

- [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
2024-08-13 10:24:30 -04:00
Elliot DeNolf
390f88867f chore(release): v3.0.0-beta.78 [skip ci] 2024-08-13 09:21:05 -04:00
James Mikrut
b33b5f43f4 fix: #7580 config deepmerge (#7639)
## Description

https://github.com/payloadcms/payload/issues/7580 - Fixes an infinite
loop caused by a faulty deepMerge in config sanitization.
2024-08-12 16:50:21 -04:00
Paul
56aded8507 feat: add support for custom image size file names (#7634)
Add support for custom file names in images sizes

```ts
{
  name: 'thumbnail',
  width: 400,
  height: 300,
  generateImageName: ({ height, sizeName, extension, width }) => {
    return `custom-${sizeName}-${height}-${width}.${extension}`
  },
}
```
2024-08-12 12:25:20 -06:00
Paul
78dd6a2d5b feat(plugin-form-builder): pass beforeChange params into beforeEmail hook and add types to it (#7626)
Form Builder Plugin BeforeEmail hook now takes a generic for your
generated types and it has the full hook params available to it.

```ts
import type { BeforeEmail } from '@payloadcms/plugin-form-builder'
// Your generated FormSubmission type
import type {FormSubmission} from '@payload-types'

// Pass it through and 'data' or 'originalDoc' will now be typed
const beforeEmail: BeforeEmail<FormSubmission> = (emailsToSend, beforeChangeParams) => {
  // modify the emails in any way before they are sent
  return emails.map((email) => ({
    ...email,
    html: email.html, // transform the html in any way you'd like (maybe wrap it in an html template?)
  }))
}
```
2024-08-12 12:22:52 -06:00
Alessio Gravili
a063b81460 fix: autoLogin not working if old, invalid token is present (#7456) 2024-08-12 12:41:45 -04:00
James Mikrut
18d9314f22 docs: adds prod migrations (#7631)
## Description

Adds docs for executing migrations in production.
2024-08-12 11:45:39 -04:00
Patrik
8d120373a7 fix(payload): filtering by polymorphic relationships with drafts enabled (#7570)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/7565)

- [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
2024-08-12 10:34:21 -04:00
Patrik
f88cef5470 fix(ui): render singular label for ArrayCell when length is 1 (#7586)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/7585)

- [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] Existing test suite passes locally with my changes
2024-08-12 10:33:28 -04:00
Paul
5dfcffa281 feat(plugin-redirects): added new option for redirect type in the redirects collection (#7625)
You can now add a redirect type to your redirects if needed:

```ts
// Supported types
redirectTypes: ['301', '302'],

// Override the select field
redirectTypeFieldOverride: {
  label: 'Redirect Type (Overridden)',
},
```
2024-08-11 13:18:49 -06:00
Elliot DeNolf
fa3d250053 feat: indent migration sql (#7475)
Properly indent migration sql
2024-08-09 22:41:28 -04:00
Paul
4b2a9f75d0 fix(ui): field permissions not being correctly updated when locale changes (#7611)
Closes https://github.com/payloadcms/payload/issues/7262
2024-08-09 18:39:14 -06:00
Dan Ribbens
e225783d76 chore(db-sqlite): readme header (#7609) 2024-08-09 16:45:33 -04:00
Tylan Davis
0d552fd523 chore: adjusts admin UI styling (#7557)
## Description

- Improves mobile styling of Payload admin UI.
- Reduces font size on dashboard cards.
- Improves the block/collapsible/array field styling.

- [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

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [x] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-09 11:19:36 -04:00
Paul
69ada97df5 fix(ui): apiKey field not being customisable and field access control not being updated with correct data (#7591)
You can now override the apiKey field with access control by adding this
field to your auth collection:

```ts
{
  name: 'apiKey',
  type: 'text',
  access: {
    update: ({ req }) => req.user.role === 'admin',
  }
}
```

Translated labels are now also supported.

Note that `siblingData` isn't working still in FieldAccess control and
`data` only works in non-dynamic fields, eg. fields not in an array or
block for now.
2024-08-09 08:55:17 -06:00
Paul
81e7355ee0 fix: set correct step nav path to Account on account page (#7599) 2024-08-09 00:56:11 +00:00
Paul
ce8b95f6bb fix: add editDepth to account view so that it doesn't redirect from modals (#7597)
Closes https://github.com/payloadcms/payload/issues/7593
2024-08-09 00:32:46 +00:00
James Mikrut
c1b0d93c93 feat: adds classnames to list, edit views (#7596)
## Description

Copy of #7595 for beta branch
2024-08-08 20:05:07 -04:00
Jarrod Flesch
6227276d2c fix: corrects local strategy user lookup when using loginWithUsername (#7587)
## Description

Fixes the local strategy user lookup.

- [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
- [ ] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-08 19:51:12 -04:00
Elliot DeNolf
ee62ed6ebb chore(release): v3.0.0-beta.77 [skip ci] 2024-08-08 17:13:02 -04:00
Elliot DeNolf
0283039257 chore(db-*): remove unneeded drizzle import (#7590)
Removes unused drizzle snapshot
2024-08-08 17:11:34 -04:00
Jessica Chowdhury
b546c7b655 fix: empty path in error message (#7555)
## Description

Closes #7524

The query path is overwritten as an empty string in the
`getLocalizedPaths()` function - then when it should throw an invalid
path error it no longer has this info.

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [X] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-08 10:29:03 +00:00
Elliot DeNolf
a933eb7311 chore(release): v3.0.0-beta.76 [skip ci] 2024-08-07 15:18:17 -04:00
Elliot DeNolf
b5d65dd1ac fix(richtext-lexical): next.js multiple refs of same fix (#7572)
Fixes some issue w/ Next.js and passing the same ref multiple times.
2024-08-07 15:17:33 -04:00
Elliot DeNolf
c4ee623907 chore(release): v3.0.0-beta.75 [skip ci] 2024-08-07 14:01:09 -04:00
James Mikrut
1cb1e5e8b3 feat(db-*): allows for running migrations in production automatically (#7563)
## Description

Introduces a pattern for running migrations upon Payload init in
production.
2024-08-07 13:57:12 -04:00
Paul
e0699838e1 chore(ui): update useField jsdoc comment to point to the right internal hook (#7568) 2024-08-07 17:49:32 +00:00
Dan Ribbens
46f70d9df4 fix(db-postgres): #7492 migrate snapshots (#7540)
## Description

Fixes #7492 

In order to run createMigration, we need to read in the previous
snapshot file if one exists. When that snapshot was generated from an
older version of drizzle-kit, we have to first migrate it up match the
latest version for drizzle to generate the new migration. This change
adds in the call to check the version and migrate the snapshot if
needed.
2024-08-07 13:49:08 -04:00
Paul
b7e2c59622 fix(plugin-seo): issue with generating image from a function (#7566) 2024-08-07 17:35:43 +00:00
Jarrod Flesch
0cc7184023 fix: hydrate permissions on dashboard, fix active menu item logic 2024-08-07 12:14:58 -04:00
Jarrod Flesch
e905675a05 chore!: adjusts auth hydration from server (#7545)
Fixes https://github.com/payloadcms/payload/issues/6823

Allows the server to initialize the AuthProvider via props. Renames
`HydrateClientUser` to `HydrateAuthProvider`. It now only hydrates the
permissions as the user can be set from props. Permissions can be
initialized from props, but still need to be hydrated for some pages as
access control can be specific to docs/lists etc.

**BREAKING CHANGE**
- Renames exported `HydrateClientUser` to `HydrateAuthProvider`
2024-08-07 11:10:53 -04:00
Paul
4a20a63563 fix(ui): fixes issue when filtering by checkbox value in a different language (#7547)
Fixes https://github.com/payloadcms/payload/issues/7447
2024-08-07 00:48:50 +00:00
Paul
8d1fc6e8fb feat!: bump next canary to 104 and update withPayload for new config (#7541)
We are now bumping up the Next canary version to `15.0.0-canary.104` and
`react` and `react-dom` to `^19.0.0-rc-06d0b89e-20240801`.

Your new dependencies should look like this:
```
"next": "15.0.0-canary.104",
"react": "^19.0.0-rc-06d0b89e-20240801",
"react-dom": "^19.0.0-rc-06d0b89e-20240801",
```

---------

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-08-06 23:54:34 +00:00
Patrik
62744e79ac fix(next, payload): enable relationship & upload version tracking when localization enabled (#7508) 2024-08-06 12:28:06 -04:00
Jarrod Flesch
e8bed7b315 chore: call refresh after the subscription is ready, fixes CI (#7542)
LivePreview data was stale if the user entered data while the socket
connection was being established. This change ensures fresh data is
fetched after the connection is established.

This is easy to see when turning on 4G connection and in CI, where it is
especially slow.
2024-08-06 12:17:50 -04:00
Alessio Gravili
f2b8ddb299 Merge PR: fix lexical upload html converter, export missing nodes #7539
Fixes https://github.com/payloadcms/payload/issues/7495

When the Upload HTML Converter was called from the local API, the upload
document did not populate properly due to overrideAccess not being
passed through to the dataloader. This PR also adds new properties to
the afterRead field hook, so that these can be used in the lexical html
field.

Reproduction here:
https://github.com/payloadcms/payload/tree/chore/reproduce-html-converter-issue

**BREAKING:** If you define your own, custom lexical HTML Converters
that have sub-nodes, or if you directly call the
`convertLexicalNodesToHTML` function anywhere, you now need to pass
through the `showHiddenFields`, draft and `overrideAccess` props to the
`convertLexicalNodesToHTML` function. These are available in the
arguments of your HTML Converter function
2024-08-06 12:04:56 -04:00
Alessio Gravili
ffd8ea516d feat(richtext-lexical): export serialized inline blocks and table node types 2024-08-06 11:42:09 -04:00
Paul
3bf09703e9 chore: turn off autocomplete for create first user form (#7538)
Turns off autocomplete on the first user form so it doesn't conflict
with wrong credentials being autofilled
2024-08-06 15:34:26 +00:00
Alessio Gravili
c15d679b65 fix(richtext-lexical)!: html converters not respecting overrideAccess property when populating values, in local API 2024-08-06 11:15:47 -04:00
Jarrod Flesch
a422a0d568 fix: scopes preferences queries and mutations by user (#7534)
Fixes https://github.com/payloadcms/payload/issues/7530

Properly scopes preferences queries/mutations by user.
2024-08-06 10:35:46 -04:00
Jarrod Flesch
edaeb1e29f fix: ensure pw confirmation when creating users in admin panel (#7535) 2024-08-06 10:31:08 -04:00
Jessica Chowdhury
6f35c356fe fix: custom meta icons getting overwritten by default icon (#7466)
## Description

Issue reported by Trading Point.

Payload favicon is still shown even when a custom icon is provided.

To replicate add to Payload config:
```ts
  admin: {
    meta: {
      icons: [
        {
          url: '/images/test.jpg',
          fetchPriority: 'high',
          sizes: '16x16',
        },
      ],
    },
  },
```

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

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-06 14:01:46 +00:00
Elliot DeNolf
0b9397399a chore(release): v3.0.0-beta.74 [skip ci] 2024-08-06 09:38:20 -04:00
Jarrod Flesch
cdcc35ccdb chore: fixes build error stemming from LoginField (#7532) 2024-08-06 09:15:21 -04:00
Jarrod Flesch
442189ec48 fix: email and username fields rendering in drawers (#7520)
Fixes https://github.com/payloadcms/payload/issues/7428

Now email and username fields are rendered with the RenderFields
component, making them behave similarly to other fields. They now appear
and can respect doc permissions, readOnly settings, etc.
2024-08-05 20:18:32 -04:00
Alessio Gravili
5d1cc760c9 fix(richtext-lexical): various table and icon style issues (#7522) 2024-08-05 22:10:18 +00:00
Alessio Gravili
2f90683c7d Merge PR: upgrade lexical, add table feature converter (#7521)
This PR
- upgrades lexical and ports all bug fixes from the playground over
- adds table action buttons. When hovering the edges of the table,
buttons pop up to easily add a new table column or row
- adds an html converter for the table feature
- makes the placeholder shown in the editor when no text is present
accessible

**BREAKING:** This upgrades lexical from 0.16.1 to 0.17.0. If you have
any lexical packages installed in your project, please update them
accordingly. Additionally, if you depend on the lexical APIs, please
consult their changelog, as lexical may introduce breaking changes:
https://github.com/facebook/lexical/releases/tag/v0.17.0
2024-08-05 17:18:57 -04:00
Patrik
3f5403a52a fix(ui): prevents hasMany text going outside of input boundaries (#7455)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/7454)

`Before`:
![Screenshot 2024-07-31 at 12 40
50 PM](https://github.com/user-attachments/assets/ce61f4fc-e676-4273-aa4c-72610cb459b3)

`After`:
![Screenshot 2024-07-31 at 12 40
23 PM](https://github.com/user-attachments/assets/d92631eb-28fb-46ca-bc23-46c7916bba34)

- [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] Existing test suite passes locally with my changes
2024-08-05 17:10:35 -04:00
Alessio Gravili
9bccdfd60a feat(richtext-lexical): add HTML converter to table feature 2024-08-05 17:01:21 -04:00
Patrik
62666a9897 fix(ui): properly handles ID field component type based on payload.db.defaultIDType (#7416)
## Description

Fixes #7354 

Since the `defaultIDType` for IDs in `postgres` are of type `number` -
the `contains` operator should be available in the filter options.

This PR checks the `defaultIDType` of ID and properly outputs the
correct component type for IDs

I.e if ID is of type `number` - the filter operators for ID should
correspond to the the operators of type number as well

The `contains` operator only belongs on fields of type string, aka of
component type `text`

- [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] Existing test suite passes locally with my changes
2024-08-05 16:39:27 -04:00
Alessio Gravili
eb27b84854 chore(richtext-lexical): backport various minor bugfixes from lexical playground 2024-08-05 16:35:13 -04:00
Alessio Gravili
c3480811d3 feat(richtext-lexical): accessible editor placeholders 2024-08-05 16:19:02 -04:00
Alessio Gravili
12ba820de4 feat(richtext-lexical): add table hover actions to quickly add rows or columns 2024-08-05 16:08:31 -04:00
Elliot DeNolf
95fcd13929 fix(db-*): drizzle enums, bump drizzle-kit (#7514)
- bumps drizzle-kit
- Fixes https://github.com/payloadcms/payload/issues/7492 Enum issue.
2024-08-05 14:53:21 -04:00
Jarrod Flesch
6141c5950b chore: improves plugin creation docs (#7515) 2024-08-05 14:50:53 -04:00
Elliot DeNolf
0040e1756c fix(cpa): adjust template file location detection (#7507)
Adjust template file location detection. This was causing issues when
run with `pnpm create` because it is not run from a `dist` directory.

```
┌   create-payload-app
│
◇   ────────────────────────────────────────────╮
│                                               │
│  Welcome to Payload. Let's create a project!  │
│                                               │
├───────────────────────────────────────────────╯
│
▲  Payload installation detected in current project.
│
◇  Upgrade Payload in this project?
│  Yes
│
◇  Using pnpm.
│
│
◇  Updating 7 Payload packages to v3.0.0-beta.73...
│
│    - payload
│    - @payloadcms/db-mongodb
│    - @payloadcms/db-postgres
│    - @payloadcms/next
│    - @payloadcms/richtext-lexical
│    - @payloadcms/richtext-slate
│    - @payloadcms/ui
│
◇  Payload packages updated successfully.
│
◇  Updating Payload Next.js files...
│
■  ENOENT: no such file or directory, copyfile '/Users/elliot/Library/pnpm/store/v3/tmp/dlx-99797/node_modules/.pnpm/create-payload-app@3.0.0-beta.73/templates/blank-3.0/src/app/(payload)' -> '/Users/elliot/dev/payload-3.0-demo/src/app/(payload)'
```
2024-08-05 16:28:13 +00:00
Jarrod Flesch
1ebd54b315 feat: allows loginWithUsername to not require username (#7480)
Allows username to be optional when using the new loginWithUsername
feature. This can be done by the following:

```ts
auth: {
  loginWithUsername: {
    requireUsername: false, // <-- new property, default true
    requireEmail: false, // default: false
    allowEmailLogin: true, // default false
  },
},
```
2024-08-05 11:35:01 -04:00
Jessica Chowdhury
cdb2072a6d fix: error thrown in version view when localization is false (#7502)
## Description

`const localeValues = locales.map((locale) => locale.value)`

This line was previously throwing an error in the version view when
localization is false. Changed to ensure locales exist before mapping
over them.

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [X] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-05 15:10:02 +00:00
Tylan Davis
68553ff974 feat!: updated admin UI (#7424)
## Description

- Updates admin UI with more condensed spacing throughout.
- Improves hover states and read-only states for various components.
- Removes the `Merriweather` font from `next/font` and replaces with
stack of system serif fonts and fallbacks (Georgia, etc). Closes #7257

## BREAKING CHANGES
- Custom components and styling that don't utilize Payload's CSS/SCSS
variables may need adjustments to match the updated styling.
- If you are using the `Merriweather` font, you will need to manually
configure `next/font` in your own project.

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-08-05 15:08:00 +00:00
Willy Brauner
9a3bce1118 feat: expose useTableColumns hook (#7448)
fix #4990 (v3)

## Description

Expose
[useTableColumns](b160686fff/packages/ui/src/elements/TableColumns/index.tsx (L25))
hook from client exported members of the ui packages.

The use of this hook, covered the case of custom ListView creation which
was not possible due to the lack of possibility to select a file if we
were in the "list-draw" view.

With `useTableColumns` we can execute the `onClick` defined in
`TableColumnsProvider` witch allows the selection on the clicked file.


b160686fff/packages/ui/src/elements/ListDrawer/DrawerContent.tsx (L290-L296)

## Use case

CustomListView.tsx:
```ts
const CustomListView = () => {
  // ...

  const tableColumns = useTableColumns()
  
  const handleItemClicked = (doc) => {
    const onClick = tableColumns.columns[0].cellProps?.onClick
    if (typeof onClick === 'function') {
      // we are in "list-drawer" view, execute the onClick function
      onClick({
        cellData: undefined,
        collectionSlug: doc,
        rowData: doc,
      })
    } else {
      // we are in "collection-admin" view, push the new route with next/navigation
      void router.push(`${collectionSlug}/${doc.id}`)
    }
  }
 
  return  <div className={"list"}>
            {data.docs?.length > 0 && (
              <RelationshipProvider>
                {docs.map((e, i) => (
                  <div className={"item"} key={i} onClick={() => handleItemClicked(e)}>
                     // ...
                  </div>
                ))}
              </RelationshipProvider>
            )}
          </div>
} 
```

This video shows the click of a file inside a CustomListView, in the
case of an "admin-collection" view then a "list-drawer" view.


https://github.com/user-attachments/assets/8aa17af5-a7aa-49de-b988-fc0db7ac8e47

- [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

<!-- Please delete options that are not relevant. -->

- [x] Chore (non-breaking change which does not add functionality)
- [x] Bug fix (non-breaking change which fixes an issue)

## Checklist:

- [x] Existing test suite passes locally with my changes
2024-08-05 14:52:47 +00:00
James Mikrut
005befcbe2 fix: #7488, cant deploy SQLite to Vercel (#7490)
## Description

Closes #7488 

Note - you'll also need to manually have `@libsql/client` installed in
your Next.js repository. This is not ideal, but it might be outside the
scope of what we can handle internally.

- [x] I have read and understand the
[CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md)
document in this repository.
2024-08-05 10:41:12 -04:00
Alessio Gravili
e65b6478c9 feat(richtext-lexical)!: upgrade lexical from 0.16.1 to 0.17.0 2024-08-05 09:58:27 -04:00
Elliot DeNolf
a79e92a145 chore(release): v3.0.0-beta.73 [skip ci] 2024-08-02 09:53:56 -04:00
Alessio Gravili
995f51d941 fix: too many RSC props were being passed, inflating initial HTML size (#7474)
The following config caused the html size to grow to 500mb:

```ts
import type { ArrayField, Block, CollectionConfig } from 'payload'

import { BlocksFeature, lexicalEditor } from '@payloadcms/richtext-lexical'

const richTextLayoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [],
    },
  ],
}

const richTextLayoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes2],
}

const richTextBlock2: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock2] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock2],
    },
  ],
}

const richTextLayoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes1],
}

const richTextBlock1: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock1] }),
        ],
      }),
    },
  ],
}

const richTextLayoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock1],
    },
  ],
}

const richTextLayoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'RichTextLayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [richTextLayoutBlockGridBoxes],
}

const richTextBlock: Block = {
  slug: 'rich-text',
  interfaceName: 'RichTextBlock',
  labels: { singular: 'Rich Text', plural: 'Rich Text' },
  fields: [
    {
      name: 'richTextContent',
      label: 'Rich Text',
      type: 'richText',
      required: true,
      editor: lexicalEditor({
        features: ({ defaultFeatures }) => [
          ...defaultFeatures,
          BlocksFeature({ blocks: [richTextLayoutBlock] }),
        ],
      }),
    },
  ],
}

const layoutBlockGridBoxes2: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [richTextBlock],
    },
  ],
}

const layoutBlock2: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes2],
}

const layoutBlockGridBoxes1: ArrayField = {
  name: 'gridBx',
  label: 'Grid Boxes',
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock2, richTextBlock],
    },
  ],
}

const layoutBlock1: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes1],
}

const layoutBlockGridBoxes: ArrayField = {
  name: 'gridBx',
  labels: { singular: 'Grid Box', plural: 'Grid Boxes' },
  type: 'array',
  fields: [
    {
      name: 'gridBx',
      label: 'Grid Box Content',
      type: 'blocks',
      maxRows: 1,
      blocks: [layoutBlock1, richTextBlock],
    },
  ],
}

const layoutBlock: Block = {
  slug: 'layout',
  interfaceName: 'LayoutBlock',
  labels: { singular: 'Layout', plural: 'Layout' },
  fields: [layoutBlockGridBoxes],
}

export const Pages: CollectionConfig = {
  slug: 'pages',
  fields: [
    {
      name: 'content',
      type: 'blocks',
      blocks: [layoutBlock],
    },
  ],
}
```

---------

Co-authored-by: James <james@trbl.design>
2024-08-02 13:17:56 +00:00
Radosław Kłos
4d19e64961 feat: adds upload's relationship thumbnail (#7473)
## Description
https://github.com/payloadcms/payload/pull/5015 's version for beta
branch. @JessChowdhury

- [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

<!-- Please delete options that are not relevant. -->

- [X] New feature (non-breaking change which adds functionality)
- [X] This change requires a documentation update

## 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-08-02 14:03:12 +01:00
Elliot DeNolf
31143599f6 feat(cpa): add sqlite (#7470)
Add `sqlite` as an option for create-payload-app.
2024-08-01 12:50:14 -04:00
Jessica Chowdhury
f752804410 fix: set active nav item (#7467)
## Description

Nav items not displaying different style when active.

We were previously using `NavLink` which determines if the item is
active and applies the classname. Now we are using the standard `Link`
and need to add the `active` classname manually.

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [X] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-01 16:01:57 +00:00
Elliot DeNolf
a18d4061ea chore(release): v3.0.0-beta.72 [skip ci] 2024-08-01 10:48:31 -04:00
Dan Ribbens
449c16d28f fix(db-postgres): incorrect schema type on adapter (#7459)
fixes a db-postgres type issue that was introduced in
https://github.com/payloadcms/payload/pull/7453
2024-08-01 10:39:54 -04:00
Jessica Chowdhury
d307d627ab feat: adds restore as draft option to versions (#7100)
## Description

Adds option to restore a version as a draft.

1. Run `versions` test suite
2. Go to `drafts` and choose any doc with `status: published`
3. Open the version
4. See new `restore as draft` option

<img width="1693" alt="Screenshot 2024-07-12 at 1 01 17 PM"
src="https://github.com/user-attachments/assets/14d4f806-c56c-46be-aa93-1a2bd04ffd5c">

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [X] 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

## Checklist:

- [ ] I have added tests that prove my fix is effective or that my
feature works
- [X] Existing test suite passes locally with my changes
- [ ] I have made corresponding changes to the documentation
2024-08-01 15:33:40 +01:00
Dan Ribbens
075819964d fix(db-postgres, db-sqlite): enum schema (#7453)
- updates drizzle-kit and drizzle-orm
- fix enum creation to fully support custom schemas
- sqlite by default will not use transactions
2024-07-31 16:42:00 -04:00
Dan Ribbens
1ec78a16f0 fix(db-postgres): localized array inside blocks field (#7457)
fixes #7371, #5240
2024-07-31 16:33:52 -04:00
Jarrod Flesch
290ffd3287 fix: validates password and confirm password on the server (#7410)
Fixes https://github.com/payloadcms/payload/issues/7380

Adjusts how the password/confirm-password fields are validated. Moves
validation to the server, adds them to a custom schema under the schema
path `${collectionSlug}.auth` for auth enabled collections.
2024-07-31 14:55:08 -04:00
Patrik
3d89508ce3 fix(ui): reincorporate basePath into logout component link (#7451)
## Description

Fixes issue where the `basePath` from the `next-config` was not
respected for the `logout` button link

- [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] Existing test suite passes locally with my changes
2024-07-31 11:00:02 -04:00
Elliot DeNolf
b160686fff ci: adjust canary release conditions 2024-07-31 00:39:22 -04:00
Elliot DeNolf
ba6ef6777f ci: auto release canary on success (#7444)
Automatically release canary on successful workflow.
2024-07-31 00:11:28 -04:00
Paul
febd7f7073 feat(ui): expose custom errors in deleteMany (#7438)
Closes https://github.com/payloadcms/payload/issues/7214
Exposes custom errors in the DeleteMany component so they can be more
descriptive:


![image](https://github.com/user-attachments/assets/f0c2f2e3-71a9-455f-9137-23eccfd21dbb)
2024-07-30 18:00:11 +00:00
Dan Ribbens
695ef32d1e feat(db-*): add defaultValues to database schemas (#7368)
## Description

Prior to this change, the `defaultValue` for fields have only been used
in the application layer of Payload. With this change, you get the added
benefit of having the database columns get the default also. This is
especially helpful when adding new columns to postgres with existing
data to avoid needing to write complex migrations. In MongoDB this
change applies the default to the Mongoose model which is useful when
calling payload.db.create() directly.

This only works for statically defined values.

🙏 A big thanks to @r1tsuu for the feature and implementation idea as I
lifted some code from PR https://github.com/payloadcms/payload/pull/6983

- [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] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## 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-07-30 13:41:18 -04:00
Elliot DeNolf
b5b2bb1907 fix(db-postgres): proper migrations table detection query (#7436)
Fixes postgres sql query to detect migrations table.

`error: syntax error at or near "exists"`
2024-07-30 11:38:28 -04:00
Elliot DeNolf
6f5cf5d916 feat(cpa): warn on unsupported Next.js version (#7434)
Improves messaging if running an unsupported version of Next.js.

Closes #7430
2024-07-30 11:14:57 -04:00
Alessio Gravili
aaf3a39f7e chore: upgrade typescript from 5.5.3 to 5.5.4 (#7435)
TypeScript 5.5.4 apparently speeds up linting by a lot:
https://github.com/microsoft/TypeScript/issues/59101
2024-07-30 15:09:28 +00:00
Jessica Chowdhury
5ef2951829 fix: formats locales for version comparison view (#7433)
Closes #7381
2024-07-30 10:24:55 -04:00
Paul
a943487fca fix: hide force unlock button if the user has no permissions to interact with it (#7418) 2024-07-29 20:49:57 +00:00
Jarrod Flesch
3a941c7c8a chore: duplicates prev value PRs from v2 (#7414)
Updates V3 with V2 PR's
- previousVersion type https://github.com/payloadcms/payload/pull/6805
- tests from https://github.com/payloadcms/payload/pull/6805
2024-07-29 16:28:28 -04:00
Dan Ribbens
354588898f feat(db-*, payload): better transactions (#7395)
## Description

### payload
- Removes calls to beginTransaction and commitTransaction from read
operations

### db-sqlite, db-postgres
- beginTransaction() options are passed through and used to create a
transaction
- declare module type adds beginTransaction with proper transaction
config args for postgres and sqlite
2024-07-29 15:35:19 -04:00
Jessica Chowdhury
ada9978a8c fix: page param not getting reset when applying filters (#7243)
Closes #7188

In the collection list view, after adding a filter, the page number
should be reset since the doc count will have changed.

---------

Co-authored-by: Jarrod Flesch <jarrodmflesch@gmail.com>
2024-07-29 13:25:43 -04:00
Jacob Fletcher
874279c530 fix(next): infinite loop when logging into root admin (#7412) 2024-07-29 12:57:57 -04:00
Paul
7ed6634bc5 fix: types for the 'validate' property across fields so internal validation functions can be reused (#7394)
Fixes the types for validate functions so that internal validation
functions can be re-used

Currently this has a type error
```ts
validate: (value, args) => {
  return text(value, args)
},
```
2024-07-29 12:36:28 -04:00
Michel v. Varendorff
09a0ee3ab9 fix: export default was not found in graphql (#6975) 2024-07-29 11:37:58 -04:00
Lynn Dylan Hurley
67acab2cd5 fix(searchPlugin): ensure search updates are unique to collection (#6363) 2024-07-29 11:33:59 -04:00
Jarrod Flesch
b3dc6cc811 chore: extends buildConfigWithDefaults to accept options arg (#7411) 2024-07-29 11:10:46 -04:00
Jarrod Flesch
5cd0c7ec7d fix: layout preferences for array/blocks were being saved twice in dev mode (#7396)
Fixes an issue where preferences for array/block collapsible's were not
being set correctly. React strict mode surfaced this issue.
2024-07-29 09:59:05 -04:00
Elliot DeNolf
cd592cb3a2 chore(release): v3.0.0-beta.71 [skip ci] 2024-07-29 08:43:45 -04:00
Dan Ribbens
6d066c2ba4 fix(db-sqlite): migration template errors (#7404)
- Fix migration template for sqlite
- Add declare for payload.db.drizzle as type LibSQLDatabase
- Correct drizzle snapshot version
2024-07-27 22:10:09 -04:00
Dan Ribbens
1dc428823a fix(db-postgres): migration template type error (#7403)
Fixes #7402

This fixes a regression from changes to the postgres migration template
that were incorrect. It also fixes other type errors for
`payload.db.drizzle` which needed to be declared for postgres to avoid
confusing it with Libsql for SQLite.
2024-07-27 21:52:36 -04:00
James Mikrut
c8da9b148c fix: merges headers safely in nextjs route handlers (#7399)
## Description

Merges headers safely within Payload-handled Next.js route handlers.
2024-07-27 16:34:06 +00:00
Jacob Fletcher
2021028d64 fix(ui): stacking drawers (#7397) 2024-07-27 09:33:31 -04:00
Paul
2ea56fe0f8 fix(docs): update import path for validation functions for fields (#7392) 2024-07-26 18:32:58 +00:00
Jacob Fletcher
ea16119af7 chore(cpa): replaces missing type assertion (#7391) 2024-07-26 14:13:46 -04:00
Jacob Fletcher
97837f0708 feat(ui)!: passes field props to custom components (#7360)
## Description

Currently, there is no way to read field props from within a custom
field component, i.e. `admin.components.Description`. For example, if
you set `maxLength: 100` on your field, your custom description
component cannot read it from `props.maxLength` or any other methods.
Because these components are rendered on the server, there is also no
way of using `admin.component.Field` to inject custom props yourself,
either. To support this, we can simply pass the base component props
into these components on the server, as expected. This has also led to
custom field component props becoming more strictly typed within the
config.

This change is considered breaking only because the types have changed.
This only affects you if you were previously importing the following
types into your own custom components. To migrate, simply change the
import paths for that type.

Old:
```ts
import type {
  ArrayFieldProps,
  ReducedBlock,
  BlocksFieldProps,
  CheckboxFieldProps,
  CodeFieldProps,
  CollapsibleFieldProps,
  DateFieldProps,
  EmailFieldProps,
  GroupFieldProps,
  HiddenFieldProps,
  JSONFieldProps,
  NumberFieldProps,
  PointFieldProps,
  RadioFieldProps,
  RelationshipFieldProps,
  RichTextComponentProps,
  RowFieldProps,
  SelectFieldProps,
  TabsFieldProps,
  TextFieldProps,
  TextareaFieldProps,
  UploadFieldProps,
  ErrorProps,
  FormFieldBase, 
  FieldComponentProps,
  FieldMap,
  MappedField,
  MappedTab,
  ReducedBlock,
} from '@payloadcms/ui'
```

New:
```ts
import type {
  FormFieldBase, 
  // etc.
} from 'payload'
```

Custom field components are now much more strongly typed. To make this
happen, an explicit type for every custom component has been generated
for every field type. The convention is to append
`DescriptionComponent`, `LabelComponent`, and `ErrorComponent` onto the
end of the field name, i.e. `TextFieldDescriptionComponent`. Here's an
example:

```ts
import type { TextFieldDescriptionComponent } from 'payload'

import React from 'react'

export const CustomDescription: TextFieldDescriptionComponent = (props) => {
  return (
    <div id="custom-field-description">{`The max length of this field is: ${props?.maxLength}`}</div>
  )
}
```

Here's the full list of all new types:

Label Components:

```ts
import type {
  ArrayFieldLabelComponent,
  BlocksFieldLabelComponent,
  CheckboxFieldLabelComponent,
  CodeFieldLabelComponent,
  CollapsibleFieldLabelComponent,
  DateFieldLabelComponent,
  EmailFieldLabelComponent,
  GroupFieldLabelComponent,
  HiddenFieldLabelComponent,
  JSONFieldLabelComponent,
  NumberFieldLabelComponent,
  PointFieldLabelComponent,
  RadioFieldLabelComponent,
  RelationshipFieldLabelComponent,
  RichTextFieldLabelComponent,
  RowFieldLabelComponent,
  SelectFieldLabelComponent,
  TabsFieldLabelComponent,
  TextFieldLabelComponent,
  TextareaFieldLabelComponent,
  UploadFieldLabelComponent
} from 'payload'
```

Error Components:

```tsx
import type {
  ArrayFieldErrorComponent,
  BlocksFieldErrorComponent,
  CheckboxFieldErrorComponent,
  CodeFieldErrorComponent,
  CollapsibleFieldErrorComponent,
  DateFieldErrorComponent,
  EmailFieldErrorComponent,
  GroupFieldErrorComponent,
  HiddenFieldErrorComponent,
  JSONFieldErrorComponent,
  NumberFieldErrorComponent,
  PointFieldErrorComponent,
  RadioFieldErrorComponent,
  RelationshipFieldErrorComponent,
  RichTextFieldErrorComponent,
  RowFieldErrorComponent,
  SelectFieldErrorComponent,
  TabsFieldErrorComponent,
  TextFieldErrorComponent,
  TextareaFieldErrorComponent,
  UploadFieldErrorComponent
} from 'payload'
```

Description Components:

```tsx
import type {
  ArrayFieldDescriptionComponent,
  BlocksFieldDescriptionComponent,
  CheckboxFieldDescriptionComponent,
  CodeFieldDescriptionComponent,
  CollapsibleFieldDescriptionComponent,
  DateFieldDescriptionComponent,
  EmailFieldDescriptionComponent,
  GroupFieldDescriptionComponent,
  HiddenFieldDescriptionComponent,
  JSONFieldDescriptionComponent,
  NumberFieldDescriptionComponent,
  PointFieldDescriptionComponent,
  RadioFieldDescriptionComponent,
  RelationshipFieldDescriptionComponent,
  RichTextFieldDescriptionComponent,
  RowFieldDescriptionComponent,
  SelectFieldDescriptionComponent,
  TabsFieldDescriptionComponent,
  TextFieldDescriptionComponent,
  TextareaFieldDescriptionComponent,
  UploadFieldDescriptionComponent
} from 'payload'
```

This PR also:
- Standardizes the `FieldBase['label']` type with a new `LabelStatic`
type. This makes type usage much more consistent across components.
- Simplifies some of the typings in the field component map, removes
unneeded `<Omit>`, etc.
- Fixes misc. linting issues around voiding promises

- [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] New feature (non-breaking change which adds functionality)

## 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-07-26 14:03:25 -04:00
Paul
e734d51760 chore(ui)!: update the names of internal components so that they respect eslint rules (#7362)
So `_Upload` becomes `UploadComponent` which doesnt break the naming
convention of react components and **we no longer export these internal
components**
2024-07-26 17:50:23 +00:00
Patrik
5655266daa fix(ui): handle abort() call signal error (#7390)
## Description

Swallows `.abort()` call signal errors

- [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] Existing test suite passes locally with my changes
2024-07-26 13:16:22 -04:00
James Mikrut
f9e5573c1e feat: adds keepAfterRead to plugin-relationship-objectid (#7388)
## Description

Duplicate of
https://github.com/payloadcms/plugin-relationship-object-ids/pull/6 for
3.x
2024-07-26 15:39:39 +00:00
Paul
e823051a8e fix(ui): spacing in row fields by using gap instead of inner margins (#7387) 2024-07-26 15:34:30 +00:00
Elliot DeNolf
49df61d9ec chore(release): v3.0.0-beta.70 [skip ci] 2024-07-26 11:16:04 -04:00
Paul
4704c8db2a feat(templates): add live preview breakpoints for mobile, tablet and desktop to website template (#7384) 2024-07-26 14:41:59 +00:00
Elliot DeNolf
a64f37e014 feat(cpa): support next.config.ts (#7367)
Support new `next.config.ts` config file.

Had to do some weird gymnastics around `swc` in order to use it within
unit tests. Had to pass through the `parsed.span.end` value of any
previous iteration and account for it.

Looks to be an open issue here:
https://github.com/swc-project/swc/issues/1366

Fixes #7318
2024-07-26 10:33:46 -04:00
Elliot DeNolf
55c6ce92b0 fix(db-postgres): properly reference drizzle createTableName function (#7383)
Fix incorrect relative import of drizzle package's `createTableName`
function. Now uses proper package import.

Fixes #7373
2024-07-26 10:08:31 -04:00
Elliot DeNolf
2ecbcee378 chore(release): v3.0.0-beta.69 [skip ci] 2024-07-25 22:17:04 -04:00
James Mikrut
70f2e1698a fix: filterOptions for upload fields (#7347)
## Description

Fixes uploads `filterOptions` not being respected in the Payload admin
UI.

Needs a test written, fixes to types in build, as well as any tests that
fail due to this change in CI.

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

- [ ] 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
2024-07-25 21:42:36 +00:00
Patrik
8ba39aa5ca fix(db-mongodb): adds new optional collation feature flag behind mongodb collation option (#7361)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/7359)

- [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)
- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## Checklist:

- [x] Existing test suite passes locally with my changes
- [x] I have made corresponding changes to the documentation
2024-07-25 12:38:18 -04:00
Elliot DeNolf
f8c79d2f84 ci: label pr on open 2024-07-25 10:48:54 -04:00
Paul
128d72185d fix(ui): hide 'Create new' button entirely if user has no access to create a media item (#7348)
Makes it so that if you don't have access to create a new media you
don't get the button shown at all:

![image](https://github.com/user-attachments/assets/2a9c1b24-a4cb-41f3-9145-514cd51a2f1f)
2024-07-25 14:35:43 +00:00
Jarrod Flesch
abc786d864 chore: removes todo comment in AuthProvider (#7356) 2024-07-25 10:06:11 -04:00
Elliot DeNolf
791fa68820 ci: disable app-build-with-packed 2024-07-24 16:34:03 -04:00
Jarrod Flesch
2796d2100f fix: attempts to use query.locale when present in createLocalReq (#7345)
Fixes https://github.com/payloadcms/payload/issues/7341

req.locale was incorrectly set, stemming from initPage, where
req.query.locale was not being used if present inside the
`createLocaleReq` function.
2024-07-24 16:30:05 -04:00
Jarrod Flesch
cbac62a36f fix: relaxes equality check for relationship options in filter (#7343)
Fixes https://github.com/payloadcms/payload/issues/7271

When extracting the value from the querystring, it is _always_ a string.
We were using a strict equality check which would cause the filter
options to never find the correct option. This caused an infinite loop
when using PG as ID's are numbers by default.
2024-07-24 15:53:29 -04:00
Patrik
b5afc62e14 feat(payload): allows metadata to be appended to the file of the output media (#7293)
## Description

Fixes #6951 

`Feat`: Adds new prop `withMetadata` to `uploads` config that allows the
user to allow media metadata to be appended to the file of the output
media.

- [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)
- [x] New feature (non-breaking change which adds functionality)
- [x] This change requires a documentation update

## 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-07-24 15:32:39 -04:00
Elliot DeNolf
0627272d6c chore(scripts): adjust release notes indent 2024-07-24 14:27:36 -04:00
Ritsu
51f1c8e7e8 fix(db-postgres): localized groups/tabs and nested fields (#6158)
---------

Co-authored-by: Dan Ribbens <dan.ribbens@gmail.com>
2024-07-24 13:57:10 -04:00
Dan Ribbens
09ad6e4280 feat(drizzle): abstract shared sql code to new package (#7320)
- Abstract shared sql code to a new drizzle package
- Adds sqlite package, not ready to publish until drizzle patches some
issues
- Add `transactionOptions` to allow customizing or disabling db
transactions
- Adds "experimental" label to the `schemaName` property until drizzle
patches an issue
2024-07-24 12:43:29 -04:00
Paul
c129c10f0f fix: some email adapters not working if they're promises due to config sanitisation (#7326) 2024-07-24 14:23:04 +00:00
Jacob Fletcher
904ec0160e feat: adds @payloadcms/live-preview-vue to release pipeline (#7328) 2024-07-24 10:07:34 -04:00
Jessica Chowdhury
b2814eb67c fix: misc issues with loginWithUsername (#7311)
- improves types
- fixes create-first-user fields
2024-07-23 15:14:12 -04:00
Paul
c405e5958f fix(ui): email field now correctly renders autocomplete attribute (#7322)
Adds test as well for the email field
2024-07-23 18:57:53 +00:00
Jacob Fletcher
a35979f74e fix(plugin-stripe): properly types async webhooks (#7317) 2024-07-23 14:30:09 -04:00
Jacob Fletcher
863abc0e6b feat(next): root admin (#7276) 2024-07-23 13:44:44 -04:00
Paul
b9cf6c73a9 fix(ui): Where query selectors for checkboxes are now translated (#7309)
Fixes https://github.com/payloadcms/payload/issues/7204
2024-07-23 17:12:18 +00:00
Jessica Chowdhury
f2b3305cb0 fix: first version doc throws error (#7314)
## Description

The first version document throws an error because `latestPublished` and
`latestDraft` are undefined.

- [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] Existing test suite passes locally with my changes
2024-07-23 16:36:16 +00:00
Patrik
b3e8ddf302 fix(db-mongodb): removes precedence of regular chars over international chars in sort (#7294)
## Description

V2 PR [here](https://github.com/payloadcms/payload/pull/6923)

- [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
2024-07-23 09:03:00 -04:00
Jacob Fletcher
b6d4bc4d37 docs: cleanup to individual field docs (#7202) 2024-07-22 23:46:06 -04:00
Elliot DeNolf
83ad453a89 fix(cpa): check cmd exists after first checking flag and lock file (#7297)
Adjust logic for determining package manager. Needed to move command
exists logic to be evaluated only after other possibilities were
exhausted.

Closes #7290
2024-07-22 22:11:44 -04:00
Elliot DeNolf
4e6a7d489c chore(scripts): delete-recursively output spacing 2024-07-22 21:26:21 -04:00
Elliot DeNolf
a8d88b8238 chore(release): v3.0.0-beta.68 [skip ci] 2024-07-22 16:05:04 -04:00
Jarrod Flesch
5aa3283dc0 fix: search plugin localized fields (#7292) 2024-07-22 15:47:39 -04:00
Alessio Gravili
45844789f2 feat: upgrade pino and pino-pretty, clean up hacky esm imports (#7291)
Doesn't look like those hacky esm-cjs imports are needed anymore.

These major pino releases only drop Node.js version support for versions
which payload doesn't support anyways.
2024-07-22 15:11:34 -04:00
Alessio Gravili
79975f48cf chore: ensure the correct next & react versions are installed in templates and core (#7283)
Some package.json's were on older or mismatching Next.js / React
versions. This includes other Next.js packages like @next/env
2024-07-22 18:33:54 +00:00
Paul
bba7cf37f8 fix(templates): website template building error with postgres number IDs (#7281) 2024-07-22 17:40:58 +00:00
Paul
1ae71a3d24 fix(ui): not updating permissions when locale changes (#7245)
Closes https://github.com/payloadcms/payload/issues/7163
2024-07-22 17:31:20 +00:00
Alessio Gravili
e83eb99436 feat: remove joi schema validation (#7226)
We do not really need runtime joi schema validation - this is what TypeScript is for. If people are ignoring TypeScript errors in your schema, or JavaScript errors, that is their fault and does not warrant an extra dependency (joi), lots of code to maintain, as well as slower startups.

If we wanna keep runtime schema validation, we should switch to zod so that we can generate TypeScript types based on the schema and do not have to manually maintain config properties in 2 different places (types & schema).

**joi PROs:**
- Safety for JavaScript-only evangelists messing up their schema
- Safety for people putting @ts-expect-error or `as any` everywhere in their code

**joi CONs:**
- Larger bundle size
- More Modules
- Slower Compilation Speed in dev. Worse DX
- Slower Startup (it needs to validate) in dev. Worse DX
- More code to maintain. For every schema change we'll have to change the types AND the joi schema
- TypeScript already throws proper errors if you mess up your schema. Why have runtime errors?
- The errors are bad. They might tell you what field has an issue, but they do not tell you what exactly is wrong. You have probably seen those "Field XY, value is incorrect" errors - and value could mean anything. Worse DX
- Having extra properties in your schema, even if they are useless, doesn't cause any harm

Cons outweigh the pros
2024-07-22 13:22:54 -04:00
Dan Ribbens
f50e599684 chore: add index to status for versions (#6257) 2024-07-22 13:13:09 -04:00
Dan Ribbens
7dab75d85e chore: make ui bundle script windows compatible (#7197) 2024-07-22 13:10:07 -04:00
Alessio Gravili
c45fbb9149 feat!: 700% faster deepCopyObject, refactor deep merging and deep copying, type improvements (#7272)
**BREAKING:**
- The `deepMerge` exported from payload now handles more complex data and
is slower. The old, simple deepMerge is now exported as `deepMergeSimple`
- `combineMerge` is no longer exported. You can use
`deepMergeWithCombinedArrays` instead
- The behavior of the exported `deepCopyObject` and `isPlainObject` may
be different and more reliable, as the underlying algorithm has changed
2024-07-22 13:01:52 -04:00
Patrik
2c16c608ba fix(payload): resizes images first before applying focal point (#7277)
Fixes #7275
2024-07-22 12:28:35 -04:00
Paul
c3f6c81dc6 chore: add custom ID warning about forbidden characters (#7268) 2024-07-22 02:23:53 +00:00
Alessio Gravili
a7b0f8ba36 feat!: new server-only, faster and immediate autoLogin (#7224)
- When autoLogin is enabled, it will no longer flash an unresponsive
"login" screen. Instead, it will straight up open the admin panel.
That's because, on the server, we will now always & immediately see the
user as authenticated, thus no initial login view is pushed to the
client until the client component sends the auth request anymore. Less
useless requests. Additionally, jwt verification is now completely
skipped
- No more auto-login related frontend code. autoLogin handling has been
removed from the frontend `Auth` component
- less code to maintain, this is way simpler now

**For reviewers:**
- The new logic for autoFill without prefillOnly is here: [jwt auth
strategy](https://github.com/payloadcms/payload/pull/7224/files#diff-7d40839079a8b2abb58233e5904513ab321023a70538229dfaf1dfee067dc8bfR21)
- The new logic for autoFill with prefillOnly is here: [Server Login
View](https://github.com/payloadcms/payload/pull/7224/files#diff-683770104f196196743398a698fbf8987f00e4426ca1c0ace3658d18ab80e82dL72)
=> [Client Login
Form](https://github.com/payloadcms/payload/pull/7224/files#diff-ac3504d3b3b0489455245663649bef9e84477bf0c1185da5a4d3a612450f01eeL20)

**BREAKING**
`autoLogin` without `prefillOnly` set now also affects graphQL/Rest
operations. Only the user specified in `autoLogin` will be returned.
Within the graphQL/Rest/Local API, this should still allow you to
authenticate with a different user, as the autoLogin user is only used
if no token is set.
2024-07-20 23:25:50 +00:00
Paul
014ee1a1b2 feat(ui): change autosave logic to send updates as soon as possible, improving live preview speed (#7201)
Now has a minimum animation time for the autosave but it fires off the
send events sooner to improve the live preview timing.
2024-07-19 15:24:53 -04:00
Patrik
cf6da0186b chore(translations, ui): updates addImage translation to addFile translation (#7231) 2024-07-19 13:36:37 -04:00
Jacob Fletcher
18063bd256 chore(examples): proper module resolution and migrations for multi-tenant single-domain example (#7240) 2024-07-19 13:18:13 -04:00
Paul
76b3075369 feat: update reserved fields name check to be more comprehensive and only check top level fields (#7235)
Continuation of https://github.com/payloadcms/payload/pull/7179
2024-07-19 15:53:00 +00:00
Jacob Fletcher
3d63ce94bb fix: api errors not populating in prod (#7232) 2024-07-19 11:42:53 -04:00
Paul
f8a5103ed7 chore(docs): update rest API handler to async (#7237)
Closes https://github.com/payloadcms/payload/issues/7077
2024-07-19 15:41:10 +00:00
Paul
2bd53a06eb chore(templates): add react cache to queryPostBySlug in website template (#7219) 2024-07-18 18:20:05 +00:00
Elliot DeNolf
442518dbc9 ci: make release script synchronous to ensure consistency 2024-07-18 14:09:36 -04:00
Elliot DeNolf
d3131122db chore(release): v3.0.0-beta.67 [skip ci] 2024-07-18 14:00:49 -04:00
Alessio Gravili
6d0dfeafc8 chore: ensure fs operations in bundle scripts finish in sync (#7218)
Hopefully fixes broken releases
2024-07-18 13:44:26 -04:00
Patrik
00771b1f2a fix(ui): uploading from drawer & focal point positioning (#7117)
Fixes #7101
Fixes #7006

Drawers were sending duplicate query params. This new approach modeled after the fix in V2, ensures that each drawer has its own action url created per document and the query params will be created when that is generated.

Also fixes the following:
- incorrect focal point cropping
- generated filenames for animated image names used incorrect heights
2024-07-18 13:43:53 -04:00
Jarrod Flesch
448186f374 chore: use href for locale switching, warns user before leaving (#7215)
Opts to use links instead of router.replace when switching locales. The
main benefit is now the user will be warned if they have changes and
want to switch locales. Before it would switch locales and they would
lose any unsaved changes in the locale they came from.
2024-07-18 12:59:27 -04:00
Elliot DeNolf
0ada3df220 chore(release): v3.0.0-beta.66 [skip ci] 2024-07-18 12:25:49 -04:00
Jarrod Flesch
478fb8d3fd fix: cherry picks lockUntil fix from #6052 (#7213) 2024-07-18 12:14:31 -04:00
Jacob Fletcher
700baf1899 fix: aliases AfterMe, AfterLogout, and AfterRefresh hook types (#7216) 2024-07-18 15:49:50 +00:00
Jarrod Flesch
7b3b02198c feat: ability to login with email, username or both (#7086)
`auth.loginWithUsername`:

```ts
auth: {
  loginWithUsername: {
    allowEmailLogin: true, // default: false
    requireEmail: false, // default: false
  }
}
```

#### `allowEmailLogin`
This property will allow you to determine if users should be able to
login with either email or username. If set to `false`, the default
value, then users will only be able to login with usernames when using
the `loginWithUsername` property.

#### `requireEmail`
Require that users also provide emails when using usernames.
2024-07-18 10:29:44 -04:00
Paul
a3af3605f0 fix(templates): bad import in website seed script (#7198) 2024-07-17 18:20:43 +00:00
Paul
502548a581 feat: add db idType to generated payload types (#7186)
Makes it so generated types now includes a `db` object with `idType` set
to `string` or `number` depending on the database

```ts
db: {
  defaultIDType: number;
};
```
2024-07-17 18:01:28 +00:00
Alessio Gravili
1fe6761d43 fix: maxListenersExceeded warning due to atomically, which is a peerdep of conf (#7182)
The conf dependency being bundled (not even executed) causes frequent
HMR runs (around 10+) to throw multiple MaxListenersExceeded warnings in
the console.

This PR
- fixes telemetry which was previously broken (threw an error which we
ignored) due to a conf version upgrade
- Removes the conf dependency (which is large and comes with a lot of
unneeded dependencies from functionality we don't need, like dot
notation or ajv validation). The important parts of the source code were
copied over - it's now dependency-free
- makes sure we only register the Next.js HMR websocket listener once,
by adding it to the cache

Before this PR:
![CleanShot 2024-07-16 at 19 35
22](https://github.com/user-attachments/assets/cfd926b7-fe5d-440a-9b35-91f61eaa69fd)


After this PR:

![CleanShot 2024-07-16 at 19 37
41](https://github.com/user-attachments/assets/f5d0f0f3-4e00-4d28-8e32-be42db2f5f6c)

Canary: 3.0.0-canary.ca3dd1c
2024-07-17 13:19:08 -04:00
Paul
f909f0663b fix(ui): search queries remain between navigation (#7169)
Closes https://github.com/payloadcms/payload/issues/7085
2024-07-17 17:17:46 +00:00
Jacob Fletcher
edb501349f docs: improves authentication docs (#7195) 2024-07-17 12:52:41 -04:00
Alessio Gravili
4ff8b20ddb chore(templates): clean up templates dependencies (#7139)
- use react 19 types
- no need for dotenv - next has their own dotenv file loader
- disable deprecation warnings by default (newer node version spam you
with it)
- disable turbo by default as hmr is broken and we cannot test against
it yet
- remove ts-node mention in tsconfig as it's not used anymore
- remove unused packages
- [fix: potential seed issues due to parallel payload operations being
on the same
transaction](f899f6a408)
and
b3b565dd75
@DanRibbens can you sense-check this? I do remember that anything
running in parallel should never be on the same transaction

---------

Co-authored-by: Paul Popus <paul@nouance.io>
2024-07-17 02:43:58 +00:00
Alessio Gravili
fe23ca5b1a fix(richtext-lexical): slash menu keyboard navigation not triggering auto-scroll (#7185)
`ref` was not added to internal slash menu items correctly.

Works as expected now:
![CleanShot 2024-07-16 at 22 05
41](https://github.com/user-attachments/assets/cfb32ec8-a449-41a7-a556-1e5ac365c6bc)
2024-07-17 02:30:04 +00:00
Alessio Gravili
8fdd88bd66 fix: webpack error if dbName or enumName was set (#7184)
Something like this:

```ts
  {
    name: 'select',
    type: 'select',
    dbName: ({ tableName }) => `${tableName}_customSelect`,
    enumName: 'selectEnum',
    hasMany: true,
    options: ['a', 'b', 'c'],
},
```
        
caused the "Functions cannot be passed directly to Client Components"
error, as the dbName function was sent to the client.

Now, you can run `pnpm dev database` again without it erroring
2024-07-17 01:02:42 +00:00
Alessio Gravili
676dfa3ecf feat(richtext-lexical): inline blocks (#7102) 2024-07-17 00:42:36 +00:00
Jessica Chowdhury
1ea2e323bc fix(ui): date field background color specificity (#7181)
## Description

Fixes `date` field background in dark mode.

Before:
<img width="464" alt="Screenshot 2024-07-16 at 5 22 42 PM"
src="https://github.com/user-attachments/assets/90235512-bd97-4b0a-b7b8-3e4ce49a8ba2">

After:
<img width="502" alt="Screenshot 2024-07-16 at 5 22 53 PM"
src="https://github.com/user-attachments/assets/ce3f5bc9-8693-4fc8-a0e3-d0042a92756f">

- [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] Chore (non-breaking change which does not add functionality)
2024-07-16 21:36:34 +00:00
Jessica Chowdhury
8fb17c2752 fix: version comparison view showing empty localized fields (#7180)
## Description

Localized fields show no data for the base comparison data in the
version comparison view.

Before:
<img width="1419" alt="Screenshot 2024-07-16 at 4 48 45 PM"
src="https://github.com/user-attachments/assets/c4c063a6-41c1-41a5-92b3-ff7d1febe9f1">

After:
<img width="1382" alt="Screenshot 2024-07-16 at 4 46 31 PM"
src="https://github.com/user-attachments/assets/bbfa9faf-2753-450d-a911-fbbca27ab051">

- [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] Existing test suite passes locally with my changes
2024-07-16 21:08:48 +00:00
Jacob Fletcher
2d96a1f0b6 docs: misc improvements to high-level docs (#7177) 2024-07-16 15:47:56 -04:00
Paul
2f0aa83a93 fix: localised relationship fields (#7178)
Fixes the issue where locale is not passed into the relationship field
resulting in documents without titles in some situations


![image](https://github.com/user-attachments/assets/67f0a70c-29a0-4f54-a395-f4aa9b132d6f)
2024-07-16 19:22:37 +00:00
Jacob Fletcher
0371aea711 docs: moves collection and global admin options to admin docs (#7168) 2024-07-16 12:08:21 -04:00
Alessio Gravili
36ae125caf chore(richtext-lexical): adjust error message when loading the editor on unmigrated data (#7170) 2024-07-16 16:07:53 +00:00
Jarrod Flesch
fa07b317b1 chore(examples): updates to multi tenant single domain example (#7165) 2024-07-16 09:06:46 -04:00
Alessio Gravili
08f50bb441 chore: run esbuild scripts in sync, hopefully fixing publishing issues (#7159)
We are suspecting that operations within those esbuild scripts are not
awaited properly - potentially causing issues in the publish script,
publishing the next package without any built .js files
2024-07-15 17:31:48 -04:00
Jacob Fletcher
2925c3bb90 docs: root hooks (#7160) 2024-07-15 17:15:34 -04:00
Alessio Gravili
c6da04a061 feat(next): strongly type getNextRequestI18n (#7157)
Fixes https://github.com/payloadcms/payload/issues/7137
2024-07-15 20:48:17 +00:00
Alessio Gravili
809ae41725 chore(richtext-lexical): add e2e test which reproduces #7128 (#7156)
Fix for this is in separate PR:
https://github.com/payloadcms/payload/pull/7155
2024-07-15 20:47:03 +00:00
Elliot DeNolf
ee6ab214a5 chore(release): v3.0.0-beta.65 [skip ci] 2024-07-15 16:29:22 -04:00
Elliot DeNolf
bda43b4b54 chore(release): v3.0.0-beta.64 [skip ci] 2024-07-15 16:24:59 -04:00
Alessio Gravili
35f7a9e706 fix(richtext-lexical): newly created upload nodes with extra fields do not display fields when opening extra fields drawer (#7155)
Fixes #7128
2024-07-15 20:18:21 +00:00
Alessio Gravili
a4c7fddc87 Merge PR: richttext migration and field recursion issues (#7153) 2024-07-15 15:41:23 -04:00
Jacob Fletcher
0e673c6335 docs: improves access control docs (#7154) 2024-07-15 15:29:11 -04:00
Alessio Gravili
8c5a1f08df fix(richtext-*): nested field recursion for named tabs did not work 2024-07-15 14:51:29 -04:00
Alessio Gravili
6d68a4a269 fix(richtext-lexical): one-line migrators not detecting richText migrations in nested fields 2024-07-15 14:47:57 -04:00
Alessio Gravili
0132367036 chore(eslint-config): add missing recommended config for eslint-plugin-react-hooks (#7152)
Adds back eslint warnings if, for example, the dependencies array of a
Hook does not include all the required dependencies.
2024-07-15 17:56:59 +00:00
Hulpoi George-Valentin
9c72ab97b0 feat: configure cors allowed headers (#6837)
## Description

Currently, the Payload doesn't support to extend the Allowed Headers in
CORS context. With this PR, `cors` property can be an object with
`origins` and `headers`.

- [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

- [ ] Chore (non-breaking change which does not add functionality)
- [ ] Bug fix (non-breaking change which fixes an issue)
- [x] 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)
- [x] This change requires a documentation update

## 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

Co-authored-by: Alessio Gravili <alessio@gravili.de>
2024-07-15 13:26:29 -04:00
Jasper Beaurain
f494ebabbf fix(email-nodemailer): skipVerify behavior being reversed (#6790)
Fixes #6789

The skipVerify field in NodemailerAdapterArgs worked in reverse of what
it was supposed to do:
- With skipVerify = true -> Verified transport
- With skipVerify = false -> Did not verify transport

This PR makes the property work in the intended way:
- With skipVerify = true -> DO NOT verify transport
- With skipVerify = false -> DO verify transport
2024-07-15 12:52:09 -04:00
Jarrod Flesch
598542dd51 chore(examples): multi tenant single domain updates (#7149) 2024-07-15 11:53:40 -04:00
Paul
24f55c90c8 fix: custom tabs not working in globals (#7148) 2024-07-15 15:31:45 +00:00
Alessio Gravili
940d0ad562 chore(templates): improve website template lexical types (#7135)
Uses the new lexical types. Fully-typed nodes array, no more assertions
2024-07-13 16:41:18 -04:00
Elliot DeNolf
ed1dc4b129 chore(release): v3.0.0-beta.63 [skip ci] 2024-07-12 16:59:10 -04:00
Elliot DeNolf
f3eb5b2f05 chore(release): v3.0.0-beta.62 [skip ci] 2024-07-12 16:29:38 -04:00
Paul
03d854ed18 feat: validate field names for reserved names (#7130)
We now validate the names of the field against an array of protected
field names.

Also added JSDoc since we can't enforce type strictness yet if `string |
const[]` as it always evaluates to `string`.

```
The name of the field. Must be alphanumeric and cannot contain ' . '

Must not be one of protected field names: ['__v', 'salt', 'hash', 'file']

@link — [https://payloadcms.com/docs/fields/overview#field-names](vscode-file://vscode-app/usr/share/code/resources/app/out/vs/code/electron-sandbox/workbench/workbench.html)
```
2024-07-12 16:27:10 -04:00
Tylan Davis
c359c34ee8 feat(ui): various admin panel styling improvements (#7121)
- Improves color contrast of various components in the admin panel.
- Adjusts placement of field error tooltips for consistency.
- Corrects misaligned modals.
- Fixes issue where `admin.layout: vertical` was not being applied to
`radio` fields.
2024-07-12 20:16:27 +00:00
Jacob Fletcher
6578b85057 docs: improves hooks docs (#7133) 2024-07-12 19:51:17 +00:00
Elliot DeNolf
b750ebf166 feat: suppress email adapter warning on build (#7129)
Email adapter warnings are triggered on production builds. The
`NEXT_PHASE` env var is now evaluated before logging this warning.
2024-07-12 13:05:25 -04:00
Alessio Gravili
31b7a7046b Merge PR: lexical type improvements (#7132) 2024-07-12 12:58:00 -04:00
Jessica Chowdhury
c019969271 feat(ui): updates version status UI to be more informative (#6661)
## Description

Improves the status pill in the version archive and version comparison
views.

- [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] New feature (non-breaking change which adds functionality)

## Checklist:

- [X] Existing test suite passes locally with my changes
2024-07-12 16:48:18 +00:00
Alessio Gravili
1c8bed5c35 feat(richtext-lexical): add missing SerializedLineBreakNode to default node types, remove SerializedBlockNode from default node types 2024-07-12 11:59:09 -04:00
Alessio Gravili
10336ba6a8 feat(richtext-lexical): allow SerializedBlockNode fields to be typed via generic 2024-07-12 11:57:48 -04:00
Elliot DeNolf
43b971c40b chore(release): v3.0.0-beta.61 [skip ci] 2024-07-12 09:24:34 -04:00
Jacob Fletcher
fac5425ec0 docs: improves queries docs (#7122) 2024-07-11 17:49:54 -04:00
Paul
840e07577e fix(ui): ctrl+s not triggering a save if autosave is enabled (#7120) 2024-07-11 20:38:26 +00:00
Paul
1baf775aa4 fix(templates): website template gitignore issue for case sensitivity (#7118) 2024-07-11 20:28:21 +00:00
Elliot DeNolf
588b84a967 chore: switch to @eslint-react/eslint-plugin, lint entire codebase (#7119) 2024-07-11 16:19:07 -04:00
Alessio Gravili
e5d5126d14 chore: regenerate all types in test dir, and add to eslint & prettier ignores 2024-07-11 15:59:38 -04:00
Alessio Gravili
ebcfc2d284 chore(eslint-config): disable broken jest/prefer-spy-on rule 2024-07-11 15:44:18 -04:00
Alessio Gravili
29205cd209 chore: remove unnecessary newlines in payload/src/index.ts 2024-07-11 15:34:14 -04:00
Alessio Gravili
926c87e912 chore: add full codebase lint commit hash to .git-blame-ignore-revs 2024-07-11 15:28:54 -04:00
Alessio Gravili
83fd4c6622 chore: run lint and prettier on entire codebase 2024-07-11 15:27:01 -04:00
Paul
7a7f93c066 chore: lint templates (#7116) 2024-07-11 15:21:15 -04:00
Jacob Fletcher
e9adeecc7a docs: more misc improvements (#7115) 2024-07-11 14:55:13 -04:00
Alessio Gravili
f8ab5a9f1e chore(eslint-config): warn instead of error for jest/no-conditional-in-test and jest/prefer-strict-equal 2024-07-11 14:42:29 -04:00
Alessio Gravili
45ada0d3bb chore(eslint-config): switch from eslint-plugin-react to @eslint-react/eslint-plugin 2024-07-11 14:36:49 -04:00
Alessio Gravili
f86e0edf9e feat!: upgrade minimum react, react-dom, @types/react and @types/react-dom versions to match exactly what Next.js is using, various dependency cleanup (#7106)
**BREAKING:**
- Upgrades minimum supported @types/react version from
npm:types-react@19.0.0-beta.2 to npm:types-react@19.0.0-rc.0
- Upgrades minimum supported @types/react-dom version from
npm:types-react-dom@19.0.0-beta.2 to npm:types-react-dom@19.0.0-rc.0
- Upgrades minimum supported react and react-dom version from
19.0.0-rc-f994737d14-20240522 to 19.0.0-rc-6230622a1a-20240610
2024-07-11 18:33:45 +00:00
Jarrod Flesch
e4eb5eb37e chore(examples): multi tenant using a tenant selector (#7111) 2024-07-11 10:49:14 -04:00
Paul
fb6956328f chore: eslint ignore templates (#7112) 2024-07-11 10:09:50 -04:00
Jacob Fletcher
a1bb661a1a docs: misc improvements (#7107) 2024-07-11 09:54:21 -04:00
Paul
e2b06abb60 chore(templates): update website template to use transactions for seeding (#7098) 2024-07-11 09:45:35 -04:00
Jacob Fletcher
7be80e31c3 docs: cleans up configuration (#7105) 2024-07-10 23:56:02 -04:00
Patrik
d99bff9ec3 feat: adds ability to upload files from a remote url (#7063)
Adds new button to uploads labeled `Paste URL` 

![Screenshot 2024-07-08 at 10 46
14 AM](https://github.com/payloadcms/payload/assets/35232443/5024fc20-c860-48e5-bdc8-b69ac3c9cc53)

Upon clicking it, a modal with an input field will appear to where one
can input a remote url of an image.

![Screenshot 2024-07-08 at 10 46
22 AM](https://github.com/payloadcms/payload/assets/35232443/5ea67977-f118-4d34-9dfb-d270b3578262)
2024-07-10 16:55:47 -04:00
Alessio Gravili
edf743ef70 fix(richtext-lexical): export types as type-only exports (#7097) 2024-07-10 20:33:27 +00:00
Elliot DeNolf
08fea01d7e chore(release): v3.0.0-beta.60 [skip ci] 2024-07-10 11:28:59 -04:00
Paul
2bc8666bff feat(plugin-search)!: make search collection fields override into a function that provides defaultFields inline with other plugins (#7095)
searchPlugin's searchOverrides for the collection now takes in a fields
function instead of array similar to other plugins and patterns we use
to allow you to map over existing fields as well if needed.

```ts
// before
searchPlugin({
  searchOverrides: {
    slug: 'search-results',
    fields: [
      {
        name: 'excerpt',
        type: 'textarea',
        admin: {
          position: 'sidebar',
        },
      },
    ]
  },
}),

// current
searchPlugin({
  searchOverrides: {
    slug: 'search-results',
    fields: ({ defaultFields }) => [
      ...defaultFields,
      {
        name: 'excerpt',
        type: 'textarea',
        admin: {
          position: 'sidebar',
        },
      },
    ]
  },
}),
```
2024-07-10 15:22:12 +00:00
Elliot DeNolf
8ea87afd24 chore(scripts): improve release notes tag filtering 2024-07-10 11:05:27 -04:00
Paul
89ae5bbd22 chore: update all plugin docs installation and import steps (#7094) 2024-07-10 14:23:04 +00:00
Paul
c1c12bc60d feat(cpa): add website template to CPA (#7079)
- Adds website to cpa list
- Reworks .env handling
2024-07-10 09:44:07 -04:00
3081 changed files with 195282 additions and 90791 deletions

View File

@@ -19,3 +19,12 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
# 3.0 prettier & lint everywhere
6789e61488a1d3de56f472ac3214faf344030005
# 3.0 prettier & lint everywhere again
83fd4c66222d7846eeb5cc332dfa99bf1e830831
# Upgrade to typescript-eslint v8, then prettier & lint everywhere
86fdad0bb8ab27810599c8a32f3d8cba1341e1df
# Prettier and lint remaining db packages
7fd736ea5b2e9fc4ef936e9dc9e5e3d722f6d8bf

21
.github/CODEOWNERS vendored
View File

@@ -1,24 +1,23 @@
# Order matters. The last matching pattern takes precedence.
# Approvals are not required currently but may be enabled in the future.
### Package Exports ###
/**/exports/ @denolfe @jmikrut
/**/exports/ @denolfe @jmikrut @DanRibbens
### Packages ###
/packages/richtext-*/ @AlessioGr
/packages/plugin-cloud*/ @denolfe
/packages/email-*/ @denolfe
/packages/storage-*/ @denolfe
/packages/create-payload-app/ @denolfe
/packages/eslint-*/ @denolfe
/packages/plugin-cloud*/src/ @denolfe
/packages/email-*/src/ @denolfe
/packages/storage-*/src/ @denolfe
/packages/create-payload-app/src/ @denolfe
/packages/eslint-*/ @denolfe @AlessioGr
### Templates ###
/templates/ @jacobsfletch @denolfe
/templates/_data/ @denolfe
/templates/_template/ @denolfe
### Build Files ###
/**/package.json @denolfe
/tsconfig.json @denolfe
/**/tsconfig*.json @denolfe
/jest.config.js @denolfe
/**/jest.config.js @denolfe
@@ -26,5 +25,5 @@
/package.json @denolfe
/scripts/ @denolfe
/.husky/ @denolfe
/.vscode/ @denolfe
/.vscode/ @denolfe @AlessioGr
/.github/ @denolfe

View File

@@ -0,0 +1,13 @@
module.exports = {
env: {
es6: true,
node: true,
},
extends: ['eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended'],
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
plugins: ['@typescript-eslint'],
}

View File

@@ -0,0 +1,74 @@
# Release Commenter
This GitHub Action automatically comments on and/or labels Issues and PRs when a fix is released for them.
> [!IMPORTANT]
> 🔧 Heavily modified version of https://github.com/apexskier/github-release-commenter
## Fork Modifications
- Filters to closed PRs only
- Adds tag filter to support non-linear releases
- Better logging
- Moved to pnpm
- Uses @vercel/ncc for packaging
- Comments on locked issues by unlocking then re-locking
## How it works
Use this action in a workflow [triggered by a release](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#release). It will scan commits between that and the prior release, find associated Issues and PRs, and comment on them to let people know a release has been made. Associated Issues and PRs can be directly [linked](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) to the commit or manually linked from a PR associated with the commit.
## Inputs
**GITHUB_TOKEN**
A GitHub personal access token with repo scope, such as [`secrets.GITHUB_TOKEN`](https://docs.github.com/en/free-pro-team@latest/actions/reference/authentication-in-a-workflow#about-the-github_token-secret).
**comment-template** (optional)
Override the comment posted on Issues and PRs. Set to the empty string to disable commenting. Several variables strings will be automatically replaced:
- `{release_link}` - a markdown link to the release
- `{release_name}` - the release's name
- `{release_tag}` - the release's tag
**label-template** (optional)
Add the given label. Multiple labels can be separated by commas. Several variable strings will be automatically replaced:
- `{release_name}` - the release's name
- `{release_tag}` - the release's tag
**skip-label** (optional)
Skip processing if any of the given labels are present. Same processing rules as **label-template**. Default is "dependencies".
## Example
```yml
on:
release:
types: [published]
jobs:
release:
steps:
- uses: apexskier/github-release-commenter@v1
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
comment-template: |
Release {release_link} addresses this.
```
## Known limitations
These are some known limitations of this action. I'd like to try to address them in the future.
- Non-linear releases aren't supported. For example, releasing a patch to a prior major release after a new major release has been bumped.
- Non-sequential releases aren't supported. For example, if you release multiple prereleases between two official releases, this will only create a comment for the first prerelease in which a fix is released, not the final release.
- The first release for a project will be ignored. This is intentional, as the use case is unlikely. Most projects will either have several alphas that don't need release comments, or won't use issues/PRs for the first commit.
- If a large number of things are commented on, you may see the error `Error: You have triggered an abuse detection mechanism. Please wait a few minutes before you try again.`. Consider using the `skip-label` input to reduce your load on the GitHub API.
## Versions
Workflows will automatically update the tags `v1` and `latest`, allowing you to reference one of those instead of locking to a specific release.

View File

@@ -0,0 +1,32 @@
name: Release Commenter
description: Comment on PRs and Issues when a fix is released
branding:
icon: message-square
color: blue
inputs:
GITHUB_TOKEN:
description: |
A GitHub personal access token with repo scope, such as
secrets.GITHUB_TOKEN.
required: true
comment-template:
description: |
Text template for the comment string.
required: false
default: |
Included in release {release_link}
label-template:
description: Add the given label. Multiple labels can be separated by commas.
required: false
skip-label:
description: Skip commenting if any of the given label are present. Multiple labels can be separated by commas.
required: false
default: 'dependencies'
tag-filter:
description: |
Filter tags by a regular expression. Must be escaped. e.g. 'v\\d' to isolate tags between major versions.
required: false
default: null
runs:
using: node20
main: dist/index.js

File diff suppressed because one or more lines are too long

View File

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

View File

@@ -0,0 +1,34 @@
{
"name": "release-commenter",
"version": "0.0.0",
"private": true,
"description": "GitHub Action to automatically comment on PRs and Issues when a fix is released.",
"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/release-commenter/pnpm-lock.yaml generated vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,266 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`tests feature tests can apply labels 1`] = `
[
[
{
"issue_number": 123,
"labels": [
":dart: landed",
"release-current_tag_name",
"Release Name",
],
},
],
[
{
"issue_number": 7,
"labels": [
":dart: landed",
"release-current_tag_name",
"Release Name",
],
},
],
]
`;
exports[`tests main test 1`] = `
{
"graphql": [MockFunction] {
"calls": [
[
"
{
resource(url: "http://repository/commit/SHA1") {
... on Commit {
messageHeadlineHTML
messageBodyHTML
associatedPullRequests(first: 10) {
pageInfo {
hasNextPage
}
edges {
node {
bodyHTML
number
state
labels(first: 10) {
pageInfo {
hasNextPage
}
nodes {
name
}
}
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
pageInfo {
hasNextPage
}
nodes {
... on ConnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
... on DisconnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
}
}
}
}
}
}
}
}
",
],
[
"
{
resource(url: "http://repository/commit/SHA2") {
... on Commit {
messageHeadlineHTML
messageBodyHTML
associatedPullRequests(first: 10) {
pageInfo {
hasNextPage
}
edges {
node {
bodyHTML
number
state
labels(first: 10) {
pageInfo {
hasNextPage
}
nodes {
name
}
}
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
pageInfo {
hasNextPage
}
nodes {
... on ConnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
... on DisconnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
}
}
}
}
}
}
}
}
",
],
],
"results": [
{
"type": "return",
"value": Promise {},
},
{
"type": "return",
"value": Promise {},
},
],
},
"rest": {
"issues": {
"addLabels": [MockFunction],
"createComment": [MockFunction] {
"calls": [
[
{
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
"issue_number": 3,
},
],
[
{
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
"issue_number": 123,
},
],
[
{
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
"issue_number": 7,
},
],
],
"results": [
{
"type": "return",
"value": Promise {},
},
{
"type": "return",
"value": Promise {},
},
{
"type": "return",
"value": Promise {},
},
],
},
"get": [MockFunction] {
"calls": [
[
{
"issue_number": 3,
},
],
[
{
"issue_number": 123,
},
],
[
{
"issue_number": 7,
},
],
],
"results": [
{
"type": "return",
"value": Promise {},
},
{
"type": "return",
"value": Promise {},
},
{
"type": "return",
"value": Promise {},
},
],
},
},
"repos": {
"compareCommits": [MockFunction] {
"calls": [
[
{
"base": "prior_tag_name",
"head": "current_tag_name",
},
],
],
"results": [
{
"type": "return",
"value": Promise {},
},
],
},
"listReleases": [MockFunction] {
"calls": [
[
{
"per_page": 100,
},
],
],
"results": [
{
"type": "return",
"value": Promise {},
},
],
},
},
},
}
`;

View File

@@ -0,0 +1,399 @@
import type * as githubModule from '@actions/github'
import type * as coreModule from '@actions/core'
import { mock } from 'node:test'
jest.mock('@actions/core')
jest.mock('@actions/github')
type Mocked<T> = {
-readonly [P in keyof T]: T[P] extends Function ? jest.Mock<T[P]> : jest.Mocked<Partial<T[P]>>
}
const github = require('@actions/github') as jest.Mocked<Mocked<typeof githubModule>>
const core = require('@actions/core') as jest.Mocked<Mocked<typeof coreModule>>
describe('tests', () => {
let mockOctokit: any = {}
let currentTag: string = 'current_tag_name'
;(core.warning as any) = jest.fn(console.warn.bind(console))
;(core.error as any) = jest.fn(console.error.bind(console))
let commentTempate: string = ''
let labelTemplate: string | null = null
const skipLabelTemplate: string | null = 'skip,test'
let tagFilter: string | RegExp | null = null
let simpleMockOctokit: any = {}
beforeEach(() => {
tagFilter = null
currentTag = 'current_tag_name'
;(github.context as any) = {
payload: {
repo: {
owner: 'owner',
repo: 'repo',
},
release: {
tag_name: currentTag,
},
repository: { html_url: 'http://repository' },
},
}
github.getOctokit.mockReset().mockImplementationOnce(((token: string) => {
expect(token).toBe('GITHUB_TOKEN_VALUE')
return mockOctokit
}) as any)
;(core.getInput as any).mockImplementation((key: string) => {
if (key == 'GITHUB_TOKEN') {
return 'GITHUB_TOKEN_VALUE'
}
if (key == 'comment-template') {
return commentTempate
}
if (key == 'label-template') {
return labelTemplate
}
if (key == 'skip-label') {
return skipLabelTemplate
}
if (key == 'tag-filter') {
return tagFilter
}
fail(`Unexpected input key ${key}`)
})
commentTempate =
'Included in release {release_link}. Replacements: {release_name}, {release_tag}.'
labelTemplate = null
simpleMockOctokit = {
rest: {
issues: {
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
createComment: jest.fn(() => Promise.resolve()),
addLabels: jest.fn(() => Promise.resolve()),
},
repos: {
listReleases: jest.fn(() =>
Promise.resolve({
data: [
{
name: 'Release Name',
tag_name: 'current_tag_name',
html_url: 'http://current_release',
},
{
tag_name: 'prior_tag_name',
html_url: 'http://prior_release',
},
],
}),
),
compareCommits: jest.fn(() =>
Promise.resolve({
data: { commits: [{ sha: 'SHA1' }] },
}),
),
},
},
graphql: jest.fn(() =>
Promise.resolve({
resource: {
messageHeadlineHTML: '',
messageBodyHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
associatedPullRequests: {
pageInfo: { hasNextPage: false },
edges: [],
},
},
}),
),
}
})
afterEach(() => {
expect(core.error).not.toHaveBeenCalled()
expect(core.warning).not.toHaveBeenCalled()
expect(core.setFailed).not.toHaveBeenCalled()
})
test('main test', async () => {
mockOctokit = {
...simpleMockOctokit,
rest: {
issues: {
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
createComment: jest.fn(() => Promise.resolve()),
addLabels: jest.fn(() => Promise.resolve()),
},
repos: {
listReleases: jest.fn(() =>
Promise.resolve({
data: [
{
tag_name: 'current_tag_name',
html_url: 'http://current_release',
},
{
tag_name: 'prior_tag_name',
html_url: 'http://prior_release',
},
],
}),
),
compareCommits: jest.fn(() =>
Promise.resolve({
data: { commits: [{ sha: 'SHA1' }, { sha: 'SHA2' }] },
}),
),
},
},
graphql: jest.fn(() =>
Promise.resolve({
resource: {
messageHeadlineHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #3.">Closes</span> <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="718013420" data-permission-text="Title is private" data-url="https://github.com/apexskier/github-release-commenter/issues/1" data-hovercard-type="issue" data-hovercard-url="/apexskier/github-release-commenter/issues/1/hovercard" href="https://github.com/apexskier/github-release-commenter/issues/1">#1</a>',
messageBodyHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
associatedPullRequests: {
pageInfo: { hasNextPage: false },
edges: [
{
node: {
bodyHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #4.">Closes</span> <span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #5.">Closes</span>',
number: 9,
labels: {
pageInfo: { hasNextPage: false },
nodes: [{ name: 'label1' }, { name: 'label2' }],
},
timelineItems: {
pageInfo: { hasNextPage: false },
nodes: [
{
isCrossRepository: true,
__typename: 'ConnectedEvent',
subject: { number: 1 },
},
{
isCrossRepository: false,
__typename: 'ConnectedEvent',
subject: { number: 2 },
},
{
isCrossRepository: false,
__typename: 'DisconnectedEvent',
subject: { number: 2 },
},
{
isCrossRepository: false,
__typename: 'ConnectedEvent',
subject: { number: 2 },
},
],
},
},
},
{
node: {
bodyHTML: '',
number: 42,
labels: {
pageInfo: { hasNextPage: false },
nodes: [{ name: 'label1' }, { name: 'skip' }],
},
timelineItems: {
pageInfo: { hasNextPage: false },
nodes: [
{
isCrossRepository: true,
__typename: 'ConnectedEvent',
subject: { number: 82 },
},
],
},
},
},
],
},
},
}),
),
}
jest.isolateModules(() => {
require('./index')
})
await new Promise<void>(setImmediate)
expect(mockOctokit).toMatchSnapshot()
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledTimes(3)
})
describe('can filter tags', () => {
const v3prev = 'v3.0.1'
const v3current = 'v3.0.2'
const v2prev = 'v2.0.1'
const v2current = 'v2.0.2'
const listReleasesData = [
{
name: 'Current Release Name',
tag_name: v3current,
html_url: 'http://v3.0.2',
},
{
name: 'Prev Release Name',
tag_name: v3prev,
html_url: 'http://v3.0.1',
},
{
name: 'v2 Current Release Name',
tag_name: v2current,
html_url: 'http://v2.0.2',
},
{
name: 'v2 Prev Release Name',
tag_name: v2prev,
html_url: 'http://v2.0.1',
},
]
it.each`
description | prevTag | currentTag | filter
${'no filter'} | ${v3prev} | ${v3current} | ${null}
${'v3'} | ${v3prev} | ${v3current} | ${'v\\d'}
${'v2'} | ${v2prev} | ${v2current} | ${'v\\d'}
`('should filter tags with $description', async ({ prevTag, currentTag, filter }) => {
// @ts-ignore
github.context.payload.release.tag_name = currentTag
tagFilter = filter
mockOctokit = {
...simpleMockOctokit,
rest: {
issues: {
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
createComment: jest.fn(() => Promise.resolve()),
addLabels: jest.fn(() => Promise.resolve()),
},
repos: {
listReleases: jest.fn(() =>
Promise.resolve({
data: listReleasesData,
}),
),
compareCommits: jest.fn(() =>
Promise.resolve({
data: { commits: [{ sha: 'SHA1' }] },
}),
),
},
},
graphql: jest.fn(() =>
Promise.resolve({
resource: {
messageHeadlineHTML: '',
messageBodyHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
associatedPullRequests: {
pageInfo: { hasNextPage: false },
edges: [],
},
},
}),
),
}
jest.isolateModules(() => {
require('./index')
})
await new Promise<void>((resolve) => setImmediate(() => resolve()))
expect(github.getOctokit).toHaveBeenCalled()
expect(mockOctokit.rest.repos.compareCommits.mock.calls).toEqual([
[{ base: prevTag, head: currentTag }],
])
})
})
describe('feature tests', () => {
beforeEach(() => {
mockOctokit = simpleMockOctokit
})
it('can disable comments', async () => {
commentTempate = ''
jest.isolateModules(() => {
require('./index')
})
await new Promise<void>((resolve) => setImmediate(() => resolve()))
expect(github.getOctokit).toHaveBeenCalled()
expect(mockOctokit.rest.issues.createComment).not.toHaveBeenCalled()
})
it('should unlock and comment', async () => {
mockOctokit = {
...simpleMockOctokit,
rest: {
...simpleMockOctokit.rest,
issues: {
// Return locked for both issues to be commented on
get: jest.fn(() => Promise.resolve({ data: { locked: true } })),
lock: jest.fn(() => Promise.resolve()),
unlock: jest.fn(() => Promise.resolve()),
createComment: jest.fn(() => Promise.resolve()),
},
},
graphql: jest.fn(() =>
Promise.resolve({
resource: {
messageHeadlineHTML: '',
messageBodyHTML:
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
associatedPullRequests: {
pageInfo: { hasNextPage: false },
edges: [],
},
},
}),
),
}
jest.isolateModules(() => {
require('./index')
})
await new Promise<void>((resolve) => setImmediate(() => resolve()))
expect(github.getOctokit).toHaveBeenCalled()
// Should call once for both linked issues
expect(mockOctokit.rest.issues.unlock).toHaveBeenCalledTimes(2)
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledTimes(2)
expect(mockOctokit.rest.issues.lock).toHaveBeenCalledTimes(2)
})
it.skip('can apply labels', async () => {
labelTemplate = ':dart: landed,release-{release_tag},{release_name}'
jest.isolateModules(() => {
require('./index')
})
await new Promise<void>((resolve) => setImmediate(() => resolve()))
expect(github.getOctokit).toHaveBeenCalled()
expect(mockOctokit.rest.issues.addLabels.mock.calls).toMatchSnapshot()
})
})
})

View File

@@ -0,0 +1,349 @@
import * as core from '@actions/core'
import * as github from '@actions/github'
import type * as Webhooks from '@octokit/webhooks-types'
const closesMatcher = /aria-label="This (?:commit|pull request) closes issue #(\d+)\."/g
const releaseLinkTemplateRegex = /{release_link}/g
const releaseNameTemplateRegex = /{release_name}/g
const releaseTagTemplateRegex = /{release_tag}/g
;(async function main() {
try {
const payload = github.context.payload as Webhooks.EventPayloadMap['release']
const githubToken = core.getInput('GITHUB_TOKEN')
const tagFilter = core.getInput('tag-filter') || undefined // Accept tag filter as an input
const octokit = github.getOctokit(githubToken)
const commentTemplate = core.getInput('comment-template')
const labelTemplate = core.getInput('label-template') || null
const skipLabelTemplate = core.getInput('skip-label') || null
// Fetch the releases with the optional tag filter applied
const { data: rawReleases } = await octokit.rest.repos.listReleases({
...github.context.repo,
per_page: 100,
})
// Get the current release tag or latest tag
const currentTag = payload?.release?.tag_name || rawReleases?.[0]?.tag_name
let releases = rawReleases
// Filter releases by the tag filter if provided
if (tagFilter) {
core.info(`Filtering releases by tag filter: ${tagFilter}`)
// Get the matching part of the current release tag
const regexMatch = currentTag.match(tagFilter)?.[0]
if (!regexMatch) {
core.error(`Current release tag ${currentTag} does not match the tag filter ${tagFilter}`)
return
}
core.info(`Matched string from filter: ${regexMatch}`)
releases = releases
.filter((release) => {
const match = release.tag_name.match(regexMatch)?.[0]
return match
})
.slice(0, 2)
}
core.info(`Releases: ${JSON.stringify(releases, null, 2)}`)
if (releases.length < 2) {
if (!releases.length) {
core.error(`No releases found with the provided tag filter: '${tagFilter}'`)
return
}
core.info('first release')
return
}
const [currentRelease, priorRelease] = releases
core.info(`${priorRelease.tag_name}...${currentRelease.tag_name}`)
const {
data: { commits },
} = await octokit.rest.repos.compareCommits({
...github.context.repo,
base: priorRelease.tag_name,
head: currentRelease.tag_name,
})
if (!currentRelease.name) {
core.info('Current release has no name, will fall back to the tag name.')
}
const releaseLabel = currentRelease.name || currentRelease.tag_name
const comment = commentTemplate
.trim()
.split(releaseLinkTemplateRegex)
.join(`[${releaseLabel}](${currentRelease.html_url})`)
.split(releaseNameTemplateRegex)
.join(releaseLabel)
.split(releaseTagTemplateRegex)
.join(currentRelease.tag_name)
const parseLabels = (rawInput: string | null) =>
rawInput
?.split(releaseNameTemplateRegex)
.join(releaseLabel)
?.split(releaseTagTemplateRegex)
.join(currentRelease.tag_name)
?.split(',')
?.map((l) => l.trim())
.filter((l) => l)
const labels = parseLabels(labelTemplate)
const skipLabels = parseLabels(skipLabelTemplate)
const linkedIssuesPrs = new Set<number>()
await Promise.all(
commits.map((commit) =>
(async () => {
const query = `
{
resource(url: "${payload.repository.html_url}/commit/${commit.sha}") {
... on Commit {
messageHeadlineHTML
messageBodyHTML
associatedPullRequests(first: 10) {
pageInfo {
hasNextPage
}
edges {
node {
bodyHTML
number
state
labels(first: 10) {
pageInfo {
hasNextPage
}
nodes {
name
}
}
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
pageInfo {
hasNextPage
}
nodes {
... on ConnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
... on DisconnectedEvent {
__typename
isCrossRepository
subject {
... on Issue {
number
}
}
}
}
}
}
}
}
}
}
}
`
const response: {
resource: null | {
messageHeadlineHTML: string
messageBodyHTML: string
associatedPullRequests: {
pageInfo: { hasNextPage: boolean }
edges: ReadonlyArray<{
node: {
bodyHTML: string
number: number
state: 'OPEN' | 'CLOSED' | 'MERGED'
labels: {
pageInfo: { hasNextPage: boolean }
nodes: ReadonlyArray<{
name: string
}>
}
timelineItems: {
pageInfo: { hasNextPage: boolean }
nodes: ReadonlyArray<{
__typename: 'ConnectedEvent' | 'DisconnectedEvent'
isCrossRepository: boolean
subject: {
number: number
}
}>
}
}
}>
}
}
} = await octokit.graphql(query)
if (!response.resource) {
return
}
// core.info(JSON.stringify(response.resource, null, 2))
core.info(`Checking commit: ${payload.repository.html_url}/commit/${commit.sha}`)
const associatedClosedPREdges = response.resource.associatedPullRequests.edges.filter(
(e) => e.node.state === 'MERGED',
)
if (associatedClosedPREdges.length) {
core.info(
` Associated Merged PRs:\n ${associatedClosedPREdges.map((pr) => `${payload.repository.html_url}/pull/${pr.node.number}`).join('\n ')}`,
)
} else {
core.info(' No associated merged PRs')
}
const html = [
response.resource.messageHeadlineHTML,
response.resource.messageBodyHTML,
...associatedClosedPREdges.map((pr) => pr.node.bodyHTML),
].join(' ')
for (const match of html.matchAll(closesMatcher)) {
const [, num] = match
linkedIssuesPrs.add(parseInt(num, 10))
core.info(
` Linked issue/PR from closesMatcher: ${payload.repository.html_url}/pull/${num}`,
)
}
if (response.resource.associatedPullRequests.pageInfo.hasNextPage) {
core.warning(`Too many PRs associated with ${commit.sha}`)
}
const seen = new Set<number>()
for (const associatedPR of associatedClosedPREdges) {
if (associatedPR.node.timelineItems.pageInfo.hasNextPage) {
core.warning(`Too many links for #${associatedPR.node.number}`)
}
if (associatedPR.node.labels.pageInfo.hasNextPage) {
core.warning(`Too many labels for #${associatedPR.node.number}`)
}
// a skip labels is present on this PR
if (
skipLabels?.some((l) => associatedPR.node.labels.nodes.some(({ name }) => name === l))
) {
continue
}
linkedIssuesPrs.add(associatedPR.node.number)
core.info(
` Linked issue/PR from associated PR: ${payload.repository.html_url}/pull/${associatedPR.node.number}`,
)
// These are sorted by creation date in ascending order. The latest event for a given issue/PR is all we need
// ignore links that aren't part of this repo
const links = associatedPR.node.timelineItems.nodes
.filter((node) => !node.isCrossRepository)
.reverse()
for (const link of links) {
if (seen.has(link.subject.number)) {
continue
}
if (link.__typename == 'ConnectedEvent') {
linkedIssuesPrs.add(link.subject.number)
core.info(
`Linked issue/PR from connected event: ${payload.repository.html_url}/pull/${link.subject.number}`,
)
}
seen.add(link.subject.number)
}
}
})(),
),
)
core.info(
`Final issues/PRs to be commented on: \n${Array.from(linkedIssuesPrs)
.map((num) => ` ${payload.repository.html_url}/pull/${num}`)
.join('\n')}`,
)
const requests: Array<Promise<unknown>> = []
for (const issueNumber of linkedIssuesPrs) {
const baseRequest = {
...github.context.repo,
issue_number: issueNumber,
}
if (comment) {
const commentRequest = {
...baseRequest,
body: comment,
}
// Check if issue is locked or not
const { data: issue } = await octokit.rest.issues.get(baseRequest)
let createCommentPromise: () => Promise<void>
if (!issue.locked) {
createCommentPromise = async () => {
try {
await octokit.rest.issues.createComment(commentRequest)
} catch (error) {
core.error(error as Error)
core.error(
`Failed to comment on issue/PR: ${issueNumber}. ${payload.repository.html_url}/pull/${issueNumber}`,
)
}
}
} else {
core.info(
`Issue/PR is locked: ${issueNumber}. Unlocking, commenting, and re-locking. ${payload.repository.html_url}/pull/${issueNumber}`,
)
createCommentPromise = async () => {
try {
core.debug(`Unlocking issue/PR: ${issueNumber}`)
await octokit.rest.issues.unlock(baseRequest)
core.debug(`Commenting on issue/PR: ${issueNumber}`)
await octokit.rest.issues.createComment(commentRequest)
core.debug(`Re-locking issue/PR: ${issueNumber}`)
await octokit.rest.issues.lock(baseRequest)
} catch (error) {
core.error(error as Error)
core.error(
`Failed to unlock, comment, and re-lock issue/PR: ${issueNumber}. ${payload.repository.html_url}/pull/${issueNumber}`,
)
}
}
}
requests.push(createCommentPromise())
}
if (labels) {
const request = {
...baseRequest,
labels,
}
// core.info(JSON.stringify(request, null, 2))
requests.push(octokit.rest.issues.addLabels(request))
}
}
await Promise.all(requests)
} catch (error) {
core.error(error as Error)
core.setFailed((error as Error).message)
}
})()

View File

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

View File

@@ -5,11 +5,11 @@ inputs:
node-version:
description: 'The Node.js version to use'
required: true
default: 18.20.2
default: 22.6.2
pnpm-version:
description: 'The pnpm version to use'
required: true
default: 8.15.7
default: 9.7.1
runs:
using: composite
@@ -25,7 +25,7 @@ runs:
node-version: ${{ inputs.node-version }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ inputs.pnpm-version }}
run_install: false

3927
.github/pnpm-lock.yaml generated vendored Normal file

File diff suppressed because it is too large Load Diff

2
.github/pnpm-workspace.yaml vendored Normal file
View File

@@ -0,0 +1,2 @@
packages:
- 'actions/*'

View File

@@ -32,8 +32,26 @@ jobs:
script: |
const type = context.payload.pull_request ? 'pull_request' : 'issue';
const association = context.payload[type].author_association;
let label = ''
if (association === 'MEMBER' || association === 'OWNER') {
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';
@@ -47,4 +65,4 @@ jobs:
repo: context.repo.repo,
labels: [label],
});
console.log('Added created-by: Payload team label');
console.log(`Added '${label}' label`);

View File

@@ -17,8 +17,8 @@ concurrency:
cancel-in-progress: true
env:
NODE_VERSION: 18.20.2
PNPM_VERSION: 8.15.7
NODE_VERSION: 22.6.0
PNPM_VERSION: 9.7.1
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry
@@ -74,7 +74,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -120,7 +120,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -167,7 +167,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -196,6 +196,7 @@ jobs:
- postgres-custom-schema
- postgres-uuid
- supabase
- sqlite
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
@@ -206,6 +207,9 @@ jobs:
AWS_REGION: us-east-1
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 25
# https://github.com/actions/virtual-environments/issues/1187
- name: tune linux network
run: sudo ethtool -K eth0 tx off rx off
@@ -216,17 +220,12 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
- name: Restore build
uses: actions/cache@v4
timeout-minutes: 10
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- run: pnpm install
- name: Start LocalStack
run: pnpm docker:start
@@ -292,6 +291,7 @@ jobs:
- access-control
- admin__e2e__1
- admin__e2e__2
- admin-root
- auth
- field-error-states
- fields-relationship
@@ -310,6 +310,7 @@ jobs:
- fields__collections__Upload
- live-preview
- localization
- locked-documents
- i18n
- plugin-cloud-storage
- plugin-form-builder
@@ -330,7 +331,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -369,7 +370,7 @@ jobs:
run: pnpm exec playwright install-deps chromium
- name: E2E Tests
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e ${{ matrix.suite }}
run: PLAYWRIGHT_JSON_OUTPUT_NAME=results_${{ matrix.suite }}.json pnpm test:e2e:prod:ci ${{ matrix.suite }}
env:
PLAYWRIGHT_JSON_OUTPUT_NAME: results_${{ matrix.suite }}.json
NEXT_TELEMETRY_DISABLED: 1
@@ -390,6 +391,7 @@ jobs:
# job-summary: true
app-build-with-packed:
if: false # Disable until package resolution in tgzs can be figured out
runs-on: ubuntu-latest
needs: build
@@ -404,7 +406,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -417,15 +419,15 @@ jobs:
key: ${{ github.sha }}-${{ github.run_number }}
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.10.0
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: 6.0
- name: Pack and build app
run: |
set -ex
pnpm run script:pack --dest templates/blank-3.0
cd templates/blank-3.0
pnpm run script:pack --dest templates/blank
cd templates/blank
cp .env.example .env
ls -la
pnpm add ./*.tgz --ignore-workspace
@@ -448,7 +450,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -489,7 +491,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Start MongoDB
uses: supercharge/mongodb-github-action@1.10.0
uses: supercharge/mongodb-github-action@1.11.0
with:
mongodb-version: 6.0
@@ -517,7 +519,7 @@ jobs:
node-version: ${{ env.NODE_VERSION }}
- name: Install pnpm
uses: pnpm/action-setup@v3
uses: pnpm/action-setup@v4
with:
version: ${{ env.PNPM_VERSION }}
run_install: false
@@ -546,3 +548,16 @@ jobs:
steps:
- if: ${{ always() && (contains(needs.*.result, 'failure') || contains(needs.*.result, 'cancelled')) }}
run: exit 1
publish-canary:
name: Publish Canary
runs-on: ubuntu-latest
needs:
- all-green
steps:
# debug github.ref output
- run: |
echo github.ref: ${{ github.ref }}
echo isBeta: ${{ github.ref == 'refs/heads/beta' }}
echo isMain: ${{ github.ref == 'refs/heads/main' }}

30
.github/workflows/post-release.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: post-release
on:
release:
types:
- published
workflow_dispatch:
jobs:
post_release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
# Only needed if debugging on a branch other than default
# ref: ${{ github.event.release.target_commitish || github.ref }}
- uses: ./.github/actions/release-commenter
continue-on-error: true
env:
ACTIONS_STEP_DEBUG: true
with:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
tag-filter: 'v\d'
# Change to blank to disable commenting
# comment-template: ''
comment-template: |
🚀 This is included in version {release_link}

View File

@@ -38,6 +38,9 @@ jobs:
db-\*
db-mongodb
db-postgres
db-vercel-postgres
db-sqlite
drizzle
email-nodemailer
eslint
graphql
@@ -50,7 +53,6 @@ jobs:
plugin-form-builder
plugin-nested-docs
plugin-redirects
plugin-relationship-object-ids
plugin-search
plugin-sentry
plugin-seo
@@ -61,6 +63,7 @@ jobs:
storage-\*
storage-azure
storage-gcs
storage-uploadthing
storage-vercel-blob
storage-s3
translations
@@ -101,3 +104,19 @@ jobs:
with:
header: pr-title-lint-error
delete: true
label-pr-on-open:
name: label-pr-on-open
runs-on: ubuntu-latest
if: github.event.action == 'opened'
steps:
- name: Tag with main branch with v2
if: github.event.pull_request.base.ref == 'main'
uses: actions-ecosystem/action-add-labels@v1
with:
labels: v2
- name: Tag with beta branch with v3
if: github.event.pull_request.base.ref == 'beta'
uses: actions-ecosystem/action-add-labels@v1
with:
labels: v3

View File

@@ -6,8 +6,8 @@ on:
- beta
env:
NODE_VERSION: 18.20.2
PNPM_VERSION: 8.15.7
NODE_VERSION: 22.6.0
PNPM_VERSION: 9.7.1
DO_NOT_TRACK: 1 # Disable Turbopack telemetry
NEXT_TELEMETRY_DISABLED: 1 # Disable Next telemetry

18
.gitignore vendored
View File

@@ -5,6 +5,10 @@ dist
!/.idea/runConfigurations
!/.idea/payload.iml
# Custom actions
!.github/actions/**/dist
test/packed
test-results
.devcontainer
.localstack
@@ -22,6 +26,10 @@ meta_shared.json
# Ignore test directory media folder/files
/media
test/media
*payloadtests.db
*payloadtests.db-journal
*payloadtests.db-shm
*payloadtests.db-wal
/versions
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
@@ -149,6 +157,7 @@ out
# Nuxt.js build / generate output
.nuxt
dist
dist_optimized
# Gatsby files
.cache/
@@ -296,3 +305,12 @@ $RECYCLE.BIN/
/build
.swc
app/(payload)/admin/importMap.js
test/live-preview/app/(payload)/admin/importMap.js
/test/live-preview/app/(payload)/admin/importMap.js
test/admin-root/app/(payload)/admin/importMap.js
/test/admin-root/app/(payload)/admin/importMap.js
test/app/(payload)/admin/importMap.js
/test/app/(payload)/admin/importMap.js
test/pnpm-lock.yaml
test/databaseAdapter.js

7
.idea/payload.iml generated
View File

@@ -26,6 +26,7 @@
<excludeFolder url="file://$MODULE_DIR$/packages/live-preview/dist" />
<excludeFolder url="file://$MODULE_DIR$/packages/next/.swc" />
<excludeFolder url="file://$MODULE_DIR$/packages/next/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/next/dist" />
<excludeFolder url="file://$MODULE_DIR$/packages/payload/fields" />
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud-storage/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/plugin-cloud-storage/dist" />
@@ -75,8 +76,12 @@
<excludeFolder url="file://$MODULE_DIR$/packages/ui/.swc" />
<excludeFolder url="file://$MODULE_DIR$/packages/ui/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/ui/dist" />
<excludeFolder url="file://$MODULE_DIR$/packages/drizzle/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/drizzle/dist" />
<excludeFolder url="file://$MODULE_DIR$/packages/db-sqlite/.turbo" />
<excludeFolder url="file://$MODULE_DIR$/packages/db-sqlite/dist" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
</module>

View File

@@ -1,8 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="--no-deprecation fields" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
<envs>
<env name="NODE_OPTIONS" value="--no-deprecation" />
</envs>
<configuration default="false" name="Run Dev Fields" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<arguments value="fields" />
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -1,8 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="--no-deprecation _community" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
<envs>
<env name="NODE_OPTIONS" value="--no-deprecation" />
</envs>
<configuration default="false" name="Run Dev _community" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<arguments value="_community" />
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -0,0 +1,13 @@
<component name="ProjectRunConfigurationManager">
<configuration default="false" name="Run Dev admin" type="js.build_tools.npm">
<package-json value="$PROJECT_DIR$/package.json" />
<command value="run" />
<scripts>
<script value="dev" />
</scripts>
<arguments value="admin" />
<node-interpreter value="project" />
<envs />
<method v="2" />
</configuration>
</component>

View File

@@ -1,7 +1,7 @@
<component name="ProjectRunConfigurationManager">
<configuration default="true" type="JavaScriptTestRunnerJest">
<node-interpreter value="project" />
<node-options value="--experimental-vm-modules --no-deprecation" />
<node-options value="--no-deprecation" />
<envs />
<scope-kind value="ALL" />
<method v="2" />

View File

@@ -1 +1 @@
v18.20.2
v22.6.0

3
.npmrc
View File

@@ -1,2 +1,3 @@
symlink=true
node-linker=isolated # due to a typescript bug, isolated mode requires @types/express-serve-static-core, terser and monaco-editor to be installed https://github.com/microsoft/TypeScript/issues/47663#issuecomment-1519138189 along with two other changes in the code which I've marked with (tsbugisolatedmode) in the code
node-linker=isolated
hoist-workspace-packages=false # the default in pnpm v9 is true, but that can break our runtime dependency checks

2
.nvmrc
View File

@@ -1 +1 @@
v18.20.2
v22.6.0

2
.tool-versions Normal file
View File

@@ -0,0 +1,2 @@
pnpm 9.7.1
nodejs 22.6.0

21
.vscode/launch.json vendored
View File

@@ -56,6 +56,20 @@
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js fields-relationship",
"cwd": "${workspaceFolder}",
"name": "Run Dev Fields-Relationship",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js login-with-username",
"cwd": "${workspaceFolder}",
"name": "Run Dev Login-With-Username",
"request": "launch",
"type": "node-terminal"
},
{
"command": "pnpm run dev plugin-cloud-storage",
"cwd": "${workspaceFolder}",
@@ -104,6 +118,13 @@
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js locked-documents",
"cwd": "${workspaceFolder}",
"name": "Run Dev Locked Documents",
"request": "launch",
"type": "node-terminal"
},
{
"command": "node --no-deprecation test/dev.js uploads",
"cwd": "${workspaceFolder}",

15
.vscode/settings.json vendored
View File

@@ -31,8 +31,15 @@
"editor.formatOnSave": true
},
"editor.formatOnSaveMode": "file",
// All ESLint rules to 'warn' to differentate from TypeScript's 'error' level
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
"eslint.rules.customizations": [
// Defaultt all ESLint errors to 'warn' to differentate from TypeScript's 'error' level
{ "rule": "*", "severity": "warn" },
// Silence some warnings that will get auto-fixed
{ "rule": "perfectionist/*", "severity": "off", "fixable": true },
{ "rule": "curly", "severity": "off", "fixable": true },
{ "rule": "object-shorthand", "severity": "off", "fixable": true }
],
"typescript.tsdk": "node_modules/typescript/lib",
// Load .git-blame-ignore-revs file
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
@@ -42,8 +49,8 @@
}
},
"files.insertFinalNewline": true,
"jestrunner.jestCommand": "pnpm exec cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-deprecation\" node 'node_modules/jest/bin/jest.js'",
"jestrunner.jestCommand": "pnpm exec cross-env NODE_OPTIONS=\"--no-deprecation\" node 'node_modules/jest/bin/jest.js'",
"jestrunner.debugOptions": {
"runtimeArgs": ["--experimental-vm-modules", "--no-deprecation"]
"runtimeArgs": ["--no-deprecation"]
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -63,7 +63,7 @@ Each test directory is split up in this way specifically to reduce friction when
The following command will start Payload with your config: `pnpm dev my-test-dir`. Example: `pnpm dev fields` for the test/`fields` test suite. This command will start up Payload using your config and refresh a test database on every restart. If you're using VS Code, the most common run configs are automatically added to your editor - you should be able to find them in your VS Code launch tab.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/config#admin-autologin) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
By default, payload will [automatically log you in](https://payloadcms.com/docs/authentication/overview#admin-autologin) with the default credentials. To disable that, you can either pass in the --no-auto-login flag (example: `pnpm dev my-test-dir --no-auto-login`) or set the `PAYLOAD_PUBLIC_DISABLE_AUTO_LOGIN` environment variable to `false`.
The default credentials are `dev@payloadcms.com` as E-Mail and `test` as password. These are used in the auto-login.
@@ -120,5 +120,5 @@ This is how you can preview changes you made locally to the docs:
2. Run `yarn install`
3. Duplicate the `.env.example` file and rename it to `.env`
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
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/)

View File

@@ -1,6 +1,7 @@
<a href="https://payloadcms.com"><img width="100%" src="https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/assets/images/github-banner-alt.jpg?raw=true" alt="Payload headless CMS Admin panel built with React" /></a>
<br />
<br />
<p align="left">
<a href="https://github.com/payloadcms/payload/actions"><img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/payloadcms/payload/main.yml?style=flat-square"></a>
&nbsp;

14
app/(app)/layout.tsx Normal file
View File

@@ -0,0 +1,14 @@
import React from 'react'
export const metadata = {
description: 'Generated by Next.js',
title: 'Next.js',
}
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>{children}</body>
</html>
)
}

11
app/(app)/test/page.tsx Normal file
View File

@@ -0,0 +1,11 @@
import configPromise from '@payload-config'
import { getPayloadHMR } from '@payloadcms/next/utilities'
export const Page = async ({ params, searchParams }) => {
const payload = await getPayloadHMR({
config: configPromise,
})
return <div>test ${payload?.config?.collections?.length}</div>
}
export default Page

View File

@@ -5,6 +5,8 @@ import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { NotFoundPage, generatePageMetadata } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
segments: string[]
@@ -17,6 +19,7 @@ type Args = {
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const NotFound = ({ params, searchParams }: Args) => NotFoundPage({ config, params, searchParams })
const NotFound = ({ params, searchParams }: Args) =>
NotFoundPage({ config, importMap, params, searchParams })
export default NotFound

View File

@@ -5,6 +5,8 @@ import config from '@payload-config'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import { RootPage, generatePageMetadata } from '@payloadcms/next/views'
import { importMap } from '../importMap.js'
type Args = {
params: {
segments: string[]
@@ -17,6 +19,7 @@ type Args = {
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
generatePageMetadata({ config, params, searchParams })
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
const Page = ({ params, searchParams }: Args) =>
RootPage({ config, importMap, params, searchParams })
export default Page

View File

@@ -1,6 +1,9 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import { RootLayout } from '@payloadcms/next/layouts'
import { importMap } from './admin/importMap.js'
// import '@payloadcms/ui/styles.css' // Uncomment this line if `@payloadcms/ui` in `tsconfig.json` points to `/ui/dist` instead of `/ui/src`
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import React from 'react'
@@ -11,6 +14,10 @@ type Args = {
children: React.ReactNode
}
const Layout = ({ children }: Args) => <RootLayout config={configPromise}>{children}</RootLayout>
const Layout = ({ children }: Args) => (
<RootLayout config={configPromise} importMap={importMap}>
{children}
</RootLayout>
)
export default Layout

View File

@@ -6,96 +6,140 @@ desc: With Collection-level Access Control you can define which users can create
keywords: collections, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You can define Collection-level Access Control within each Collection's `access` property. All Access Control functions accept one `args` argument.
Collection Access Control is [Access Control](../access-control) used to restrict access to Documents within a [Collection](../collections/overview), as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Collection.
## Available Controls
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------------- |
| **[`create`](#create)** | Used in the `create` operation |
| **[`read`](#read)** | Used in the `find` and `findByID` operations |
| **[`update`](#update)** | Used in the `update` operation |
| **[`delete`](#delete)** | Used in the `delete` operation |
#### Auth-enabled Controls
If a Collection supports [`Authentication`](/docs/authentication/overview), the following Access Controls become available:
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------------------------------- |
| **[`admin`](#admin)** | Used to restrict access to the [Admin Panel](../admin/overview) |
| **[`unlock`](#unlock)** | Used to restrict which users can access the `unlock` operation |
**Example Collection config:**
To add Access Control to a Collection, use the `access` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload';
export const Posts: CollectionConfig = {
slug: "posts",
export const CollectionWithAccessControl: CollectionConfig = {
// ...
access: { // highlight-line
// ...
},
}
```
## Config Options
Access Control is specific to the operation of the request.
To add Access Control to a Collection, use the `access` property in your [Collection Config](../configuration/collections):
```ts
import type { CollectionConfig } from 'payload';
export const CollectionWithAccessControl: CollectionConfig = {
// ...
// highlight-start
access: {
create: ({ req: { user } }) => { ... },
read: ({ req: { user } }) => { ... },
update: ({ req: { user } }) => { ... },
delete: ({ req: { user } }) => { ... },
admin: ({ req: { user } }) => { ... },
create: () => {...},
read: () => {...},
update: () => {...},
delete: () => {...},
// Auth-enabled Collections only
admin: () => {...},
unlock: () => {...},
// Version-enabled Collections only
readVersions: () => {...},
},
// highlight-end
};
}
```
The following options are available:
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------------- |
| **`create`** | Used in the `create` operation. [More details](#create). |
| **`read`** | Used in the `find` and `findByID` operations. [More details](#read). |
| **`update`** | Used in the `update` operation. [More details](#update). |
| **`delete`** | Used in the `delete` operation. [More details](#delete). |
If a Collection supports [`Authentication`](../authentication/overview), the following additional options are available:
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------------------------------- |
| **`admin`** | Used to restrict access to the [Admin Panel](../admin/overview). [More details](#admin). |
| **`unlock`** | Used to restrict which users can access the `unlock` operation. [More details](#unlock). |
If a Collection supports [Versions](../versions/overview), the following additional options are available:
| Function | Allows/Denies Access |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. [More details](#read-versions). |
### Create
Returns a boolean which allows/denies access to the `create` request.
**Available argument properties:**
| Option | Description |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`data`** | The data passed to create the document with. |
**Example:**
To add create Access Control to a Collection, use the `create` property in the [Collection Config](../collections/overview):
```ts
const PublicUsers = {
slug: 'public-users',
import { CollectionConfig } from 'payload'
export const CollectionWithCreateAccess: CollectionConfig = {
// ...
access: {
// highlight-start
// allow guest users to self-registration
create: () => true,
create: ({ req: { user }, data }) => {
return Boolean(user)
},
// highlight-end
...
},
fields: [ ... ],
}
```
The following arguments are provided to the `create` function:
| Option | Description |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`data`** | The data passed to create the document with. |
### Read
Read access functions can return a boolean result or optionally return a [query constraint](/docs/queries/overview) which limits the documents that are returned to only those that match the constraint you provide. This can be helpful to restrict users' access to only certain documents however you specify.
Returns a boolean which allows/denies access to the `read` request.
**Available argument properties:**
To add read Access Control to a Collection, use the `read` property in the [Collection Config](../collections/overview):
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of document requested, if within `findByID` |
```ts
import type { CollectionConfig } from 'payload'
**Example:**
export const CollectionWithReadAccess: CollectionConfig = {
// ...
access: {
// highlight-start
read: ({ req: { user } }) => {
return Boolean(user)
},
// highlight-end
},
}
```
<Banner type="success">
<strong>Tip:</strong>
Return a [Query](../queries/overview) to limit the Documents to only those that match the constraint. This can be helpful to restrict users' access to specific Documents. [More details](../queries/overview).
</Banner>
As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:
```ts
import type { Access } from 'payload'
const canReadPage: Access = ({ req: { user } }) => {
// allow authenticated users
export const canReadPage: Access = ({ req: { user } }) => {
// Allow authenticated users
if (user) {
return true
}
// using a query constraint, guest users can access when a field named 'isPublic' is set to true
// By returning a Query, guest users can read public Documents
// Note: this assumes you have a `isPublic` checkbox field on your Collection
return {
// assumes we have a checkbox field named 'isPublic'
isPublic: {
equals: true,
},
@@ -103,55 +147,96 @@ const canReadPage: Access = ({ req: { user } }) => {
}
```
The following arguments are provided to the `read` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`id`** | `id` of document requested, if within `findByID`. |
### Update
Update access functions can return a boolean result or optionally return a [query constraint](/docs/queries/overview) to limit the document(s) that can be updated by the currently authenticated user. For example, returning a `query` from the `update` Access Control is helpful in cases where you would like to restrict a user to only being able to update the documents containing a `createdBy` relationship field equal to the user's ID.
Returns a boolean which allows/denies access to the `update` request.
**Available argument properties:**
To add update Access Control to a Collection, use the `update` property in the [Collection Config](../collections/overview):
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`id`** | `id` of document requested to update |
| **`data`** | The data passed to update the document with |
```ts
import type { CollectionConfig } from 'payload'
**Example:**
export const CollectionWithUpdateAccess: CollectionConfig = {
// ...
access: {
// highlight-start
update: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
<Banner type="success">
<strong>Tip:</strong>
Return a [Query](../queries/overview) to limit the Documents to only those that match the constraint. This can be helpful to restrict users' access to specific Documents. [More details](../queries/overview).
</Banner>
As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:
```ts
import type { Access } from 'payload'
const canUpdateUser: Access = ({ req: { user }, id }) => {
// allow users with a role of 'admin'
export const canUpdateUser: Access = ({ req: { user }, id }) => {
// Allow users with a role of 'admin'
if (user.roles && user.roles.some((role) => role === 'admin')) {
return true
}
// allow any other users to update only oneself
return user.id === id
}
```
The following arguments are provided to the `update` function:
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`id`** | `id` of document requested to update. |
| **`data`** | The data passed to update the document with. |
### Delete
Similarly to the Update function, returns a boolean or a [query constraint](/docs/queries/overview) to limit which documents can be deleted by which users.
**Available argument properties:**
To add delete Access Control to a Collection, use the `delete` property in the [Collection Config](../collections/overview):
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object with additional `user` property, which is the currently logged in user |
| **`id`** | `id` of document requested to delete |
```ts
import type { CollectionConfig } from 'payload'
**Example:**
export const CollectionWithDeleteAccess: CollectionConfig = {
// ...
access: {
// highlight-start
delete: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
As your application becomes more complex, you may want to define your function in a separate file and import them into your Collection Config:
```ts
import type { Access } from 'payload'
const canDeleteCustomer: Access = async ({ req, id }) => {
export const canDeleteCustomer: Access = async ({ req, id }) => {
if (!id) {
// allow the admin UI to show controls to delete since it is indeterminate without the id
// allow the admin UI to show controls to delete since it is indeterminate without the `id`
return true
}
// query another collection using the id
// Query another Collection using the `id`
const result = await req.payload.find({
collection: 'contracts',
limit: 0,
@@ -165,22 +250,90 @@ const canDeleteCustomer: Access = async ({ req, id }) => {
}
```
The following arguments are provided to the `delete` function:
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object with additional `user` property, which is the currently logged in user. |
| **`id`** | `id` of document requested to delete.
### Admin
If the Collection is use to access the [Admin Panel](../admin/overview#the-admin-user-collection), the `Admin` Access Control function determines whether or not the currently logged in user can access the admin UI.
**Available argument properties:**
To add Admin Access Control to a Collection, use the `admin` property in the [Collection Config](../collections/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionWithAdminAccess: CollectionConfig = {
// ...
access: {
// highlight-start
admin: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
The following arguments are provided to the `admin` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
### Unlock
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/config#options).
Determines which users can [unlock](/docs/authentication/operations#unlock) other users who may be blocked from authenticating successfully due to [failing too many login attempts](/docs/authentication/overview#options).
**Available argument properties:**
To add Unlock Access Control to a Collection, use the `unlock` property in the [Collection Config](../collections/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionWithUnlockAccess: CollectionConfig = {
// ...
access: {
// highlight-start
unlock: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
The following arguments are provided to the `unlock` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
### Read Versions
If the Collection has [Versions](../versions/overview) enabled, the `readVersions` Access Control function determines whether or not the currently logged in user can access the version history of a Document.
To add Read Versions Access Control to a Collection, use the `readVersions` property in the [Collection Config](../collections/overview):
```ts
import type { CollectionConfig } from 'payload'
export const CollectionWithVersionsAccess: CollectionConfig = {
// ...
access: {
// highlight-start
readVersions: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
The following arguments are provided to the `readVersions` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |

View File

@@ -1,22 +1,36 @@
---
title: Field-level Access Control
label: Fields
order: 30
order: 40
desc: Field-level Access Control is specified within a field's config, and allows you to define which users can create, read or update Fields.
keywords: fields, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Field Access Control is specified with functions inside a field's config. All field-level Controls return a boolean value to allow or deny access for the specified operation. No field-level Access Controls support returning query constraints. All Access Control functions accept one `args` argument.
Field Access Control is [Access Control](../access-control) used to restrict access to specific [Fields](../fields/overview) within a Document.
## Available Controls
To add Access Control to a Field, use the `access` property in your [Field Config](../fields/overview):
| Function | Purpose |
| ----------------------- | -------------------------------------------------------------------------------- |
| **[`create`](#create)** | Allows or denies the ability to set a field's value when creating a new document |
| **[`read`](#read)** | Allows or denies the ability to read a field's value |
| **[`update`](#update)** | Allows or denies the ability to update a field's value |
```ts
import type { Field } from 'payload';
**Example Collection config:**
export const FieldWithAccessControl: Field = {
// ...
access: { // highlight-line
// ...
},
}
```
<Banner type="warning">
<strong>Note:</strong>
Field Access Controls does not support returning [Query](../queries/overview) constraints like [Collection Access Control](./collections) does.
</Banner>
## Config Options
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';
@@ -39,6 +53,14 @@ export const Posts: CollectionConfig = {
};
```
The following options are available:
| Function | Purpose |
| ----------------------- | -------------------------------------------------------------------------------- |
| **`create`** | Allows or denies the ability to set a field's value when creating a new document. [More details](#create). |
| **`read`** | Allows or denies the ability to read a field's value. [More details](#read). |
| **`update`** | Allows or denies the ability to update a field's value [More details](#update). |
### Create
Returns a boolean which allows or denies the ability to set a field's value when creating a new document. If `false` is returned, any passed values will be discarded.

View File

@@ -1,35 +1,44 @@
---
title: Globals Access Control
label: Globals
order: 40
order: 30
desc: Global-level Access Control is specified within each Global's `access` property and allows you to define which users can read or update Globals.
keywords: globals, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
You can define Global-level Access Control within each Global's `access` property. All Access Control functions accept one `args` argument.
Global Access Control is [Access Control](../access-control) used to restrict access to [Global](../globals/overview) Documents, as well as what they can and cannot see within the [Admin Panel](../admin/overview) as it relates to that Global.
## Available Controls
To add Access Control to a Global, use the `access` property in your [Global Config](../configuration/globals):
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------- |
| **[`read`](#read)** | Used in the `findOne` Global operation |
| **[`update`](#update)** | Used in the `update` Global operation |
```ts
import type { GlobalConfig } from 'payload';
**Example Global config:**
export const GlobalWithAccessControl: GlobalConfig = {
// ...
access: { // highlight-line
// ...
},
}
```
## Config Options
Access Control is specific to the operation of the request.
To add Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../globals/overview):
```ts
import { GlobalConfig } from 'payload'
const Header: GlobalConfig = {
slug: 'header',
const GlobalWithAccessControl: GlobalConfig = {
// ...
// highlight-start
access: {
read: ({ req: { user } }) => {
/* */
},
update: ({ req: { user } }) => {
/* */
},
read: ({ req: { user } }) => {...},
update: ({ req: { user } }) => {...},
// Version-enabled Globals only
readVersion: () => {...},
},
// highlight-end
}
@@ -37,23 +46,97 @@ const Header: GlobalConfig = {
export default Header
```
The following options are available:
| Function | Allows/Denies Access |
| ----------------------- | -------------------------------------- |
| **`read`** | Used in the `findOne` Global operation. [More details](#read). |
| **`update`** | Used in the `update` Global operation. [More details](#update). |
If a Global supports [Versions](../versions/overview), the following additional options are available:
| Function | Allows/Denies Access |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. [More details](#read-versions). |
### Read
Returns a boolean result or optionally a [query constraint](/docs/queries/overview) which limits who can read this global based on its current properties.
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can read this global based on its current properties.
**Available argument properties:**
To add read Access Control to a [Global](../configuration/globals), use the `read` property in the [Global Config](../globals/overview):
```ts
import { GlobalConfig } from 'payload'
const Header: GlobalConfig = {
// ...
// highlight-start
read: {
read: ({ req: { user } }) => {
return Boolean(user)
},
}
// highlight-end
}
```
The following arguments are provided to the `read` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
### Update
Returns a boolean result or optionally a [query constraint](/docs/queries/overview) which limits who can update this global based on its current properties.
Returns a boolean result or optionally a [query constraint](../queries/overview) which limits who can update this global based on its current properties.
**Available argument properties:**
To add update Access Control to a [Global](../configuration/globals), use the `access` property in the [Global Config](../globals/overview):
```ts
import { GlobalConfig } from 'payload'
const Header: GlobalConfig = {
// ...
// highlight-start
access: {
update: ({ req: { user }, data }) => {
return Boolean(user)
},
}
// highlight-end
}
```
The following arguments are provided to the `update` function:
| Option | Description |
| ---------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user` |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |
| **`data`** | The data passed to update the global with. |
### Read Versions
If the Global has [Versions](../versions/overview) enabled, the `readVersions` Access Control function determines whether or not the currently logged in user can access the version history of a Document.
To add Read Versions Access Control to a Collection, use the `readVersions` property in the [Global Config](../globals/overview):
```ts
import type { GlobalConfig } from 'payload'
export const GlobalWithVersionsAccess: GlobalConfig = {
// ...
access: {
// highlight-start
readVersions: ({ req: { user }}) => {
return Boolean(user)
},
// highlight-end
},
}
```
The following arguments are provided to the `readVersions` function:
| Option | Description |
| --------- | -------------------------------------------------------------------------- |
| **`req`** | The [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object containing the currently authenticated `user`. |

View File

@@ -2,84 +2,59 @@
title: Access Control
label: Overview
order: 10
desc: Payload makes it simple to define and manage access control. By declaring roles, you can set permissions and restrict what your users can interact with.
desc: Payload makes it simple to define and manage Access Control. By declaring roles, you can set permissions and restrict what your users can interact with.
keywords: overview, access control, permissions, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Access control within Payload is extremely powerful while remaining easy and intuitive to manage. Declaring who should have access to what documents is no more complex than writing a simple JavaScript function that either returns a `boolean` or a [`query`](/docs/queries/overview) constraint to restrict which documents users can interact with.
<YouTube id="DoPLyXG26Dg" title="Overview of Payload Access Control" />
**Example use cases:**
Access Control determines what a user can and cannot do with any given Document, as well as what they can and cannot see within the [Admin Panel](../admin/overview). By implementing Access Control, you can define granular restrictions based on the user, their roles (RBAC), Document data, or any other criteria your application requires.
- Allowing anyone `read` access to all `Post`s
- Only allowing public access to `Post`s where a `status` field is equal to `published`
- Giving only `User`s with a `role` field equal to `admin` the ability to delete `Page`(s)
- Allowing anyone to create `ContactSubmission`s, but only logged in users to `read`, `update` or `delete` them
- Restricting a `User` to only be able to see their own `Order`(s), but no others
- Allowing `User`s that belong to a certain `Organization` to access only that `Organization`'s `Resource`s
Access Control functions are scoped to the _operation_, meaning you can have different rules for `create`, `read`, `update`, `delete`, etc. Access Control functions are executed _before_ any changes are made and _before_ any operations are completed. This allows you to determine if the user has the necessary permissions before fulfilling the request.
## Default Settings
There are many use cases for Access Control, including:
**By default, all Collections and Globals require that a user is logged in to be able to interact in any way.** The default Access Control function evaluates the `user` from the `req` and returns `true` if a user is logged in, and `false` if not.
- Allowing anyone `read` access to all posts
- 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
- Allowing users that belong to a certain organization to access only that organization's resources
**Default Access function:**
There are three main types of Access Control in Payload:
- [Collection Access Control](./collections)
- [Global Access Control](./globals)
- [Field Access Control](./fields)
## Default Access Control
Payload provides default Access Control so that your data is secured behind [Authentication](../authentication) without additional configuration. To do this, Payload sets a default function that simply checks if a user is present on the request. You can override this default behavior by defining your own Access Control functions as needed.
Here is the default Access Control that Payload provides:
```ts
const defaultPayloadAccess = ({ req: { user } }) => {
// Return `true` if a user is found
// and `false` if it is undefined or null
return Boolean(user)
return Boolean(user) // highlight-line
}
```
<Banner type="success">
<strong>Note:</strong>
<br />
In the Local API, all Access Control functions are skipped by default, allowing your server to do
whatever it needs. But, you can opt back in by setting the option
<strong>
overrideAccess
</strong>
{' '}
to <strong>false</strong>.
<Banner type="warning">
<strong>Important:</strong>
In the [Local API](../local-api/overview), all Access Control is _skipped_ by default. This allows your server to have full control over your application. To opt back in, you can set the `overrideAccess` option to `false` in your requests.
</Banner>
## Access Control Types
## The Access Operation
You can manage access within Payload on three different levels:
The Admin Panel responds dynamically to your changes to Access Control. For example, if you restrict editing `ExampleCollection` to only users that feature an "admin" role, Payload will **hide** that Collection from the Admin Panel entirely. This is super powerful and allows you to control who can do what within your Admin Panel using the same functions that secure your APIs.
- [Collections](/docs/access-control/collections)
- [Fields](/docs/access-control/fields)
- [Globals](/docs/access-control/globals)
## When Access Control is Executed
<Banner type="success">
<strong>Note:</strong>
<br />
Access control functions are utilized in two places. It's important to understand how and when
your access control is executed.
</Banner>
### As you execute operations
When you perform Payload operations like `create`, `read`, `update`, and `delete`, your access control functions will be executed before any changes or operations are completed.
### Within the Admin UI
The Payload Admin UI responds dynamically to the access control that you define. For example, if you restrict editing a `ExampleCollection` to only users that feature a `role` of `admin`, the Payload Admin UI will **hide** the `ExampleCollection` from the Admin UI entirely. This is super powerful and allows you to control who can do what with your Admin UI.
To accomplish this, Payload ships with an `Access` operation, which is executed when a user logs into the Admin UI. Payload will execute each one of your access control functions, across all collections, globals, and fields, at the top level and return a response that contains a reflection of what the currently authenticated user can do with your application.
## Argument Availability
To accomplish this, Payload exposes the [Access Operation](../authentication/operations#access). Upon login, Payload executes each Access Control function at the top level, across all Collections, Globals, and Fields, and returns a response that contains a reflection of what the currently authenticated user can do within your application.
<Banner type="warning">
<strong>Important:</strong>
<br />
When your access control functions are executed via the <strong>access</strong> operation, the{' '}
<strong>id</strong> and <strong>data</strong> arguments will be <strong>undefined</strong>,
because Payload is executing your functions without referencing a specific document.
When your access control functions are executed via the [Access Operation](../authentication/operations#access), the `id` and `data` arguments will be `undefined`. This is because Payload is executing your functions without referencing a specific Document.
</Banner>
If you use `id` or `data` within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your access control is being executed via the `access` operation, to determine solely what the user can do within the Admin UI.
If you use `id` or `data` within your access control functions, make sure to check that they are defined first. If they are not, then you can assume that your Access Control is being executed via the Access Operation to determine solely what the user can do within the Admin Panel.

173
docs/admin/collections.mdx Normal file
View File

@@ -0,0 +1,173 @@
---
title: Collection Admin Config
label: Collections
order: 20
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Collections](../configuration/collections) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), selecting which fields to display in the List View, and more.
To configure Admin Options for Collections, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](../hooks/collections). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the Admin Panel. If no field is defined, the ID of the document is used as the title. |
| **`description`** | Text to display below the Collection label in the List View to give editors more information. Alternatively, you can use the `admin.components.Description` to render a React component. [More details](#components). |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Page metadata overrides to apply to this Collection within the Admin Panel. [More details](./metadata). |
| **`preview`** | Function to generate preview URLs within the Admin Panel that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](#components). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
### Components
Collections can set their own [Custom Components](./components) which only apply to [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Collection Components, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { SanitizedCollectionConfig } from 'payload'
export const MyCollection: SanitizedCollectionConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table
| **`Description`** | A component to render below the Collection label in the List View. An alternative to the `admin.description` property. |
| **`edit.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`edit.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`edit.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Note:</strong>
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>
### Pagination
All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis, and uses the same [Pagination](../queries/pagination) API that Payload provides.
To configure pagination options, use the `admin.pagination` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List View. |
### List Searchable Fields
In the List View, there is a "search" box that allows you to quickly find a document through a simple text search. By default, it searches on the ID field. If defined, the `admin.useAsTitle` field is used. Or, you can explicitly define which fields to search based on the needs of your application.
To define which fields should be searched, use the `admin.listSearchableFields` property in your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
<strong>Tip:</strong>
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>

View File

@@ -1,7 +1,7 @@
---
title: Swap in your own React components
label: Custom Components
order: 20
order: 40
desc: Fully customize your Admin Panel by swapping in your own React components. Add fields, remove views, update routes and change functions to sculpt your perfect Dashboard.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -18,12 +18,226 @@ All Custom Components in Payload are [React Server Components](https://react.dev
There are four main types of Custom Components in Payload:
- [Root Components](#root-components)
- [Collection Components](#collection-components)
- [Global Components](#global-components)
- [Collection Components](./collections#components)
- [Global Components](./globals#components)
- [Field Components](./fields)
To swap in your own Custom Component, consult the list of available components. Determine the scope that corresponds to what you are trying to accomplish, then [author your React component(s)](#building-custom-components) accordingly.
## Defining Custom Components in the Payload Config
In the Payload Config, you can define custom React Components to enhance the admin interface. However, these components should not be imported directly into the server-only Payload Config to avoid including client-side code. Instead, you specify the path to the component. Heres how you can do it:
src/components/Logout.tsx
```tsx
'use client'
import React from 'react'
export const MyComponent = () => {
return (
<button>Click me!</button>
)
}
```
payload.config.ts:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
components: {
logout: {
Button: '/src/components/Logout#MyComponent'
}
}
},
})
```
In the path `/src/components/Logout#MyComponent`, `/src/components/Logout` is the file path, and `MyComponent` is the named export. If the component is the default export, the export name can be omitted. Path and export name are separated by a `#`.
### Configuring the Base Directory
Component paths, by default, are relative to your working directory - this is usually where your Next.js config lies. To simplify component paths, you have the option to configure the *base directory* using the `admin.baseDir.baseDir` property:
```ts
import { buildConfig } from 'payload'
import { fileURLToPath } from 'node:url'
import path from 'path'
const filename = fileURLToPath(import.meta.url)
const dirname = path.dirname(filename)
const config = buildConfig({
// ...
admin: { // highlight-line
importMap: {
baseDir: path.resolve(dirname, 'src'),
},
components: {
logout: {
Button: '/components/Logout#MyComponent'
}
}
},
})
```
In this example, we set the base directory to the `src` directory - thus we can omit the `/src/` part of our component path string.
### Passing Props
Each React Component in the Payload Config is typed as `PayloadComponent`. This usually is a string, but can also be an object containing the following properties:
| Property | Description |
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
| `clientProps` | Props to be passed to the React Component if it's a Client Component |
| `exportName` | Instead of declaring named exports using `#` in the component path, you can also omit them from `path` and pass them in here. |
| `path` | Path to the React Component. Named exports can be appended to the end of the path, separated by a `#` |
| `serverProps` | Props to be passed to the React Component if it's a Server Component |
To pass in props from the config, you can use the `clientProps` and/or `serverProps` properties. This alleviates the need to use an HOC (Higher-Order-Component) to declare a React Component with props passed in.
Here is an example:
src/components/Logout.tsx
```tsx
'use client'
import React from 'react'
export const MyComponent = ({ text }: { text: string }) => {
return (
<button>Click me! {text}</button>
)
}
```
payload.config.ts:
```ts
import { buildConfig } from 'payload'
const config = buildConfig({
// ...
admin: { // highlight-line
components: {
logout: {
Button: {
path: '/src/components/Logout',
clientProps: {
text: 'Some Text.'
},
exportName: 'MyComponent'
}
}
}
},
})
```
### Import Maps
It's essential to understand how `PayloadComponent` paths function behind the scenes. Directly importing React Components into your Payload Config using import statements can introduce client-only modules like CSS into your server-only config. This could error when attempting to load the Payload Config in server-only environments and unnecessarily increase the size of the Payload Config, which should remain streamlined and efficient for server use.
Instead, we utilize component paths to reference React Components. This method enhances the Payload Config with actual React Component imports on the client side, without affecting server-side usage. A script is deployed to scan the Payload Config, collecting all component paths and creating an `importMap.js`. This file, located in app/(payload)/admin/importMap.js, must be statically imported by your Next.js root page and layout. The script imports all the React Components from the specified paths into a Map, associating them with their respective paths (the ones you defined).
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.
### Component paths in external packages
Component paths are resolved relative to your project's base directory, which is either your current working directory or the directory specified in `config.admin.baseDir`. When using custom components from external packages, you can't use relative paths. Instead, use an import path that's accessible as if you were writing an import statement in your project's base directory.
For example, to export a field with a custom component from an external package named `my-external-package`:
```ts
import type { Field } from 'payload'
export const MyCustomField: Field = {
type: 'text',
name: 'MyField',
admin: {
components: {
Field: 'my-external-package/client#MyFieldComponent'
}
}
}
```
Despite `MyFieldComponent` living in `src/components/MyFieldComponent.tsx` in `my-external-package`, this will not be accessible from the consuming project. Instead, we recommend exporting all custom components from one file in the external package. For example, you can define a `src/client.ts file in `my-external-package`:
```ts
'use client'
export { MyFieldComponent } from './components/MyFieldComponent'
```
Then, update the package.json of `my-external-package:
```json
{
...
"exports": {
"./client": {
"import": "./dist/client.js",
"types": "./dist/client.d.ts",
"default": "./dist/client.js"
}
}
}
```
This setup allows you to specify the component path as `my-external-package/client#MyFieldComponent` as seen above. The import map will generate:
```ts
import { MyFieldComponent } from 'my-external-package/client'
```
which is a valid way to access MyFieldComponent that can be resolved by the consuming project.
### Custom Components from unknown locations
By default, any component paths from known locations are added to the import map. However, if you need to add any components from unknown locations to the import map, you can do so by adding them to the `admin.dependencies` array in your Payload Config. This is mostly only relevant for plugin authors and not for regular Payload users.
Example:
```ts
export default {
// ...
admin: {
// ...
dependencies: {
myTestComponent: { // myTestComponent is the key - can be anything
path: '/components/TestComponent.js#TestComponent',
type: 'component',
clientProps: {
test: 'hello',
},
},
},
}
}
```
This way, `TestComponent` is added to the import map, no matter if it's referenced in a known location or not. On the client, you can then use the component like this:
```tsx
'use client'
import { RenderComponent, useConfig } from '@payloadcms/ui'
import React from 'react'
export const CustomView = () => {
const { config } = useConfig()
return (
<div>
<RenderComponent mappedComponent={config.admin.dependencies?.myTestComponent} />
</div>
)
}
```
## Root Components
Root Components are those that effect the [Admin Panel](./overview) generally, such as the logo or the main nav.
@@ -33,16 +247,14 @@ To override Root Components, use the `admin.components` property in your [Payloa
```ts
import { buildConfig } from 'payload'
import { MyCustomLogo } from './MyCustomLogo'
export default buildConfig({
// ...
admin: {
// highlight-start
components: {
graphics: {
Logo: MyCustomLogo, // highlight-line
},
// ...
},
// highlight-end
},
})
```
@@ -63,30 +275,30 @@ The following options are available:
| **`logout.Button`** | The button displayed in the sidebar that logs the user out. |
| **`graphics.Icon`** | The simplified logo used in contexts like the the `Nav` component. |
| **`graphics.Logo`** | The full logo used in contexts like the `Login` view. |
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire [Admin Panel](./overview). [More details](#custom-providers). |
| **`actions`** | An array of Custom Components to be rendered in the header of the [Admin Panel](./overview), providing additional interactivity and functionality. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
| **`providers`** | Custom [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context) providers that will wrap the entire Admin Panel. [More details](#custom-providers). |
| **`actions`** | An array of Custom Components to be rendered _within_ the header of the Admin Panel, providing additional interactivity and functionality. |
| **`header`** | An array of Custom Components to be injected above the Payload header. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong> You can also use the `admin.components` property in your _[Collection](#collection-components) or [Global](#global-components)_.
<strong>Note:</strong>
You can also use set [Collection Components](./collections#components) and [Global Components](./globals#components) in their respective configs.
</Banner>
### Custom Providers
As you add more and more Custom Components to your [Admin Panel](./overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s). Payload allows you to inject your own context providers in your app where you can export your own custom hooks, etc.
As you add more and more Custom Components to your [Admin Panel](./overview), you may find it helpful to add additional [React Context](https://react.dev/learn/scaling-up-with-reducer-and-context)(s). Payload allows you to inject your own context providers in your app so you can export your own custom hooks, etc.
To add a Custom Provider, use the `admin.components.providers` property in your [Payload Config](../getting-started/overview):
```ts
import { buildConfig } from 'payload'
import { MyProvider } from './MyProvider'
export default buildConfig({
// ...
admin: {
components: {
providers: [MyProvider], // highlight-line
providers: ['/path/to/MyProvider'], // highlight-line
},
},
})
@@ -115,80 +327,6 @@ export const useMyCustomContext = () => useContext(MyCustomContext)
<strong>Reminder:</strong> Custom Providers are by definition Client Components. This means they must include the `use client` directive at the top of their files and cannot use server-only code.
</Banner>
## Collection Components
Collection Components are those that effect [Collection](../configuration/collections)-specific UI within the [Admin Panel](./overview), such as the save button or the List View.
To override Collection Components, use the `admin.components` property in your [Collection Config](../configuration/collections):
```ts
import type { SanitizedCollectionConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
admin: {
components: {
edit: {
SaveButton: CustomSaveButton, // highlight-line
},
},
},
// ...
}
```
_For details on how to build Custom Components, see [Building Custom Components](#building-custom-components)._
The following options are available:
| Path | Description |
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| **`beforeList`** | An array of components to inject _before_ the built-in List View |
| **`beforeListTable`** | An array of components to inject _before_ the built-in List View's table |
| **`afterList`** | An array of components to inject _after_ the built-in List View |
| **`afterListTable`** | An array of components to inject _after_ the built-in List View's table |
| **`edit.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled |
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
| **`edit.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
| **`edit.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
## Global Components
Global Components are those that effect [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview), such as the save button or the Edit View.
To override Global Components, use the `admin.components` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
import { CustomSaveButton } from './CustomSaveButton'
export const MyGlobal: SanitizedGlobalConfig = {
slug: 'my-global',
admin: {
components: {
elements: {
SaveButton: CustomSaveButton, // highlight-line
},
},
},
// ...
}
```
_For details on how to build Custom Components, see [Building Custom Components](#building-custom-components)._
The following options are available:
| Path | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`elements.SaveButton`** | Replace the default `Save` button with a Custom Component. Drafts must be disabled. |
| **`elements.SaveDraftButton`** | Replace the default `Save Draft` button with a Custom Component. Drafts must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default `Publish` button with a Custom Component. Drafts must be enabled. |
| **`elements.PreviewButton`** | Replace the default `Preview` button with a Custom Component. |
| **`views`** | Override or create new views within the [Admin Panel](./overview). [More details](./views). |
## 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.
@@ -219,7 +357,7 @@ Each Custom Component receives the following props by default:
| Prop | Description |
| ------------------------- | ----------------------------------------------------------------------------------------------------- |
| `payload` | The [Payload](../local-api/overview) class. |
| `i18n` | The [i18n](../i18n) object. |
| `i18n` | The [i18n](../configuration/i18n) object. |
Custom Components also receive various other props that are specific to the context in which the Custom Component is being rendered. For example, [Custom Views](./views) receive the `user` prop. For a full list of available props, consult the documentation related to the specific component you are working with.
@@ -280,7 +418,7 @@ import React from 'react'
import { useConfig } from '@payloadcms/ui'
export const MyClientComponent: React.FC = () => {
const { serverURL } = useConfig() // highlight-line
const { config: { serverURL } } = useConfig() // highlight-line
return (
<Link href={serverURL}>
@@ -294,6 +432,22 @@ export const MyClientComponent: React.FC = () => {
See [Using Hooks](#using-hooks) for more details.
</Banner>
All [Field Components](./fields) automatically receive their respective Field Config through a common [`field`](./fields#the-field-prop) prop:
```tsx
'use client'
import React from 'react'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
}
```
### Using Hooks
To make it easier to [build your Custom Components](#building-custom-components), you can use [Payload's built-in React Hooks](./hooks) in any Client Component. For example, you might want to interact with one of Payload's many React Contexts:

View File

@@ -1,7 +1,7 @@
---
title: Customizing CSS & SCSS
label: Customizing CSS
order: 60
order: 80
desc: Customize the Payload Admin Panel further by adding your own CSS or SCSS style sheet to the configuration, powerful theme and design options are waiting for you.
keywords: admin, css, scss, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---

View File

@@ -1,7 +1,7 @@
---
title: Customizing Fields
label: Customizing Fields
order: 40
order: 60
desc:
keywords:
---
@@ -18,7 +18,7 @@ For example, your app might need to render a specific interface that Payload doe
## Admin Options
You can customize the appearance and behavior of fields within the [Admin Panel](./overvieW) through the `admin` property of any [Field Config](../fields/overview):
You can customize the appearance and behavior of fields within the [Admin Panel](./overview) through the `admin` property of any [Field Config](../fields/overview):
```ts
import type { CollectionConfig } from 'payload'
@@ -117,7 +117,7 @@ export const CollectionConfig: CollectionConfig = {
// ...
admin: {
components: {
Field: MyFieldComponent, // highlight-line
Field: '/path/to/MyFieldComponent', // highlight-line
},
},
}
@@ -135,32 +135,13 @@ All Field Components receive the following props:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`AfterInput`** | The rendered result of the `admin.components.afterInput` property. [More details](#afterinput-and-beforeinput). |
| **`BeforeInput`** | The rendered result of the `admin.components.beforeInput` property. [More details](#afterinput-and-beforeinput). |
| **`CustomDescription`** | The rendered result of the `admin.components.Description` property. [More details](#the-description-component). |
| **`CustomError`** | The rendered result of the `admin.components.Error` property. [More details](#the-error-component). |
| **`CustomLabel`** | The rendered result of the `admin.components.Label` property. [More details](#the-label-component).
| **`path`** | The static path of the field at render time. [More details](./hooks#usefieldprops). |
| **`disabled`** | The `admin.disabled` property defined in the [Field Config](../fields/overview). |
| **`required`** | The `admin.required` property defined in the [Field Config](../fields/overview). |
| **`className`** | The `admin.className` property defined in the [Field Config](../fields/overview). |
| **`style`** | The `admin.style` property defined in the [Field Config](../fields/overview). |
| **`custom`** | The `admin.custom` property defined in the [Field Config](../fields/overview).
| **`placeholder`** | The `admin.placeholder` property defined in the [Field Config](../fields/overview). |
| **`descriptionProps`** | An object that contains the props for the `FieldDescription` component. |
| **`labelProps`** | An object that contains the props needed for the `FieldLabel` component. |
| **`errorProps`** | An object that contains the props for the `FieldError` component. |
| **`docPreferences`** | An object that contains the preferences for the document. |
| **`label`** | The label value provided in the field, it can be used with i18n. |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
| **`locale`** | The locale of the field. [More details](../configuration/localization). |
| **`localized`** | A boolean value that represents if the field is localized or not. [More details](../fields/localized). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`rtl`** | A boolean value that represents if the field should be rendered right-to-left or not. [More details](../configuration/i18n). |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
| **`validate`** | A function that can be used to validate the field. |
| **`hasMany`** | If a [`relationship`](../fields/relationship) field, the `hasMany` property defined in the [Field Config](../fields/overview). |
| **`maxLength`** | If a [`text`](../fields/text) field, the `maxLength` property defined in the [Field Config](../fields/overview). |
| **`minLength`** | If a [`text`](../fields/text) field, the `minLength` property defined in the [Field Config](../fields/overview). |
<Banner type="success">
<strong>Reminder:</strong>
@@ -193,6 +174,82 @@ export const CustomTextField: React.FC = () => {
For a complete list of all available React hooks, see the [Payload React Hooks](./hooks) documentation. For additional help, see [Building Custom Components](./components#building-custom-components).
</Banner>
#### TypeScript
When building Custom Field Components, you can import the component type to ensure type safety. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and for every client/server environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### The `field` Prop
All Field Components are passed their own Field Config through a common `field` prop. Within Server Components, this is the original Field Config as written within your Payload Config. Within Client Components, however, this is a "Client Config", which is a sanitized, client-friendly version of the Field Config. This is because the original Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), meaning it cannot be passed into Client Components without first being transformed.
The Client Field Config is an exact copy of the original Field Config, minus all non-serializable properties, plus all evaluated functions such as field labels, [Custom Components](../components), etc.
Server Component:
```tsx
import React from 'react'
import type { TextFieldServerComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
export const MyServerField: TextFieldServerComponent = ({ clientField }) => {
return <TextField field={clientField} />
}
```
<Banner type="info">
<strong>Tip:</strong>
Server Components can still access the original Field Config through the `field` prop.
</Banner>
Client Component:
```tsx
'use client'
import React from 'react'
import type { TextFieldClientComponent } from 'payload'
export const MyTextField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />
}
```
The following additional properties are also provided to the `field` prop:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`_isPresentational`** | A boolean indicating that the field is purely visual and does not directly affect data or change data shape, i.e. the [UI Field](../fields/ui). |
| **`_path`** | A string representing the direct, dynamic path to the field at runtime, i.e. `myGroup.myArray[0].myField`. |
| **`_schemaPath`** | A string representing the direct, static path to the [Field Config](../fields/overview), i.e. `myGroup.myArray.myField` |
<Banner type="info">
<strong>Note:</strong>
These properties are underscored to denote that they are not part of the original Field Config, and instead are attached during client sanitization to make fields easier to work with on the front-end.
</Banner>
#### TypeScript
When building Custom Field Components, you can import the client field props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to prepend the field type onto the target type, i.e. `TextFieldClientComponent`:
```tsx
import type {
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### The Cell Component
The Cell Component is rendered in the table of the List View. It represents the value of the field when displayed in a table cell.
@@ -207,7 +264,7 @@ export const myField: Field = {
type: 'text',
admin: {
components: {
Cell: MyCustomCell, // highlight-line
Cell: '/path/to/MyCustomCellComponent', // highlight-line
},
},
}
@@ -219,20 +276,10 @@ All Cell Components receive the following props:
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`name`** | The name of the field. |
| **`className`** | The `admin.className` property defined in the [Field Config](../fields/overview). |
| **`fieldType`** | The `type` property defined in the [Field Config](../fields/overview). |
| **`schemaPath`** | The path to the field in the schema. Similar to `path`, but without dynamic indices. |
| **`isFieldAffectingData`** | A boolean value that represents if the field is affecting the data or not. |
| **`label`** | The label value provided in the field, it can be used with i18n. |
| **`labels`** | An object that contains the labels for the field. |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
| **`link`** | A boolean representing whether this cell should be wrapped in a link. |
| **`onClick`** | A function that is called when the cell is clicked. |
| **`dateDisplayFormat`** | If a [`date`](../fields/date) field, the `admin.dateDisplayFormat` property defined in the [Field Config](../fields/overview). |
| **`options`** | If a [`select`](../fields/select) field, this is an array of options defined in the [Field Config](../fields/overview). [More details](../fields/select). |
| **`relationTo`** | If a [`relationship`](../fields/relationship). or [`upload`](../fields/upload) field, this is the collection(s) the field is related to. |
| **`richTextComponentMap`** | If a [`richText`](../fields/rich-text) field, this is an object that maps the rich text components. [More details](../fields/rich-text). |
| **`blocks`** | If a [`blocks`](../fields/blocks) field, this is an array of labels and slugs representing the blocks defined in the [Field Config](../fields/overview). [More details](../fields/blocks). |
<Banner type="info">
<strong>Tip:</strong>
@@ -258,7 +305,7 @@ export const myField: Field = {
type: 'text',
admin: {
components: {
Label: MyCustomLabel, // highlight-line
Label: '/path/to/MyCustomLabelComponent', // highlight-line
},
},
}
@@ -266,19 +313,30 @@ export const myField: Field = {
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
All Label Components receive the following props:
Custom Label Components receive all [Field Component](#the-field-component) props, plus the following props:
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`label`** | Label value provided in field, it can be used with i18n. |
| **`required`** | The `admin.required` property defined in the [Field Config](../fields/overview). |
| **`schemaPath`** | The path to the field in the schema. Similar to `path`, but without dynamic indices. |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### TypeScript
When building Custom Label Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Label Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `LabelServerComponent` or `LabelClientComponent` to the type of field, i.e. `TextFieldLabelClientComponent`.
```tsx
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// ...and so on for each Field Type
} from 'payload'
```
### The Error Component
The Error Component is rendered when a field fails validation. It is typically displayed beneath the field input in a visually-compelling style.
@@ -293,7 +351,7 @@ export const myField: Field = {
type: 'text',
admin: {
components: {
Error: MyCustomError, // highlight-line
Error: '/path/to/MyCustomErrorComponent', // highlight-line
},
},
}
@@ -301,17 +359,30 @@ export const myField: Field = {
_For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components)._
All Error Components receive the following props:
Custom Error Components receive all [Field Component](#the-field-component) props, plus the following props:
| Property | Description |
| --------------- | ------------------------------------------------------------- |
| **`path`*** | The static path of the field at render time. [More details](./hooks#usefieldprops). |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### TypeScript
When building Custom Error Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Error Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `ErrorServerComponent` or `ErrorClientComponent` to the type of field, i.e. `TextFieldErrorClientComponent`.
```tsx
import type {
TextFieldErrorServerComponent,
TextFieldErrorClientComponent,
// And so on for each Field Type
} from 'payload'
```
### The Description Property
Field Descriptions are used to provide additional information to the editor about a field, such as special instructions. Their placement varies from field to field, but typically are displayed with subtle style differences beneath the field inputs.
@@ -385,7 +456,6 @@ To easily add a Description Component to a field, use the `admin.components.Desc
```ts
import type { SanitizedCollectionConfig } from 'payload'
import { MyCustomDescription } from './MyCustomDescription'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
@@ -396,7 +466,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
type: 'text',
admin: {
components: {
Description: MyCustomDescription, // highlight-line
Description: '/path/to/MyCustomDescriptionComponent', // highlight-line
}
}
}
@@ -406,17 +476,30 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
_For details on how to build a Custom Description, see [Building Custom Components](./components#building-custom-components)._
All Description Components receive the following props:
Custom Description Components receive all [Field Component](#the-field-component) props, plus the following props:
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`description`** | The `description` property defined in the [Field Config](../fields/overview). |
| **`field`** | In Server Components, this is the original Field Config. In Client Components, this is the sanitized Client Field Config. [More details](#the-field-prop). |
| **`clientField`** | Server components receive the Client Field Config through this prop. [More details](#the-field-prop). |
<Banner type="success">
<strong>Reminder:</strong>
All [Custom Server Components](./components) receive the `payload` and `i18n` properties by default. See [Building Custom Components](./components#building-custom-components) for more details.
</Banner>
#### TypeScript
When building Custom Description Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Description Component, one for every [Field Type](../fields/overview) and server/client environment. The convention is to append `DescriptionServerComponent` or `DescriptionClientComponent` to the type of field, i.e. `TextFieldDescriptionClientComponent`.
```tsx
import type {
TextFieldDescriptionServerComponent,
TextFieldDescriptionClientComponent,
// And so on for each Field Type
} from 'payload'
```
### afterInput and beforeInput
With these properties you can add multiple components _before_ and _after_ the input element, as their name suggests. This is useful when you need to render additional elements alongside the field without replacing the entire field component.
@@ -436,8 +519,8 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
admin: {
components: {
// highlight-start
beforeInput: [MyCustomComponent],
afterInput: [MyOtherCustomComponent],
beforeInput: ['/path/to/MyCustomComponent'],
afterInput: ['/path/to/MyOtherCustomComponent'],
// highlight-end
}
}

107
docs/admin/globals.mdx Normal file
View File

@@ -0,0 +1,107 @@
---
title: Global Admin Config
label: Globals
order: 30
desc:
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The behavior of [Globals](../configuration/globals) within the [Admin Panel](./overview) can be fully customized to fit the needs of your application. This includes grouping or hiding their navigation links, adding [Custom Components](./components), setting page metadata, and more.
To configure Admin Options for Globals, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
## Admin Options
The following options are available:
| Option | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](#components). |
| **`preview`** | Function to generate a preview URL within the Admin Panel for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Page metadata overrides to apply to this Global within the Admin Panel. [More details](./metadata). |
### Components
Globals can set their own [Custom Components](./components) which only apply to [Global](../configuration/globals)-specific UI within the [Admin Panel](./overview). This includes elements such as the Save Button, or entire layouts such as the Edit View.
To override Global Components, use the `admin.components` property in your [Global Config](../configuration/globals):
```ts
import type { SanitizedGlobalConfig } from 'payload'
export const MyGlobal: SanitizedGlobalConfig = {
// ...
admin: {
components: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Path | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| **`elements.SaveButton`** | Replace the default Save Button with a Custom Component. [Drafts](../versions/drafts) must be disabled. |
| **`elements.SaveDraftButton`** | Replace the default Save Draft Button with a Custom Component. [Drafts](../versions/drafts) must be enabled and autosave must be disabled. |
| **`elements.PublishButton`** | Replace the default Publish Button with a Custom Component. [Drafts](../versions/drafts) must be enabled. |
| **`elements.PreviewButton`** | Replace the default Preview Button with a Custom Component. [Preview](#preview) must be enabled. |
| **`views`** | Override or create new views within the Admin Panel. [More details](./views). |
<Banner type="success">
<strong>Note:</strong>
For details on how to build Custom Components, see [Building Custom Components](./components#building-custom-components).
</Banner>
### Preview
It is possible to display a Preview Button within the Edit View of the Admin Panel. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MainMenu: GlobalConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The Document being edited. |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Note:</strong>
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>

View File

@@ -1,7 +1,7 @@
---
title: React Hooks
label: React Hooks
order: 50
order: 70
desc: Make use of all of the powerful React hooks that Payload provides.
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -52,7 +52,7 @@ The `useField` hook accepts the following arguments:
The `useField` hook returns the following object:
```ts
type FieldResult<T> = {
type FieldType<T> = {
errorMessage?: string
errorPaths?: string[]
filterOptions?: FilterOptionsResult
@@ -65,7 +65,7 @@ type FieldResult<T> = {
readOnly?: boolean
rows?: Row[]
schemaPath: string
setValue: (val: unknown, disableModifyingForm?: boolean) => voi
setValue: (val: unknown, disableModifyingForm?: boolean) => void
showError: boolean
valid?: boolean
value: T
@@ -74,9 +74,9 @@ type FieldResult<T> = {
## useFieldProps
All [Custom Field Components](./fields#the-field-component) are rendered on the server, and as such, only have access to static props at render time. But, some fields can be dynamic, such as when nested in an [`array`](../fields/array) or [`blocks`](../fields/block) field. For example, items can be added, re-ordered, or deleted on-the-fly.
[Custom Field Components](./fields#the-field-component) can be rendered on the server. When using a server component as a custom field component, you can access dynamic props from within any client component rendered by your custom server component. This is done using the `useFieldProps` hook. This is important because some fields can be dynamic, such as when nested in an [`array`](../fields/array) or [`blocks`](../fields/block) field. For example, items can be added, re-ordered, or deleted on-the-fly.
For this reason, dynamic props like `path` are managed in their own React context, which can be accessed using the `useFieldProps` hook:
You can use the `useFieldProps` hooks to access dynamic props like `path`:
```tsx
'use client'
@@ -113,7 +113,7 @@ You can pass a Redux-like selector into the hook, which will ensure that you ret
```tsx
'use client'
import type { useFormFields } from '@payloadcms/ui'
import { useFormFields } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// Get only the `amount` field state, and only cause a rerender when that field changes
@@ -463,7 +463,7 @@ export const CustomArrayManager = () => {
name: "customArrayManager",
admin: {
components: {
Field: CustomArrayManager,
Field: '/path/to/CustomArrayManagerField',
},
},
},
@@ -560,7 +560,7 @@ export const CustomArrayManager = () => {
name: "customArrayManager",
admin: {
components: {
Field: CustomArrayManager,
Field: '/path/to/CustomArrayManagerField',
},
},
},
@@ -670,7 +670,7 @@ export const CustomArrayManager = () => {
name: "customArrayManager",
admin: {
components: {
Field: CustomArrayManager,
Field: '/path/to/CustomArrayManagerField',
},
},
},
@@ -818,7 +818,7 @@ import { useConfig } from '@payloadcms/ui'
const MyComponent: React.FC = () => {
// highlight-start
const config = useConfig()
const { config } = useConfig()
// highlight-end
return <span>{config.serverURL}</span>

View File

@@ -0,0 +1,79 @@
---
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.
keywords: locking, document locking, edit locking, document, concurrency, Payload, headless, Content Management System, cms, javascript, react, node, nextjs
---
Document locking in Payload ensures that only one user at a time can edit a document, preventing data conflicts and accidental overwrites. When a document is locked, other users are prevented from making changes until the lock is released, ensuring data integrity in collaborative environments.
The lock is automatically triggered when a user begins editing a document within the Admin Panel and remains in place until the user exits the editing view or the lock expires due to inactivity.
## 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:
- 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.
- 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.
<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>
### 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.
Heres an example configuration for document locking:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
slug: 'posts',
fields: [
{
name: 'title',
type: 'text',
},
// other fields...
],
lockDocuments: {
duration: 600, // Duration in seconds
},
}
```
#### Locking Options
| Option | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`lockDocuments`** | Enables or disables document locking for the collection or global. By default, document locking is enabled. Set to an object to configure, or set to false to disable locking. |
| **`duration`** | Specifies the duration (in seconds) for how long a document remains locked without user interaction. The default is 300 seconds (5 minutes). |
### 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.
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.
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`.
```ts
const result = await payload.update({
collection: 'posts',
id: '123',
data: {
title: 'New title',
},
overrideLock: false, // Enforces the document lock, preventing updates if the document is locked
})
```
This option is particularly useful in scenarios where administrative privileges or specific workflows require you to override the lock and ensure the operation is completed.

216
docs/admin/metadata.mdx Normal file
View File

@@ -0,0 +1,216 @@
---
title: Page Metadata
label: Metadata
order: 70
desc: Customize the metadata of your pages within the Admin Panel
keywords: admin, components, custom, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Every page within the Admin Panel automatically receives dynamic, auto-generated metadata derived from live document data, the user's current locale, and more, without any additional configuration. This includes the page title, description, og:image and everything in between. Metadata is fully configurable at the root level and cascades down to individual collections, documents, and custom views, allowing for the ability to control metadata on any page with high precision.
Within the Admin Panel, metadata can be customized at the following levels:
- [Root Metadata](#root-metadata)
- [Collection Metadata](#collection-metadata)
- [Global Metadata](#global-metadata)
- [View Metadata](#view-metadata)
All of these types of metadata share a similar structure, with a few key differences on the Root level. To customize metadata, consult the list of available scopes. Determine the scope that corresponds to what you are trying to accomplish, then author your metadata within the Payload Config accordingly.
## Root Metadata
Root Metadata is the metadata that is applied to all pages within the Admin Panel. This is where you can control things like the suffix appended onto each page's title, the favicon displayed in the browser's tab, and the Open Graph data that is used when sharing the Admin Panel on social media.
To customize Root Metadata, use the `admin.meta` key in your Payload Config:
```ts
{
// ...
admin: {
// highlight-start
meta: {
// highlight-end
title: 'My Admin Panel',
description: 'The best admin panel in the world',
icons: [
{
rel: 'icon',
type: 'image/png',
href: '/favicon.png',
},
],
},
},
}
```
The following options are available for Root Metadata:
| Key | Type | Description |
| --- | --- | --- |
| **`title`** | `string` | The title of the Admin Panel. |
| **`description`** | `string` | The description of the Admin Panel. |
| **`defaultOGImageType`** | `dynamic` (default), `static`, or `off` | The type of default OG image to use. If set to `dynamic`, Payload will use Next.js image generation to create an image with the title of the page. If set to `static`, Payload will use the `defaultOGImage` URL. If set to `off`, Payload will not generate an OG image. |
| **`icons`** | `IconConfig[]` | An array of icon objects. [More details](#icons) |
| **`keywords`** | `string` | A comma-separated list of keywords to include in the metadata of the Admin Panel. |
| **`openGraph`** | `OpenGraphConfig` | An object containing Open Graph metadata. [More details](#open-graph) |
| **`titleSuffix`** | `string` | A suffix to append to the end of the title of every page. Defaults to "- Payload". |
<Banner type="success">
<strong>Reminder:</strong>
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Metadata](./collections), [Global Metadata](./globals), and [Document Metadata](./documents) in their respective configs.
</Banner>
### Icons
The Icons Config corresponds to the `<link>` tags that are used to specify icons for the Admin Panel. The `icons` key is an array of objects, each of which represents an individual icon. Icons are differentiated from one another by their `rel` attribute, which specifies the relationship between the document and the icon.
The most common icon type is the favicon, which is displayed in the browser tab. This is specified by the `rel` attribute `icon`. Other common icon types include `apple-touch-icon`, which is used by Apple devices when the Admin Panel is saved to the home screen, and `mask-icon`, which is used by Safari to mask the Admin Panel icon.
To customize icons, use the `icons` key within the `admin.meta` object in your Payload Config:
```ts
{
// ...
admin: {
meta: {
// highlight-start
icons: [
// highlight-end
{
rel: 'icon',
type: 'image/png',
href: '/favicon.png',
},
{
rel: 'apple-touch-icon',
type: 'image/png',
href: '/apple-touch-icon.png',
},
],
},
},
}
```
The following options are available for Icons:
| Key | Type | Description |
| --- | --- | --- |
| **`rel`** | `string` | The HTML `rel` attribute of the icon. |
| **`type`** | `string` | The MIME type of the icon. |
| **`color`** | `string` | The color of the icon. |
| **`fetchPriority`** | `string` | The [fetch priority](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/fetchPriority) of the icon. |
| **`media`** | `string` | The [media query](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_media_queries/Using_media_queries) of the icon. |
| **`sizes`** | `string` | The [sizes](https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/sizes) of the icon. |
| **`url`** | `string` | The URL pointing the resource of the icon. |
### Open Graph
Open Graph metadata is a set of tags that are used to control how URLs are displayed when shared on social media platforms. Open Graph metadata is automatically generated by Payload, but can be customized at the Root level.
To customize Open Graph metadata, use the `openGraph` key within the `admin.meta` object in your Payload Config:
```ts
{
// ...
admin: {
meta: {
// highlight-start
openGraph: {
// highlight-end
description: 'The best admin panel in the world',
images: [
{
url: 'https://example.com/image.jpg',
width: 800,
height: 600,
},
],
siteName: 'Payload',
title: 'My Admin Panel',
},
},
},
}
```
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. |
| **`siteName`** | `string` | The name of the site. |
| **`title`** | `string` | The title of the Admin Panel. |
## Collection Metadata
Collection Metadata is the metadata that is applied to all pages within any given Collection within the Admin Panel. This metadata is used to customize the title and description of all views within any given Collection, unless overridden by the view itself.
To customize Collection Metadata, use the `admin.meta` key within your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const MyCollection: CollectionConfig = {
// ...
admin: {
// highlight-start
meta: {
// highlight-end
title: 'My Collection',
description: 'The best collection in the world',
},
},
}
```
The Collection Meta config has the same options as the [Root Metadata](#root-metadata) config.
## Global Metadata
Global Metadata is the metadata that is applied to all pages within any given Global within the Admin Panel. This metadata is used to customize the title and description of all views within any given Global, unless overridden by the view itself.
To customize Global Metadata, use the `admin.meta` key within your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MyGlobal: GlobalConfig = {
// ...
admin: {
// highlight-start
meta: {
// highlight-end
title: 'My Global',
description: 'The best
},
},
}
```
The Global Meta config has the same options as the [Root Metadata](#root-metadata) config.
## View Metadata
View Metadata is the metadata that is applied to specific [Views](./views) within the Admin Panel. This metadata is used to customize the title and description of a specific view, overriding any metadata set at the [Root](#root-metadata), [Collection](#collection-metadata), or [Global](#global-metadata) level.
To customize View Metadata, use the `meta` key within your View Config:
```ts
{
// ...
admin: {
views: {
dashboard: {
// highlight-start
meta: {
// highlight-end
title: 'My Dashboard',
description: 'The best dashboard in the world',
}
},
},
},
}

View File

@@ -6,7 +6,7 @@ desc: Manage your data and customize the Payload Admin Panel by swapping in your
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) admin panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more.
Payload dynamically generates a beautiful, [fully type-safe](../typescript/overview) Admin Panel to manage your users and data. It is highly performant, even with 100+ fields, and is translated in over 30 languages. Within the Admin Panel you can manage content, [render your site](../live-preview/overview), preview drafts, [diff versions](../versions/overview), and so much more.
The Admin Panel is designed to [white-label your brand](https://payloadcms.com/blog/white-label-admin-ui). You can endlessly customize and extend the Admin UI by swapping in your own [Custom Components](./components)—everything from simple field labels to entire views can be modified or replaced to perfectly tailor the interface for your editors.
@@ -55,6 +55,11 @@ As shown above, all Payload routes are nested within the `(payload)` route group
The `admin` directory contains all the _pages_ related to the interface itself, whereas the `api` and `graphql` directories contains all the _routes_ related to the [REST API](../rest-api/overview) and [GraphQL API](../graphql/overview). All admin routes are [easily configurable](#customizing-routes) to meet your application's exact requirements.
<Banner type="warning">
<strong>Note:</strong>
If you don't use the [REST API](../rest/overview) or [GraphQL API](../graphql/overview), you can delete the [Next.js files corresponding to those routes](../admin/overview#project-structure), however, the overhead of this API is completely constrained to these endpoints, and will not slow down or affect Payload outside of the endpoints.
</Banner>
Finally, the `custom.scss` file is where you can add or override globally-oriented styles in the Admin Panel, such as modify the color palette. Customizing the look and feel through CSS alone is a powerful feature of the Admin Panel, [more on that here](./customizing-css).
All auto-generated files will contain the following comments at the top of each file:
@@ -81,23 +86,24 @@ const config = buildConfig({
The following options are available:
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `user` | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
| `buildPath` | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| `meta` | Base metadata to use for the Admin Panel. Included properties are `titleSuffix`, `icons`, and `openGraph`. Can be overridden on a per Collection or per Global basis. |
| `disable` | If set to `true`, the entire Admin Panel will be disabled. |
| `dateFormat` | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More details](../authentication/config). |
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| `components` | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| `routes` | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| `custom` | Any custom properties you wish to pass to the Admin Panel. |
| Option | Description |
|---------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`avatar`** | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
| **`autoLogin`** | Used to automate log-in for dev and demonstration convenience. [More details](../authentication/overview). |
| **`buildPath`** | Specify an absolute path for where to store the built Admin bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
| **`components`** | Component overrides that affect the entirety of the Admin Panel. [More details](./components). |
| **`custom`** | Any custom properties you wish to pass to the Admin Panel. |
| **`dateFormat`** | The date format that will be used for all dates within the Admin Panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
| **`disable`** | If set to `true`, the entire Admin Panel will be disabled. |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`meta`** | Base metadata to use for the Admin Panel. [More details](./metadata). |
| **`routes`** | Replace built-in Admin Panel routes with your own custom routes. [More details](#customizing-routes). |
| **`theme`** | Restrict the Admin Panel theme to use only one of your choice. Default is `all`.
| **`user`** | The `slug` of the Collection that you want to allow to login to the Admin Panel. [More details](#the-admin-user-collection). |
<Banner type="success">
<strong>Reminder:</strong>
These are the _root-level_ options for the Admin Panel. You can also customize the admin options for _Collections and Globals_ through their respective `admin` keys.
These are the _root-level_ options for the Admin Panel. You can also customize [Collection Admin Options](./collections) and [Global Admin Options](./globals) through their respective `admin` keys.
</Banner>
### The Admin User Collection
@@ -132,7 +138,7 @@ To do this, specify `admin: { user: 'admins' }` in your config. This will provid
### Role-based Access Control
It is also possible to allow multiple user types into the Admin Panel with limited permissions. For example, you may wish to have two roles within the `admins` Collection:
It is also possible to allow multiple user types into the Admin Panel with limited permissions, known as role-based access control (RBAC). For example, you may wish to have two roles within the `admins` Collection:
- `super-admin` - full access to the Admin Panel to perform any action
- `editor` - limited access to the Admin Panel to only manage content
@@ -162,21 +168,34 @@ const config = buildConfig({
The following options are available:
| Option | Default route | Description |
| ------------------ | ----------------------- | ------------------------------------- |
| `admin` | `/admin` | The Admin Panel itself. |
| `api` | `/api` | The [REST API](../rest-api/overview) base path. |
| `graphQL` | `/graphql` | The [GraphQL API](../graphql/overview) base path. |
| `graphQLPlayground`| `/graphql-playground` | The GraphQL Playground. |
<Banner type="warning">
<strong>Warning:</strong>
Changing Root-level Routes _after_ your project was generated will also require you to manually update the corresponding directories in your project. For example, changing `routes.admin` will require you to rename the `(payload)/admin` directory in your project to match the new route. [More details](#project-structure).
</Banner>
| Option | Default route | Description |
|---------------------|-----------------------|---------------------------------------------------|
| `admin` | `/admin` | The Admin Panel itself. |
| `api` | `/api` | The [REST API](../rest-api/overview) base path. |
| `graphQL` | `/graphql` | The [GraphQL API](../graphql/overview) base path. |
| `graphQLPlayground` | `/graphql-playground` | The GraphQL Playground. |
<Banner type="success">
<strong>Tip:</strong>
You can easily add _new_ routes to the Admin Panel through the `endpoints` property of the Payload Config. See [Custom Endpoints](../rest-api/overview#custom-endpoints) for more information.
You can easily add _new_ routes to the Admin Panel through [Custom Endpoints](../rest-api/overview#custom-endpoints) and [Custom Views](./views).
</Banner>
#### Customizing Root-level Routes
You can change the Root-level Routes as needed, such as to mount the Admin Panel at the root of your application.
Changing Root-level Routes also requires a change to [Project Structure](#project-structure) to match the new route. For example, if you set `routes.admin` to `/`, you would need to completely remove the `admin` directory from the project structure:
```plaintext
app/
├─ (payload)/
├── [[...segments]]/
├──── ...
```
<Banner type="warning">
<strong>Note:</strong>
If you set Root-level Routes _before_ auto-generating the Admin Panel, your [Project Structure](#project-structure) will already be set up correctly.
</Banner>
### Admin-level Routes

View File

@@ -1,7 +1,7 @@
---
title: Managing User Preferences
label: Preferences
order: 50
order: 70
desc: Store the preferences of your users as they interact with the Admin Panel.
keywords: admin, preferences, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
@@ -22,7 +22,7 @@ Out of the box, Payload handles the persistence of your users' preferences in a
that is reading or setting a preference via all provided authentication methods.
</Banner>
## Use cases
## Use Cases
This API is used significantly for internal operations of the Admin Panel, as mentioned above. But, if you're building your own React components for use in the Admin Panel, you can allow users to set their own preferences in correspondence to their usage of your components. For example:

View File

@@ -1,14 +1,14 @@
---
title: Customizing Views
label: Customizing Views
order: 30
order: 50
desc:
keywords:
---
Views are the individual pages that make up the [Admin Panel](./overview), such as the Dashboard, List, and Edit views. One of the most powerful ways to customize the Admin Panel is to create Custom Views. These are [Custom Components](./components) that can either replace built-in views or can be entirely new.
Within the Admin Panel, there are four types of views:
There are four types of views within the Admin Panel:
- [Root Views](#root-views)
- [Collection Views](#collection-views)
@@ -31,31 +31,70 @@ const config = buildConfig({
admin: {
components: {
views: {
Dashboard: MyCustomDashboardView, // highlight-line
customView: {
Component: '/path/to/MyCustomView#MyCustomView', // highlight-line
path: '/my-custom-view',
}
},
},
},
})
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
Your Custom Root Views can optionally use one of the templates that Payload provides. The most common of these is the Default Template which provides the basic layout and navigation. Here is an example of what that might look like:
```tsx
import type { AdminViewProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const MyCustomView: React.FC<AdminViewProps> = ({
initPageResult,
params,
searchParams,
}) => {
return (
<DefaultTemplate
i18n={initPageResult.req.i18n}
locale={initPageResult.locale}
params={params}
payload={initPageResult.req.payload}
permissions={initPageResult.permissions}
searchParams={searchParams}
user={initPageResult.req.user || undefined}
visibleEntities={initPageResult.visibleEntities}
>
<Gutter>
<h1>Custom Default Root View</h1>
<br />
<p>This view uses the Default Template.</p>
</Gutter>
</DefaultTemplate>
)
}
```
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
The following options are available:
| Property | Description |
| --------------- | ----------------------------------------------------------------------------- |
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
| **`Dashboard`** | The main landing page of the [Admin Panel](./overview). |
| **`account`** | The Account view is used to show the currently logged in user's Account page. |
| **`dashboard`** | The main landing page of the [Admin Panel](./overview). |
For more granular control, pass a configuration object instead. Payload exposes the following properties for each view:
| Property | Description |
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **`Component`** \* | Pass in the component that should be rendered when a user navigates to this route. |
| **`Component`** \* | Pass in the component path that should be rendered when a user navigates to this route. |
| **`path`** \* | Any valid URL path or array of paths that [`path-to-regexp`](https://www.npmjs.com/package/path-to-regex) understands. |
| **`exact`** | Boolean. When true, will only match if the path matches the `usePathname()` exactly. |
| **`strict`** | When true, a path that has a trailing slash will only match a `location.pathname` with a trailing slash. This has no effect when there are additional URL segments in the pathname. |
| **`sensitive`** | When true, will match if the path is case sensitive. |
| **`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._
@@ -72,9 +111,9 @@ const config = buildConfig({
components: {
views: {
// highlight-start
MyCustomView: {
myCustomView: {
// highlight-end
Component: MyCustomView,
Component: '/path/to/MyCustomView#MyCustomViewComponent',
path: '/my-custom-view',
},
},
@@ -108,26 +147,41 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
admin: {
components: {
views: {
Edit: MyCustomEditView, // highlight-line
edit: {
root: {
Component: '/path/to/MyCustomEditView', // highlight-line
}
// other options include:
// default
// versions
// version
// api
// livePreview
// [key: string]
// See "Document Views" for more details
},
list: {
Component: '/path/to/MyCustomListView',
}
},
},
},
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
The `Edit` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `Edit.Default` key instead.
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
The following options are available:
| Property | Description |
| ---------- | ----------------------------------------------------------------------------------------------------------------- |
| **`Edit`** | The Edit View is used to edit a single document for any given Collection. [More details](#document-views). |
| **`List`** | The List View is used to show a list of documents for any given Collection. |
| **`edit`** | The Edit View is used to edit a single document for any given Collection. [More details](#document-views). |
| **`list`** | The List View is used to show a list of documents for any given Collection. |
<Banner type="success">
<strong>Note:</strong>
@@ -148,25 +202,36 @@ export const MyGlobalConfig: SanitizedGlobalConfig = {
admin: {
components: {
views: {
Edit: MyCustomEditView, // highlight-line
edit: {
root: {
Component: '/path/to/MyCustomEditView', // highlight-line
}
// other options include:
// default
// versions
// version
// api
// livePreview
// [key: string]
},
},
},
},
})
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
The `Edit` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `Edit.Default` key instead.
The `root` property will replace the _entire_ Edit View, including the title, tabs, etc., _as well as all nested [Document Views](#document-views)_, such as the API, Live Preview, and Version views. To replace only the Edit View precisely, use the `edit.default` key instead.
</Banner>
The following options are available:
| Property | Description |
| ---------- | ------------------------------------------------------------------- |
| **`Edit`** | The Edit View is used to edit a single document for any given Global. [More details](#document-views). |
| **`edit`** | The Edit View is used to edit a single document for any given Global. [More details](#document-views). |
<Banner type="success">
<strong>Note:</strong>
@@ -187,37 +252,38 @@ export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
admin: {
components: {
views: {
Edit: {
API: {
Component: MyCustomAPIView, // highlight-line
edit: {
api: {
Component: '/path/to/MyCustomAPIViewComponent', // highlight-line
},
},
},
},
},
})
}
```
_For details on how to build Custom Views, see [Building Custom Views](#building-custom-views)._
_For details on how to build Custom Views, including all available props, see [Building Custom Views](#building-custom-views)._
<Banner type="warning">
<strong>Note:</strong>
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `Edit` key itself. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
If you need to replace the _entire_ Edit View, including _all_ nested Document Views, use the `root` key. See [Custom Collection Views](#collection-views) or [Custom Global Views](#global-views) for more information.
</Banner>
The following options are available:
| Property | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
| **`Default`** | The Default view is the primary view in which your document is edited. |
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions). |
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview). |
| **`root`** | The Root View overrides all other nested views and routes. No document controls or tabs are rendered when this key is set. |
| **`default`** | The Default View is the primary view in which your document is edited. It is rendered within the "Edit" tab. |
| **`versions`** | The Versions View is used to navigate the version history of a single document. It is rendered within the "Versions" tab. [More details](../versions). |
| **`version`** | The Version View is used to edit a single version of a document. It is rendered within the "Version" tab. [More details](../versions). |
| **`api`** | The API View is used to display the REST API JSON response for a given document. It is rendered within the "API" tab. |
| **`livePreview`** | The LivePreview view is used to display the Live Preview interface. It is rendered within the "Live Preview" tab. [More details](../live-preview). |
### Document Tabs
Each Document View can be given a new tab in the Edit View, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way. To add or customize tabs in the Edit View, use the `Component.Tab` key:
Each Document View can be given a new tab in the Edit View, if desired. Tabs are highly configurable, from as simple as changing the label to swapping out the entire component, they can be modified in any way. To add or customize tabs in the Edit View, use the `tab` key:
```ts
import type { SanitizedCollectionConfig } from 'payload'
@@ -227,17 +293,19 @@ export const MyCollection: SanitizedCollectionConfig = {
admin: {
components: {
views: {
Edit: {
MyCustomTab: {
Component: MyCustomTab,
edit: {
myCustomTab: {
Component: '/path/to/MyCustomTab',
path: '/my-custom-tab',
Tab: MyCustomTab // highlight-line
tab: {
Component: '/path/to/MyCustomTabComponent' // highlight-line
}
},
AnotherCustomView: {
Component: AnotherCustomView,
anotherCustomTab: {
Component: '/path/to/AnotherCustomView',
path: '/another-custom-view',
// highlight-start
Tab: {
tab: {
label: 'Another Custom View',
href: '/another-custom-view',
}
@@ -261,14 +329,15 @@ Custom Views are just [Custom Components](./components) rendered at the page-lev
```ts
import type { SanitizedCollectionConfig } from 'payload'
import { MyCustomView } from './MyCustomView'
export const MyCollectionConfig: SanitizedCollectionConfig = {
// ...
admin: {
components: {
views: {
Edit: MyCustomView, // highlight-line
edit: {
Component: '/path/to/MyCustomView' // highlight-line
}
},
},
},
@@ -278,14 +347,12 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
Your Custom Views will be provided with the following props:
| Prop | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- | |
| **`user`** | The currently logged in user. |
| **`locale`** | The current [Locale](../configuration/localization) of the [Admin Panel](./overview). |
| **`navGroups`** | The grouped navigation items according to `admin.group` in your [Collection Config](../collections/overview) or [Global Config](../globals/overview). |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`permissions`** | The permissions of the currently logged in user. |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
| **`visibleEntities`** | The current user's visible entities according to your [Access Control](../access-control/overview). |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`initPageResult`** | An object containing `req`, `payload`, `permissions`, etc. |
| **`clientConfig`** | The Client Config object. [More details](../components#accessing-the-payload-config). |
| **`importMap`** | The import map object. |
| **`params`** | An object containing the [Dynamic Route Parameters](https://nextjs.org/docs/app/building-your-application/routing/dynamic-routes). |
| **`searchParams`** | An object containing the [Search Parameters](https://developer.mozilla.org/docs/Learn/Common_questions/What_is_a_URL#parameters). |
<Banner type="success">
<strong>Reminder:</strong>

View File

@@ -48,7 +48,7 @@ your API keys will not be.
### HTTP Authentication
To authenticate REST or GraphQL API requests using an API key, set the `Authorization` header. The header is case-sensitive and needs the slug of the `auth.useAPIKey` enabled collection, then " API-Key ", followed by the `apiKey` that has been assigned. Payload's built-in middleware will then assign the user document to `req.user` and handle requests with the proper access control. By doing this, Payload recognizes the request being made as a request by the user associated with that API key.
To authenticate REST or GraphQL API requests using an API key, set the `Authorization` header. The header is case-sensitive and needs the slug of the `auth.useAPIKey` enabled collection, then " API-Key ", followed by the `apiKey` that has been assigned. Payload's built-in middleware will then assign the user document to `req.user` and handle requests with the proper [Access Control](../access-control/overview). By doing this, Payload recognizes the request being made as a request by the user associated with that API key.
**For example, using Fetch:**
@@ -62,7 +62,7 @@ const response = await fetch('http://localhost:3000/api/pages', {
})
```
Payload ensures that the same, uniform access control is used across all authentication strategies. This enables you to utilize your existing access control configurations with both API keys and the standard email/password authentication. This consistency can aid in maintaining granular control over your API keys.
Payload ensures that the same, uniform [Access Control](../access-control/overview) is used across all authentication strategies. This enables you to utilize your existing Access Control configurations with both API keys and the standard email/password authentication. This consistency can aid in maintaining granular control over your API keys.
### API Key Only Auth

View File

@@ -1,206 +0,0 @@
---
title: Authentication Config
label: Config
order: 20
desc: Enable and customize options in the Authentication config for features including Forgot Password, Login Attempts, API key usage and more.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload's Authentication is extremely powerful and gives you everything you need when you go to build a new app or site in a secure and responsible manner.
To enable Authentication on a collection, define an `auth` property and set it to either `true` or to an object containing the options below.
## Options
| Option | Description |
|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More](/docs/authentication/config#api-keys) |
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
| **`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. |
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
| **`depth`** | How many levels deep a `user` document should be populated when creating the JWT and binding the `user` to the `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
| **`cookies`** | Set cookie options, including `secure`, `sameSite`, and `domain`. For advanced users. |
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More](/docs/authentication/config#forgot-password) |
| **`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](/docs/authentication/config#email-verification) |
| **`disableLocalStrategy`** | Advanced - disable Payload's built-in local auth strategy. Only use this property if you have replaced Payload's auth mechanisms with your own. |
| **`strategies`** | Advanced - an array of custom authentification strategies to extend this collection's authentication with. [More](/docs/authentication/custom-strategies) |
### Forgot Password
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
**`generateEmailHTML`**
Function that accepts one argument, containing `{ req, token, user }`, that 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.
<Banner type="success">
<strong>Tip:</strong>
<br />
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are
free to choose your own.
</Banner>
Example:
```ts
import { CollectionConfig } from 'payload/types'
export const Customers: CollectionConfig = {
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to reset their password
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`
return `
<!doctype html>
<html>
<body>
<h1>Here is my custom email template!</h1>
<p>Hello, ${user.email}!</p>
<p>Click below to reset your password.</p>
<p>
<a href="${resetPasswordURL}">${resetPasswordURL}</a>
</p>
</body>
</html>
`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
you. Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
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.
Example:
```ts
{
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
### Email Verification
If you'd like to require email verification before a user can successfully log in, you can enable it by passing `true` or an `options` object to `auth.verify`. The following options are available:
**`generateEmailHTML`**
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.
Example:
```ts
import { CollectionConfig } from 'payload/types'
export const Customers: CollectionConfig = {
slug: 'customers',
auth: {
verify: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to verify their account
const url = `https://yourfrontend.com/verify?token=${token}`
return `Hey ${user.email}, verify your email by clicking here: ${url}`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
<br />
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
Above, it was passed via query parameter.
</Banner>
**`generateEmailSubject`**
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.
Example:
```ts
{
slug: 'customers',
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
### Admin autologin
For testing and demo purposes you may want to skip forcing the admin user to login in order to access the panel.
The `admin.autologin` property is used to configure the how visitors are handled when accessing the admin panel.
The default is that all users will have to login and this should not be enabled for environments where data needs to protected.
#### autoLogin Options
| Option | Description |
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
The recommended way to use this feature is behind an environment variable to ensure it is disabled when in production.
**Example:**
```ts
export default buildConfig({
admin: {
user: 'users',
// highlight-start
autoLogin:
process.env.PAYLOAD_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
},
collections: [
/** */
],
})
```

View File

@@ -1,19 +1,16 @@
---
title: Cookie Strategy
label: Cookie Strategy
order: 30
order: 40
desc: Enable HTTP Cookie based authentication to interface with Payload.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload `login`, `logout`, and `refresh` operations make use of HTTP-only cookies for authentication purposes.
Payload offers the ability to [Authenticate](./overview) via HTTP-only cookies. These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
<br />
You can access the logged-in user from access control functions and hooks from the `req.user` property.
<br />
[Learn more about token data](/docs/authentication/token-data).
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
### Automatic browser inclusion
@@ -38,7 +35,6 @@ For more about including cookies in requests from your app to your Payload API,
<Banner type="success">
<strong>Tip:</strong>
<br />
To make sure you have a Payload cookie set properly in your browser after logging in, you can use
the browsers Developer Tools > Application > Cookies > [your-domain-here]. The Developer tools
will still show HTTP-only cookies.
@@ -65,7 +61,7 @@ In this scenario, if your cookie was still valid, malicious-intent.com would be
### CSRF Prevention
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload config to do this:
Define domains that your trust and are willing to accept Payload HTTP-only cookie based requests from. Use the `csrf` option on the base Payload Config to do this:
```ts
// payload.config.ts
@@ -89,3 +85,47 @@ const config = buildConfig({
export default config
```
#### Cross domain authentication
If your frontend is on a different domain than your Payload API then you will not be able to use HTTP-only cookies for authentication by default as they will be considered third-party cookies by the browser.
There are a few strategies to get around this:
##### 1. Use subdomains
Cookies can cross subdomains without being considered third party cookies, for example if your API is at api.example.com then you can authenticate from example.com.
##### 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:
```
SameSite: None // allows the cookie to cross domains
Secure: true // ensures its sent over HTTPS only
HttpOnly: true // ensures its not accessible via client side JavaScript
```
Configuration example:
```ts
{
slug: 'users',
auth: {
cookies: {
sameSite: 'None',
secure: true,
}
},
fields: [
// your auth fields here
]
},
```
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.
<Banner type="success">
<strong>Good to know:</strong>
Setting up <code>secure: true</code> will not work if you're developing on <code>http://localhost</code> or any non-https domain. For local development you should conditionally set this to <code>false</code> based on the environment.
</Banner>

View File

@@ -13,7 +13,7 @@ keywords: authentication, config, configuration, overview, documentation, Conten
### Creating a strategy
At the core, a strategy is a way to authenticate a user making a request. As of `3.0` we moved away from passportJS in favor of pulling back the curtain and putting you in full control.
At the core, a strategy is a way to authenticate a user making a request. As of `3.0` we moved away from [Passport](https://www.passportjs.org) in favor of pulling back the curtain and putting you in full control.
A strategy is made up of the following:

View File

@@ -0,0 +1,203 @@
---
title: Authentication Emails
label: Email Verification
order: 30
desc: Email Verification allows users to verify their email address before they're account is fully activated. Email Verification ties directly into the Email functionality that Payload provides.
keywords: authentication, email, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
[Authentication](./overview) ties directly into the [Email](../email) functionality that Payload provides. This allows you to send emails to users for verification, password resets, and more. While Payload provides default email templates for these actions, you can customize them to fit your brand.
## Email Verification
Email Verification forces users to prove they have access to the email address they can authenticate. This will help to reduce spam accounts and ensure that users are who they say they are.
To enable Email Verification, use the `auth.verify` property on your [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: true // highlight-line
},
}
```
<Banner type="info">
<strong>Tip:</strong>
Verification emails are fully customizable. [More details](#generateEmailHTML).
</Banner>
The following options are available:
| Option | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users indicating how to validate their account. [More details](#generateEmailHTML). |
| **`generateEmailSubject`** | Allows for overriding the subject of the email that is sent to users indicating how to validate their account. [More details](#generateEmailSubject). |
#### generateEmailHTML
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'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to verify their account
const url = `https://yourfrontend.com/verify?token=${token}`
return `Hey ${user.email}, verify your email by clicking here: ${url}`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
If you specify a different URL to send your users to for email verification, such as a page on the
frontend of your app or similar, you need to handle making the call to the Payload REST or GraphQL
verification operation yourself on your frontend, using the token that was provided for you.
Above, it was passed via query parameter.
</Banner>
#### generateEmailSubject
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'
export const Customers: CollectionConfig = {
// ...
auth: {
verify: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
## Forgot Password
You can customize how the Forgot Password workflow operates with the following options on the `auth.forgotPassword` property:
```ts
import { CollectionConfig } from 'payload'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: { // highlight-line
// ...
},
},
}
```
The following options are available:
| Option | Description |
|----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`generateEmailHTML`** | Allows for overriding the HTML within emails that are sent to users attempting to reset their password. [More details](#generateEmailHTML). |
| **`generateEmailSubject`** | Allows for overriding the subject of the email that is sent to users attempting to reset their password. [More details](#generateEmailSubject). |
#### generateEmailHTML
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'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: {
// highlight-start
generateEmailHTML: ({ req, token, user }) => {
// Use the token provided to allow your user to reset their password
const resetPasswordURL = `https://yourfrontend.com/reset-password?token=${token}`
return `
<!doctype html>
<html>
<body>
<h1>Here is my custom email template!</h1>
<p>Hello, ${user.email}!</p>
<p>Click below to reset your password.</p>
<p>
<a href="${resetPasswordURL}">${resetPasswordURL}</a>
</p>
</body>
</html>
`
},
// highlight-end
},
},
}
```
<Banner type="warning">
<strong>Important:</strong>
If you specify a different URL to send your users to for resetting their password, such as a page
on the frontend of your app or similar, you need to handle making the call to the Payload REST or
GraphQL reset-password operation yourself on your frontend, using the token that was provided for
you. Above, it was passed via query parameter.
</Banner>
<Banner type="success">
<strong>Tip:</strong>
HTML templating can be used to create custom email templates, inline CSS automatically, and more.
You can make a reusable function that standardizes all email sent from Payload, which makes
sending custom emails more DRY. Payload doesn't ship with an HTML templating engine, so you are
free to choose your own.
</Banner>
The following arguments are passed to the `generateEmailHTML` function:
| Argument | Description |
|----------|-----------------------------------------------------------------------------------------------|
| `req` | The request object. |
| `token` | The token that is generated for the user to reset their password. |
| `user` | The user document that is attempting to reset their password. |
#### generateEmailSubject
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'
export const Customers: CollectionConfig = {
// ...
auth: {
forgotPassword: {
// highlight-start
generateEmailSubject: ({ req, user }) => {
return `Hey ${user.email}, reset your password!`;
}
// highlight-end
}
}
}
```
The following arguments are passed to the `generateEmailSubject` function:
| Argument | Description |
|----------|-----------------------------------------------------------------------------------------------|
| `req` | The request object. |
| `user` | The user document that is attempting to reset their password. |

View File

@@ -6,14 +6,11 @@ desc: Enable JSON Web Token based authentication to interface with Payload.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload offers the ability to authenticate via `JWT` (JSON web token). These can be read from the responses of `login`, `refresh`, and `me` auth operations.
Payload offers the ability to [Authenticate](./overview) via JSON Web Tokens (JWT). These can be read from the responses of `login`, `logout`, `refresh`, and `me` auth operations.
<Banner type="success">
<strong>Tip:</strong>
<br />
You can access the logged-in user from access control functions and hooks from the `req.user` property.
<br />
[Learn more about token data](/docs/authentication/token-data).
You can access the logged-in user from within [Access Control](../access-control/overview) and [Hooks](../hooks/overview) through the `req.user` argument. [More details](./token-data).
</Banner>
### Identifying Users Via The Authorization Header

View File

@@ -1,16 +1,16 @@
---
title: Authentication Operations
label: Operations
order: 80
order: 20
desc: Enabling Authentication automatically makes key operations available such as Login, Logout, Verify, Unlock, Reset Password and more.
keywords: authentication, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Enabling Authentication on a Collection automatically exposes additional auth-based operations in the Local, REST, and GraphQL APIs.
Enabling [Authentication](./overview) on a [Collection](../configuration/collections) automatically exposes additional auth-based operations in the [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview).
## Access
The Access operation returns what a logged in user can and can't do with the collections and globals that are registered via your config. This data can be immensely helpful if your app needs to show and hide certain features based on access control, as the [Admin Panel](../admin/overview) does.
The Access operation returns what a logged in user can and can't do with the collections and globals that are registered via your config. This data can be immensely helpful if your app needs to show and hide certain features based on [Access Control](../access-control/overview), just as the [Admin Panel](../admin/overview) does.
**REST API endpoint**:
@@ -308,7 +308,7 @@ Payload comes with built-in forgot password functionality. Submitting an email a
The link to reset the user's password contains a token which is what allows the user to securely reset their password.
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/config#forgot-password).
By default, the Forgot Password operations send users to the [Admin Panel](../admin/overview) to reset their password, but you can customize the generated email to send users to the frontend of your app instead by [overriding the email HTML](/docs/authentication/overview#forgot-password).
**Example REST API Forgot Password**:

View File

@@ -11,38 +11,47 @@ keywords: authentication, config, configuration, overview, documentation, Conten
title="Simplified Authentication for Headless CMS: Unlocking Reusability in One Line"
/>
<Banner>
Payload provides for highly secure and customizable user Authentication out of the box, which
allows for users to identify themselves to Payload.
</Banner>
Authentication is a critical part of any application. Payload provides a secure, portable way to manage user accounts out of the box. Payload Authentication is designed to be used in both the [Admin Panel](../admin/overview), all well as your own external applications, completely eliminating the need for paid, third-party platforms and services.
Authentication is used within the [Admin Panel](../admin/overview) itself as well as throughout your app(s) themselves however you determine necessary.
Here are some common use cases of Authentication in your own applications:
![Authentication admin panel functionality](https://payloadcms.com/images/docs/auth-admin.jpg)
_Admin Panel screenshot depicting an Admins Collection with Auth enabled_
- Customer accounts for an e-commerce app
- User accounts for a SaaS product
- P2P apps or social sites where users need to log in and manage their profiles
- Online games where players need to track their progress over time
**Here are some common use cases of Authentication outside of Payload's dashboard itself:**
When Authentication is enabled on a [Collection](../configuration/collections), Payload injects all necessary functionality to support the entire user flow. This includes all [auth-related operations](./operations) like account creation, logging in and out, and resetting passwords, all [auth-related emails](./email) like email verification and password reset, as well as any necessary UI to manage users from the Admin Panel.
- Customer accounts for an ecommerce app
- Customer accounts for a SaaS product
- P2P app or social site where users need to log in and manage their profiles
- Online game where players need to track their progress over time
By default, Payload provides you with a `User` collection that supports Authentication, which is used to access the [Admin Panel](../admin/overview). But, you can add support to one or many Collections of your own. For more information on how to customize, override, or remove the default `User` collection, [click here](/docs/admin/overview#the-admin-user-collection).
## Enabling Auth on a collection
Every Payload Collection can opt-in to supporting Authentication by specifying the `auth` property on the Collection's config to either `true` or to an object containing `auth` options.
**For a full list of all `auth` options, [click here](/docs/authentication/config).**
Simple example collection:
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collection#auth):
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const Users: CollectionConfig = {
// ...
auth: true, // highlight-line
}
```
![Authentication Admin Panel functionality](https://payloadcms.com/images/docs/auth-admin.jpg)
_Admin Panel screenshot depicting an Admins Collection with Auth enabled_
## Config Options
Any [Collection](../configuration/collections) can opt-in to supporting Authentication. Once enabled, each Document that is created within the Collection can be thought of as a "user". This enables a complete authentication workflow on your Collection, such as logging in and out, resetting their password, and more.
<Banner type="warning">
<strong>Note:</strong>
By default, Payload provides an auth-enabled `User` Collection which is used to access the Admin Panel. [More details](../admin/overview#the-admin-user-collection).
</Banner>
To enable Authentication on a Collection, use the `auth` property in the [Collection Config](../configuration/collections):
```ts
import { CollectionConfig } from 'payload'
export const Admins: CollectionConfig = {
slug: 'admins',
// ...
// highlight-start
auth: {
tokenExpiration: 7200, // How many seconds to keep the user logged in
@@ -52,53 +61,137 @@ export const Admins: CollectionConfig = {
// More options are available
},
// highlight-end
fields: [
{
name: 'role',
type: 'select',
required: true,
options: ['user', 'admin', 'editor', 'developer'],
},
],
}
```
**By enabling Authentication on a config, the following modifications will automatically be made to your Collection:**
<Banner type="info">
<strong>Tip:</strong>
For default auth behavior, set `auth: true`. This is a good starting point for most applications.
</Banner>
1. `email` as well as password `salt` & `hash` fields will be added to your Collection's schema
1. The [Admin Panel](../admin/overview) will feature a new set of corresponding UI to allow for changing password and editing email
1. [A new set of `operations`](/docs/authentication/operations) will be exposed via Payload's REST, Local, and GraphQL APIs
<Banner type="warning">
<strong>Note:</strong>
Auth-enabled Collections with be automatically injected with the `hash`, `salt`, and `email` fields. [More details](../fields/overview#field-names).
</Banner>
Once enabled, each document that is created within the Collection can be thought of as a `user` - who can make use of commonly required authentication functions such as logging in / out, resetting their password, and more.
The following options are available:
## Authentication Strategies
| Option | Description |
|----------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`cookies`** | Set cookie options, including `secure`, `sameSite`, and `domain`. For advanced users. |
| **`depth`** | How many levels deep a `user` document should be populated when creating the JWT and binding the `user` to the `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
| **`disableLocalStrategy`** | Advanced - disable Payload's built-in local auth strategy. Only use this property if you have replaced Payload's auth mechanisms with your own. |
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More details](./email#forgot-password). |
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
| **`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). |
| **`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). |
Out of the box Payload ships with a few powerful authentication strategies. HTTP-Only Cookies, JWT's and API-Keys, they can work together or individually. You can also have multiple collections that have auth enabled, but only 1 of them can be used to log into the admin panel.
### Login With Username
You can allow users to login with their username instead of their email address by setting the `loginWithUsername` property to `true`.
Example:
```ts
{
slug: 'customers',
auth: {
loginWithUsername: true,
},
}
```
Or, you can pass an object with additional options:
```ts
{
slug: 'customers',
auth: {
loginWithUsername: {
allowEmailLogin: true, // default: false
requireEmail: false, // default: false
},
},
}
```
**`allowEmailLogin`**
If set to `true`, users can log in with either their username or email address. If set to `false`, users can only log in with their username.
**`requireEmail`**
If set to `true`, an email address is required when creating a new user. If set to `false`, email is not required upon creation.
## Auto-Login
For testing and demo purposes you may want to skip forcing the user to login in order to access your application. Typically, all users should be required to login, however, you can speed up local development time by enabling auto-login.
To enable auto-login, set the `autoLogin` property in the [Admin Config](../configuration/admin):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
// highlight-start
autoLogin:
process.env.NEXT_PUBLIC_ENABLE_AUTOLOGIN === 'true'
? {
email: 'test@example.com',
password: 'test',
prefillOnly: true,
}
: false,
// highlight-end
})
```
<Banner type="warning">
<strong>Warning:</strong>
The recommended way to use this feature is behind an [Environment Variable](../configuration/environment-vars). This will ensure it is _disabled_ in production.
</Banner>
The following options are available:
| Option | Description |
|-------------------|-----------------------------------------------------------------------------------------------------------------|
| **`username`** | The username of the user to login as |
| **`email`** | The email address of the user to login as |
| **`password`** | The password of the user to login as. This is only needed if `prefillOnly` is set to true |
| **`prefillOnly`** | If set to true, the login credentials will be prefilled but the user will still need to click the login button. |
## Operations
All auth-related operations are available via Payload's REST, Local, and GraphQL APIs. These operations are automatically added to your Collection when you enable Authentication. [More details](./operations).
## Strategies
Out of the box Payload ships with a three powerful Authentication strategies:
- [HTTP-Only Cookies](./cookies)
- [JSON Web Tokens (JWT)](./jwt)
- [API-Keys](./api-keys)
Each of these strategies can work together or independently. You can also create your own custom strategies to fit your specific needs. [More details](./custom-strategies).
### HTTP-Only Cookies
HTTP-only cookies are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and <strong>cannot be read by JavaScript in the browser</strong>, unlike JWT's.
You can learn more about this strategy from the [HTTP-Only Cookies](/docs/authentication/http-only-cookies) docs.
[HTTP-only cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies) are a highly secure method of storing identifiable data on a user's device so that Payload can automatically recognize a returning user until their cookie expires. They are totally protected from common XSS attacks and <strong>cannot be read by JavaScript in the browser</strong>, unlike JWT's. [More details](./cookies).
### JSON Web Tokens
JWT (JSON Web Tokens) can also be utilized to perform authentication. Tokens are generated on `login`, `refresh` and `me` operations and can be attached to future requests to authenticate users.
You can learn more about this strategy from the [JWT](/docs/authentication/jwt) docs.
JWT (JSON Web Tokens) can also be utilized to perform authentication. Tokens are generated on `login`, `refresh` and `me` operations and can be attached to future requests to authenticate users. [More details](./jwt).
### API Keys
API Keys can be enabled on auth collections. These are particularly useful when you want to authenticate against Payload from a third party service.
You can learn more about this strategy from the [API Keys](/docs/authentication/api-keys) docs.
API Keys can be enabled on auth collections. These are particularly useful when you want to authenticate against Payload from a third party service. [More details](./api-keys).
### Custom Strategies
There are cases where these may not be enough for your application. Payload is extendable by design so you can wire up your own strategy when you need to.
You can learn more about custom strategies from the [Custom Strategies](/docs/authentication/custom-strategies) docs.
## Logging in / out, resetting password, etc.
[Click here](/docs/authentication/operations) for a list of all automatically-enabled Auth operations, including `login`, `logout`, `refresh`, and others.
There are cases where these may not be enough for your application. Payload is extendable by design so you can wire up your own strategy when you need to. [More details](./custom-strategies).

View File

@@ -78,7 +78,7 @@ export const Users: CollectionConfig = {
### Using Token Data
This is especially helful when writing hooks and access control that depend on user defined fields.
This is especially helpful when writing [Hooks](../hooks/overview) and [Access Control](../access-control/overview) that depend on user defined fields.
```ts
import type { CollectionConfig } from 'payload'

View File

@@ -59,9 +59,7 @@ You can update settings from your Projects Settings tab. Changes to your buil
From the Environment Variables page of the Settings tab, you can add, update and delete variables for use in your project. Like build settings, these changes will trigger a redeployment of your project.
<Banner>
Note: For security reasons, any variables you wish to provide to the [Admin Panel](../admin/overview) must be prefixed
with `PAYLOAD_PUBLIC_`.  Learn more
[here](../configuration/environment-vars).
Note: For security reasons, any variables you wish to provide to the [Admin Panel](../admin/overview) must be prefixed with `NEXT_PUBLIC_`. [More details](../configuration/environment-vars).
</Banner>
## Custom Domains
@@ -98,13 +96,13 @@ From there, you are ready to make updates to your project. When you are ready to
## Cloud Plugin
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:
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`
```js
import { payloadCloud } from '@payloadcms/plugin-cloud'
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
plugins: [payloadCloud()],
@@ -113,7 +111,7 @@ export default buildConfig({
```
<Banner type="warning">
**Note:** If your Payload config already has an email with transport, this will take precedence
**Note:** If your Payload Config already has an email with transport, this will take precedence
over Payload Cloud's email service.
</Banner>

View File

@@ -6,11 +6,13 @@ desc: Structure your Collections for your needs by defining fields, adding slugs
keywords: collections, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload Collections are defined through configs of their own. You can define as many Collections as your application needs. Each Collection will automatically scaffold a new collection / table in your database of choice, based on fields that you define.
A Collection is a group of records, called Documents, that all share a common schema. You can define as many Collections as your application needs. Each Document in a Collection is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
## Config Options
Collections are also used to achieve [Authentication](../authentication/overview) in Payload. By defining a Collection with `auth` options, that Collection receives additional operations to support user authentication.
To define a Collection Config, use the `collection` property in your [Payload Config](./overview).
Collections are the primary way to structure recurring data in your application, such as users, products, pages, posts, and other types of content that you might want to manage. Each Collection can have its own unique [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Admin Options](#admin-options), and more.
To define a Collection Config, use the `collection` property in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
@@ -18,12 +20,19 @@ import { buildConfig } from 'payload'
export default buildConfig({
// ...
collections: [ // highlight-line
// Your Collection Configs go here
// Your Collections go here
],
})
```
It's often best practice to write your Collections in separate files and then import them into the main Payload Config.
<Banner type="success">
<strong>Tip:</strong>
If your Collection is only ever meant to contain a single Document, consider using a [Global](./globals) instead.
</Banner>
## Config Options
It's often best practice to write your Collections in separate files and then import them into the main [Payload Config](../overview).
Here is what a simple Collection Config might look like:
@@ -43,184 +52,56 @@ export const Posts: CollectionConfig = {
<Banner type="success">
<strong>Reminder:</strong>
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
The following options are available:
| Option | Description |
|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel. [More details](#admin-options). |
| **`access`** | Provide access control functions to define exactly who should be able to do what with Documents in this Collection. [More details](../access-control/overview/#collections). |
| **`auth`** | Specify options if you would like this Collection to feature authentication. For more, consult the [Authentication](../authentication/config) documentation. |
| **`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. [Click here](../fields/overview) for a full list of field types as well as how to configure them. |
| **`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 points to "tie in" to Collection actions at specific points. [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. |
| **`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. |
| **`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). |
_\* An asterisk denotes that a property is required._
## Admin Options
### Fields
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis.
To configure Collection Admin Options, use the `admin` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Collection from navigation and admin routing. |
| **`hooks`** | Admin-specific hooks for this Collection. [More details](#admin-hooks). |
| **`useAsTitle`** | Specify a top-level field to use for a document title throughout the [Admin Panel](../admin/overview). If no field is defined, the ID of the document is used as the title. |
| **`description`** | Text or React component to display below the Collection label in the List View to give editors more information. |
| **`defaultColumns`** | Array of field names that correspond to which columns to show by default in this Collection's List View. |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this Collection. |
| **`enableRichTextLink`** | The [Rich Text](../fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`enableRichTextRelationship`** | The [Rich Text](../fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
| **`meta`** | Metadata overrides to apply to the [Admin Panel](../admin/overview). Included properties are `description` and `openGraph`. |
| **`preview`** | Function to generate preview URLs within the [Admin Panel](../admin/overview) that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`components`** | Swap in your own React components to be used within this Collection. [More details](../admin/components#collections). |
| **`listSearchableFields`** | Specify which fields should be searched in the List search view. [More details](#list-searchable-fields). |
| **`pagination`** | Set pagination-specific options for this Collection. [More details](#pagination). |
#### Preview
It is possible to display a Preview Button in the Admin Panel within the Edit View. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The document being edited |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Reminder:</strong>
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>
### Pagination
All Collections receive their own List View which displays a paginated list of documents that can be sorted and filtered. The pagination behavior of the List View can be customized on a per-Collection basis.
To configure pagination options, use the `admin.pagination` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
pagination: {
defaultLimit: 10,
limits: [10, 20, 50],
},
// highlight-end
},
}
```
The following options are available:
| Option | Description |
| -------------- | --------------------------------------------------------------------------------------------------- |
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List View. |
Fields define the schema of the Documents within a Collection. To learn more, go to the [Fields](../fields/overview) documentation.
### Access Control
You can specify extremely granular access control (what users can do with documents in a Collection) on a Collection by
Collection basis. To learn more, go to the [Access Control](../access-control/overview) docs.
[Collection Access Control](../access-control/overview) determines what a user can and cannot do with any given Document within a Collection. To learn more, go to the [Access Control](../access-control/overview) documentation.
### Hooks
Hooks are a powerful way to extend Collection functionality and execute your own logic, and can be defined on a
Collection by Collection basis. To learn more, go to the [Hooks](../hooks/overview) documentation.
[Collection Hooks](../hooks/collections) allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
### List Searchable Fields
### Admin Options
In the List View, there is a "search" box that allows you to quickly find a document through a simple text search. By default, it searches on the ID field. If defined, the `admin.useAsTitle` field is used. Or, you can explicitly define which fields to search based on the needs of your application.
To define which fields should be searched, use the `admin.listSearchableFields` property in your Collection Config:
```ts
import { CollectionConfig } from 'payload'
export const Posts: CollectionConfig = {
// ...
admin: {
// highlight-start
listSearchableFields: ['title', 'slug'],
// highlight-end
},
}
```
<Banner type="warning">
<strong>Tip:</strong>
If you are adding `listSearchableFields`, make sure you index each of these fields so your admin queries can remain performant.
</Banner>
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Collection-by-Collection basis. To learn more, go to the [Collection Admin Options](../admin/collections) documentation.
## TypeScript
You can import Collection types as follows:
You can import types from Payload to help make writing your Collection configs easier and type-safe. There are two main types that represent the Collection Config, `CollectionConfig` and `SanitizeCollectionConfig`.
The `CollectionConfig` type represents a raw Collection Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedCollectionConfig` type represents a Collection Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import { CollectionConfig } from 'payload'
// This is the type used for incoming Collection configs.
// Only the bare minimum properties are marked as required.
```
```ts
import { SanitizedCollectionConfig } from 'payload'
// This is the type used after an incoming Collection config is fully sanitized.
// Generally, this is only used internally by Payload.
import type { CollectionConfig, SanitizedCollectionConfig } from 'payload'
```

View File

@@ -7,9 +7,11 @@ desc: Learn how to use Environment Variables in your Payload project
Environment Variables are a way to store sensitive information that your application needs to function. This could be anything from API keys to [Database](../database/overview) credentials. Payload allows you to easily use Environment Variables within your config and throughout your application.
If you are using Next.js, no additional setup is required other than creating your `.env` file. Otherwise, you can use the `dotenv` package to load your Environment Variables into `process.env`. [More details](#outside-of-nextjs).
## Next.js Applications
Environment Variables are typically stored in an `.env` file at the root of your project:
If you are using Next.js, no additional setup is required other than creating your `.env` file.
To use Environment Variables, add a `.env` file to the root of your project:
```plaintext
project-name/
@@ -25,7 +27,7 @@ SERVER_URL=localhost:3000
DATABASE_URI=mongodb://localhost:27017/my-database
```
To use Environment Variables in your Payload config, you can access them directly from `process.env`:
To use Environment Variables in your Payload Config, you can access them directly from `process.env`:
```ts
import { buildConfig } from 'payload'

View File

@@ -6,9 +6,9 @@ desc: Set up your Global config for your needs by defining fields, adding slugs
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload Globals are in many ways similar to [Collections](../configuration/collections). The big difference is that Collections will potentially contain _many_ documents, while a Global is a "one-off". Globals are perfect for things like header nav, site-wide banner alerts, app-wide localized strings, and other "global" data that your site or app might rely on.
Globals are in many ways similar to [Collections](../configuration/collections), except they correspond to only a single Document. You can define as many Globals as your application needs. Each Global Document is stored in the [Database](../database/overview) based on the [Fields](../fields/overview) that you define, and automatically generates a [Local API](../local-api/overview), [REST API](../rest-api/overview), and [GraphQL API](../graphql/overview) used to manage your Documents.
## Config Options
Globals are the primary way to structure singletons in Payload, such as a header navigation, site-wide banner alerts, or app-wide localized strings. Each Global can have its own unique [Access Control](../access-control/overview), [Hooks](../hooks/overview), [Admin Options](#admin-options), and more.
To define a Global Config, use the `globals` property in your [Payload Config](./overview):
@@ -18,12 +18,19 @@ import { buildConfig } from 'payload'
export default buildConfig({
// ...
globals: [ // highlight-line
// Your Global Configs go here
// Your Globals go here
],
})
```
It's often best practice to write your Globals in separate files and then import them into the main Payload Config.
<Banner type="success">
<strong>Tip:</strong>
If you have more than one Global that share the same structure, consider using a [Collection](../configuration/collections) instead.
</Banner>
## Config Options
It's often best practice to write your Globals in separate files and then import them into the main [Payload Config](./overview).
Here is what a simple Global Config might look like:
@@ -53,118 +60,52 @@ export const Nav: GlobalConfig = {
<Banner type="success">
<strong>Reminder:</strong>
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
The following options are available:
| Option | Description |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`access`** | Provide access control functions to define exactly who should be able to do what with this Global. [More details](../access-control/overview/#globals). |
| **`admin`** | The configuration options for the Admin Panel. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`dbName`** | Custom table or collection name for this Global depending on the database adapter. Auto-generated from slug if not defined. |
| **`description`** | Text or React component to display below the Global header to give editors more information. |
| **`endpoints`** | Add custom routes to the REST API. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [Click here](../fields/overview) for a full list of field types as well as how to configure them. |
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
| **`hooks`** | Entry points to "tie in" to collection actions at specific points. [More details](../hooks/overview#global-hooks). |
| **`label`** | Text for the name in the Admin Panel or an object with keys for each language. Auto-generated from slug if not defined. |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Global. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#globals-config). |
| Option | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`access`** | Provide Access Control functions to define exactly who should be able to do what with this Global. [More details](../access-control/globals). |
| **`admin`** | The configuration options for the Admin Panel. [More details](../admin/globals). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`dbName`** | Custom table or collection name for this Global depending on the Database Adapter. Auto-generated from slug if not defined. |
| **`description`** | Text or React component to display below the Global header to give editors more information. |
| **`endpoints`** | Add custom routes to the REST API. [More details](../rest-api/overview#custom-endpoints). |
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [More details](../fields/overview). |
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
| **`hooks`** | Entry point for Hooks. [More details](../hooks/overview#global-hooks). |
| **`label`** | Text for the name in the Admin Panel or an object with keys for each language. Auto-generated from slug if not defined. |
| **`lockDocuments`** | Enables or disables document locking. By default, document locking is enabled. Set to an object to configure, or set to `false` to disable locking. [More details](../admin/locked-documents). |
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Global. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`versions`** | Set to true to enable default options, or configure with object properties. [More details](../versions/overview#globals-config). |
_\* An asterisk denotes that a property is required._
### Fields
Fields define the schema of the Global. To learn more, go to the [Fields](../fields/overview) documentation.
### Access Control
As with Collections, you can specify extremely granular access control (what users can do with this Global) on a Global-by-Global basis. However, Globals only have `update` and `read` access control due to their nature of only having one document. To learn more, go to the [Access Control](../access-control/overview) docs.
[Global Access Control](../access-control/globals) determines what a user can and cannot do with any given Global Document. To learn more, go to the [Access Control](../access-control/overview) documentation.
### Hooks
Globals also fully support a smaller subset of Hooks. To learn more, go to the [Hooks](../hooks/overview) documentation.
[Global Hooks](../hooks/globals) allow you to tie into the lifecycle of your Documents so you can execute your own logic during specific events. To learn more, go to the [Hooks](../hooks/overview) documentation.
### Admin Options
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis.
To configure Collection Admin Options, use the `admin` property in your Global Config:
```ts
import { GlobalConfig } from 'payload'
const MyGlobal: GlobalConfig = {
// ...
admin: { // highlight-line
// ...
},
}
```
The following options are available:
| Option | Description |
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
| **`group`** | Text used as a label for grouping Collection and Global links together in the navigation. |
| **`hidden`** | Set to true or a function, called with the current user, returning true to exclude this Global from navigation and admin routing. |
| **`components`** | Swap in your own React components to be used within this Global. [More details](../admin/components#globals). |
| **`preview`** | Function to generate a preview URL within the [Admin Panel](../admin/overview) for this Global that can point to your app. [More details](#preview). |
| **`livePreview`** | Enable real-time editing for instant visual feedback of your front-end application. [More details](../live-preview/overview). |
| **`hideAPIURL`** | Hides the "API URL" meta field while editing documents within this collection. |
| **`meta`** | Metadata overrides to apply to the [Admin Panel](../admin/overview). Included properties are `description` and `openGraph`. |
#### Preview
It is possible to display a Preview Button in the Admin Panel within the Edit View. This will allow editors to visit the frontend of your app the corresponds to the document they are actively editing. This way they can preview the latest, potentially unpublished changes.
To configure the Preview Button, set the `admin.preview` property to a function in your Global Config:
```ts
import { GlobalConfig } from 'payload'
export const MainMenu: GlobalConfig = {
// ...
admin: {
// highlight-start
preview: (doc, { locale }) => {
if (doc?.slug) {
return `/${doc.slug}?locale=${locale}`
}
return null
},
// highlight-end
},
}
```
The preview function receives two arguments:
| Argument | Description |
| --- | --- |
| **`doc`** | The document being edited |
| **`ctx`** | An object containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT. |
<Banner type="success">
<strong>Reminder:</strong>
For fully working example of this, check of the official [Draft Preview Example](https://github.com/payloadcms/payload/tree/main/examples/draft-preview) in the [Examples Directory](https://github.com/payloadcms/payload/tree/main/examples).
</Banner>
You can customize the way that the [Admin Panel](../admin/overview) behaves on a Global-by-Global basis. To learn more, go to the [Global Admin Options](../admin/globals) documentation.
## TypeScript
You can import Global types as follows:
You can import types from Payload to help make writing your Global configs easier and type-safe. There are two main types that represent the Global Config, `GlobalConfig` and `SanitizeGlobalConfig`.
The `GlobalConfig` type represents a raw Global Config in its full form, where only the bare minimum properties are marked as required. The `SanitizedGlobalConfig` type represents a Global Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import { GlobalConfig } from 'payload'
// This is the type used for incoming Global configs.
// Only the bare minimum properties are marked as required.
```
```ts
import { SanitizedGlobalConfig } from 'payload/types'
// This is the type used after an incoming Global config is fully sanitized.
// Generally, this is only used internally by Payload.
import type { GlobalConfig, SanitizedGlobalConfig } from 'payload'
```

View File

@@ -6,9 +6,22 @@ desc: Manage and customize internationalization support in your CMS editor exper
keywords: internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The [Admin Panel](../admin/overview) is translated in over [30 languages and counting](https://github.com/payloadcms/payload/tree/beta/packages/translations). With i18n, editors can navigate the interface and read API error messages in their preferred language. Users can easily select a language from the Account View and have their preference saved for future visits.
The [Admin Panel](../admin/overview) is translated in over [30 languages and counting](https://github.com/payloadcms/payload/tree/beta/packages/translations). With I18n, editors can navigate the interface and read API error messages in their preferred language. This is similar to [Localization](./localization), but instead of managing translations for the data itself, you are managing translations for your application's interface.
By default, Payload comes with preinstalled with English, but you can easily load other languages into your own application. Languages are automatically detected based on the user's browser. If no language was detected, or if the user's language is not yet supported by your application, English will be chosen.
By default, Payload comes with preinstalled with English, but you can easily load other languages into your own application. Languages are automatically detected based on the request. If no language was detected, or if the user's language is not yet supported by your application, English will be chosen.
To configure I18n, use the `i18n` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
i18n: { // highlight-line
// ...
},
})
```
<Banner type="success">
<strong>Note:</strong>
@@ -19,19 +32,44 @@ By default, Payload comes with preinstalled with English, but you can easily loa
You can easily customize and override any of the i18n settings that Payload provides by default. Payload will use your custom options and merge them in with its own.
To add a new language, use the `i18n` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
import { en } from 'payload/i18n/en'
import { de } from 'payload/i18n/de'
export default buildConfig({
// ...
// highlight-start
i18n: {
// Payload will support either English or German,
// able to be specified in preferences on a user-by-user basis
fallbackLanguage: 'en', // default
debug: false, // default
}
// highlight-end
})
```
The following options are available:
| Option | Description |
| --------------------- | --------------------------------|
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
| **`debug`** | Whether to log debug information to the console. Default is `false`. |
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
## Adding Languages
You can easily add new languages to your Payload app by providing the translations for the new language. Payload maintains a number of built-in translations that can be imported from `@payloadcms/translations`, but you can also provide your own [Custom Translations](#custom-translations) to support any language.
To add a new language, use the `i18n.supportedLanguages` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
import { en } from '@payloadcms/translations/languages/en'
import { de } from '@payloadcms/translations/languages/de'
export default buildConfig({
// ...
// highlight-start
i18n: {
supportedLanguages: { en, de },
},
// highlight-end
@@ -43,27 +81,18 @@ export default buildConfig({
It's best to only support the languages that you need so that the bundled JavaScript is kept to a minimum for your project.
</Banner>
The following options are available:
### Custom Translations
| Option | Description |
| --------------------- | --------------------------------|
| **`fallbackLanguage`** | The language to fall back to if the user's preferred language is not supported. Default is `'en'`. |
| **`debug`** | Whether to log debug information to the console. Default is `false`. |
| **`translations`** | An object containing the translations. The keys are the language codes and the values are the translations. |
| **`supportedLanguages`** | An object containing the supported languages. The keys are the language codes and the values are the translations. |
You can customize Payload's built-in translations either by extending existing languages or by adding new languages entirely. This can be done by injecting new translation strings into existing languages, or by providing an entirely new language keys altogether.
## Custom Translations
Here is an example of how you can add custom translations to your project:
To add Custom Translations, use the `i18n.translations` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
export default buildConfig({
//...
i18n: {
fallbackLanguage: 'en', // default
debug: false, // default
// highlight-start
translations: {
en: {
@@ -83,9 +112,11 @@ export default buildConfig({
})
```
While Payload's built-in features come translated, you may want to also translate parts of your project's configuration too. This is possible in places like Collections and Globals labels and groups, field labels, descriptions and input placeholder text. The admin UI will display all the correct translations you provide based on the user's language.
### Project Translations
Here is an example of a simple collection supporting both English and Spanish editors:
While Payload's built-in features come fully translated, you may also want to translate parts of your own project. This is possible in places like [Collections](./collections) and [Globals](./globals), such as on their labels and groups, field labels, descriptions or input placeholder text.
To do this, provide the translations wherever applicable, keyed to the language code:
```ts
import { CollectionConfig } from 'payload'
@@ -94,39 +125,45 @@ export const Articles: CollectionConfig = {
slug: 'articles',
labels: {
singular: {
// highlight-start
en: 'Article',
es: 'Artículo',
// highlight-end
},
plural: {
// highlight-start
en: 'Articles',
es: 'Artículos',
// highlight-end
},
},
admin: {
group: { en: 'Content', es: 'Contenido' },
group: {
// highlight-start
en: 'Content',
es: 'Contenido',
// highlight-end
},
},
fields: [
{
name: 'title',
type: 'text',
label: {
// highlight-start
en: 'Title',
es: 'Título',
// highlight-end
},
admin: {
placeholder: { en: 'Enter title', es: 'Introduce el título' },
placeholder: {
// highlight-start
en: 'Enter title',
es: 'Introduce el título'
// highlight-end
},
},
},
{
name: 'type',
type: 'radio',
options: [
{
value: 'news',
label: { en: 'News', es: 'Noticias' },
}, // etc...
],
},
],
}
```
@@ -135,7 +172,7 @@ export const Articles: CollectionConfig = {
Payload's backend sets the language on incoming requests before they are handled. This allows backend validation to return error messages in the user's own language or system generated emails to be sent using the correct translation. You can make HTTP requests with the `accept-language` header and Payload will use that language.
Anywhere in your Payload app that you have access to the `req` object, you can access payload's extensive internationalization features assigned to `req.i18n`. To access text translations you can use `req.t('namespace:key')`.
Anywhere in your Payload app that you have access to the `req` object, you can access Payload's extensive internationalization features assigned to `req.i18n`. To access text translations you can use `req.t('namespace:key')`.
## TypeScript
@@ -169,7 +206,7 @@ export const MyComponent: React.FC = () => {
```
Additionally, payload exposes the `t` function in various places, for example in labels. Here is how you would type those:
Additionally, Payload exposes the `t` function in various places, for example in labels. Here is how you would type those:
```ts
import type {
@@ -177,7 +214,7 @@ import type {
NestedKeysStripped,
TFunction,
} from '@payloadcms/translations'
import type { Field } from 'payload/types'
import type { Field } from 'payload'
const customTranslations = {
en: {

View File

@@ -2,36 +2,45 @@
title: Localization
label: Localization
order: 50
desc: Add and maintain as many locales as you need by adding Localization to your Payload config, set options for default locale, fallbacks, fields and more.
desc: Add and maintain as many locales as you need by adding Localization to your Payload Config, set options for default locale, fallbacks, fields and more.
keywords: localization, internationalization, i18n, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload features deep field-based localization support. Maintaining as many locales as you need is easy. All
localization support is opt-in by default. To do so, follow the two steps below.
Localization is one of the most important features of a modern CMS. It allows you to manage content in multiple languages, then serve it to your users based on their requested language. This is similar to [I18n](./i18n), but instead of managing translations for your application's interface, you are managing translations for the data itself.
## Enabling in the Payload config
With Localization, you can begin to serve personalized content to your users based on their specific language preferences, such as a multilingual website or multi-site application. There are no limits to the number of locales you can add to your Payload project.
Add the `localization` property to your Payload config to enable localization project-wide. You'll need to provide a
list of all locales that you'd like to support as well as set a few other options.
**Example Payload config set up for localization:**
To configure Localization, use the `localization` key in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
collections: [
// collections go here
],
localization: {
locales: ['en', 'es', 'de'],
defaultLocale: 'en',
fallback: true,
// ...
localization: { // highlight-line
// ...
},
})
```
**Example Payload config set up for localization with full locales objects:**
## Config Options
Add the `localization` property to your Payload Config to enable Localization project-wide. You'll need to provide a list of all locales that you'd like to support as well as set a few other options.
To configure locales, use the `localization.locales` property in your [Payload Config](./overview):
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
localization: {
locales: ['en', 'es', 'de'] // highlight-line
},
})
```
You can also define locales using [full configuration objects](#locale-object):
```ts
import { buildConfig } from 'payload'
@@ -60,50 +69,26 @@ export default buildConfig({
})
```
**Example Payload config set up for localization with full locales objects (
including [internationalization](/docs/configuration/i18n) support):**
<Banner type="success">
<strong>Tip:</strong>
Localization works very well alongside [I18n](/docs/configuration/i18n).
</Banner>
```ts
import { buildConfig } from 'payload'
The following options are available:
export default buildConfig({
collections: [
// collections go here
],
localization: {
locales: [
{
label: {
en: 'English', // English label
nb: 'Engelsk', // Norwegian label
},
code: 'en',
},
{
label: {
en: 'Norwegian', // English label
nb: 'Norsk', // Norwegian label
},
code: 'nb',
},
],
defaultLocale: 'en',
fallback: true,
},
})
```
| Option | Description |
| -------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| **`locales`** | Array of all the languages that you would like to support. [More details](#locales) |
| **`defaultLocale`** | Required string that matches one of the locale codes from the array provided. By default, if no locale is specified, documents will be returned in this locale. |
| **`fallback`** | Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a localized value corresponding to the requested locale, then if this property is enabled, the document will automatically fall back to the fallback locale value. If this property is not enabled, the value will not be populated. |
**Here is a brief explanation of each of the options available within the `localization` property:**
### Locales
**`locales`**
The locales array is a list of all the languages that you would like to support. This can be strings for each language code, or [full configuration objects](#locale-object) for more advanced options.
Array-based list of all the languages that you would like to support. This can be an array containing strings for each
language code you want your project to store and serve or objects with a `label`, a locale `code`, `rtl` (
right-to-left), and `fallbackLocale` property. The locale codes do not need to be in any specific format. It's up to you
to define how to represent your locales. Common patterns are to use two-letter ISO 639 language codes or four-letter
language and country codes (ISO 31661) such as `en-US`, `en-UK`, `es-MX`, etc.
The locale codes do not need to be in any specific format. It's up to you to define how to represent your locales. Common patterns are to use two-letter ISO 639 language codes or four-letter language and country codes (ISO 31661) such as `en-US`, `en-UK`, `es-MX`, etc.
## Locale Object Properties
#### Locale Object
| Option | Description |
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
@@ -114,23 +99,11 @@ language and country codes (ISO 31661) such as `en-US`, `en-UK`, `es-MX`, etc
_\* An asterisk denotes that a property is required._
**`defaultLocale`**
## Field Localization
Required string that matches one of the locale codes from the array provided. By default, if no locale is specified,
documents will be returned in this locale.
Payload Localization works on a **field** level—not a document level. In addition to configuring the base Payload Config to support Localization, you need to specify each field that you would like to localize.
**`fallback`**
Boolean enabling "fallback" locale functionality. If a document is requested in a locale, but a field does not have a
localized value corresponding to the requested locale, then if this property is enabled, the document will automatically
fall back to the fallback locale value. If this property is not enabled, the value will not be populated.
## Field by field localization
Payload localization works on a **field** level—not a document level. In addition to configuring the base Payload config
to support localization, you need to specify each field that you would like to localize.
**Here is an example of how to enable localization for a field:**
**Here is an example of how to enable Localization for a field:**
```js
{
@@ -142,31 +115,27 @@ to support localization, you need to specify each field that you would like to l
}
```
With the above configuration, the `title` field will now be saved in the database as an object of all locales instead of
a single string.
With the above configuration, the `title` field will now be saved in the database as an object of all locales instead of a single string.
All field types with a `name` property support the `localized` property—even the more complex field types like `array`s
and `block`s.
All field types with a `name` property support the `localized` property—even the more complex field types like `array`s and `block`s.
<Banner>
<Banner type="info">
<strong>Note:</strong>
<br />
Enabling localization for field types that support nested fields will automatically create
Enabling Localization for field types that support nested fields will automatically create
localized "sets" of all fields contained within the field. For example, if you have a page layout
using a blocks field type, you have the choice of either localizing the full layout, by enabling
localization on the top-level blocks field, or only certain fields within the layout.
Localization on the top-level blocks field, or only certain fields within the layout.
</Banner>
<Banner type="warning">
<strong>Important:</strong>
<br />
When converting an existing field to or from `localized: true` the data structure in the document
will change for this field and so existing data for this field will be lost. Before changing the
localization setting on fields with existing data, you may need to consider a field migration
Localization setting on fields with existing data, you may need to consider a field migration
strategy.
</Banner>
## Retrieving localized docs
## Retrieving Localized Docs
When retrieving documents, you can specify which locale you'd like to receive as well as which fallback locale should be
used.
@@ -182,7 +151,7 @@ Specify your desired locale by providing the `locale` query parameter directly i
**`?fallback-locale=`**
Specify fallback locale to be used by providing the `fallback-locale` query parameter. This can be provided as either a
valid locale as provided to your base Payload config, or `'null'`, `'false'`, or `'none'` to disable falling back.
valid locale as provided to your base Payload Config, or `'null'`, `'false'`, or `'none'` to disable falling back.
**Example:**
@@ -234,10 +203,9 @@ const posts = await payload.find({
})
```
<Banner type="alert">
<Banner type="success">
<strong>Tip:</strong>
<br />
The REST and Local APIs can return all localization data in one request by passing 'all' or '*' as
The REST and Local APIs can return all Localization data in one request by passing 'all' or '*' as
the <strong>locale</strong> parameter. The response will be structured so that field values come
back as the full objects keyed for each locale instead of the single, translated value.
</Banner>

View File

@@ -6,7 +6,7 @@ desc: The Payload Config is central to everything that Payload does, from adding
keywords: overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Payload is a _config-based_, code-first CMS and application framework. The Payload Config is central to everything that Payload does, allowing for the deep configuration of your application through a simple API.
Payload is a _config-based_, code-first CMS and application framework. The Payload Config is central to everything that Payload does, allowing for deep configuration of your application through a simple and intuitive API. The Payload Config is a fully-typed JavaScript object that can be infinitely extended upon.
Everything from your [Database](../database/overview) choice, to the appearance of the [Admin Panel](../admin/overview), is fully controlled through the Payload Config. From here you can define [Fields](../fields/overview), add [Localization](./localization), enable [Authentication](../authentication/overview), configure [Access Control](../access-control/overview), and so much more.
@@ -36,7 +36,6 @@ Here is one of the simplest possible Payload configs:
```ts
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
// import { postgresAdapter } from '@payloadcms/db-postgres'
export default buildConfig({
secret: process.env.PAYLOAD_SECRET,
@@ -58,67 +57,133 @@ export default buildConfig({
```
<Banner type="success">
<strong>More:</strong>
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub.
<strong>Note:</strong>
For a more complex example, see the [Public Demo](https://github.com/payloadcms/public-demo) source code on GitHub, or the [Templates](https://github.com/payloadcms/payload/tree/main/templates) and [Examples](https://github.com/payloadcms/payload/tree/main/examples) directories in the Payload repository.
</Banner>
The following options are available:
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts with the `payload` bin function. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| **`localization`** | Opt-in and control how Payload handles the translation of your content into multiple locales. [More details](./localization). |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More details](../authentication/overview#csrf-protection). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../getting-started/concepts#depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | Tap into Payload-wide hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Payload plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of custom API endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
| Option | Description |
|----------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`admin`** | The configuration options for the Admin Panel, including Custom Components, Live Preview, etc. [More details](../admin/overview#admin-options). |
| **`bin`** | Register custom bin scripts for Payload to execute. |
| **`editor`** | The Rich Text Editor which will be used by `richText` fields. [More details](../rich-text/overview). |
| **`db`** \* | The Database Adapter which will be used by Payload. [More details](../database/overview). |
| **`serverURL`** | A string used to define the absolute URL of your app. This includes the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port. |
| **`collections`** | An array of Collections for Payload to manage. [More details](./collections). |
| **`compatibility`** | Compatibility flags for earlier versions of Payload. [More details](#compatibility-flags). |
| **`globals`** | An array of Globals for Payload to manage. [More details](./globals). |
| **`cors`** | Cross-origin resource sharing (CORS) is a mechanism that accept incoming requests from given domains. You can also customize the `Access-Control-Allow-Headers` header. [More details](#cors). |
| **`localization`** | Opt-in to translate your content into multiple locales. [More details](./localization). |
| **`logger`** | Logger options, logger options with a destination stream, or an instantiated logger instance. [More details](https://getpino.io/#/docs/api?id=options). |
| **`graphQL`** | Manage GraphQL-specific functionality, including custom queries and mutations, query complexity limits, etc. [More details](../graphql/overview#graphql-options). |
| **`cookiePrefix`** | A string that will be prefixed to all cookies that Payload sets. |
| **`csrf`** | A whitelist array of URLs to allow Payload to accept cookies from. [More details](../authentication/overview#csrf-protection). |
| **`defaultDepth`** | If a user does not specify `depth` while requesting a resource, this depth will be used. [More details](../queries/depth). |
| **`defaultMaxTextLength`** | The maximum allowed string length to be permitted application-wide. Helps to prevent malicious public document creation. |
| **`maxDepth`** | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. [More details](../queries/depth). |
| **`indexSortableFields`** | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
| **`upload`** | Base Payload upload configuration. [More details](../upload/overview#payload-wide-upload-options). |
| **`routes`** | Control the routing structure that Payload binds itself to. [More details](../admin/overview#root-level-routes). |
| **`email`** | Configure the Email Adapter for Payload to use. [More details](../email/overview). |
| **`debug`** | Enable to expose more detailed error information. |
| **`telemetry`** | Disable Payload telemetry by passing `false`. [More details](#telemetry). |
| **`rateLimit`** | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks, etc. [More details](../production/preventing-abuse#rate-limiting-requests). |
| **`hooks`** | An array of Root Hooks. [More details](../hooks/overview). |
| **`plugins`** | An array of Plugins. [More details](../plugins/overview). |
| **`endpoints`** | An array of Custom Endpoints added to the Payload router. [More details](../rest-api/overview#custom-endpoints). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins). |
| **`i18n`** | Internationalization configuration. Pass all i18n languages you'd like the admin UI to support. Defaults to English-only. [More details](./i18n). |
| **`secret`** \* | A secure, unguessable string that Payload will use for any encryption workflows - for example, password salt / hashing. |
| **`sharp`** | If you would like Payload to offer cropping, focal point selection, and automatic media resizing, install and pass the Sharp module to the config here. |
| **`typescript`** | Configure TypeScript settings here. [More details](#typescript). |
_\* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Reminder:</strong>
<strong>Note:</strong>
Some properties are removed from the client-side bundle. [More details](../admin/components#accessing-the-payload-config).
</Banner>
### Typescript Config
Payload exposes a variety of TypeScript settings that you can leverage. These settings are used to auto-generate TypeScript interfaces for your [Collections](../configuration/collections) and [Globals](../configuration/globals), and to ensure that Payload uses your [Generated Types](../typescript/overview) for all [Local API](../local-api/overview) methods.
To customize the TypeScript settings, use the `typescript` property in your Payload Config:
```ts
import { buildConfig } from 'payload'
export default buildConfig({
// ...
typescript: { // highlight-line
// ...
}
})
```
The following options are available:
| Option | Description |
| --------------- | --------------------- |
| **`autoGenerate`** | By default, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines. Opt out by setting `typescript.autoGenerate: false`. [More details](../typescript/overview). |
| **`declare`** | By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. Opt out by setting `typescript.declare: false`. |
| **`outputFile`** | Control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path. |
## Config Location
For Payload command-line scripts, we need to be able to locate your Payload Config. We'll check a variety of locations for the presence of `payload.config.ts` by default, including the root current working directory, your `tsconfig`'s `rootDir`, and your `tsconfig`'s `outDir`.
For Payload command-line scripts, we need to be able to locate your Payload Config. We'll check a variety of locations for the presence of `payload.config.ts` by default, including:
In development mode, if the configuration file is not found at the root, Payload will attempt to read your `tsconfig.json`, and search in the directory specified in `compilerOptions.rootDir` (typically "src").
1. The root current working directory
1. The `compilerOptions` in your `tsconfig`*
1. The `dist` directory*
In production mode, Payload will first attempt to find the config file in the output directory specified in `compilerOptions.outDir` of your `tsconfig.json`, then fallback to the source directory (`compilerOptions.rootDir`), and finally will check the 'dist' directory.
_\* Config location detection is different between development and production environments. See below for more details._
Please ensure your `tsconfig.json` is properly configured if you want Payload to accurately auto-detect your configuration file location. If `tsconfig.json` does not exist or doesn't specify `rootDir` or `outDir`, Payload will default to the current working directory.
<Banner type="warning">
<strong>Important:</strong>
Ensure your `tsconfig.json` is properly configured for Payload to auto-detect your config location. If if does not exist, or does not specify the proper `compilerOptions`, Payload will default to the current working directory.
</Banner>
**Development Mode**
In development mode, if the configuration file is not found at the root, Payload will attempt to read your `tsconfig.json`, and attempt to find the config file specified in the `rootDir`:
```json
{
// ...
// highlight-start
"compilerOptions": {
"rootDir": "src"
}
// highlight-end
}
```
**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:
```json
{
// ...
// highlight-start
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
}
// highlight-end
}
```
If none was in either location, Payload will finally check the `dist` directory.
### Customizing the Config Location
In addition to the above automated detection, you can specify your own location for the Payload Config. This is done by using the environment variable `PAYLOAD_CONFIG_PATH`. The path you provide via this environment variable can either be absolute or relative to your current working directory. This can be useful in situations where your Payload Config is not in a standard location, or you wish to switch between multiple configurations.
In addition to the above automated detection, you can specify your own location for the Payload Config. This can be useful in situations where your config is not in a standard location, or you wish to switch between multiple configurations. To do this, Payload exposes an [Environment Variable](..environment-variables) to bypass all automatic config detection.
**Example in package.json:**
To use a custom config location, set the `PAYLOAD_CONFIG_PATH` environment variable:
```json
{
@@ -128,48 +193,75 @@ In addition to the above automated detection, you can specify your own location
}
```
When `PAYLOAD_CONFIG_PATH` is set, Payload will use this path to load the configuration, bypassing all automated detection.
## TypeScript
Payload exposes a variety of TypeScript settings that you can leverage on your Config's `typescript` property.
**`autoGenerate`**
By default, in Next.js development mode, Payload will auto-generate TypeScript interfaces for all collections and globals that your config defines.
You can opt out by setting `typescript.autoGenerate: false`.
**`declare`**
By default, Payload adds a `declare` block to your generated types, which makes sure that Payload uses your generated types for all Local API methods. This promotes strong typing across all of Payload's APIs. However, if you are using your Payload Config in a monorepo sub-package, and you are using it in multiple applications, you might want to disable this automatic declaration and then manually add the `declare` block to a file that you control.
In these cases, you can set `typescript.declare: false` to opt out.
**`outputFile`**
You can control the output path and filename of Payload's auto-generated types by defining the `typescript.outputFile` property to a full, absolute path.
### Importing Payload Config types
You can import config types as follows:
```ts
import { Config } from 'payload'
// This is the type used for an incoming Payload Config.
// Only the bare minimum properties are marked as required.
```
```ts
import { SanitizedConfig } from 'payload'
// This is the type used after an incoming Payload Config is fully sanitized.
// Generally, this is only used internally by Payload.
```
<Banner type="info">
<strong>Tip:</strong>
`PAYLOAD_CONFIG_PATH` can be either an absolute path, or path relative to your current working directory.
</Banner>
## Telemetry
Payload collects **completely anonymous** telemetry data about general usage. This data is super important to us and helps us accurately understand how we're growing and what we can do to build the software into everything that it can possibly be. The telemetry that we collect also help us demonstrate our growth in an accurate manner, which helps us as we seek investment to build and scale our team. If we can accurately demonstrate our growth, we can more effectively continue to support Payload as free and open-source software. To opt out of telemetry, you can pass `telemetry: false` within your Payload Config.
For more information about what we track, take a look at our [privacy policy](/privacy).
## Cross-origin resource sharing (CORS)
Cross-origin resource sharing (CORS) can be configured with either a whitelist array of URLS to allow CORS requests from, a wildcard string (`*`) to accept incoming requests from any domain, or a object with the following properties:
| Option | Description |
| --------- | --------------------------------------------------------------------------------------------------------------------------------------- |
| **`origins`** | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
| **`headers`** | A list of allowed headers that will be appended in `Access-Control-Allow-Headers`. |
Here's an example showing how to allow incoming requests from any domain:
```ts
import { buildConfig } from 'payload/config'
export default buildConfig({
// ...
cors: '*' // highlight-line
})
```
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'
export default buildConfig({
// ...
// highlight-start
cors: {
origins: ['http://localhost:3000']
headers: ['x-custom-header']
}
// highlight-end
})
```
## TypeScript
You can import types from Payload to help make writing your config easier and type-safe. There are two main types that represent the Payload Config, `Config` and `SanitizedConfig`.
The `Config` type represents a raw Payload Config in its full form. Only the bare minimum properties are marked as required. The `SanitizedConfig` type represents a Payload Config after it has been fully sanitized. Generally, this is only used internally by Payload.
```ts
import type { Config, SanitizedConfig } from 'payload'
```
## Server vs. Client
The Payload Config only lives on the server and is not allowed to contain any client-side code. That way, you can load up the Payload Config in any server environment or standalone script, without having to use Bundlers or Node.js loaders to handle importing client-only modules (e.g. scss files or React Components) without any errors.
Behind the curtains, the Next.js-based Admin Panel generates a ClientConfig, which strips away any server-only code and enriches the config with React Components.
## Compatibility flags
The Payload Config can accept compatibility flags for running the newest versions but with older databases. You should only use these flags if you need to, and should confirm that you need to prior to enabling these flags.
`allowLocalizedWithinLocalized`
Payload localization works on a field-by-field basis. As you can nest fields within other fields, you could potentially nest a localized field within a localized field—but this would be redundant and unnecessary. There would be no reason to define a localized field within a localized parent field, given that the entire data structure from the parent field onward would be localized.
By default, Payload will remove the `localized: true` property from sub-fields if a parent field is localized. Set this compatibility flag to `true` only if you have an existing Payload MongoDB database from pre-3.0, and you have nested localized fields that you would like to maintain without migrating.

View File

@@ -33,10 +33,6 @@ A migration file has two exports - an `up` function, which is called when a migr
that will be called if for some reason the migration fails to complete successfully. The `up` function should contain
all changes that you attempt to make within the migration, and the `down` should ideally revert any changes you make.
For an added level of safety, migrations should leverage Payload [transactions](/docs/database/transactions). Migration
functions should make use of the `req` by adding it to the arguments of your payload local API calls such
as `payload.create` and database adapter methods like `payload.db.create`.
Here is an example migration file:
```ts
@@ -53,6 +49,14 @@ export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
}
```
## Using Transactions
When migrations are run, each migration is performed in a new [transactions](/docs/database/transactions) for you. All
you need to do is pass the `req` object to any [local API](/docs/local-api/overview) or direct database calls, such as
`payload.db.updateMany()`, to make database changes inside the transaction. Assuming no errors were thrown, the transaction is committed
after your `up` or `down` function runs. If the migration errors at any point or fails to commit, it is caught and the
transaction gets aborted. This way no change is made to the database if the migration fails.
## Migrations Directory
Each DB adapter has an optional property `migrationDir` where you can override where you want your migrations to be
@@ -127,7 +131,7 @@ npm run payload migrate:fresh
## When to run migrations
Depending on which database adapter you use, your migration workflow might differ subtly.
Depending on which Database Adapter you use, your migration workflow might differ subtly.
In relational databases, migrations will be **required** for non-development database environments. But with MongoDB, you might only need to run migrations once in a while (or never even need them).
@@ -139,7 +143,7 @@ In this case, you can create a migration by running `pnpm payload migrate:create
#### Postgres
In relational databases like Postgres, migrations are a bit more important, because each time you add a new field or a new collection, you'll need to update the shape of your database to match your Payload config (otherwise you'll see errors upon trying to read / write your data).
In relational databases like Postgres, migrations are a bit more important, because each time you add a new field or a new collection, you'll need to update the shape of your database to match your Payload Config (otherwise you'll see errors upon trying to read / write your data).
That means that Postgres users of Payload should become familiar with the entire migration workflow from top to bottom.
@@ -167,14 +171,14 @@ But importantly, you do not need to run migrations against your development data
**2 - create a migration**
Once you're done with working in your Payload config, you can create a migration. It's best practice to try and complete a specific task or fully build out a feature before you create a migration.
Once you're done with working in your Payload Config, you can create a migration. It's best practice to try and complete a specific task or fully build out a feature before you create a migration.
But once you're ready, you can run `pnpm payload migrate:create`, which will perform the following steps for you:
- We will look for any existing migrations, and automatically generate SQL changes necessary to convert your schema from its prior state to the new state of your Payload config
- We will look for any existing migrations, and automatically generate SQL changes necessary to convert your schema from its prior state to the new state of your Payload Config
- We will then create a new migration file in your `/migrations` folder that contains all the SQL necessary to be run
We won't immediately run this migration for you, however.
We won't immediately run this migration for you, however.
<Banner type="success">
Tip: migrations created by Payload are relatively programmatic in nature, so there should not be any surprises, but before you check in the created migration it's a good idea to always double-check the contents of the migration files.
@@ -210,4 +214,33 @@ In the example above, we've specified a `ci` script which we can use as our "bui
This will require that your build pipeline can connect to your database, and it will simply run the `payload migrate` command prior to starting the build process. By calling `payload migrate`, Payload will automatically execute any migrations in your `/migrations` folder that have not yet been executed against your production database, in the order that they were created.
If it fails, the deployment will be rejected. But now, with your build script set up to run your migrations, you will be all set! Next time you deploy, your CI will execute the required migrations for you, and your database will be caught up with the shape that your Payload config requires.
If it fails, the deployment will be rejected. But now, with your build script set up to run your migrations, you will be all set! Next time you deploy, your CI will execute the required migrations for you, and your database will be caught up with the shape that your Payload Config requires.
## Running migrations in production
In certain cases, you might want to run migrations at runtime when the server starts. Running them during build time may be impossible due to not having access to your database connection while building or similar reasoning.
If you're using a long-running server or container where your Node server starts up one time and then stays initialized, you might prefer to run migrations on server startup instead of within your CI.
In order to run migrations at runtime, on initialization, you can pass your migrations to your database adapter under the `prodMigrations` key as follows:
```ts
// Import your migrations from the `index.ts` file
// that Payload generates for you
import { migrations } from './migrations'
import { buildConfig } from 'payload'
export default buildConfig({
// your config here
db: postgresAdapter({
// your adapter config here
prodMigrations: migrations
})
})
```
Passing your migrations as shown above will tell Payload, in production only, to execute any migrations that need to be run prior to completing the initialization of Payload. This is ideal for long-running services where Payload will only be initialized at startup.
<Banner type="warning">
Warning - if Payload is instructed to run migrations in production, this may slow down serverless cold starts on platforms such as Vercel. Generally, this option should only be used for long-running servers / containers.
</Banner>

View File

@@ -9,7 +9,7 @@ keywords: MongoDB, documentation, typescript, Content Management System, cms, he
To use Payload with MongoDB, install the package `@payloadcms/db-mongodb`. It will come with everything you need to
store your Payload data in MongoDB.
Then from there, pass it to your Payload config as follows:
Then from there, pass it to your Payload Config as follows:
```ts
import { mongooseAdapter } from '@payloadcms/db-mongodb'
@@ -37,6 +37,7 @@ export default buildConfig({
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
| `migrationDir` | Customize the directory that migrations are stored. |
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. |
| `collation` | Enable language-specific string comparison with customizable options. Available on MongoDB 3.4+. Defaults locale to "en". Example: `{ strength: 3 }`. For a full list of collation options and their definitions, see the [MongoDB documentation](https://www.mongodb.com/docs/manual/reference/collation/). |
## Access to Mongoose models

View File

@@ -6,20 +6,45 @@ keywords: database, mongodb, postgres, documentation, Content Management System,
desc: With Payload, you bring your own database and own your data. You have full control.
---
Payload interacts with your database via the database adapter that you choose. Right now, Payload officially supports two database adapters:
Payload is database agnostic, meaning you can use any type of database behind Payload's familiar APIs. Payload is designed to interact with your database through a Database Adapter, which is a thin layer that translates Payload's internal data structures into your database's native data structures.
1. [MongoDB](/docs/database/mongodb) w/ [Mongoose](https://mongoosejs.com/)
1. [Postgres](/docs/database/postgres) w/ [Drizzle](https://drizzle.team/)
Currently, Payload officially supports the following Database Adapters:
We will be adding support for SQLite and MySQL in the near future using Drizzle ORM.
- [MongoDB](/docs/database/mongodb) with [Mongoose](https://mongoosejs.com/)
- [Postgres](/docs/database/postgres) with [Drizzle](https://drizzle.team/)
- [SQLite](/docs/database/sqlite) with [Drizzle](https://drizzle.team/)
To use a specific database adapter, you need to install it and configure it according to its own specifications. Visit the documentation for your applicable database adapter to learn more.
To configure a Database Adapter, use the `db` property in your [Payload Config](../configuration/overview):
## Selecting a database
```ts
import { buildConfig } from 'payload'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
export default buildConfig({
// ...
// highlight-start
db: mongooseAdapter({
url: process.env.DATABASE_URI,
}),
// highlight-end
})
```
<Banner type="warning">
<strong>Reminder:</strong>
The Database Adapter is an external dependency and must be installed in your project separately from Payload. You can find the installation instructions for each Database Adapter in their respective documentation.
</Banner>
## Selecting a Database
There are several factors to consider when choosing which database technology and hosting option is right for your project and workload. Payload can theoretically support any database, but it's up to you to decide which database to use.
### When to use MongoDB
There are two main categories of databases to choose from:
- [Non-Relational Databases](#non-relational-databases)
- [Relational Databases](#relational-databases)
### Non-Relational Databases
If your project has a lot of dynamic fields, and you are comfortable with allowing Payload to enforce data integrity across your documents, MongoDB is a great choice. With it, your Payload documents are stored as _one_ document in your database—no matter if you have localization enabled, how many block or array fields you have, etc. This means that the shape of your data in your database will very closely reflect your field schema, and there is minimal complexity involved in storing or retrieving your data.
@@ -27,47 +52,21 @@ You should prefer MongoDB if:
- You prefer simplicity within your database
- You don't want to deal with keeping production / staging databases in sync via [DDL changes](https://en.wikipedia.org/wiki/Data_definition_language)
- Most (or everything) in your project is localized
- You leverage a lot of array fields, block fields, or `hasMany` select fields and similar
- Most (or everything) in your project is [Localized](../configuration/localization)
- You leverage a lot of [Arrays](../fields/array), [Blocks](../fields/blocks), or `hasMany` [Select](../fields/select) fields
### When to use a relational DB
### Relational Databases
Many projects might call for more rigid database architecture where the shape of your data is strongly enforced at the database level. For example, if you know the shape of your data and it's relatively "flat", and you don't anticipate it to change often, your workload might suit relational databases like Postgres very well.
You should prefer a relational DB like Postgres if:
You should prefer a relational DB like Postgres or SQLite if:
- You are comfortable with migration workflows
- You are comfortable with [Migrations](./migrations)
- You require enforced data consistency at the database level
- You have a lot of relationships between collections and require relationships to be enforced
### Differences in Payload features
## Payload Differences
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
It's important to note that nearly every Payload feature is available in all of our officially supported Database Adapters, including [Localization](../configuration/localization), [Arrays](../fields/array), [Blocks](../fields/blocks), etc. The only thing that is not supported in Postgres yet is the [Point Field](/docs/fields/point), but that should be added soon.
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
It's up to you to choose which database you would like to use.
## Configuration
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
Here's an example:
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
export default buildConfig({
// Your config goes here
collections: [
// Collections go here
],
// Here is where you pass your database adapter
// and the adapter will require options specific to itself
db: postgresAdapter({
pool: {
connectionString: process.env.DATABASE_URI,
},
}),
})
```
It's up to you to choose which database you would like to use based on the requirements of your project. Payload has no opinion on which database you should ultimately choose.

View File

@@ -2,24 +2,26 @@
title: Postgres
label: Postgres
order: 50
desc: Payload supports Postgres through an officially supported Drizzle database adapter.
desc: Payload supports Postgres through an officially supported Drizzle Database Adapter.
keywords: Postgres, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
---
To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It leverages Drizzle ORM and `node-postgres` to interact with a Postgres database that you provide.
Alternatively, the `@payloadcms/db-vercel-postgres` package is also available and is optimized for use with Vercel.
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
To configure Payload to use Postgres, pass the `postgresAdapter` to your Payload config as follows:
To configure Payload to use Postgres, pass the `postgresAdapter` to your Payload Config as follows:
### Usage
`@payloadcms/db-postgres`:
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
export default buildConfig({
// Your config goes here
collections: [
// Collections go here
],
// Configure the Postgres adapter here
db: postgresAdapter({
// Postgres-specific arguments go here.
@@ -31,20 +33,38 @@ export default buildConfig({
})
```
`@payloadcms/db-vercel-postgres`:
```ts
import { vercelPostgresAdapter } from '@payloadcms/db-vercel-postgres'
export default buildConfig({
// Automatically uses proces.env.POSTGRES_URL if no options are provided.
db: vercelPostgresAdapter(),
// Optionally, can accept the same options as the @vercel/postgres package.
db: vercelPostgresAdapter({
pool: {
connectionString: process.env.DATABASE_URL
},
}),
})
```
## Options
| Option | Description |
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `pool` \* | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
| `schemaName` | A string for the postgres schema to use, defaults to 'public'. |
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |
| `versionsSuffix` | A string appended to the end of table names for storing versions. Defaults to '_v'. |
| Option | Description |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `pool` \* | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres` or to `@vercel/postgres` |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `schemaName` (experimental) | A string for the postgres schema to use, defaults to 'public'. |
| `idType` | A string of 'serial', or 'uuid' that is used for the data type given to id columns. |
| `transactionOptions` | A PgTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |
| `versionsSuffix` | A string appended to the end of table names for storing versions. Defaults to '_v'. |
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
## Access to Drizzle
@@ -68,14 +88,145 @@ In addition to exposing Drizzle directly, all of the tables, Drizzle relations,
Drizzle exposes two ways to work locally in development mode.
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload Config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload Config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
Alternatively, you can disable `push` and rely solely on migrations to keep your local database in sync with your Payload config.
Alternatively, you can disable `push` and rely solely on migrations to keep your local database in sync with your Payload Config.
## Migration workflows
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).
## Drizzle schema hooks
### beforeSchemaInit
Runs before the schema is built. You can use this hook to extend your database structure with tables that won't be managed by Payload.
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { integer, pgTable, serial } from 'drizzle-orm/pg-core'
postgresAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
return {
...schema,
tables: {
...schema.tables,
addedTable: pgTable('added_table', {
id: serial('id').notNull(),
}),
},
}
},
],
})
```
One use case is preserving your existing database structure when migrating to Payload. By default, Payload drops the current database schema, which may not be desirable in this scenario.
To quickly generate the Drizzle schema from your database you can use [Drizzle Introspection](https://orm.drizzle.team/kit-docs/commands#introspect--pull)
You should get the `schema.ts` file which may look like this:
```ts
import { pgTable, uniqueIndex, serial, varchar, text } from 'drizzle-orm/pg-core'
export const users = pgTable('users', {
id: serial('id').primaryKey(),
fullName: text('full_name'),
phone: varchar('phone', { length: 256 }),
})
export const countries = pgTable(
'countries',
{
id: serial('id').primaryKey(),
name: varchar('name', { length: 256 }),
},
(countries) => {
return {
nameIndex: uniqueIndex('name_idx').on(countries.name),
}
},
)
```
You can import them into your config and append to the schema with the `beforeSchemaInit` hook like this:
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { users, countries } from '../drizzle/schema'
postgresAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
return {
...schema,
tables: {
...schema.tables,
users,
countries
},
}
},
],
})
```
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
### afterSchemaInit
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
```ts
import { postgresAdapter } from '@payloadcms/db-postgres'
import { index, integer } from 'drizzle-orm/pg-core'
import { buildConfig } from 'payload'
export default buildConfig({
collections: [
{
slug: 'places',
fields: [
{
name: 'country',
type: 'text',
},
{
name: 'city',
type: 'text',
},
],
},
],
db: postgresAdapter({
afterSchemaInit: [
({ schema, extendTable, adapter }) => {
extendTable({
table: schema.tables.places,
columns: {
extraIntegerColumn: integer('extra_integer_column'),
},
extraConfig: (table) => ({
country_city_composite_index: index('country_city_composite_index').on(
table.country,
table.city,
),
}),
})
return schema
},
],
}),
})
```

212
docs/database/sqlite.mdx Normal file
View File

@@ -0,0 +1,212 @@
---
title: SQLite
label: SQLite
order: 60
desc: Payload supports SQLite through an officially supported Drizzle Database Adapter.
keywords: SQLite, documentation, typescript, Content Management System, cms, headless, javascript, node, react, nextjs
---
To use Payload with SQLite, install the package `@payloadcms/db-sqlite`. It leverages Drizzle ORM and `libSQL` to interact with a SQLite database that you provide.
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
To configure Payload to use SQLite, pass the `sqliteAdapter` to your Payload Config as follows:
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
export default buildConfig({
// Your config goes here
collections: [
// Collections go here
],
// Configure the SQLite adapter here
db: sqliteAdapter({
// SQLite-specific arguments go here.
// `client.url` is required.
client: {
url: process.env.DATABASE_URL,
authToken: process.env.DATABASE_AUTH_TOKEN,
}
}),
})
```
## Options
| Option | Description |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `client` \* | [Client connection options](https://orm.drizzle.team/docs/get-started-sqlite#turso) that will be passed to `createClient` from `@libsql/client`. |
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
| `migrationDir` | Customize the directory that migrations are stored. |
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
| `transactionOptions` | A SQLiteTransactionConfig object for transactions, or set to `false` to disable using transactions. [More details](https://orm.drizzle.team/docs/transactions) |
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |
| `versionsSuffix` | A string appended to the end of table names for storing versions. Defaults to '_v'. |
| `beforeSchemaInit` | Drizzle schema hook. Runs before the schema is built. [More Details](#beforeschemainit) |
| `afterSchemaInit` | Drizzle schema hook. Runs after the schema is built. [More Details](#afterschemainit) |
## Access to Drizzle
After Payload is initialized, this adapter will expose the full power of Drizzle to you for use if you need it.
You can access Drizzle as follows:
```text
payload.db.drizzle
```
## Tables and relations
In addition to exposing Drizzle directly, all of the tables and Drizzle relations are exposed for you via the `payload.db` property as well.
- Tables - `payload.db.tables`
- Relations - `payload.db.relations`
## Prototyping in development mode
Drizzle exposes two ways to work locally in development mode.
The first is [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push), which automatically pushes changes you make to your Payload Config (and therefore, Drizzle schema) to your database so you don't have to manually migrate every time you change your Payload Config. This only works in development mode, and should not be mixed with manually running [`migrate`](/docs/database/migrations) commands.
You will be warned if any changes that you make will entail data loss while in development mode. Push is enabled by default, but you can opt out if you'd like.
Alternatively, you can disable `push` and rely solely on migrations to keep your local database in sync with your Payload Config.
## Migration workflows
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).
## Drizzle schema hooks
### beforeSchemaInit
Runs before the schema is built. You can use this hook to extend your database structure with tables that won't be managed by Payload.
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { integer, sqliteTable } from 'drizzle-orm/sqlite-core'
sqliteAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
return {
...schema,
tables: {
...schema.tables,
addedTable: sqliteTable('added_table', {
id: integer('id').primaryKey({ autoIncrement: true }),
}),
},
}
},
],
})
```
One use case is preserving your existing database structure when migrating to Payload. By default, Payload drops the current database schema, which may not be desirable in this scenario.
To quickly generate the Drizzle schema from your database you can use [Drizzle Introspection](https://orm.drizzle.team/kit-docs/commands#introspect--pull)
You should get the `schema.ts` file which may look like this:
```ts
import { sqliteTable, text, uniqueIndex, integer } from 'drizzle-orm/sqlite-core'
export const users = sqliteTable('users', {
id: integer('id').primaryKey({ autoIncrement: true }),
fullName: text('full_name'),
phone: text('phone', {length: 256}),
})
export const countries = sqliteTable(
'countries',
{
id: integer('id').primaryKey({ autoIncrement: true }),
name: text('name', { length: 256 }),
},
(countries) => {
return {
nameIndex: uniqueIndex('name_idx').on(countries.name),
}
},
)
```
You can import them into your config and append to the schema with the `beforeSchemaInit` hook like this:
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { users, countries } from '../drizzle/schema'
sqliteAdapter({
beforeSchemaInit: [
({ schema, adapter }) => {
return {
...schema,
tables: {
...schema.tables,
users,
countries
},
}
},
],
})
```
Make sure Payload doesn't overlap table names with its collections. For example, if you already have a collection with slug "users", you should either change the slug or `dbName` to change the table name for this collection.
### afterSchemaInit
Runs after the Drizzle schema is built. You can use this hook to modify the schema with features that aren't supported by Payload, or if you want to add a column that you don't want to be in the Payload config.
To extend a table, Payload exposes `extendTable` utillity to the args. You can refer to the [Drizzle documentation](https://orm.drizzle.team/docs/sql-schema-declaration).
The following example adds the `extra_integer_column` column and a composite index on `country` and `city` columns.
```ts
import { sqliteAdapter } from '@payloadcms/db-sqlite'
import { index, integer } from 'drizzle-orm/sqlite-core'
import { buildConfig } from 'payload'
export default buildConfig({
collections: [
{
slug: 'places',
fields: [
{
name: 'country',
type: 'text',
},
{
name: 'city',
type: 'text',
},
],
},
],
db: sqliteAdapter({
afterSchemaInit: [
({ schema, extendTable, adapter }) => {
extendTable({
table: schema.tables.places,
columns: {
extraIntegerColumn: integer('extra_integer_column'),
},
extraConfig: (table) => ({
country_city_composite_index: index('country_city_composite_index').on(
table.country,
table.city,
),
}),
})
return schema
},
],
}),
})
```

View File

@@ -68,3 +68,49 @@ The following functions can be used for managing transactions:
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
`payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
Payload uses the `req` object to pass the transaction ID through to the database adapter. If you are not using the `req` object, you can make a new object to pass the transaction ID directly to database adapter methods and local API calls.
Example:
```ts
import payload from 'payload'
import config from './payload.config'
const standalonePayloadScript = async () => {
// initialize Payload
await payload.init({ config })
const transactionID = await payload.db.beginTransaction()
try {
// Make an update using the local API
await payload.update({
collection: 'posts',
data: {
some: 'data',
},
where: {
slug: { equals: 'my-slug' }
},
req: { transactionID },
})
/*
You can make additional db changes or run other functions
that need to be committed on an all or nothing basis
*/
// Commit the transaction
await payload.db.commitTransaction(transactionID)
} catch (error) {
// Rollback the transaction
await payload.db.rollbackTransaction(transactionID)
}
}
standalonePayloadScript()
```
## Disabling Transactions
If you wish to disable transactions entirely, you can do so by passing `false` as the `transactionOptions` in your database adapter configuration. All the official Payload database adapters support this option.

View File

@@ -10,7 +10,7 @@ keywords: email, overview, config, configuration, documentation, Content Managem
Payload has a few email adapters that can be imported to enable email functionality. The [@payloadcms/email-nodemailer](https://www.npmjs.com/package/@payloadcms/email-nodemailer) package will be the package most will want to install. This package provides an easy way to use [Nodemailer](https://nodemailer.com) for email and won't get in your way for those already familiar.
The email adapter should be passed into the `email` property of the Payload config. This will allow Payload to send emails for things like password resets, new user verification, and any other email sending needs you may have.
The email adapter should be passed into the `email` property of the Payload Config. This will allow Payload to send [auth-related emails](../authentication/email) for things like password resets, new user verification, and any other email sending needs you may have.
## Configuration
@@ -49,7 +49,7 @@ Simple Mail Transfer Protocol (SMTP) options can be passed in using the `transpo
**Example email options using SMTP:**
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
export default buildConfig({
@@ -72,7 +72,7 @@ export default buildConfig({
**Example email options using nodemailer.createTransport:**
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
import nodemailer from 'nodemailer'
@@ -99,7 +99,7 @@ You also have the ability to bring your own nodemailer transport. This is an exa
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
import { nodemailerAdapter } from '@payloadcms/email-nodemailer'
import nodemailerSendgrid from 'nodemailer-sendgrid'
@@ -136,7 +136,7 @@ The Resend adapter requires an API key to be passed in the options. This can be
| apiKey | The API key for the Resend service. |
```ts
import { buildConfig } from 'payload/config'
import { buildConfig } from 'payload'
import { resendAdapter } from '@payloadcms/email-resend'
export default buildConfig({
@@ -150,7 +150,7 @@ export default buildConfig({
## Sending Mail
With a working transport you can call it anywhere you have access to payload by calling `payload.sendEmail(message)`. The `message` will contain the `to`, `subject` and `html` or `text` for the email being sent. Other options are also available and can be seen in the sendEmail args. Support for these will depend on the adapter being used.
With a working transport you can call it anywhere you have access to Payload by calling `payload.sendEmail(message)`. The `message` will contain the `to`, `subject` and `html` or `text` for the email being sent. Other options are also available and can be seen in the sendEmail args. Support for these will depend on the adapter being used.
```ts
// Example of sending an email

View File

@@ -11,6 +11,7 @@ Payload provides a vast array of examples to help you get started with your proj
Examples are changing every day, so be sure to check back often to see what new examples have been added. If you have a specific example you would like to see, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.
- [Auth](https://github.com/payloadcms/payload/tree/main/examples/auth)
- [Custom Components](https://github.com/payloadcms/payload/tree/main/examples/custom-components)
- [Custom Server](https://github.com/payloadcms/payload/tree/main/examples/custom-server)
- [Draft Preview](https://github.com/payloadcms/payload/tree/main/examples/draft-preview)
- [Email](https://github.com/payloadcms/payload/tree/main/examples/email)

View File

@@ -2,57 +2,84 @@
title: Array Field
label: Array
order: 20
desc: Array fields are intended for sets of repeating fields, that you define. Learn how to use array fields, see examples and options.
desc: Array Fields are intended for sets of repeating fields, that you define. Learn how to use Array Fields, see examples and options.
keywords: array, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Array field type is used when you need to have a set of "repeating" fields. It stores an array
of objects containing the fields that you define. Its uses can be simple or highly complex.
</Banner>
The Array Field is used when you need to have a set of "repeating" [Fields](./overview). It stores an array of objects containing fields that you define. These fields can be of any type, including other arrays to achieve infinitely nested structures.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/array.png"
srcDark="https://payloadcms.com/images/docs/fields/array-dark.png"
alt="Array field with two Rows in Payload admin panel"
caption="Admin Panel screenshot of an Array field with two Rows"
/>
**Example uses:**
Arrays are useful for many different types of content from simple to complex, such as:
- A "slider" with an image ([upload field](/docs/fields/upload)) and a caption ([text field](/docs/fields/text))
- Navigational structures where editors can specify nav items containing pages ([relationship field](/docs/fields/relationship)), an "open in new tab" [checkbox field](/docs/fields/checkbox)
- Event agenda "timeslots" where you need to specify start & end time ([date field](/docs/fields/date)), label ([text field](/docs/fields/text)), and Learn More page [relationship](/docs/fields/relationship)
## Config
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/array.png"
srcDark="https://payloadcms.com/images/docs/fields/array-dark.png"
alt="Array field with two Rows in Payload Admin Panel"
caption="Admin Panel screenshot of an Array field with two Rows"
/>
To create an Array Field, set the `type` to `array` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyArrayField: Field = {
// ...
// highlight-start
type: 'array',
fields: [
// ...
],
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as the heading in the [Admin Panel](../admin/overview) or an object with keys for each language. Auto-generated from name if not defined. |
| **`label`** | Text used as the heading in the [Admin Panel](../admin/overview) or an object with keys for each language. Auto-generated from name if not defined. |
| **`fields`** \* | Array of field types to correspond to each row of the Array. |
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More](/docs/fields/overview#validation) |
| **`validate`** | Provide a custom validation function that will be executed on both the [Admin Panel](../admin/overview) and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide an array of row data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Array will be kept, so there is no need to specify each nested field as `localized`. |
| **`required`** | Require this field to have a value. |
| **`labels`** | Customize the row labels appearing in the Admin dashboard. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`dbName`** | Custom table name for the field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`dbName`** | Custom table name for the field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
The 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'
export const MyArrayField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Array Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
@@ -62,10 +89,10 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
## Example
`collections/ExampleCollection.ts`
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/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -2,16 +2,17 @@
title: Blocks Field
label: Blocks
order: 30
desc: The Blocks field type is a great layout build and can be used to construct any flexible content model. Learn how to use Block fields, see examples and options.
desc: The Blocks Field is a great layout build and can be used to construct any flexible content model. Learn how to use Block Fields, see examples and options.
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Blocks field type is <strong>incredibly powerful</strong> and can be used as a{' '}
<em>layout builder</em> as well as to define any other flexible content model you can think of. It
stores an array of objects, where each object must match the shape of one of your provided block
configs.
</Banner>
The Blocks Field is <strong>incredibly powerful</strong>, storing an array of objects based on the fields that your define, where each item in the array is a "block" with its own unique schema.
Blocks are a great way to create a flexible content model that can be used to build a wide variety of content types, including:
- A layout builder tool that grants editors to design highly customizable page or post layouts. Blocks could include configs such as `Quote`, `CallToAction`, `Slider`, `Content`, `Gallery`, or others.
- A form builder tool where available block configs might be `Text`, `Select`, or `Checkbox`.
- Virtual event agenda "timeslots" where a timeslot could either be a `Break`, a `Presentation`, or a `BreakoutSession`.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/blocks.png"
@@ -20,13 +21,23 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
caption="Admin Panel screenshot of add Blocks drawer view"
/>
**Example uses:**
To add a Blocks Field, set the `type` to `blocks` in your [Field Config](./overview):
- A layout builder tool that grants editors to design highly customizable page or post layouts. Blocks could include configs such as `Quote`, `CallToAction`, `Slider`, `Content`, `Gallery`, or others.
- A form builder tool where available block configs might be `Text`, `Select`, or `Checkbox`.
- Virtual event agenda "timeslots" where a timeslot could either be a `Break`, a `Presentation`, or a `BreakoutSession`.
```ts
import type { Field } from 'payload/types'
## Field config
export const MyBlocksField: Field = {
// ...
// highlight-start
type: 'blocks',
blocks: [
// ...
],
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -36,30 +47,44 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. |
| **`maxRows`** | A number for the most allowed items during validation when a value is present. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-level hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-level access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API response or the Admin Panel. |
| **`defaultValue`** | Provide an array of block data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this field will be kept, so there is no need to specify each nested field as `localized`. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`labels`** | Customize the block row labels appearing in the Admin dashboard. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
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'
export const MyBlocksField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Blocks Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ---------------------------------- |
| **`initCollapsed`** | Set the initial collapsed state |
| **`isSortable`** | Disable order sorting by setting this value to `false` |
## Block configs
## Block Configs
Blocks are defined as separate configs of their own.
@@ -82,7 +107,7 @@ Blocks are defined as separate configs of their own.
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
| **`dbName`** | Custom table name for this block type when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
| **`dbName`** | Custom table name for this block type when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
### Auto-generated data per block
@@ -102,7 +127,7 @@ The Admin Panel provides each block with a `blockName` field which optionally al
`collections/ExampleCollection.js`
```ts
import { Block, CollectionConfig } from 'payload/types'
import { Block, CollectionConfig } from 'payload'
const QuoteBlock: Block = {
slug: 'Quote', // required
@@ -145,5 +170,5 @@ export const ExampleCollection: CollectionConfig = {
As you build your own Block configs, you might want to store them in separate files but retain typing accordingly. To do so, you can import and use Payload's `Block` type:
```ts
import type { Block } from 'payload/types'
import type { Block } from 'payload'
```

View File

@@ -6,16 +6,27 @@ desc: Checkbox field types allow the developer to save a boolean value in the da
keywords: checkbox, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>The Checkbox field type saves a boolean in the database.</Banner>
The Checkbox Field saves a boolean in the database.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/checkbox.png"
srcDark="https://payloadcms.com/images/docs/fields/checkbox-dark.png"
alt="Checkbox field with text field in Payload admin panel"
alt="Checkbox field with text field in Payload Admin Panel"
caption="Admin Panel screenshot of Checkbox field with Text field below"
/>
## Config
To add a Checkbox Field, set the `type` to `checkbox` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyCheckboxField: Field = {
// ...
type: 'checkbox', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -23,25 +34,26 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value, will default to false if field is also `required`. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Example
`collections/ExampleCollection.ts`
Here is an example of a Checkbox Field in a Collection:
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -7,21 +7,27 @@ desc: The Code field type will store any string in the Database. Learn how to us
keywords: code, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Code field type saves a string in the database, but provides the Admin Panel with a code
editor styled interface.
</Banner>
The Code Field saves a string in the database, but provides the [Admin Panel](../admin/overview) with a code editor styled interface.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/code.png"
srcDark="https://payloadcms.com/images/docs/fields/code-dark.png"
alt="Shows a Code field in the Payload admin panel"
caption="Admin Panel screenshot of a Code field"
alt="Shows a Code field in the Payload Admin Panel"
caption="This field is using the `monaco-react` editor syntax highlighting."
/>
This field uses the `monaco-react` editor syntax highlighting.
To add a Code Field, set the `type` to `code` in your [Field Config](./overview):
## Config
```ts
import type { Field } from 'payload/types'
export const MyBlocksField: Field = {
// ...
type: 'code', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -32,22 +38,36 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
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'
export const MyCodeField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Code Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -59,7 +79,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
`collections/ExampleCollection.ts
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,32 +6,58 @@ desc: With the Collapsible field, you can place fields within a collapsible layo
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Collapsible field is presentational-only and only affects the Admin Panel. By using it, you
can place fields within a nice layout component that can be collapsed / expanded.
</Banner>
The Collapsible Field is presentational-only and only affects the Admin Panel. By using it, you can place fields within a nice layout component that can be collapsed / expanded.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/collapsible.png"
srcDark="https://payloadcms.com/images/docs/fields/collapsible-dark.png"
alt="Shows a Collapsible field in the Payload admin panel"
alt="Shows a Collapsible field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Collapsible field"
/>
## Config
To add a Collapsible Field, set the `type` to `collapsible` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyCollapsibleField: Field = {
// ...
// highlight-start
type: 'collapsible',
fields: [
// ...
],
// highlight-end
}
```
## Config Options
| Option | Description |
| --------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`label`** \* | A label to render within the header of the collapsible component. This can be a string, function or react component. Function/components receive `({ data, path })` as args. |
| **`fields`** \* | Array of field types to nest within this Collapsible. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
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'
export const MyCollapsibleField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Collapsible Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------- |
@@ -42,7 +68,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,21 +6,27 @@ desc: The Date field type stores a Date in the database. Learn how to use and cu
keywords: date, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Date field type saves a Date in the database and provides the Admin Panel with a customizable
time picker interface.
</Banner>
The Date Field saves a Date in the database and provides the [Admin Panel](../admin/overview) with a customizable time picker interface.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/date.png"
srcDark="https://payloadcms.com/images/docs/fields/date-dark.png"
alt="Shows a Date field in the Payload admin panel"
caption="Admin Panel screenshot of a Date field"
alt="Shows a Date field in the Payload Admin Panel"
caption="This field is using the `react-datepicker` component for UI."
/>
This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepicker) for the Admin Panel component.
To add a Date Field, set the `type` to `date` in your [Field Config](./overview):
## Config
```ts
import type { Field } from 'payload/types'
export const MyDateField: Field = {
// ...
type: 'date', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -28,22 +34,36 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the admin panel via the `date` property.
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'
export const MyDateField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Date Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
@@ -77,7 +97,7 @@ When only `pickerAppearance` is set, an equivalent format will be rendered in th
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,16 +6,27 @@ desc: The Email field enforces that the value provided is a valid email address.
keywords: email, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>The Email field enforces that the value provided is a valid email address.</Banner>
The Email Field enforces that the value provided is a valid email address.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/email.png"
srcDark="https://payloadcms.com/images/docs/fields/email-dark.png"
alt="Shows an Email field in the Payload admin panel"
alt="Shows an Email field in the Payload Admin Panel"
caption="Admin Panel screenshot of an Email field"
/>
## Config
To create an Email Field, set the `type` to `email` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyEmailField: Field = {
// ...
type: 'email', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -24,37 +35,48 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), this field type allows for the following `admin` properties:
The customize the appearance and behavior of the Email Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`placeholder`**
```ts
import type { Field } from 'payload/types'
Set this property to define a placeholder string for the field.
export const MyEmailField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`autoComplete`**
The Email Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set this property to a string that will be used for browser autocomplete.
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string for the field. |
| **`autoComplete`** | Set this property to a string that will be used for browser autocomplete. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,19 +6,32 @@ desc: The Group field allows other fields to be nested under a common property.
keywords: group, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Group field allows fields to be nested under a common property name. It also groups fields
together visually in the Admin Panel.
</Banner>
The Group Field allows [Fields](./overview) to be nested under a common property name. It also groups fields together visually in the [Admin Panel](../admin/overview).
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/group.png"
srcDark="https://payloadcms.com/images/docs/fields/group-dark.png"
alt="Shows a Group field in the Payload admin panel"
alt="Shows a Group field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Group field"
/>
## Config
To add a Group Field, set the `type` to `group` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyGroupField: Field = {
// ...
// highlight-start
type: 'group',
fields: [
// ...
],
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -26,33 +39,47 @@ keywords: group, fields, config, configuration, documentation, Content Managemen
| **`fields`** \* | Array of field types to nest within this Group. |
| **`label`** | Used as a heading in the Admin Panel and to name the generated GraphQL type. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide an object of data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Group will be kept, so there is no need to specify each nested field as `localized`. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Group allows for the following admin property:
The customize the appearance and behavior of the Group Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`hideGutter`**
```ts
import type { Field } from 'payload/types'
Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
export const MyGroupField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Group Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`hideGutter`** | Set this property to `true` to hide this field's gutter within the Admin Panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

242
docs/fields/join.mdx Normal file
View File

@@ -0,0 +1,242 @@
---
title: Join Field
label: Join
order: 140
desc: The Join field provides the ability to work on related documents. Learn how to use Join field, see examples and options.
keywords: join, relationship, junction, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
The Join Field is used to make Relationship fields in the opposite direction. It is used to show the relationship from
the other side. The field itself acts as a virtual field, in that no new data is stored on the collection with a Join
field. Instead, the Admin UI surfaces the related documents for a better editing experience and is surfaced by Payload's
APIs.
The Join field is useful in scenarios including:
- To surface `Order`s for a given `Product`
- To view and edit `Posts` belonging to a `Category`
- To work with any bi-directional relationship data
<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"
/>
For the Join field to work, you must have an existing [relationship](./relationship) field in the collection you are
joining. This will reference the collection and path of the field of the related documents.
To add a Relationship Field, set the `type` to `join` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyJoinField: Field = {
// highlight-start
name: 'relatedPosts',
type: 'join',
collection: 'posts',
on: 'category',
// highlight-end
}
// relationship field in another collection:
export const MyRelationshipField: Field = {
name: 'category',
type: 'relationship',
relationTo: 'categories',
}
```
In this example, the field is defined to show the related `posts` when added to a `category` collection. The `on`
property is used to
specify the relationship field name of the field that relates to the collection document.
With this example, if you navigate to a Category in the Admin UI or an API response, you'll now see that the Posts which
are related to the Category are populated for you. This is extremely powerful and can be used to define a wide variety
of relationship types in an easy manner.
<Banner type="success">
The Join field is extremely performant and does not add additional query overhead to your API responses until you add depth of 1 or above. It works in all database adapters. In MongoDB, we use <strong>aggregations</strong> to automatically join in related documents, and in relational databases, we use joins.
</Banner>
### Schema advice
When modeling your database, you might come across many places where you'd like to feature bi-directional relationships.
But here's an important consideration—you generally only want to store information about a given relationship in _one_
place.
Let's take the Posts and Categories example. It makes sense to define which category a post belongs to while editing the
post.
It would generally not be necessary to have a list of post IDs stored directly on the category as well, for a few
reasons:
- You want to have a "single source of truth" for relationships, and not worry about keeping two sources in sync with
one another
- If you have hundreds, thousands, or even millions of posts, you would not want to store all of those post IDs on a
given category
- Etc.
This is where the `join` field is especially powerful. With it, you only need to store the `category_id` on the `post`,
and Payload will automatically join in related posts for you when you query for categories. The related category is only
stored on the post itself - and is not duplicated on both sides. However, the `join` field is what enables
bi-directional APIs and UI for you.
### Using the Join field to have full control of your database schema
For typical polymorphic / many relationships, if you're using Postgres or SQLite, Payload will automatically create
a `posts_rels` table, which acts as a junction table to store all of a given document's relationships.
However, this might not be appropriate for your use case if you'd like to have more control over your database
architecture. You might not want to have that `_rels` table, and would prefer to maintain / control your own junction
table design.
<Banner type="success">
With the Join field, you can control your own junction table design, and avoid Payload's automatic _rels table creation.
</Banner>
The `join` field can be used in conjunction with _any_ collection - and if you wanted to define your own "junction"
collection, which, say, is called `categories_posts` and has a `post_id` and a `category_id` column, you can achieve
complete control over the shape of that junction table.
You could go a step further and leverage the `admin.hidden` property of the `categories_posts` collection to hide the
collection from appearing in the Admin UI navigation.
#### Specifying additional fields on relationships
Another very powerful use case of the `join` field is to be able to define "context" fields on your relationships. Let's
say that you have Posts and Categories, and use join fields on both your Posts and Categories collection to join in
related docs from a new pseudo-junction collection called `categories_posts`. Now, the relations are stored in this
third junction collection, and can be surfaced on both Posts and Categories. But, importantly, you could add
additional "context" fields to this shared junction collection.
For example, on this `categories_posts` collection, in addition to having the `category` and
post` fields, we could add custom "context" fields like `featured` or `
spotlight`, which would allow you to store additional information directly on relationships. The `join` field gives you
complete control over any type of relational architecture in Payload, all wrapped up in a powerful Admin UI.
## Config Options
| Option | Description |
|------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| **`name`** \* | To be used as the property name when retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`collection`** \* | The `slug`s having the relationship field. |
| **`on`** \* | The relationship field name of the field that relates to collection document. Use dot notation for nested paths, like 'myGroup.relationName'. |
| **`maxDepth`** | Default is 1, Sets a maximum population depth for this field, regardless of the remaining depth when this field is reached. [Max Depth](/docs/getting-started/concepts#field-level-max-depth) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
_\* An asterisk denotes that a property is required._
## Join Field Data
When a document is returned that for a Join field is populated with related documents. The structure returned is an
object with:
- `docs` an array of related documents or only IDs if the depth is reached
- `hasNextPage` a boolean indicating if there are additional documents
```json
{
"id": "66e3431a3f23e684075aae9c",
"relatedPosts": {
"docs": [
{
"id": "66e3431a3f23e684075aaeb9",
// other fields...
"category": "66e3431a3f23e684075aae9c",
},
// { ... }
],
"hasNextPage": false
},
// other fields...
}
```
## Query Options
The Join Field supports custom queries to filter, sort, and limit the related documents that will be returned. In
addition to the specific query options for each Join Field, you can pass `joins: false` to disable all Join Field from
returning. This is useful for performance reasons when you don't need the related documents.
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 |
These can be applied to the local API, GraphQL, and REST API.
### Local API
By adding `joins` to the local API you can customize the request for each join field by the `name` of the field.
```js
const result = await db.findOne('categories', {
where: {
title: {
equals: 'My Category'
}
},
joins: {
relatedPosts: {
limit: 5,
where: {
title: {
equals: 'My Post'
}
},
sort: 'title'
}
}
})
```
### Rest API
The rest API supports the same query options as the local API. You can use the `joins` query parameter to customize the
request for each join field by the `name` of the field. For example, an API call to get a document with the related
posts limited to 5 and sorted by title:
`/api/categories/${id}?joins[relatedPosts][limit]=5&joins[relatedPosts][sort]=title`
You can specify as many `joins` parameters as needed for the same or different join fields for a single request.
### 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.
Example:
```graphql
query {
Categories {
docs {
relatedPosts(
sort: "createdAt"
limit: 5
where: {
author: {
equals: "66e3431a3f23e684075aaeb9"
}
}
) {
docs {
title
}
hasNextPage
}
}
}
}
```

View File

@@ -7,21 +7,27 @@ desc: The JSON field type will store any string in the Database. Learn how to us
keywords: json, jsonSchema, schema, validation, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The JSON field type saves actual JSON in the database, which differs from the Code field that
saves the value as a string in the database.
</Banner>
The JSON Field saves actual JSON in the database, which differs from the Code field that saves the value as a string in the database.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/json.png"
srcDark="https://payloadcms.com/images/docs/fields/json-dark.png"
alt="Shows a JSON field in the Payload admin panel"
caption="Admin Panel screenshot of a JSON field"
alt="Shows a JSON field in the Payload Admin Panel"
caption="This field is using the `monaco-react` editor syntax highlighting."
/>
This field uses the `monaco-react` editor syntax highlighting.
To add a JSON Field, set the `type` to `json` in your [Field Config](./overview):
## Config
```ts
import type { Field } from 'payload/types'
export const MyJSONField: Field = {
// ...
type: 'json', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -31,22 +37,36 @@ This field uses the `monaco-react` editor syntax highlighting.
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin Config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
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'
export const MyJSONField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The JSON Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Option | Description |
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -57,7 +77,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -82,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/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -115,7 +135,7 @@ export const ExampleCollection: CollectionConfig = {
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,19 +6,27 @@ desc: Number fields store and validate numeric data. Learn how to use and format
keywords: number, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Number field stores and validates numeric entry and supports additional numerical validation
and formatting features.
</Banner>
The Number Field stores and validates numeric entry and supports additional numerical validation and formatting features.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/number.png"
srcDark="https://payloadcms.com/images/docs/fields/number-dark.png"
alt="Shows a Number field in the Payload admin panel"
alt="Shows a Number field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Number field"
/>
## Config
To add a Number Field, set the `type` to `number` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyNumberField: Field = {
// ...
type: 'number', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -32,41 +40,49 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), this field type allows for the following `admin` properties:
The customize the appearance and behavior of the Number Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`step`**
```ts
import type { Field } from 'payload/types'
Set a value for the number field to increment / decrement using browser controls.
export const MyNumberField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`placeholder`**
The Number Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set this property to define a placeholder string for the field.
**`autoComplete`**
Set this property to a string that will be used for browser autocomplete.
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`step`** | Set a value for the number field to increment / decrement using browser controls. |
| **`placeholder`** | Set this property to define a placeholder string for the field. |
| **`autoComplete`** | Set this property to a string that will be used for browser autocomplete. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -2,13 +2,26 @@
title: Fields Overview
label: Overview
order: 10
desc: Fields are the building blocks of Payload, find out how to add or remove a field, change field type, add hooks, define access control and validation.
desc: Fields are the building blocks of Payload, find out how to add or remove a field, change field type, add hooks, define Access Control and Validation.
keywords: overview, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
Fields are the building blocks of Payload. Both [Collections](../configuration/collections) and [Globals](../configuration/globals) use fields to define the shape of the data that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the [Admin Panel](../admin/overview).
Fields are the building blocks of Payload. They define the schema of the Documents that will be stored in the [Database](../database/overview), as well as automatically generate the corresponding UI within the [Admin Panel](../admin/overview).
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validations), [Conditional Logic](../admin/fields#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
There are many [Field Types](#field-types) to choose from, ranging anywhere from simple text strings to nested arrays and blocks. Most fields save data to the database, while others are strictly presentational. Fields can have [Custom Validations](#validation), [Conditional Logic](../admin/fields#conditional-logic), [Access Control](#field-level-access-control), [Hooks](#field-level-hooks), and so much more.
To configure fields, use the `fields` property in your [Collection](../configuration/collections) or [Global](../configuration/globals) config:
```ts
import type { CollectionConfig } from 'payload'
export const Page: CollectionConfig = {
// ...
fields: [ // highlight-line
// ...
]
}
```
<Banner type="success">
You can fully customize the appearance and behavior of all fields within the Admin Panel. [More details](../admin/fields).
@@ -130,6 +143,7 @@ The following field names are forbidden and cannot be used:
- `__v`
- `salt`
- `hash`
- `file`
### Field-level Hooks
@@ -191,7 +205,9 @@ export const MyField: Field = {
}
```
Default values can be defined as a static string or a function that returns a string. Functions are called with the following arguments:
Default values can be defined as a static value or a function that returns a value. When a `defaultValue` is defined statically, Payload's DB adapters will apply it to the database schema or models.
Functions can be written to make use of the following argument properties:
- `user` - the authenticated user object
- `locale` - the currently selected locale string
@@ -221,7 +237,7 @@ export const myField: Field = {
You can use async `defaultValue` functions to fill fields with data from API requests.
</Banner>
### Validations
### Validation
Fields are automatically validated based on their [Field Type](#field-types) and other [Field Options](#field-options) such as `required` or `min` and `max` value constraints. If needed, however, field validations can be customized or entirely replaced by providing your own custom validation functions.
@@ -280,7 +296,7 @@ When using custom validation functions, Payload will use yours in place of the d
To reuse default field validations, call them from within your custom validation function:
```ts
import { text } from 'payload/fields/validations'
import { text } from 'payload/shared'
const field: Field = {
name: 'notBad',
@@ -361,6 +377,8 @@ export const MyCollection: CollectionConfig = {
<Banner type="warning">
<strong>Reminder:</strong>
The Custom ID Fields can only be of type [`Number`](./number) or [`Text`](./text).
Custom ID fields with type `text` must not contain `/` or `.` characters.
</Banner>
## TypeScript

View File

@@ -3,27 +3,33 @@ title: Point Field
label: Point
order: 110
desc: The Point field type stores coordinates in the database. Learn how to use Point field for geolocation and geometry.
keywords: point, geolocation, geospatial, geojson, 2dsphere, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Point field type saves a pair of coordinates in the database and assigns an index for location
related queries.
</Banner>
<Banner type="warning">
<strong>Note:</strong> The Point field type is currently only supported in MongoDB.
</Banner>
The Point Field saves a pair of coordinates in the database and assigns an index for location related queries. The data structure in the database matches the GeoJSON structure to represent point. The Payload APIs simplifies the object data to only the [longitude, latitude] location.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/point.png"
srcDark="https://payloadcms.com/images/docs/fields/point-dark.png"
alt="Shows a Point field in the Payload admin panel"
alt="Shows a Point field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Point field"
/>
The data structure in the database matches the GeoJSON structure to represent point. The Payload APIs simplifies the object data to only the [longitude, latitude] location.
To add a Point Field, set the `type` to `point` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyPointField: Field = {
// ...
type: 'point', // highlight-line
}
```
<Banner type="warning">
<strong>Important:</strong>
The Point Field is currently only supported in MongoDB.
</Banner>
## Config
@@ -34,29 +40,26 @@ The data structure in the database matches the GeoJSON structure to represent po
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Note:</strong> The Point field type is currently only supported in MongoDB.
</Banner>
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,19 +6,32 @@ desc: The Radio field type allows for the selection of one value from a predefin
keywords: radio, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Radio Group field type allows for the selection of one value from a predefined set of possible
values and presents a radio group-style set of inputs to the Admin Panel.
</Banner>
The Radio Field allows for the selection of one value from a predefined set of possible values and presents a radio group-style set of inputs to the [Admin Panel](../admin/overview).
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/radio.png"
srcDark="https://payloadcms.com/images/docs/fields/radio-dark.png"
alt="Shows a Radio field in the Payload admin panel"
alt="Shows a Radio field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Radio field"
/>
## Config
To add a Radio Field, set the `type` to `radio` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyRadioField: Field = {
// ...
// highlight-start
type: 'radio',
options: [
// ...
]
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -27,17 +40,18 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. The default value must exist within provided values in `options`. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
@@ -50,20 +64,33 @@ _\* An asterisk denotes that a property is required._
being used as a GraphQL enum.
</Banner>
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Radio Group field type allows for the specification of the following `admin` properties:
The customize the appearance and behavior of the Radio Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`layout`**
```ts
import type { Field } from 'payload/types'
The `layout` property allows for the radio group to be styled as a horizonally or vertically distributed list. The default value is `horizontal`.
export const MyRadioField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
The Radio Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`layout`** | Allows for the radio group to be styled as a horizonally or vertically distributed list. The default value is `horizontal`. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,25 +6,36 @@ desc: The Relationship field provides the ability to relate documents together.
keywords: relationship, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Relationship field is one of the most powerful fields Payload features. It provides for the
ability to easily relate documents together.
</Banner>
The Relationship Field is one of the most powerful fields Payload features. It provides for the ability to easily relate documents together.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
alt="Shows a relationship field in the Payload admin panel"
alt="Shows a relationship field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Relationship field"
/>
**Example uses:**
The Relationship field is used in a variety of ways, including:
- To add `Product` documents to an `Order` document
- To allow for an `Order` to feature a `placedBy` relationship to either an `Organization` or `User` collection
- To assign `Category` documents to `Post` documents
## Config
To add a Relationship Field, set the `type` to `relationship` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyRelationshipField: Field = {
// ...
// highlight-start
type: 'relationship',
relationTo: 'products',
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -39,45 +50,49 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
<Banner type="success">
<strong>Tip:</strong>
<br />
The [Depth](/docs/getting-started/concepts#depth) parameter can be used to automatically populate
related documents that are returned by the API.
The [Depth](../queries/depth) parameter can be used to automatically populate related documents that are returned by the API.
</Banner>
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Relationship field type also
allows for the following admin-specific properties:
The customize the appearance and behavior of the Relationship Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`isSortable`**
```ts
import type { Field } from 'payload/types'
Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany`
is set to `true`).
export const MyRelationshipField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`allowCreate`**
The Relationship Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set to `false` if you'd like to disable the ability to create new documents from within the relationship field (hides
the "Add new" button in the admin UI).
| Property | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **`isSortable`** | Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany` is set to `true`). |
| **`allowCreate`** | Set to `false` if you'd like to disable the ability to create new documents from within the relationship field. |
| **`sortOptions`** | Define a default sorting order for the options within a Relationship field's dropdown. [More](#sortOptions) |
**`sortOptions`**
The `sortOptions` property allows you to define a default sorting order for the options within a Relationship field's
dropdown. This can be particularly useful for ensuring that the most relevant options are presented first to the user.
### Sort Options
You can specify `sortOptions` in two ways:
@@ -143,7 +158,7 @@ called with an argument object with the following properties:
## Example
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',
@@ -179,9 +194,15 @@ You can learn more about writing queries [here](/docs/queries/overview).
When a relationship field has both <strong>filterOptions</strong> and a custom{' '}
<strong>validate</strong> function, the api will not validate <strong>filterOptions</strong>{' '}
unless you call the default relationship field validation function imported from{' '}
<strong>payload/fields/validations</strong> in your validate function.
<strong>payload/shared</strong> in your validate function.
</Banner>
## Bi-directional relationships
The `relationship` field on its own is used to define relationships for the document that contains the relationship field, and this can be considered as a "one-way" relationship. For example, if you have a Post that has a `category` relationship field on it, the related `category` itself will not surface any information about the posts that have the category set.
However, the `relationship` field can be used in conjunction with the `Join` field to produce powerful bi-directional relationship authoring capabilities. If you're interested in bi-directional relationships, check out the [documentation for the Join field](./join).
## How the data is saved
Given the variety of options possible within the `relationship` field type, the shape of the data needed for creating

View File

@@ -6,15 +6,12 @@ desc: The Rich Text field allows dynamic content to be written through the Admin
keywords: rich text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Rich Text field is a powerful way to allow editors to write dynamic content. The content is
saved as JSON in the database and can be converted into any format, including HTML, that you need.
</Banner>
The Rich Text Field is a powerful way to allow editors to write dynamic content. The content is saved as JSON in the database and can be converted into any format, including HTML, that you need.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/richtext.png"
srcDark="https://payloadcms.com/images/docs/fields/richtext-dark.png"
alt="Shows a Rich Text field in the Payload admin panel"
alt="Shows a Rich Text field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Rich Text field"
/>
@@ -23,7 +20,7 @@ Payload's rich text field is built on an "adapter pattern" which lets you specif
Right now, Payload is officially supporting two rich text editors:
1. [SlateJS](/docs/rich-text/slate) - stable, backwards-compatible with 1.0
2. [Lexical](/docs/rich-text/lexical) - beta, where things will be moving
2. [Lexical](/docs/lexical/overview) - beta, where things will be moving
<Banner type="success">
<strong>
@@ -39,43 +36,51 @@ Right now, Payload is officially supporting two rich text editors:
will allow you to apply your learnings elsewhere as well.
</Banner>
## Config
## Config Options
| Option | Description |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`editor`** | Override the rich text editor specified in your base configuration for this field. |
| **`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 stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`editor`** | Override the rich text editor specified in your base configuration for this field. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Rich Text editor allows for the following admin properties:
The customize the appearance and behavior of the Rich Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`placeholder`**
```ts
import type { Field } from 'payload/types'
Set this property to define a placeholder string in the text input.
export const MyRichTextField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`hideGutter`**
The Rich Text Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set this property to `true` to hide this field's gutter within the admin panel. The field gutter is rendered as a vertical line and padding, but often if this field is nested within a Group, Block, or Array, you may want to hide the gutter.
| Property | Description |
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string for the field. |
| **`hideGutter`** | Set this property to `true` to hide this field's gutter within the Admin Panel. |
| **`rtl`** | Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction. |
**`rtl`**
## Editor-specific Options
Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction.
## Editor-specific options
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/lexical/overview) depending on which editor you're using.

View File

@@ -6,24 +6,37 @@ desc: With the Row field you can arrange fields next to each other in the Admin
keywords: row, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Row field is presentational-only and only affects the Admin Panel. By using it, you can
arrange fields next to each other horizontally.
</Banner>
The Row Field is presentational-only and only affects the [Admin Panel](../admin/overview). By using it, you can arrange [Fields](./overview) next to each other horizontally.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/row.png"
srcDark="https://payloadcms.com/images/docs/fields/row-dark.png"
alt="Shows a row field in the Payload admin panel"
alt="Shows a row field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Row field"
/>
## Config
To add a Row Field, set the `type` to `row` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyRowField: Field = {
// ...
// highlight-start
type: 'row',
fields: [
// ...
]
// highlight-end
}
```
## Config Options
| Option | Description |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`fields`** \* | Array of field types to nest within this Row. |
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
@@ -33,7 +46,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,71 +6,94 @@ desc: The Select field provides a dropdown-style interface for choosing options
keywords: select, multi-select, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Select field provides a dropdown-style interface for choosing options from a predefined list
as an enumeration.
</Banner>
The Select Field provides a dropdown-style interface for choosing options from a predefined list as an enumeration.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/select.png"
srcDark="https://payloadcms.com/images/docs/fields/select-dark.png"
alt="Shows a Select field in the Payload admin panel"
alt="Shows a Select field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Select field"
/>
## Config
To add a Select Field, set the `type` to `select` in your [Field Config](./overview):
| Option | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
```ts
import type { Field } from 'payload/types'
export const MySelectField: Field = {
// ...
// highlight-start
type: 'select',
options: [
// ...
]
// highlight-end
}
```
## Config Options
| Option | Description |
| ---------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
| **`label`** | Text used as a field label in the Admin Panel or an object with keys for each language. |
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-options) for more details. |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`enumName`** | Custom enum name for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`dbName`** | Custom table name (if `hasMany` set to `true`) for this field when using SQL Database Adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
<Banner type="warning">
<strong>Important:</strong>
<br />
Option values should be strings that do not contain hyphens or special characters due to GraphQL
enumeration naming constraints. Underscores are allowed. If you determine you need your option
values to be non-strings or contain special characters, they will be formatted accordingly before
being used as a GraphQL enum.
</Banner>
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Select field type also allows for the following admin-specific properties:
The customize the appearance and behavior of the Select Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`isClearable`**
```ts
import type { Field } from 'payload/types'
Set to `true` if you'd like this field to be clearable within the Admin UI.
export const MySelectField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`isSortable`**
The Select Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop. (Only works when `hasMany` is set to `true`)
| Property | Description |
| ------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------- |
| **`isClearable`** | Set to `true` if you'd like this field to be clearable within the Admin UI. |
| **`isSortable`** | Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop. (Only works when `hasMany` is set to `true`) |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,25 +6,37 @@ desc: The Tabs field is a great way to organize complex editing experiences into
keywords: tabs, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Tabs field is presentational-only and only affects the Admin Panel (unless a tab is named). By
using it, you can place fields within a nice layout component that separates certain sub-fields by
a tabbed interface.
</Banner>
The Tabs Field is presentational-only and only affects the [Admin Panel](../admin/overview) (unless a tab is named). By using it, you can place fields within a nice layout component that separates certain sub-fields by a tabbed interface.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/tabs.png"
srcDark="https://payloadcms.com/images/docs/fields/tabs-dark.png"
alt="Shows a tabs field used to separate Hero and Page layout in the Payload admin panel"
alt="Shows a tabs field used to separate Hero and Page layout in the Payload Admin Panel"
caption="Tabs field type used to separate Hero fields from Page Layout"
/>
## Config
To add a Tabs Field, set the `type` to `tabs` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyTabsField: Field = {
// ...
// highlight-start
type: 'tabs',
tabs: [
// ...
]
// highlight-end
}
```
## Config Options
| Option | Description |
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
| **`tabs`** \* | Array of tabs to render within this Tabs field. |
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
| **`admin`** | Admin-specific configuration. [More details](../admin/fields#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
### Tab-specific Config
@@ -38,6 +50,7 @@ Each tab must have either a `name` or `label` and the required `fields` array. Y
| **`fields`** \* | The fields to render within this tab. |
| **`description`** | Optionally render a description within this tab to describe the contents of the tab itself. |
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). (`name` must be present) |
| **`virtual`** | Provide `true` to disable field in the database (`name` must be present). See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
@@ -46,7 +59,7 @@ _\* An asterisk denotes that a property is required._
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

View File

@@ -6,19 +6,27 @@ desc: Text field types simply save a string to the database and provide the Admi
keywords: text, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, nextjs
---
<Banner>
The Text field type is one of the most commonly used fields. It saves a string to the database and
provides the Admin Panel with a simple text input.
</Banner>
The Text Field is one of the most commonly used fields. It saves a string to the database and provides the [Admin Panel](../admin/overview) with a simple text input.
<LightDarkImage
srcLight="https://payloadcms.com/images/docs/fields/text.png"
srcDark="https://payloadcms.com/images/docs/fields/text-dark.png"
alt="Shows a text field and read-only text field in the Payload admin panel"
alt="Shows a text field and read-only text field in the Payload Admin Panel"
caption="Admin Panel screenshot of a Text field and read-only Text field"
/>
## Config
To add a Text Field, set the `type` to `text` in your [Field Config](./overview):
```ts
import type { Field } from 'payload/types'
export const MyTextField: Field = {
// ...
type: 'text', // highlight-line
}
```
## Config Options
| Option | Description |
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
@@ -29,44 +37,52 @@ keywords: text, fields, config, configuration, documentation, Content Management
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
| **`validate`** | Provide a custom validation function that will be executed on both the Admin Panel and the backend. [More](/docs/fields/overview#validation) |
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/overview), include its data in the user JWT. |
| **`hooks`** | Provide Field Hooks to control logic for this field. [More details](../hooks/fields). |
| **`access`** | Provide Field Access Control to denote what users can see and do with this field's data. [More details](../access-control/fields). |
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin Panel. |
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
| **`required`** | Require this field to have a value. |
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
| **`admin`** | Admin-specific configuration. [More details](#admin-options). |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
| **`hasMany`** | Makes this field an ordered array of text instead of just a single text. |
| **`minRows`** | Minimum number of texts in the array, if `hasMany` is set to true. |
| **`maxRows`** | Maximum number of texts in the array, if `hasMany` is set to true. |
| **`typescriptSchema`** | Override field type generation with providing a JSON schema |
| **`virtual`** | Provide `true` to disable field in the database. See [Virtual Fields](https://payloadcms.com/blog/learn-how-virtual-fields-can-help-solve-common-cms-challenges) |
_\* An asterisk denotes that a property is required._
## Admin config
## Admin Options
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Text field type allows for the following `admin` properties:
The customize the appearance and behavior of the Text Field in the [Admin Panel](../admin/overview), you can use the `admin` option:
**`placeholder`**
```ts
import type { Field } from 'payload/types'
Set this property to define a placeholder string in the text input.
export const MyTextField: Field = {
// ...
admin: { // highlight-line
// ...
},
}
```
**`autoComplete`**
The Text Field inherits all of the default options from the base [Field Admin Config](../admin/fields#admin-options), plus the following additional options:
Set this property to a string that will be used for browser autocomplete.
**`rtl`**
Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction.
| Option | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------- |
| **`placeholder`** | Set this property to define a placeholder string in the text input. |
| **`autoComplete`** | Set this property to a string that will be used for browser autocomplete. |
| **`rtl`** | Override the default text direction of the Admin Panel for this field. Set to `true` to force right-to-left text direction. |
## Example
`collections/ExampleCollection.ts`
```ts
import { CollectionConfig } from 'payload/types'
import { CollectionConfig } from 'payload'
export const ExampleCollection: CollectionConfig = {
slug: 'example-collection',

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