Compare commits

..

63 Commits

Author SHA1 Message Date
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
Bruno Crosier
ef6fe9ca9a review comments 2024-09-02 23:52:04 +01:00
Bruno Crosier
053256d5ce more tests and better implementation 2024-08-31 23:58:20 +01:00
Bruno Crosier
efe17ff5e4 fix(row): set max-width for row 2024-08-29 02:23:54 +01:00
359 changed files with 14074 additions and 3173 deletions

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

@@ -0,0 +1,31 @@
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 }}
- run: echo "npm_version=$(npm pkg get version | tr -d '"')" >> "$GITHUB_ENV"
- 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

@@ -783,7 +783,7 @@ Here are the breaking changes and how to migrate:
- New "Views" API added, which allows for custom sub-views on List and Edit views within Admin UI
- New [bundler adapter pattern](https://payloadcms.com/docs/admin/bundlers) released
- Official [Vite bundler](https://payloadcms.com/docs/admin/vite) released
- Offical [Lexical rich text adapter](https://payloadcms.com/docs/rich-text/lexical) released
- Offical [Lexical rich text adapter](https://payloadcms.com/docs/lexical/overview) released
- Lexical rich text editor now supports drag and drop of rich text elements
- Lexical rich text now supports Payload blocks directly within rich text editor
- Upload image cropping added

View File

@@ -431,14 +431,14 @@ export const MyClientComponent: React.FC = () => {
See [Using Hooks](#using-hooks) for more details.
</Banner>
All [Field Components](./fields) automatically receive their respective Client Field Config through a common [`field`](./fields#the-field-prop) prop:
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 { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent = ({ field: { name } }: TextFieldProps) => {
export const MyClientFieldComponent: TextFieldClientComponent = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}

View File

@@ -136,7 +136,8 @@ All Field Components receive the following props:
| Property | Description |
| ---------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **`docPreferences`** | An object that contains the [Preferences](./preferences) for the document.
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`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). |
| **`readOnly`** | A boolean value that represents if the field is read-only or not. |
| **`user`** | The currently authenticated user. [More details](../authentication/overview). |
@@ -175,51 +176,50 @@ export const CustomTextField: React.FC = () => {
#### TypeScript
When building Custom Field Components, you can import the component props to ensure type safety in your component. There is an explicit type for the Field Component, one for every [Field Type](../fields/overview). The convention is to append `Props` to the type of field, i.e. `TextFieldProps`.
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 {
ArrayFieldProps,
BlocksFieldProps,
CheckboxFieldProps,
CodeFieldProps,
CollapsibleFieldProps,
DateFieldProps,
EmailFieldProps,
GroupFieldProps,
HiddenFieldProps,
JSONFieldProps,
NumberFieldProps,
PointFieldProps,
RadioFieldProps,
RelationshipFieldProps,
RichTextFieldProps,
RowFieldProps,
SelectFieldProps,
TabsFieldProps,
TextFieldProps,
TextareaFieldProps,
UploadFieldProps
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
### The `field` Prop
All Field Components are passed a client-friendly version of their Field Config through a common `field` prop. Since the raw Field Config is [non-serializable](https://react.dev/reference/rsc/use-client#serializable-types), Payload sanitized it into a [Client Config](./components#accessing-the-payload-config) that is safe to pass into Client Components.
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 exact shape of this prop is unique to the specific [Field Type](../fields/overview) being rendered, minus all non-serializable properties. Any [Custom Components](../components) are also resolved into a "mapped component" that is safe to pass.
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 { TextFieldProps } from 'payload'
import type { TextFieldClientComponent } from 'payload'
export const MyClientFieldComponent: React.FC<TextFieldProps> = ({ field: { name } }) => {
return (
<p>
{`This field's name is ${name}`}
</p>
)
export const MyTextField: TextFieldClientComponent = ({ field }) => {
return <TextField field={field} />
}
```
@@ -238,40 +238,18 @@ The following additional properties are also provided to the `field` prop:
#### 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). The convention is to append `Client` to the type of field, i.e. `TextFieldClient`.
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 {
ArrayFieldClient,
BlocksFieldClient,
CheckboxFieldClient,
CodeFieldClient,
CollapsibleFieldClient,
DateFieldClient,
EmailFieldClient,
GroupFieldClient,
HiddenFieldClient,
JSONFieldClient,
NumberFieldClient,
PointFieldClient,
RadioFieldClient,
RelationshipFieldClient,
RichTextFieldClient,
RowFieldClient,
SelectFieldClient,
TabsFieldClient,
TextFieldClient,
TextareaFieldClient,
UploadFieldClient
TextFieldClientComponent,
TextFieldServerComponent,
TextFieldClientProps,
TextFieldServerProps,
// ...and so on for each Field Type
} from 'payload'
```
When working on the client, you will never have access to objects of type `Field`. This is reserved for the server-side. Instead, you can use `ClientField` which is a union type of all the client fields:
```tsx
import type { ClientField } 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.
@@ -298,7 +276,8 @@ All Cell Components receive the following props:
| Property | Description |
| ---------------- | ----------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`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. |
@@ -338,7 +317,8 @@ Custom Label Components receive all [Field Component](#the-field-component) prop
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`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>
@@ -353,7 +333,7 @@ When building Custom Label Components, you can import the component props to ens
import type {
TextFieldLabelServerComponent,
TextFieldLabelClientComponent,
// And so on for each Field Type
// ...and so on for each Field Type
} from 'payload'
```
@@ -383,7 +363,8 @@ Custom Error Components receive all [Field Component](#the-field-component) prop
| Property | Description |
| --------------- | ------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`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>
@@ -499,7 +480,8 @@ Custom Description Components receive all [Field Component](#the-field-component
| Property | Description |
| -------------- | ---------------------------------------------------------------- |
| **`field`** | The sanitized, client-friendly version of the field's config. [More details](#the-field-prop) |
| **`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>

View File

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

View File

@@ -31,8 +31,9 @@ const config = buildConfig({
admin: {
components: {
views: {
dashboard: {
Component: '/path/to/MyCustomDashboardView#MyCustomDashboardViewComponent', // highlight-line
customView: {
Component: '/path/to/MyCustomView#MyCustomView', // highlight-line
path: '/my-custom-view',
}
},
},
@@ -40,7 +41,42 @@ const config = buildConfig({
})
```
_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:
@@ -133,7 +169,7 @@ export const MyCollectionConfig: SanitizedCollectionConfig = {
}
```
_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>
@@ -184,7 +220,7 @@ export const MyGlobalConfig: SanitizedGlobalConfig = {
}
```
_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>
@@ -227,7 +263,7 @@ export const MyCollectionOrGlobalConfig: SanitizedCollectionConfig = {
}
```
_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>
@@ -312,13 +348,11 @@ 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

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

@@ -20,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>
@@ -82,4 +82,4 @@ The Rich Text Field inherits all of the default options from the base [Field Adm
## 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

@@ -68,7 +68,7 @@ Here's a quick example of a React Server Component fetching data using the Local
```tsx
import React from 'react'
import config from '@payload-config'
import { getPayloadHMR } from '@payloadcms/next'
import { getPayloadHMR } from '@payloadcms/next/utilities'
const MyServerComponent: React.FC = () => {
// If you're working in Next.js, and you want HMR,

View File

@@ -34,7 +34,7 @@ Then, render the `RefreshRouteOnSave` component anywhere in your `page.tsx`. Her
```tsx
import { RefreshRouteOnSave } from './RefreshRouteOnSave.tsx'
import { getPayloadHMR } from '@payloadcms/next'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import config from '../payload.config'
export default async function Page() {

View File

@@ -48,7 +48,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
```ts
import { headers as getHeaders } from 'next/headers.js'
import { getPayloadHMR } from '@payloadcms/next'
import { getPayloadHMR } from '@payloadcms/next/utilities'
import config from '../../payload.config'
export default async function AccountPage({ searchParams }) {

View File

@@ -0,0 +1,3 @@
DATABASE_URI=mongodb://127.0.0.1/payload-example-custom-fields
PAYLOAD_SECRET=PAYLOAD_CUSTOM_FIELDS_EXAMPLE_SECRET_KEY
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000

View File

@@ -0,0 +1,4 @@
module.exports = {
root: true,
extends: ['@payloadcms'],
}

5
examples/custom-components/.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
build
dist
node_modules
package-lock.json
.env

View File

@@ -0,0 +1,24 @@
{
"$schema": "https://json.schemastore.org/swcrc",
"sourceMaps": true,
"jsc": {
"target": "esnext",
"parser": {
"syntax": "typescript",
"tsx": true,
"dts": true
},
"transform": {
"react": {
"runtime": "automatic",
"pragmaFrag": "React.Fragment",
"throwIfNamespace": true,
"development": false,
"useBuiltins": true
}
}
},
"module": {
"type": "es6"
}
}

View File

@@ -0,0 +1,46 @@
# Payload Custom Components Example
This example demonstrates how to use Custom Components in [Payload](https://github.com/payloadcms/payload) Admin Panel. This example includes custom components for every field type available in Payload, including both server and client components. It also includes custom views, custom nav links, and more.
## Quick Start
To spin up this example locally, follow these steps:
1. Clone this repo
1. `cd` into this directory and run `pnpm i --ignore-workspace`\*, `yarn`, or `npm install`
> \*If you are running using pnpm within the Payload Monorepo, the `--ignore-workspace` flag is needed so that pnpm generates a lockfile in this example's directory despite the fact that one exists in root.
1. `pnpm dev`, `yarn dev` or `npm run dev` to start the server
- Press `y` when prompted to seed the database
1. `open http://localhost:3000` to access the home page
1. `open http://localhost:3000/admin` to access the admin panel
- Login with email `demo@payloadcms.com` and password `demo`
## How it works
### Collections
See the [Collections](https://payloadcms.com/docs/configuration/collections) docs for details on how to extend any of this functionality.
- #### Users
The `users` collection is auth-enabled which provides access to the admin panel.
For additional help with authentication, see the official [Auth Example](https://github.com/payloadcms/payload/tree/main/examples/auth/cms#readme) or the [Authentication](https://payloadcms.com/docs/authentication/overview#authentication-overview) docs.
- #### Fields
The `fields` collection contains every field type available in Payload, each with custom components filled in every available "slot", i.e. `admin.components.Field`, `admin.components.Label`, etc. There are two of every field, one for server components, and the other for client components. This pattern shows how to use custom components in both environments, no matter which field type you are using.
- #### Views
The `views` collection demonstrates how to add collection-level views, including the default view and custom tabs.
- #### Root Views
The `root-views` collection demonstrates how to add a root document-level view to the admin panel.
## Questions
If you have any issues or questions, reach out to us on [Discord](https://discord.com/invite/payload) or start a [GitHub discussion](https://github.com/payloadcms/payload/discussions).

View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,8 @@
import { withPayload } from '@payloadcms/next/withPayload'
/** @type {import('next').NextConfig} */
const nextConfig = {
// Your Next.js config here
}
export default withPayload(nextConfig)

View File

@@ -0,0 +1,43 @@
{
"name": "payload-example-custom-fields",
"version": "1.0.0",
"description": "An example of custom fields in Payload.",
"license": "MIT",
"type": "module",
"scripts": {
"_dev": "cross-env NODE_OPTIONS=--no-deprecation && pnpm generate:importmap && next dev",
"build": "cross-env NODE_OPTIONS=--no-deprecation next build",
"dev": "cross-env NODE_OPTIONS=--no-deprecation && pnpm generate:importmap && pnpm seed && next dev --turbo",
"generate:importmap": "payload generate:importmap",
"generate:schema": "payload-graphql generate:schema",
"generate:types": "payload generate:types",
"payload": "cross-env NODE_OPTIONS=--no-deprecation payload",
"seed": "npm run payload migrate:fresh",
"start": "cross-env NODE_OPTIONS=--no-deprecation next start"
},
"dependencies": {
"@payloadcms/db-mongodb": "3.0.0-beta.102",
"@payloadcms/next": "3.0.0-beta.102",
"@payloadcms/richtext-lexical": "3.0.0-beta.102",
"@payloadcms/ui": "3.0.0-beta.102",
"cross-env": "^7.0.3",
"dotenv": "^8.2.0",
"graphql": "^16.9.0",
"next": "15.0.0-canary.104",
"payload": "3.0.0-beta.102",
"react": "19.0.0-rc-06d0b89e-20240801",
"react-dom": "19.0.0-rc-06d0b89e-20240801"
},
"devDependencies": {
"@payloadcms/graphql": "3.0.0-beta.102",
"@types/react": "npm:types-react@19.0.0-beta.2",
"@types/react-dom": "npm:types-react-dom@19.0.0-beta.2",
"eslint": "^8.57.0",
"eslint-config-next": "15.0.0-canary.146",
"tsx": "^4.7.1",
"typescript": "5.5.2"
},
"engines": {
"node": "^18.20.2 || >=20.9.0"
}
}

6848
examples/custom-components/pnpm-lock.yaml generated Normal file

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@@ -0,0 +1,162 @@
import { CustomArrayFieldLabelServer as CustomArrayFieldLabelServer_0 } from '@/collections/Fields/array/components/server/Label'
import { CustomArrayFieldServer as CustomArrayFieldServer_1 } from '@/collections/Fields/array/components/server/Field'
import { CustomArrayFieldLabelClient as CustomArrayFieldLabelClient_2 } from '@/collections/Fields/array/components/client/Label'
import { CustomArrayFieldClient as CustomArrayFieldClient_3 } from '@/collections/Fields/array/components/client/Field'
import { CustomBlocksFieldServer as CustomBlocksFieldServer_4 } from '@/collections/Fields/blocks/components/server/Field'
import { CustomBlocksFieldClient as CustomBlocksFieldClient_5 } from '@/collections/Fields/blocks/components/client/Field'
import { CustomCheckboxFieldLabelServer as CustomCheckboxFieldLabelServer_6 } from '@/collections/Fields/checkbox/components/server/Label'
import { CustomCheckboxFieldServer as CustomCheckboxFieldServer_7 } from '@/collections/Fields/checkbox/components/server/Field'
import { CustomCheckboxFieldLabelClient as CustomCheckboxFieldLabelClient_8 } from '@/collections/Fields/checkbox/components/client/Label'
import { CustomCheckboxFieldClient as CustomCheckboxFieldClient_9 } from '@/collections/Fields/checkbox/components/client/Field'
import { CustomDateFieldLabelServer as CustomDateFieldLabelServer_10 } from '@/collections/Fields/date/components/server/Label'
import { CustomDateFieldServer as CustomDateFieldServer_11 } from '@/collections/Fields/date/components/server/Field'
import { CustomDateFieldLabelClient as CustomDateFieldLabelClient_12 } from '@/collections/Fields/date/components/client/Label'
import { CustomDateFieldClient as CustomDateFieldClient_13 } from '@/collections/Fields/date/components/client/Field'
import { CustomEmailFieldLabelServer as CustomEmailFieldLabelServer_14 } from '@/collections/Fields/email/components/server/Label'
import { CustomEmailFieldServer as CustomEmailFieldServer_15 } from '@/collections/Fields/email/components/server/Field'
import { CustomEmailFieldLabelClient as CustomEmailFieldLabelClient_16 } from '@/collections/Fields/email/components/client/Label'
import { CustomEmailFieldClient as CustomEmailFieldClient_17 } from '@/collections/Fields/email/components/client/Field'
import { CustomNumberFieldLabelServer as CustomNumberFieldLabelServer_18 } from '@/collections/Fields/number/components/server/Label'
import { CustomNumberFieldServer as CustomNumberFieldServer_19 } from '@/collections/Fields/number/components/server/Field'
import { CustomNumberFieldLabelClient as CustomNumberFieldLabelClient_20 } from '@/collections/Fields/number/components/client/Label'
import { CustomNumberFieldClient as CustomNumberFieldClient_21 } from '@/collections/Fields/number/components/client/Field'
import { CustomPointFieldLabelServer as CustomPointFieldLabelServer_22 } from '@/collections/Fields/point/components/server/Label'
import { CustomPointFieldServer as CustomPointFieldServer_23 } from '@/collections/Fields/point/components/server/Field'
import { CustomPointFieldLabelClient as CustomPointFieldLabelClient_24 } from '@/collections/Fields/point/components/client/Label'
import { CustomPointFieldClient as CustomPointFieldClient_25 } from '@/collections/Fields/point/components/client/Field'
import { CustomRadioFieldLabelServer as CustomRadioFieldLabelServer_26 } from '@/collections/Fields/radio/components/server/Label'
import { CustomRadioFieldServer as CustomRadioFieldServer_27 } from '@/collections/Fields/radio/components/server/Field'
import { CustomRadioFieldLabelClient as CustomRadioFieldLabelClient_28 } from '@/collections/Fields/radio/components/client/Label'
import { CustomRadioFieldClient as CustomRadioFieldClient_29 } from '@/collections/Fields/radio/components/client/Field'
import { CustomRelationshipFieldLabelServer as CustomRelationshipFieldLabelServer_30 } from '@/collections/Fields/relationship/components/server/Label'
import { CustomRelationshipFieldServer as CustomRelationshipFieldServer_31 } from '@/collections/Fields/relationship/components/server/Field'
import { CustomRelationshipFieldLabelClient as CustomRelationshipFieldLabelClient_32 } from '@/collections/Fields/relationship/components/client/Label'
import { CustomRelationshipFieldClient as CustomRelationshipFieldClient_33 } from '@/collections/Fields/relationship/components/client/Field'
import { CustomSelectFieldLabelServer as CustomSelectFieldLabelServer_34 } from '@/collections/Fields/select/components/server/Label'
import { CustomSelectFieldServer as CustomSelectFieldServer_35 } from '@/collections/Fields/select/components/server/Field'
import { CustomSelectFieldLabelClient as CustomSelectFieldLabelClient_36 } from '@/collections/Fields/select/components/client/Label'
import { CustomSelectFieldClient as CustomSelectFieldClient_37 } from '@/collections/Fields/select/components/client/Field'
import { CustomTextFieldLabelServer as CustomTextFieldLabelServer_38 } from '@/collections/Fields/text/components/server/Label'
import { CustomTextFieldServer as CustomTextFieldServer_39 } from '@/collections/Fields/text/components/server/Field'
import { CustomTextFieldLabelClient as CustomTextFieldLabelClient_40 } from '@/collections/Fields/text/components/client/Label'
import { CustomTextFieldClient as CustomTextFieldClient_41 } from '@/collections/Fields/text/components/client/Field'
import { CustomTextareaFieldLabelServer as CustomTextareaFieldLabelServer_42 } from '@/collections/Fields/textarea/components/server/Label'
import { CustomTextareaFieldServer as CustomTextareaFieldServer_43 } from '@/collections/Fields/textarea/components/server/Field'
import { CustomTextareaFieldLabelClient as CustomTextareaFieldLabelClient_44 } from '@/collections/Fields/textarea/components/client/Label'
import { CustomTextareaFieldClient as CustomTextareaFieldClient_45 } from '@/collections/Fields/textarea/components/client/Field'
import { CustomTabEditView as CustomTabEditView_46 } from '@/collections/Views/components/CustomTabEditView'
import { CustomDefaultEditView as CustomDefaultEditView_47 } from '@/collections/Views/components/CustomDefaultEditView'
import { CustomRootEditView as CustomRootEditView_48 } from '@/collections/RootViews/components/CustomRootEditView'
import { LinkToCustomView as LinkToCustomView_49 } from '@/components/afterNavLinks/LinkToCustomView'
import { LinkToCustomMinimalView as LinkToCustomMinimalView_50 } from '@/components/afterNavLinks/LinkToCustomMinimalView'
import { LinkToCustomDefaultView as LinkToCustomDefaultView_51 } from '@/components/afterNavLinks/LinkToCustomDefaultView'
import { CustomRootView as CustomRootView_52 } from '@/components/views/CustomRootView'
import { CustomDefaultRootView as CustomDefaultRootView_53 } from '@/components/views/CustomDefaultRootView'
import { CustomMinimalRootView as CustomMinimalRootView_54 } from '@/components/views/CustomMinimalRootView'
export const importMap = {
'@/collections/Fields/array/components/server/Label#CustomArrayFieldLabelServer':
CustomArrayFieldLabelServer_0,
'@/collections/Fields/array/components/server/Field#CustomArrayFieldServer':
CustomArrayFieldServer_1,
'@/collections/Fields/array/components/client/Label#CustomArrayFieldLabelClient':
CustomArrayFieldLabelClient_2,
'@/collections/Fields/array/components/client/Field#CustomArrayFieldClient':
CustomArrayFieldClient_3,
'@/collections/Fields/blocks/components/server/Field#CustomBlocksFieldServer':
CustomBlocksFieldServer_4,
'@/collections/Fields/blocks/components/client/Field#CustomBlocksFieldClient':
CustomBlocksFieldClient_5,
'@/collections/Fields/checkbox/components/server/Label#CustomCheckboxFieldLabelServer':
CustomCheckboxFieldLabelServer_6,
'@/collections/Fields/checkbox/components/server/Field#CustomCheckboxFieldServer':
CustomCheckboxFieldServer_7,
'@/collections/Fields/checkbox/components/client/Label#CustomCheckboxFieldLabelClient':
CustomCheckboxFieldLabelClient_8,
'@/collections/Fields/checkbox/components/client/Field#CustomCheckboxFieldClient':
CustomCheckboxFieldClient_9,
'@/collections/Fields/date/components/server/Label#CustomDateFieldLabelServer':
CustomDateFieldLabelServer_10,
'@/collections/Fields/date/components/server/Field#CustomDateFieldServer':
CustomDateFieldServer_11,
'@/collections/Fields/date/components/client/Label#CustomDateFieldLabelClient':
CustomDateFieldLabelClient_12,
'@/collections/Fields/date/components/client/Field#CustomDateFieldClient':
CustomDateFieldClient_13,
'@/collections/Fields/email/components/server/Label#CustomEmailFieldLabelServer':
CustomEmailFieldLabelServer_14,
'@/collections/Fields/email/components/server/Field#CustomEmailFieldServer':
CustomEmailFieldServer_15,
'@/collections/Fields/email/components/client/Label#CustomEmailFieldLabelClient':
CustomEmailFieldLabelClient_16,
'@/collections/Fields/email/components/client/Field#CustomEmailFieldClient':
CustomEmailFieldClient_17,
'@/collections/Fields/number/components/server/Label#CustomNumberFieldLabelServer':
CustomNumberFieldLabelServer_18,
'@/collections/Fields/number/components/server/Field#CustomNumberFieldServer':
CustomNumberFieldServer_19,
'@/collections/Fields/number/components/client/Label#CustomNumberFieldLabelClient':
CustomNumberFieldLabelClient_20,
'@/collections/Fields/number/components/client/Field#CustomNumberFieldClient':
CustomNumberFieldClient_21,
'@/collections/Fields/point/components/server/Label#CustomPointFieldLabelServer':
CustomPointFieldLabelServer_22,
'@/collections/Fields/point/components/server/Field#CustomPointFieldServer':
CustomPointFieldServer_23,
'@/collections/Fields/point/components/client/Label#CustomPointFieldLabelClient':
CustomPointFieldLabelClient_24,
'@/collections/Fields/point/components/client/Field#CustomPointFieldClient':
CustomPointFieldClient_25,
'@/collections/Fields/radio/components/server/Label#CustomRadioFieldLabelServer':
CustomRadioFieldLabelServer_26,
'@/collections/Fields/radio/components/server/Field#CustomRadioFieldServer':
CustomRadioFieldServer_27,
'@/collections/Fields/radio/components/client/Label#CustomRadioFieldLabelClient':
CustomRadioFieldLabelClient_28,
'@/collections/Fields/radio/components/client/Field#CustomRadioFieldClient':
CustomRadioFieldClient_29,
'@/collections/Fields/relationship/components/server/Label#CustomRelationshipFieldLabelServer':
CustomRelationshipFieldLabelServer_30,
'@/collections/Fields/relationship/components/server/Field#CustomRelationshipFieldServer':
CustomRelationshipFieldServer_31,
'@/collections/Fields/relationship/components/client/Label#CustomRelationshipFieldLabelClient':
CustomRelationshipFieldLabelClient_32,
'@/collections/Fields/relationship/components/client/Field#CustomRelationshipFieldClient':
CustomRelationshipFieldClient_33,
'@/collections/Fields/select/components/server/Label#CustomSelectFieldLabelServer':
CustomSelectFieldLabelServer_34,
'@/collections/Fields/select/components/server/Field#CustomSelectFieldServer':
CustomSelectFieldServer_35,
'@/collections/Fields/select/components/client/Label#CustomSelectFieldLabelClient':
CustomSelectFieldLabelClient_36,
'@/collections/Fields/select/components/client/Field#CustomSelectFieldClient':
CustomSelectFieldClient_37,
'@/collections/Fields/text/components/server/Label#CustomTextFieldLabelServer':
CustomTextFieldLabelServer_38,
'@/collections/Fields/text/components/server/Field#CustomTextFieldServer':
CustomTextFieldServer_39,
'@/collections/Fields/text/components/client/Label#CustomTextFieldLabelClient':
CustomTextFieldLabelClient_40,
'@/collections/Fields/text/components/client/Field#CustomTextFieldClient':
CustomTextFieldClient_41,
'@/collections/Fields/textarea/components/server/Label#CustomTextareaFieldLabelServer':
CustomTextareaFieldLabelServer_42,
'@/collections/Fields/textarea/components/server/Field#CustomTextareaFieldServer':
CustomTextareaFieldServer_43,
'@/collections/Fields/textarea/components/client/Label#CustomTextareaFieldLabelClient':
CustomTextareaFieldLabelClient_44,
'@/collections/Fields/textarea/components/client/Field#CustomTextareaFieldClient':
CustomTextareaFieldClient_45,
'@/collections/Views/components/CustomTabEditView#CustomTabEditView': CustomTabEditView_46,
'@/collections/Views/components/CustomDefaultEditView#CustomDefaultEditView':
CustomDefaultEditView_47,
'@/collections/RootViews/components/CustomRootEditView#CustomRootEditView': CustomRootEditView_48,
'@/components/afterNavLinks/LinkToCustomView#LinkToCustomView': LinkToCustomView_49,
'@/components/afterNavLinks/LinkToCustomMinimalView#LinkToCustomMinimalView':
LinkToCustomMinimalView_50,
'@/components/afterNavLinks/LinkToCustomDefaultView#LinkToCustomDefaultView':
LinkToCustomDefaultView_51,
'@/components/views/CustomRootView#CustomRootView': CustomRootView_52,
'@/components/views/CustomDefaultRootView#CustomDefaultRootView': CustomDefaultRootView_53,
'@/components/views/CustomMinimalRootView#CustomMinimalRootView': CustomMinimalRootView_54,
}

View File

@@ -0,0 +1,10 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { REST_DELETE, REST_GET, REST_OPTIONS, REST_PATCH, REST_POST } from '@payloadcms/next/routes'
export const GET = REST_GET(config)
export const POST = REST_POST(config)
export const DELETE = REST_DELETE(config)
export const PATCH = REST_PATCH(config)
export const OPTIONS = REST_OPTIONS(config)

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes'
export const GET = GRAPHQL_PLAYGROUND_GET(config)

View File

@@ -0,0 +1,6 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
/* DO NOT MODIFY it because it could be re-written at any time. */
import config from '@payload-config'
import { GRAPHQL_POST } from '@payloadcms/next/routes'
export const POST = GRAPHQL_POST(config)

View File

@@ -0,0 +1,21 @@
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
import configPromise from '@payload-config'
import '@payloadcms/next/css'
import { RootLayout } from '@payloadcms/next/layouts'
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
import React from 'react'
import { importMap } from './admin/importMap.js'
import './custom.scss'
type Args = {
children: React.ReactNode
}
const Layout = ({ children }: Args) => (
<RootLayout config={configPromise} importMap={importMap}>
{children}
</RootLayout>
)
export default Layout

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextFieldClientComponent } from 'payload'
import { TextField } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldClient: TextFieldClientComponent = (props) => {
const { field } = props
return <TextField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldLabelClient: TextFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { TextFieldServerComponent } from 'payload'
// import { TextField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomTextFieldServer: TextFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <TextField field={clientField} />
return 'This is a server component for the text field.'
}

View File

@@ -0,0 +1,12 @@
import type { TextFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextFieldLabelServer: TextFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the text field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const textFields: CollectionConfig['fields'] = [
{
name: 'textFieldServerComponent',
type: 'text',
admin: {
components: {
Field: '@/collections/Fields/text/components/server/Field#CustomTextFieldServer',
Label: '@/collections/Fields/text/components/server/Label#CustomTextFieldLabelServer',
},
},
},
{
name: 'textFieldClientComponent',
type: 'text',
admin: {
components: {
Field: '@/collections/Fields/text/components/client/Field#CustomTextFieldClient',
Label: '@/collections/Fields/text/components/client/Label#CustomTextFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextareaFieldClientComponent } from 'payload'
import { TextareaField } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldClient: TextareaFieldClientComponent = (props) => {
const { field } = props
return <TextareaField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { TextareaFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldLabelClient: TextareaFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { TextareaFieldServerComponent } from 'payload'
// import { TextareaField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomTextareaFieldServer: TextareaFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <TextareaField field={clientField} />
return 'This is a server component for the textarea field.'
}

View File

@@ -0,0 +1,12 @@
import type { TextareaFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomTextareaFieldLabelServer: TextareaFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the textarea field label.'
}

View File

@@ -0,0 +1,26 @@
import type { CollectionConfig } from 'payload'
export const textareaFields: CollectionConfig['fields'] = [
{
name: 'textareaFieldServerComponent',
type: 'textarea',
admin: {
components: {
Field: '@/collections/Fields/textarea/components/server/Field#CustomTextareaFieldServer',
Label:
'@/collections/Fields/textarea/components/server/Label#CustomTextareaFieldLabelServer',
},
},
},
{
name: 'textareaFieldClientComponent',
type: 'textarea',
admin: {
components: {
Field: '@/collections/Fields/textarea/components/client/Field#CustomTextareaFieldClient',
Label:
'@/collections/Fields/textarea/components/client/Label#CustomTextareaFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { ArrayFieldClientComponent } from 'payload'
import { ArrayField } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldClient: ArrayFieldClientComponent = (props) => {
const { field } = props
return <ArrayField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { ArrayFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldLabelClient: ArrayFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { ArrayFieldServerComponent } from 'payload'
// import { ArrayField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomArrayFieldServer: ArrayFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <ArrayField field={clientField} />
return 'This is a server component for the array field.'
}

View File

@@ -0,0 +1,12 @@
import type { ArrayFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomArrayFieldLabelServer: ArrayFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the array field label.'
}

View File

@@ -0,0 +1,38 @@
import type { CollectionConfig } from 'payload'
export const arrayFields: CollectionConfig['fields'] = [
{
name: 'arrayFieldServerComponent',
type: 'array',
admin: {
components: {
Field: '@/collections/Fields/array/components/server/Field#CustomArrayFieldServer',
Label: '@/collections/Fields/array/components/server/Label#CustomArrayFieldLabelServer',
},
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
},
{
name: 'arrayFieldClientComponent',
type: 'array',
admin: {
components: {
Field: '@/collections/Fields/array/components/client/Field#CustomArrayFieldClient',
Label: '@/collections/Fields/array/components/client/Label#CustomArrayFieldLabelClient',
},
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { BlocksFieldClientComponent } from 'payload'
import { BlocksField } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldClient: BlocksFieldClientComponent = (props) => {
const { field } = props
return <BlocksField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { BlocksFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldLabelClient: BlocksFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { BlocksFieldServerComponent } from 'payload'
// import { BlocksField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomBlocksFieldServer: BlocksFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <BlocksField field={clientField} />
return 'This is a server component for the blocks field.'
}

View File

@@ -0,0 +1,12 @@
import type { BlockFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomBlocksFieldLabelServer: BlockFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the blocks field label.'
}

View File

@@ -0,0 +1,54 @@
import type { CollectionConfig } from 'payload'
export const blocksFields: CollectionConfig['fields'] = [
{
name: 'blocksFieldServerComponent',
type: 'blocks',
admin: {
components: {
Field: '@/collections/Fields/blocks/components/server/Field#CustomBlocksFieldServer',
},
},
blocks: [
{
slug: 'text',
fields: [
{
name: 'content',
type: 'textarea',
label: 'Content',
},
],
labels: {
plural: 'Text Blocks',
singular: 'Text Block',
},
},
],
},
{
name: 'blocksFieldClientComponent',
type: 'blocks',
admin: {
components: {
Field: '@/collections/Fields/blocks/components/client/Field#CustomBlocksFieldClient',
},
},
blocks: [
{
slug: 'text',
fields: [
{
name: 'content',
type: 'textarea',
label: 'Content',
},
],
labels: {
plural: 'Text Blocks',
singular: 'Text Block',
},
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { CheckboxFieldClientComponent } from 'payload'
import { CheckboxField } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldClient: CheckboxFieldClientComponent = (props) => {
const { field } = props
return <CheckboxField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { CheckboxFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldLabelClient: CheckboxFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { CheckboxFieldServerComponent } from 'payload'
// import { CheckboxField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomCheckboxFieldServer: CheckboxFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <CheckboxField field={clientField} />
return 'This is a server component for the checkbox field.'
}

View File

@@ -0,0 +1,12 @@
import type { CheckboxFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomCheckboxFieldLabelServer: CheckboxFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the checkbox field label.'
}

View File

@@ -0,0 +1,26 @@
import type { CollectionConfig } from 'payload'
export const checkboxFields: CollectionConfig['fields'] = [
{
name: 'checkboxFieldServerComponent',
type: 'checkbox',
admin: {
components: {
Field: '@/collections/Fields/checkbox/components/server/Field#CustomCheckboxFieldServer',
Label:
'@/collections/Fields/checkbox/components/server/Label#CustomCheckboxFieldLabelServer',
},
},
},
{
name: 'checkboxFieldClientComponent',
type: 'checkbox',
admin: {
components: {
Field: '@/collections/Fields/checkbox/components/client/Field#CustomCheckboxFieldClient',
Label:
'@/collections/Fields/checkbox/components/client/Label#CustomCheckboxFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { DateFieldClientComponent } from 'payload'
import { DateTimeField } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldClient: DateFieldClientComponent = (props) => {
const { field } = props
return <DateTimeField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { DateFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldLabelClient: DateFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { DateFieldServerComponent } from 'payload'
// import { DateTimeField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomDateFieldServer: DateFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <DateTimeField field={clientField} />
return 'This is a server component for the date field.'
}

View File

@@ -0,0 +1,12 @@
import type { DateFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomDateFieldLabelServer: DateFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the date field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const dateFields: CollectionConfig['fields'] = [
{
name: 'dateFieldServerComponent',
type: 'date',
admin: {
components: {
Field: '@/collections/Fields/date/components/server/Field#CustomDateFieldServer',
Label: '@/collections/Fields/date/components/server/Label#CustomDateFieldLabelServer',
},
},
},
{
name: 'dateFieldClientComponent',
type: 'date',
admin: {
components: {
Field: '@/collections/Fields/date/components/client/Field#CustomDateFieldClient',
Label: '@/collections/Fields/date/components/client/Label#CustomDateFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { EmailFieldClientComponent } from 'payload'
import { EmailField } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldClient: EmailFieldClientComponent = (props) => {
const { field } = props
return <EmailField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { EmailFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldLabelClient: EmailFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { EmailFieldServerComponent } from 'payload'
// import { EmailField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomEmailFieldServer: EmailFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <EmailField field={clientField} />
return 'This is a server component for the email field.'
}

View File

@@ -0,0 +1,12 @@
import type { EmailFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomEmailFieldLabelServer: EmailFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the email field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const emailFields: CollectionConfig['fields'] = [
{
name: 'emailFieldServerComponent',
type: 'email',
admin: {
components: {
Field: '@/collections/Fields/email/components/server/Field#CustomEmailFieldServer',
Label: '@/collections/Fields/email/components/server/Label#CustomEmailFieldLabelServer',
},
},
},
{
name: 'emailFieldClientComponent',
type: 'email',
admin: {
components: {
Field: '@/collections/Fields/email/components/client/Field#CustomEmailFieldClient',
Label: '@/collections/Fields/email/components/client/Label#CustomEmailFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,42 @@
import type { CollectionConfig, Field } from 'payload'
import { arrayFields } from './array'
import { blocksFields } from './blocks'
import { checkboxFields } from './checkbox'
import { dateFields } from './date'
import { emailFields } from './email'
import { numberFields } from './number'
import { pointFields } from './point'
import { radioFields } from './radio'
import { relationshipFields } from './relationship'
import { selectFields } from './select'
import { textFields } from './text'
import { textareaFields } from './textarea'
export const CustomFields: CollectionConfig = {
slug: 'custom-fields',
admin: {
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
...([] as Field[]).concat(
arrayFields,
blocksFields,
checkboxFields,
dateFields,
emailFields,
numberFields,
pointFields,
radioFields,
relationshipFields,
selectFields,
textFields,
textareaFields,
),
],
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { NumberFieldClientComponent } from 'payload'
import { NumberField } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldClient: NumberFieldClientComponent = (props) => {
const { field } = props
return <NumberField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { NumberFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldLabelClient: NumberFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { NumberFieldServerComponent } from 'payload'
// import { NumberField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomNumberFieldServer: NumberFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <NumberField field={clientField} />
return 'This is a server component for the number field.'
}

View File

@@ -0,0 +1,12 @@
import type { NumberFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomNumberFieldLabelServer: NumberFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the number field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const numberFields: CollectionConfig['fields'] = [
{
name: 'numberFieldServerComponent',
type: 'number',
admin: {
components: {
Field: '@/collections/Fields/number/components/server/Field#CustomNumberFieldServer',
Label: '@/collections/Fields/number/components/server/Label#CustomNumberFieldLabelServer',
},
},
},
{
name: 'numberFieldClientComponent',
type: 'number',
admin: {
components: {
Field: '@/collections/Fields/number/components/client/Field#CustomNumberFieldClient',
Label: '@/collections/Fields/number/components/client/Label#CustomNumberFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { PointFieldClientComponent } from 'payload'
import { PointField } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldClient: PointFieldClientComponent = (props) => {
const { field } = props
return <PointField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { PointFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldLabelClient: PointFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { PointFieldServerComponent } from 'payload'
// import { PointField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomPointFieldServer: PointFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <PointField field={clientField} />
return 'This is a server component for the point field.'
}

View File

@@ -0,0 +1,12 @@
import type { PointFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomPointFieldLabelServer: PointFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the point field label.'
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const pointFields: CollectionConfig['fields'] = [
{
name: 'pointFieldServerComponent',
type: 'point',
admin: {
components: {
Field: '@/collections/Fields/point/components/server/Field#CustomPointFieldServer',
Label: '@/collections/Fields/point/components/server/Label#CustomPointFieldLabelServer',
},
},
},
{
name: 'pointFieldClientComponent',
type: 'point',
admin: {
components: {
Field: '@/collections/Fields/point/components/client/Field#CustomPointFieldClient',
Label: '@/collections/Fields/point/components/client/Label#CustomPointFieldLabelClient',
},
},
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { RadioFieldClientComponent } from 'payload'
import { RadioGroupField } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldClient: RadioFieldClientComponent = (props) => {
const { field } = props
return <RadioGroupField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { RadioFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldLabelClient: RadioFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { RadioFieldServerComponent } from 'payload'
// import { RadioGroupField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomRadioFieldServer: RadioFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <RadioGroupField field={clientField} />
return 'This is a server component for the radio field.'
}

View File

@@ -0,0 +1,12 @@
import type { RadioFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRadioFieldLabelServer: RadioFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the radio field label.'
}

View File

@@ -0,0 +1,44 @@
import type { CollectionConfig } from 'payload'
export const radioFields: CollectionConfig['fields'] = [
{
name: 'radioFieldServerComponent',
type: 'radio',
admin: {
components: {
Field: '@/collections/Fields/radio/components/server/Field#CustomRadioFieldServer',
Label: '@/collections/Fields/radio/components/server/Label#CustomRadioFieldLabelServer',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
],
},
{
name: 'radioFieldClientComponent',
type: 'radio',
admin: {
components: {
Field: '@/collections/Fields/radio/components/client/Field#CustomRadioFieldClient',
Label: '@/collections/Fields/radio/components/client/Label#CustomRadioFieldLabelClient',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
],
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { RelationshipFieldClientComponent } from 'payload'
import { RelationshipField } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldClient: RelationshipFieldClientComponent = (props) => {
const { field } = props
return <RelationshipField field={field} />
}

View File

@@ -0,0 +1,13 @@
'use client'
import type { RelationshipFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldLabelClient: RelationshipFieldLabelClientComponent = (
props,
) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { RelationshipFieldServerComponent } from 'payload'
// import { RelationshipField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomRelationshipFieldServer: RelationshipFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <RelationshipField field={clientField} />
return 'This is a server component for the relationship field.'
}

View File

@@ -0,0 +1,14 @@
import type { RelationshipFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomRelationshipFieldLabelServer: RelationshipFieldLabelServerComponent = (
props,
) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the relationship field label.'
}

View File

@@ -0,0 +1,30 @@
import type { CollectionConfig } from 'payload'
export const relationshipFields: CollectionConfig['fields'] = [
{
name: 'relationshipFieldServerComponent',
type: 'relationship',
admin: {
components: {
Field:
'@/collections/Fields/relationship/components/server/Field#CustomRelationshipFieldServer',
Label:
'@/collections/Fields/relationship/components/server/Label#CustomRelationshipFieldLabelServer',
},
},
relationTo: 'custom-fields',
},
{
name: 'relationshipFieldClientComponent',
type: 'relationship',
admin: {
components: {
Field:
'@/collections/Fields/relationship/components/client/Field#CustomRelationshipFieldClient',
Label:
'@/collections/Fields/relationship/components/client/Label#CustomRelationshipFieldLabelClient',
},
},
relationTo: 'custom-fields',
},
]

View File

@@ -0,0 +1,11 @@
'use client'
import type { SelectFieldClientComponent } from 'payload'
import { SelectField } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldClient: SelectFieldClientComponent = (props) => {
const { field } = props
return <SelectField field={field} />
}

View File

@@ -0,0 +1,11 @@
'use client'
import type { SelectFieldLabelClientComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldLabelClient: SelectFieldLabelClientComponent = (props) => {
const { field, label } = props
return <FieldLabel field={field} label={label} />
}

View File

@@ -0,0 +1,15 @@
import type { SelectFieldServerComponent } from 'payload'
// import { SelectField } from '@payloadcms/ui'
// import { createClientField } from '@payloadcms/ui/shared'
import type React from 'react'
export const CustomSelectFieldServer: SelectFieldServerComponent = (props) => {
const { field } = props
// const clientField = createClientField(field)
// return <SelectField field={clientField} />
return 'This is a server component for the select field.'
}

View File

@@ -0,0 +1,12 @@
import type { SelectFieldLabelServerComponent } from 'payload'
import { FieldLabel } from '@payloadcms/ui'
import React from 'react'
export const CustomSelectFieldLabelServer: SelectFieldLabelServerComponent = (props) => {
const { field } = props
// return <FieldLabel field={field} />
return 'This is a server component for the select field label.'
}

View File

@@ -0,0 +1,52 @@
import type { CollectionConfig } from 'payload'
export const selectFields: CollectionConfig['fields'] = [
{
name: 'selectFieldServerComponent',
type: 'select',
admin: {
components: {
Field: '@/collections/Fields/select/components/server/Field#CustomSelectFieldServer',
Label: '@/collections/Fields/select/components/server/Label#CustomSelectFieldLabelServer',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
{
label: 'Option 3',
value: 'option-3',
},
],
},
{
name: 'selectFieldClientComponent',
type: 'select',
admin: {
components: {
Field: '@/collections/Fields/select/components/client/Field#CustomSelectFieldClient',
Label: '@/collections/Fields/select/components/client/Label#CustomSelectFieldLabelClient',
},
},
options: [
{
label: 'Option 1',
value: 'option-1',
},
{
label: 'Option 2',
value: 'option-2',
},
{
label: 'Option 3',
value: 'option-3',
},
],
},
]

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomRootEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Root Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,24 @@
import type { CollectionConfig } from 'payload'
export const CustomRootViews: CollectionConfig = {
slug: 'custom-root-views',
admin: {
components: {
views: {
edit: {
root: {
Component: '@/collections/RootViews/components/CustomRootEditView#CustomRootEditView',
},
},
},
},
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
}

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomDefaultEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Default Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,12 @@
import type { ServerSideEditViewProps } from 'payload'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomTabEditView: React.FC<ServerSideEditViewProps> = () => {
return (
<Gutter>
<h1>Custom Tab Edit View</h1>
</Gutter>
)
}

View File

@@ -0,0 +1,32 @@
import type { CollectionConfig } from 'payload'
export const CustomViews: CollectionConfig = {
slug: 'custom-views',
admin: {
components: {
views: {
edit: {
customView: {
Component: '@/collections/Views/components/CustomTabEditView#CustomTabEditView',
path: '/custom-tab',
tab: {
href: '/custom-tab',
label: 'Custom Tab',
},
},
default: {
Component: '@/collections/Views/components/CustomDefaultEditView#CustomDefaultEditView',
},
},
},
},
useAsTitle: 'title',
},
fields: [
{
name: 'title',
type: 'text',
label: 'Title',
},
],
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomDefaultView: React.FC = () => {
return <Link href="/admin/custom-default">Go to Custom Default View</Link>
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomMinimalView: React.FC = () => {
return <Link href="/admin/custom-minimal">Go to Custom Minimal View</Link>
}

View File

@@ -0,0 +1,6 @@
import Link from 'next/link'
import React from 'react'
export const LinkToCustomView: React.FC = () => {
return <Link href="/admin/custom">Go to Custom View</Link>
}

View File

@@ -0,0 +1,30 @@
import type { AdminViewProps } from 'payload'
import { DefaultTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomDefaultRootView: 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>
)
}

View File

@@ -0,0 +1,17 @@
import type { AdminViewProps } from 'payload'
import { MinimalTemplate } from '@payloadcms/next/templates'
import { Gutter } from '@payloadcms/ui'
import React from 'react'
export const CustomMinimalRootView: React.FC<AdminViewProps> = () => {
return (
<MinimalTemplate>
<Gutter>
<h1>Custom Minimal Root View</h1>
<br />
<p>This view uses the Minimal Template.</p>
</Gutter>
</MinimalTemplate>
)
}

View File

@@ -0,0 +1,13 @@
import type { AdminViewProps } from 'payload'
import React from 'react'
export const CustomRootView: React.FC<AdminViewProps> = () => {
return (
<div>
<h1>Custom Root View</h1>
<br />
<p>This is a completely standalone view.</p>
</div>
)
}

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