Compare commits

..

87 Commits

Author SHA1 Message Date
Elliot DeNolf
6d2dd5849d chore(release): db-postgres/0.1.3 2023-10-10 16:09:24 -04:00
Jacob Fletcher
6d9353b53f fix: row field margins (#3558) 2023-10-10 16:00:41 -04:00
James Mikrut
1914be75aa Merge pull request #3555 from payloadcms/fix/#3521
fix: #3521
2023-10-10 15:59:52 -04:00
Elliot DeNolf
b17f627e02 chore(release): richtext-slate/1.0.2 2023-10-10 15:59:33 -04:00
Elliot DeNolf
bef79621ee chore(release): db-postgres/0.1.2 2023-10-10 15:59:33 -04:00
Jarrod Flesch
af892ecb0e fix: removes nested array field configs from array value (#3549)
* fix: array controls 'addBelow' was adding above
2023-10-10 15:55:00 -04:00
Elliot DeNolf
a42e84bbb2 chore(eslint): prepare config for publishing 2023-10-10 15:10:22 -04:00
James Mikrut
470bdb72ff Merge pull request #3553 from payloadcms/fix/#3541
fix: #3541
2023-10-10 14:49:11 -04:00
James Mikrut
5c36be949c Merge pull request #3554 from payloadcms/fix/#3540
fix: #3540
2023-10-10 14:49:01 -04:00
James
eb97acd408 fix: #3521 2023-10-10 14:46:52 -04:00
James
2567ac58ba fix: #3540 2023-10-10 14:21:12 -04:00
Jacob Fletcher
9ff014bbfe fix: row field width (#3550) 2023-10-10 14:09:47 -04:00
James
e6f0d35985 fix: #3541 2023-10-10 14:07:26 -04:00
Alessio Gravili
b1e449e005 Merge pull request #3551 from payloadcms/fix/slate-toolbar
fix: Slate toolbar rendered even if it has no elements and leaves
2023-10-10 19:36:29 +02:00
Alessio Gravili
9ae585d23c fix: Slate toolbar rendered even if it has no elements and leaves 2023-10-10 19:22:08 +02:00
Elliot DeNolf
9de3320933 chore(release): richtext-lexical/0.1.5 2023-10-10 12:08:13 -04:00
Elliot DeNolf
5d429fa7ae chore(release): live-preview-react/0.1.2 2023-10-10 12:08:08 -04:00
Elliot DeNolf
dc8f1925f0 chore(release): live-preview/0.1.2 2023-10-10 12:07:40 -04:00
Jessica Chowdhury
15f650afde docs: adds build your own plugin page (#3184)
* docs: adds build your own plugin page

* chore(docs): adds npx command to plugin template doc

* docs: update plugin doc order values

* docs: update plugin admin compatibility to coming soon

---------

Co-authored-by: Elliot DeNolf <denolfe@gmail.com>
2023-10-10 11:37:53 -04:00
Jacob Fletcher
c945384d63 fix(live-preview-react): moves react to peer dependencies (#3545) 2023-10-10 11:36:44 -04:00
Jacob Fletcher
dfada1b238 chore(live-preview): removes react dependencies (#3544) 2023-10-10 11:07:18 -04:00
Elliot DeNolf
229bdda2c1 chore: rename publish script 2023-10-10 10:48:51 -04:00
Alessio Gravili
a1d51fb410 Merge pull request #3543 from payloadcms/fix/lexical-blocks-validation
fix(richtext-lexical): blocks: missing properties passed into validation calls
2023-10-10 16:41:39 +02:00
Alessio Gravili
46430f5598 chore: prefer config.collections over payload.collections for validations 2023-10-10 16:20:11 +02:00
Alessio Gravili
e41899cd27 fix(richtext-lexical): missing properties passed into validation functions 2023-10-10 16:06:39 +02:00
Elliot DeNolf
890af8be05 ci: optimize e2e and refactor workflow (#3530)
* ci: split e2e

* chore: 3 parts

* chore: use matrix

* chore: use playwright container, bump playwright

* chore: remove playwright container

* ci: move all packages into matrix

* ci: reusable action to restore build cache

* chore: revert custom action

* chore: cleanup logs
2023-10-09 23:43:34 -04:00
Tylan Davis
8bfae6b932 docs: removes MONGODB_URI (#3482) 2023-10-09 18:07:09 -04:00
Jacob Fletcher
ace3e577f6 fix: renders global label as page title (#3532) 2023-10-09 17:58:21 -04:00
Marcus R
9198245ad9 docs(configuration/collections): moves pagination options to admin config (#3533) 2023-10-09 17:55:34 -04:00
Jarrod Flesch
f0095937ba fix: increases document controls popup list button hitbox (#3529) 2023-10-09 16:44:57 -04:00
Jarrod Flesch
0bbd7137cd chore: properly clear cart with correct data shape (#3500) 2023-10-09 16:29:15 -04:00
Thomas Dudziak
ffed34cf27 chore(docs): corrects bundler package import paths (#3523) 2023-10-09 16:03:16 -04:00
Elliot DeNolf
040f3a34d1 chore(release): payload@2.0.3 2023-10-09 15:27:26 -04:00
Elliot DeNolf
0985825b08 fix(templates/website): account view query 2023-10-09 15:25:56 -04:00
Alessio Gravili
c18d3b5f0e Merge pull request #3522 from payloadcms/chore/lexical-heading-node-improvements
fix(richtext-lexical): respect enabledHeadingSizes for markdown transformers
2023-10-09 21:22:52 +02:00
Alessio Gravili
e9e25ceac9 fix(richtext-lexical): respect enabledHeadingSizes for markdown transformers 2023-10-09 21:21:37 +02:00
James
35aed59a1a Merge branch 'main' of github.com:payloadcms/payload 2023-10-09 14:44:27 -04:00
James
26002173b1 chore: streamlines args necessary for entityToJSONSchema 2023-10-09 14:42:29 -04:00
Elliot DeNolf
41d968771e chore(release): bundler-webpack@1.0.2 2023-10-09 14:36:39 -04:00
James
26c34541d2 chore: merge 2023-10-09 14:31:31 -04:00
James
263d40d169 chore: adds safety to type generation 2023-10-09 14:31:02 -04:00
James Mikrut
6ced11d44d Merge pull request #3519 from payloadcms/fix/#3494
fix: #3494
2023-10-09 14:25:10 -04:00
James
be049cea00 fix: #3494 2023-10-09 14:24:20 -04:00
Jacob Fletcher
491e50c236 docs(admin/components): removes duplicative link 2023-10-09 14:15:59 -04:00
Jacob Fletcher
ad253db691 chore(examples/redirect): removes build files 2023-10-09 14:13:16 -04:00
Elliot DeNolf
aff5fdff8a chore(release): richtext-lexical@0.1.4 2023-10-09 14:09:17 -04:00
Alessio Gravili
aa97bebbd4 Merge pull request #3518 from payloadcms/chore/export-more-richtext-lexical
chore(richtext-lexical): export utils
2023-10-09 20:07:42 +02:00
Alessio Gravili
a2410ea9fc chore(richtext-lexical): export utils 2023-10-09 20:07:07 +02:00
Jacob Fletcher
de20ef1e8d chore(examples/form-builder): migrates to 2.0 (#3516) 2023-10-09 14:03:39 -04:00
Jacob Fletcher
08f7497040 chore(examples/redirects): migrates to 2.0 (#3514) 2023-10-09 14:03:18 -04:00
James Mikrut
74e99ce251 Merge pull request #3517 from payloadcms/fix/#3504
fix: #3504
2023-10-09 14:03:02 -04:00
Jacob Fletcher
b5c56efb4b chore(examples/multi-tenant): migrates to 2.0 (#3512) 2023-10-09 14:02:44 -04:00
Jacob Fletcher
4ff6d63c94 chore(examples/custom-server): migrates to 2.0 (#3509) 2023-10-09 14:01:51 -04:00
James
c90d1faa7f fix: #3504 2023-10-09 14:01:12 -04:00
Jacob Fletcher
1848b120ce chore(examples/live-preview): pins payload to latest and regenerates types (#3507) 2023-10-09 14:01:08 -04:00
Jacob Fletcher
62679baa91 chore(examples/auth): migrates to 2.0 (#3506) 2023-10-09 14:00:38 -04:00
Jacob Fletcher
2de36550ae chore(examples/draft-preview): migrates to 2.0 (#3505) 2023-10-09 14:00:23 -04:00
James Mikrut
61ea5becbb Merge pull request #3515 from payloadcms/fix/#3513
fix: #3513, hasMany relationships unable to be cleared
2023-10-09 13:47:34 -04:00
James
5d9384f530 fix: #3513, hasMany relationships unable to be cleared 2023-10-09 13:46:41 -04:00
Elliot DeNolf
d75ffa0ea7 chore(release): richtext-lexical@0.1.3 2023-10-09 13:31:39 -04:00
Elliot DeNolf
26967fb924 docs: move payload script mention to top of migrations 2023-10-09 13:30:06 -04:00
Alessio Gravili
830d9867b6 chore(richtext-lexical): add build:clean script to package.json 2023-10-09 19:27:01 +02:00
Elliot DeNolf
2f86c196e1 docs: payload script in package.json 2023-10-09 13:18:01 -04:00
Alessio Gravili
86a35ed441 chore(richtext-lexical): improve handling of read-only lexical editors (#3510) 2023-10-09 18:47:09 +02:00
Jessica Boezwinkle
70e068b182 docs: updates required node version 2023-10-09 16:01:49 +01:00
Elliot DeNolf
4ac01a7fa3 chore(readme): add 2.0 announcement 2023-10-09 10:05:37 -04:00
Elliot DeNolf
8058a6d800 chore(readme): add migrating link 2023-10-09 09:26:57 -04:00
Elliot DeNolf
252b04097f chore(release): richtext-slate@1.0.1 2023-10-09 09:21:49 -04:00
Elliot DeNolf
23066aec71 chore(release): richtext-lexical@0.1.2 2023-10-09 09:21:37 -04:00
Elliot DeNolf
b9a595b00c chore(release): live-preview-react@0.1.1 2023-10-09 09:21:33 -04:00
Elliot DeNolf
ea49d74941 chore(release): live-preview@0.1.1 2023-10-09 09:21:27 -04:00
Elliot DeNolf
f5f41f929e chore(release): db-postgres@0.1.1 2023-10-09 09:21:17 -04:00
Elliot DeNolf
61151c9c5d chore(release): db-mongodb@1.0.2 2023-10-09 09:21:10 -04:00
Elliot DeNolf
c12c1a7472 chore(release): bundler-webpack@1.0.1 2023-10-09 09:21:04 -04:00
Elliot DeNolf
7afa1e999d chore(release): bundler-vite@0.1.2 2023-10-09 09:20:36 -04:00
Elliot DeNolf
71c41dbe03 chore: update main and types to dist 2023-10-09 09:16:46 -04:00
dependabot[bot]
a161dc7bb6 chore(deps): bump semver in /examples/live-preview/next-app (#3490)
Bumps [semver](https://github.com/npm/node-semver) from 6.3.0 to 6.3.1.
- [Release notes](https://github.com/npm/node-semver/releases)
- [Changelog](https://github.com/npm/node-semver/blob/v6.3.1/CHANGELOG.md)
- [Commits](https://github.com/npm/node-semver/compare/v6.3.0...v6.3.1)

---
updated-dependencies:
- dependency-name: semver
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-09 09:14:34 -04:00
Jacob Fletcher
6c17222a6a docs: improves custom views (#3499) 2023-10-09 09:14:09 -04:00
Elliot DeNolf
63bf7d9303 chore(release): payload@2.0.2 2023-10-09 09:04:44 -04:00
James Mikrut
f878135e8b Update CHANGELOG.md 2023-10-09 09:03:49 -04:00
James
11a77ae489 Merge branch 'main' of github.com:payloadcms/payload 2023-10-09 09:02:11 -04:00
James
e5d6a75449 fix: beforeOperation hooks now correctly only run once 2023-10-09 09:02:04 -04:00
Jessica Boezwinkle
3cb0d9c2ca docs: misc cleanup 2023-10-09 14:00:11 +01:00
Jacob Fletcher
229149a5a6 chore: removes console log 2023-10-09 08:56:08 -04:00
Elliot DeNolf
9006643102 chore(templates): fix website template error 2023-10-09 08:56:08 -04:00
Jacob Fletcher
25ae4a24f2 chore: consolidates admin view types 2023-10-09 08:56:08 -04:00
Alessio Gravili
501ec4464f chore(richtext-slate): export ElementButton, LeafButton and toggleElement 2023-10-09 14:50:19 +02:00
430 changed files with 14149 additions and 15944 deletions

View File

@@ -31,6 +31,11 @@ body:
description: What version of Payload are you running?
validations:
required: true
- type: input
id: adapters-plugins
attributes:
label: Adapters and Plugins
description: What adapters and plugins are you using? ie. db-mongodb, db-postgres, bundler-webpack, etc.
- type: markdown
attributes:
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.

View File

@@ -108,6 +108,10 @@ jobs:
tests-e2e:
runs-on: ubuntu-latest
needs: core-build
strategy:
fail-fast: false
matrix:
part: [1/4, 2/4, 3/4, 4/4]
steps:
- name: Use Node.js 18
@@ -128,14 +132,14 @@ jobs:
key: ${{ github.sha }}-${{ github.run_number }}
- name: E2E Tests
run: pnpm test:e2e --bail
run: pnpm test:e2e --part ${{ matrix.part }} --bail
- uses: actions/upload-artifact@v3
if: always()
with:
name: test-results
path: test-results/
retention-days: 30
retention-days: 1
tests-type-generation:
runs-on: ubuntu-latest
@@ -165,11 +169,22 @@ jobs:
- name: Generate GraphQL schema file
run: pnpm dev:generate-graphql-schema graphql-schema-gen
# DB Adapters
build-db-mongodb:
build-packages:
name: Build Packages
runs-on: ubuntu-latest
needs: core-build
strategy:
fail-fast: false
matrix:
pkg:
- db-mongodb
- db-postgres
- bundler-webpack
- bundler-vite
- richtext-slate
- richtext-lexical
- live-preview
- live-preview-react
steps:
- name: Use Node.js 18
@@ -189,162 +204,5 @@ jobs:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build db-mongodb
run: pnpm turbo run build --filter=db-mongodb
build-db-postgres:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build db-postgres
run: pnpm turbo run build --filter=db-postgres
# Bundlers
build-bundler-webpack:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build bundler-webpack
run: pnpm turbo run build --filter=bundler-webpack
build-bundler-vite:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build bundler-vite
run: pnpm turbo run build --filter=bundler-vite
# Other Plugins
build-plugin-richtext-slate:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build richtext-slate
run: pnpm turbo run build --filter=richtext-slate
build-plugin-richtext-lexical:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build richtext-lexical
run: pnpm turbo run build --filter=richtext-lexical
build-plugin-live-preview:
runs-on: ubuntu-latest
needs: core-build
steps:
- name: Use Node.js 18
uses: actions/setup-node@v3
with:
node-version: 18
- name: Install pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Restore build
uses: actions/cache@v3
with:
path: ./*
key: ${{ github.sha }}-${{ github.run_number }}
- name: Build live-preview
run: pnpm turbo run build --filter=live-preview
- name: Build live-preview-react
run: pnpm turbo run build --filter=live-preview-react
- name: Build ${{ matrix.pkg }}
run: pnpm turbo run build --filter=${{ matrix.pkg }}

2
.vscode/launch.json vendored
View File

@@ -17,7 +17,7 @@
"type": "node-terminal"
},
{
"command": "pnpm run dev:postgres collections-graphql",
"command": "pnpm run dev:postgres fields",
"cwd": "${workspaceFolder}",
"name": "Run Dev Postgres",
"request": "launch",

View File

@@ -51,11 +51,29 @@ export default buildConfig({
These new properties are all now required for Payload to function, and you will have to install each separate adapter that you use. Feel free to swap out any of the adapters with your choice (Lexical, Postgres, Vite, etc.)
Make sure to install the packages that you need. In the above example, you would need to install the following:
```bash
npm install --save @payloadcms/db-mongodb @payloadcms/richtext-slate @payloadcms/bundler-webpack
```
### ⚠️ Draft versions now require a `latest: true` property to be set on the most recent draft in your `_versions` collections(s)
We have a ready-to-go migration script for your versions from v1 to v2, and to use it, all you have to do is run the following commands:
**1. Create a migration, using the new Payload migration API**
**1. First, make sure you have a `payload` npm script in your `package.json`**
```json
{
"scripts": {
"payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload"
}
}
```
Adjust the `PAYLOAD_CONFIG_PATH` to point to your Payload config file if necessary.
**2. Create a migration, using the new Payload migration API**
```bash
npm run payload migrate:create --file @payloadcms/db-mongodb/versions-v1-v2
@@ -63,7 +81,7 @@ npm run payload migrate:create --file @payloadcms/db-mongodb/versions-v1-v2
The above command will output a migration file into your `./src/migrations` folder (default migrations location). It contains a migration script to automatically add a `latest: true` flag to each of your newest drafts, for all draft-enabled collections. It works out of the box!
**2. Run migrations**
**3. Run migrations**
From there, you need to run migrations. Run the following command to execute your new migration:

View File

@@ -25,6 +25,9 @@
<a target="_blank" href="https://payloadcms.com/docs/getting-started/what-is-payload" rel="dofollow"><strong>Explore the Docs</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://demo.payloadcms.com/" rel="dofollow"><strong>Try Live Demo</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a>&nbsp;·&nbsp;<a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow"><strong>View G2 Reviews</strong></a>
</h4>
<hr/>
### 🎉 Payload 2.0 is now available! Read more in the [announcement post](https://payloadcms.com/blog/payload-2-0).
<h3>Benefits over a regular CMS</h3>
<ul>
<li>Dont hit some third-party SaaS API, hit your own API</li>
@@ -95,6 +98,8 @@ We're constantly adding more templates to our [Templates Directory](https://gith
Check out the [Payload website](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.
Migrating from v1 to v2? Check out the [2.0 Release Notes](https://github.com/payloadcms/payload/releases/tag/v2.0.0) on how to do it.
## 🙋 Contributing
If you want to add contributions to this repository, please follow the instructions in [contributing.md](./CONTRIBUTING.md).

View File

@@ -12,13 +12,13 @@ Payload has two official bundlers, the [Webpack Bundler](/docs/admin/webpack) an
Webpack (recommended):
```text
yarn add @payloadcms/webpack-bundler
yarn add @payloadcms/bundler-webpack
```
Vite (beta):
```text
yarn add @payloadcms/vite-bundler
yarn add @payloadcms/bundler-vite
```
##### Configure the bundler

View File

@@ -72,7 +72,7 @@ export default buildConfig({
#### Views
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views that can be overridden:
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views dy default, all of which can be overridden:
| Property | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
@@ -84,6 +84,7 @@ To swap out any of these views, simply pass in your custom component to the `adm
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
@@ -114,6 +115,7 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
```ts
// payload.config.ts
{
// ...
admin: {
components: {
views: {
@@ -127,7 +129,9 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
}
```
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/master/test/admin/components)._ For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/master/test/admin/components)._
For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component).
### Collections
@@ -207,19 +211,19 @@ export const MyCollection: SanitizedCollectionConfig = {
#### Collection views
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default that can be overridden:
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views dy default, all of which can be overridden:
| Property | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given Collection. |
| **`List`** | The List view is used to show a list of documents for a given Collection. |
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
| **`List`** | The List view is used to show a list of documents for a given collection. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
```ts
// Collection.ts
export const MyCollection: SanitizedCollectionConfig = {
slug: 'my-collection',
{
// ...
admin: {
components: {
views: {
@@ -231,7 +235,27 @@ export const MyCollection: SanitizedCollectionConfig = {
}
```
To swap or add new _tabs_ to the `Edit` view, you can use the `admin.components.views.Edit` property on the collection's config. See the [Custom Tabs](#custom-tabs) section for more information. For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
To swap specific _nested_ views within the parent `Edit` view, you can use the `admin.components.views.Edit` property on the globals's config. This will only replace the nested view, leaving the page breadcrumbs, title, tabs, etc intact.
```ts
// Collection.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: MyCustomDefaultTab,
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Globals
@@ -247,17 +271,18 @@ As with Collections, you can override components on a global-by-global basis via
#### Global views
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default that you can override:
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views dy default, all of which can be overridden:
| Property | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
```ts
export const MyGlobal: SanitizedGlobalConfig = {
slug: 'my-global',
// Global.ts
{
// ...
admin: {
components: {
views: {
@@ -268,17 +293,37 @@ export const MyGlobal: SanitizedGlobalConfig = {
}
```
To swap or add new _tabs_ to the `Edit` view, you can use the `admin.components.views.Edit` property on the collection's config. See the [Custom Tabs](#custom-tabs) section for more information. For help on how to build your own custom view components, see the [Building a custom view component](#building-a-custom-view-component) section.
_For help on how to build your own custom view components, see [building a custom view component](#building-a-custom-view-component)._
To swap specific _nested_ views within the parent `Edit` view, you can use the `admin.components.views.Edit` property on the globals's config. This will only replace the nested view, leaving the page breadcrumbs, title, and tabs intact.
```ts
// Global.ts
{
// ...
admin: {
components: {
views: {
Edit: {
Default: MyCustomDefaultTab,
},
},
},
},
}
```
You can also add _new_ tabs to the `Edit` view by adding another key to the `components.views.Edit[key]` object with a `path` and `Component` property. See [Custom Tabs](#custom-tabs) for more information.
### Custom Tabs
To can swap collection or global tabs, pass an _object_ to the `admin.components.views.Edit` property on any collection or global config. Payload renders the following views by default which can be overridden:
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views dy default, all of which can be overridden:
| Property | Description |
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
| **`Default`** | The Default view is the primary view in which your document is edited. |
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
| **`Version`** | The Version view is used to view a single version of a single document for a given Collection. [More details](../versions). |
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
@@ -291,7 +336,7 @@ export const MyCollection: SanitizedCollectionConfig = {
admin: {
components: {
views: {
Edit: {
Edit: { // You can also define `components.views.Edit` as a component, this will override _all_ nested views
Default: MyCustomDefaultTab,
Versions: MyCustomVersionsTab,
Version: MyCustomVersionTab,
@@ -304,7 +349,7 @@ export const MyCollection: SanitizedCollectionConfig = {
}
```
To add a _new_ tab to the `Edit` view, simply add another key to the `views.Edit` object with at least a `path` and `Component` property. For example:
To add a _new_ tab to the `Edit` view, simply add another key to `components.views.Edit[key]` with at least a `path` and `Component` property. For example:
```ts
// `Collection.ts` or `Global.ts`
@@ -317,6 +362,17 @@ export const MyCollection: SanitizedCollectionConfig = {
MyCustomTab: {
Component: MyCustomTab,
path: '/my-custom-tab',
// You an swap the entire tab component out for your own
Tab: MyCustomTab
},
AnotherCustomView: {
Component: AnotherCustomView,
path: '/another-custom-view',
// Or you can use the default tab component and just pass in your own label and href
Tab: {
label: 'Another Custom View',
href: '/another-custom-view',
}
},
},
},

View File

@@ -5,8 +5,6 @@ order: 100
desc: NEEDS TO BE WRITTEN
---
TODO: expand on this and make sure it looks nice, talk about how if you use a `process.env.SERVER_URL`, it might not be usable in your Payload config in your admin UI, but it needs to be, so it should be prefixed like `process.env.PAYLOAD_PUBLIC_SERVER_URL` to work in both places
## Admin environment vars
<Banner type="warning">

View File

@@ -5,18 +5,16 @@ order: 70
desc: Learn how to exclude server-only code from the Payload Admin UI bundle
---
### Aliasing server-only modules
Because the Admin Panel browser bundle includes your Payload Config file, files using server-only modules need to be excluded.
It's common for your config to rely on server only modules to perform logic in access control functions, hooks, and other contexts.
Any file that imports a server-only module such as `fs`, `stripe`, `authorizenet`, `nodemailer`, etc. **cannot** be included in the browser bundle.
#### Let's Look at an example
#### Example Scenario
Say we have a collection called `Subscriptions` that has a `beforeChange` hook that creates a Stripe subscription whenever a Subscription document is created in Payload.
##### Your collection config
**Collection config**:
```ts
// collections/Subscriptions/index.ts
@@ -39,7 +37,7 @@ export const Subscription: CollectionConfig = {
}
```
##### Your collection hook
**Collection hook**:
```ts
// collections/Subscriptions/hooks/createStripeSubscription.ts

View File

@@ -347,7 +347,7 @@ The `useForm` hook returns an object with the following properties: |
value: <strong><code>rowIndex</code></strong>,
},
{
value: "The index of the row to add",
value: "The index of the row to add. If omitted, the row will be added to the end of the array.",
},
],
[

View File

@@ -29,7 +29,6 @@ It's often best practice to write your Collections in separate files and then im
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. Set to `false` to disable GraphQL. |
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
| **`defaultSort`** | Pass a top-level field to sort by default in the collection List view. Prefix the name of the field with a minus symbol ("-") to sort in descending order. |
| **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) |
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
_\* An asterisk denotes that a property is required._
@@ -84,6 +83,7 @@ property on a collection's config.
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
| `components` | Swap in your own React components to be used within this collection. [More](/docs/admin/components#collections) |
| `listSearchableFields` | Specify which fields should be searched in the List search view. [More](#list-searchable-fields) |
| **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) |
### Preview

View File

@@ -6,10 +6,18 @@ keywords: database, migrations, ddl, sql, mongodb, postgres, documentation, Cont
desc: Payload features first-party database migrations all done in TypeScript.
---
## Migrations
Payload exposes a full suite of migration controls available for your use. Migration commands are accessible via the `npm run payload` command in your project directory.
Ensure you have an npm script called "payload" in your `package.json` file.
```json
{
"scripts": {
"payload": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload"
}
}
```
<Banner>
Note that you need to run Payload migrations through the package manager that you are using, because Payload should not be globally installed on your system.
</Banner>

View File

@@ -11,8 +11,8 @@ keywords: documentation, getting started, guide, Content Management System, cms,
Payload requires the following software:
- Yarn or NPM
- Node.js version 14+
- A Database (MongoDB or Postgres)
- Node.js version 16+
- Any [compatible database](/docs/database/overview) (MongoDB or Postgres)
<Banner type="warning">
Before proceeding any further, please ensure that you have the above requirements met.
@@ -104,43 +104,43 @@ PAYLOAD_SECRET=your-payload-secret
Here is a list of all properties available to pass through `payload.init`:
##### `secret`
##### secret
**Required**. This is a secure string that will be used to authenticate with Payload. It can be random but should be at least 14 characters and be very difficult to guess.
Payload uses this secret key to generate secure user tokens (JWT). Behind the scenes, we do not use your secret key to encrypt directly - instead, we first take the secret key and create an encrypted string using the SHA-256 hash function. Then, we reduce the encrypted string to its first 32 characters. This final value is what Payload uses for encryption.
##### `config`
##### config
Allows you to pass your config directly to the onInit function. The config passed here should match the payload.config file.
##### `disableOnInit`
##### disableOnInit
A boolean that disables running your `onInit` function when Payload starts up.
##### `disableDBConnect`
##### disableDBConnect
A boolean that disables the database connection when Payload starts up.
##### `email`
##### email
An object used to configure SMTP. [Read more](/docs/email/overview).
##### `express`
##### express
This is your Express app as shown above. Payload will tie into your existing `app` and scope all of its functionalities to sub-routers. By default, Payload will add an `/admin` router and an `/api` router, but you can customize these paths.
##### `local`
##### local
A boolean that when set to `true` tells Payload to start in local-only mode which will bypass setting up API routes. When set to `true`, `express` is not required. This is useful when running scripts that need to use Payload's [local-api](/docs/local-api/overview).
##### `loggerDestination`
##### loggerDestination
Specify destination stream for the built-in Pino logger that Payload uses for internal logging. See [Pino Docs](https://getpino.io/#/docs/api?id=pino-destination) for more info on what is available.
##### `loggerOptions`
##### loggerOptions
Specify options for the built-in Pino logger that Payload uses for internal logging. See [Pino Docs](https://getpino.io/#/docs/api?id=options) for more info on what is available.
##### `onInit`
##### onInit
A function that is called immediately following startup that receives the Payload instance as it's only argument.

View File

@@ -412,7 +412,7 @@ dotenv.config({
path: path.resolve(__dirname, '../.env'),
})
const { PAYLOAD_SECRET, MONGODB_URI } = process.env
const { PAYLOAD_SECRET } = process.env
const doAction = async (): Promise<void> => {
await payload.init({

View File

@@ -1,10 +1,10 @@
---
title: Admin panel compatibility
label: Admin compatibility
order: 20
order: 30
desc: NEEDS TO BE WRITTEN
---
TODO: talk about how plugins need to ensure compatibility with both Vite and Webpack
- It's best practice to alias your plugin to an admin-only version, so if you have admin-only changes, put them in the admin plugin, and then leave the full plugin, complete with server code, to be installed on the server side
<Banner type="success">
COMING SOON: This page is a work in progress. Check back soon for more information.
</Banner>

View File

@@ -0,0 +1,294 @@
---
title: Building Your Own Plugin
label: Build Your Own
order: 20
desc: Starting to build your own plugin? Find everything you need and learn best practices with the Payload plugin template.
keywords: plugins, template, config, configuration, extensions, custom, documentation, Content Management System, cms, headless, javascript, node, react, express
---
Building your own plugin is easy, and if you&apos;re already familiar with Payload then you&apos;ll have everything you need to get started. You can either start from scratch or use the Payload plugin template to get up and running quickly.
<Banner type="success">
To use the template, run `npx create-payload-app@latest -t plugin -n my-new-plugin` directly in your terminal or [clone the template directly from GitHub](https://github.com/payloadcms/payload-plugin-template).
</Banner>
Our plugin template includes everything you need to build a full life-cycle plugin:
* Example files and functions for extending the payload config
* A local dev environment to develop the plugin
* Test suite with integrated GitHub workflow
By abstracting your code into a plugin, you&apos;ll be able to reuse your feature across multiple projects and make it available for other developers to use.
### Plugins Recap
Here is a brief recap of how to integrate plugins with Payload, to learn more head back to the [plugin overview page](https://payloadcms.com/docs/plugins/overview).
#### How to install a plugin
To install any plugin, simply add it to your Payload config in the plugins array.
```
import samplePlugin from 'sample-plugin';
const config = buildConfig({
plugins: [
// Add plugins here
samplePlugin({
enabled: true,
}),
],
});
export default config;
```
#### Initialization
The initialization process goes in the following order:
1. Incoming config is validated
2. Plugins execute
3. Default options are integrated
4. Sanitization cleans and validates data
5. Final config gets initialized
### Plugin Template
In the [Payload plugin template](https://github.com/payloadcms/payload-plugin-template), you will see a common file structure that is used across plugins:
1. root folder - general configuration
2. /src folder - everything related to the plugin
3. /dev folder - sanitized test project for development
#### Root
In the root folder, you will see various files related to the configuration of the plugin. We set up our environment in a similar manner in Payload core and across other projects. The only two files you need to modify are:
* **README**.md - This contains instructions on how to use the template. When you are ready, update this to contain instructions on how to use your Plugin.
* **package**.json - Contains necessary scripts and dependencies. Overwrite the metadata in this file to describe your Plugin.
#### Dev
The purpose of the **dev** folder is to provide a sanitized local Payload project. so you can run and test your plugin while you are actively developing it.
Do **not** store any of the plugin functionality in this folder - it is purely an environment to _assist_ you with developing the plugin.
If you&apos;re starting from scratch, you can easily setup a dev environment like this:
```
mkdir dev
cd dev
npx create-payload-app
```
If you&apos;re using the plugin template, the dev folder is built out for you and the `samplePlugin` has already been installed in `dev/payload.config()`.
```
plugins: [
// when you rename the plugin or add options, make sure to update it here
samplePlugin({
enabled: false,
})
]
```
You can add to the `dev/payload.config` and build out the dev project as needed to test your plugin.
When you&apos;re ready to start development, navigate into this folder with `cd dev`
And then start the project with `yarn dev` and pull up `http://localhost:3000` in your browser.
### Testing
Another benefit of the dev folder is that you have the perfect environment established for testing.
A good test suite is essential to ensure quality and stability in your plugin. Payload typically uses [Jest](https://jestjs.io/); a popular testing framework, widely used for testing JavaScript and particularly for applications built with React.
Jest organizes tests into test suites and cases. We recommend creating tests based on the expected behavior of your plugin from start to finish. Read more about tests in the [Jest documentation.](https://jestjs.io/)
The plugin template provides a stubbed out test suite at `dev/plugin.spec.ts` which is ready to go - just add in your own test conditions and you&apos;re all set!
```
import payload from 'payload'
describe('Plugin tests', () => {
// Example test to check for seeded data
it('seeds data accordingly', async () => {
const newCollectionQuery = await payload.find({
collection: 'newCollection',
sort: 'createdAt',
})
newCollection = newCollectionQuery.docs
expect(newCollectionQuery.totalDocs).toEqual(1)
})
})
```
### Seeding data
For development and testing, you will likely need some data to work with. You can streamline this process by seeding and dropping your database - instead of manually entering data.
In the plugin template, you can navigate to `dev/src/server.ts` and see an example seed function.
```
if (process.env.PAYLOAD_SEED === 'true') {
await seed(payload)
}
```
A sample seed function has been created for you at `dev/src/seed`, update this file with additional data as needed.
```
export const seed = async (payload: Payload): Promise<void> => {
payload.logger.info('Seeding data...')
await payload.create({
collection: 'new-collection',
data: {
title: 'Seeded title',
},
})
// Add additional seed data here
}
```
#### Src
Now that we have our environment setup and dev project ready to go - it&apos;s time to build the plugin!
**index.ts**
First up, the `src/index.ts` file - this is where the plugin should be imported from. It is best practice not to build the plugin directly in this file, instead we use this to export the plugin and types from their respective files.
**Plugin.ts**
To reiterate, the essence of a payload plugin is simply to extend the Payload config - and that is exactly what we are doing in this file.
```
export const samplePlugin =
(pluginOptions: PluginTypes) =>
(incomingConfig: Config): Config => {
let config = { ...incomingConfig }
// do something cool with the config here
return config
}
```
1. First, you need to receive the existing Payload config along with any plugin options.
2. Then set the variable `config` to be equal to a copy of the existing config.
3. From here, you can extend the config however you like!
4. Finally, return the config and you&apos;re all set.
### Spread Syntax
[Spread syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Spread_syntax) (or the spread operator) is a feature in JavaScript that uses the dot notation **(...)** to spread elements from arrays, strings, or objects into various contexts.
We are going to use spread syntax to allow us to add data to existing arrays without losing the existing data. It is crucial to spread the existing data correctly, else this can cause adverse behavior and conflicts with Payload config and other plugins.
Let&apos;s say you want to build a plugin that adds a new collection:
```
config.collections = [
...(config.collections || []),
newCollection,
// Add additional collections here
]
```
First, you need to spread the `config.collections` to ensure that we don&apos;t lose the existing collections. Then you can add any additional collections, just as you would in a regular payload config.
This same logic is applied to other properties like admin, globals, hooks:
```
config.globals = [
...(config.globals || []),
// Add additional globals here
]
config.hooks = {
...(config.hooks || {}),
// Add additional hooks here
}
```
Some properties will be slightly different to extend, for instance the `onInit` property:
```
config.onInit = async payload => {
if (incomingConfig.onInit) await incomingConfig.onInit(payload)
// Add additional onInit code by using the onInitExtension function
onInitExtension(pluginOptions, payload)
}
```
If you wish to add to the `onInit`, you must include the async/await. We don&apos;t use spread syntax in this case, instead you must await the existing `onInit` before running additional functionality.
In the template, we have stubbed out a basic `onInitExtension` file that you can use, if not needed feel free to delete it.
### Webpack
If any of your files use server only packages such as fs, stripe, nodemailer, etc, they will need to be removed from the browser bundle. To do that, you can [alias the file imports with webpack](https://payloadcms.com/docs/admin/webpack#aliasing-server-only-modules).
When files are bundled for the browser, the import paths are essentially crawled to determine what files to include in the bundle. To prevent the server only files from making it into the bundle, we can alias their import paths to a file that can be included in the browser. This will short-circuit the import path crawling and ensure browser only code is bundled.
Webpack is another part of the Payload config that can be a little more tricky to extend. To help here, the template includes a helper function `extendWebpackConfig()` which takes care of spreading the existing webpack, so you can just add your new stuff:
```
config.admin = {
...(config.admin || {}),
// Add your aliases to the helper function below
webpack: extendWebpackConfig(incomingConfig)
}
```
### Types
If your plugin has options, you should define and provide types for these options in a separate file which gets exported from the main `index.ts`.
```
export interface PluginTypes {
/**
* Enable or disable plugin
* @default false
*/
enabled?: boolean
}
```
If possible, include [JSDoc comments](https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#types-1) to describe the options and their types. This allows a developer to see details about the options in their editor.
### Best practices
In addition to the setup covered above, here are other best practices to follow:
##### Providing an enable / disable option:
For a better user experience, provide a way to disable the plugin without uninstalling it. This is especially important if your plugin adds additional webpack aliases, this will allow you to still let the webpack run to prevent errors.
##### Include tests in your GitHub CI workflow:
If you&apos;ve configured tests for your package, integrate them into your workflow to run the tests each time you commit to the plugin repository. Learn more about [how to configure tests into your GitHub CI workflow.](https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs)
##### Publish your finished plugin to NPM:
The best way to share and allow others to use your plugin once it is complete is to publish an NPM package. This process is straightforward and well documented, find out more about [creating and publishing a NPM package here](https://docs.npmjs.com/creating-and-publishing-scoped-public-packages/).
##### Add payload-plugin topic tag:
Apply the tag **payload-plugin** to your GitHub repository. This will boost the visibility of your plugin and ensure it gets listed with [existing payload plugins](https://github.com/topics/payload-plugin).
##### Use [Semantic Versioning](https://semver.org/) (SemVar):
With the SemVar system you release version numbers that reflect the nature of changes (major, minor, patch). Ensure all major versions reference their Payload compatibility.

View File

@@ -160,7 +160,7 @@ DigitalOcean provides extremely helpful documentation that can walk you through
## Docker
This is an example of a multi-stage docker build of Payload for production. Ensure you are setting your environment variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `MONGODB_URI` if needed.
This is an example of a multi-stage docker build of Payload for production. Ensure you are setting your environment variables on deployment, like `PAYLOAD_SECRET`, `PAYLOAD_CONFIG_PATH`, and `DATABASE_URI` if needed.
```dockerfile
FROM node:18-alpine as base
@@ -210,7 +210,7 @@ services:
depends_on:
- mongo
environment:
MONGODB_URI: mongodb://mongo:27017/payload
DATABASE_URI: mongodb://mongo:27017/payload
PORT: 3000
NODE_ENV: development
PAYLOAD_SECRET: TESTING

View File

@@ -1 +1 @@
NEXT_PUBLIC_CMS_URL=http://localhost:3000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000

View File

@@ -8,7 +8,7 @@ export const USER = `
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const gql = async (query: string): Promise<any> => {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/graphql`, {
const res = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/graphql`, {
method: 'POST',
credentials: 'include',
headers: {

View File

@@ -18,7 +18,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const create = useCallback<Create>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users`, args)
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, args)
setUser(user)
return user
}
@@ -40,7 +40,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const login = useCallback<Login>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/login`, args)
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/login`, args)
setUser(user)
return user
}
@@ -64,7 +64,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const logout = useCallback<Logout>(async () => {
if (api === 'rest') {
await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/logout`)
await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/logout`)
setUser(null)
return
}
@@ -83,7 +83,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const fetchMe = async () => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/me`,
{},
{
method: 'GET',
@@ -113,7 +113,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
async args => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/forgot-password`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
args,
)
setUser(user)
@@ -134,7 +134,10 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const resetPassword = useCallback<ResetPassword>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/reset-password`, args)
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,
args,
)
setUser(user)
return user
}

View File

@@ -14,7 +14,7 @@ export const getMeUser = async (args?: {
const cookieStore = cookies()
const token = cookieStore.get('payload-token')?.value
const meUserReq = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`, {
const meUserReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/me`, {
headers: {
Authorization: `JWT ${token}`,
},

View File

@@ -39,7 +39,9 @@ export const AccountForm: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
if (user) {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/${user.id}`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/${user.id}`,
{
// Make sure to include cookies with fetch
credentials: 'include',
method: 'PATCH',
@@ -47,7 +49,8 @@ export const AccountForm: React.FC = () => {
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
const json = await response.json()

View File

@@ -22,7 +22,7 @@ export default async function Account() {
<h1>Account</h1>
<p>
{`This is your account dashboard. Here you can update your account information and more. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -38,7 +38,7 @@ export const CreateAccountForm: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users`, {
const response = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
@@ -75,7 +75,7 @@ export const CreateAccountForm: React.FC = () => {
<form onSubmit={handleSubmit(onSubmit)} className={classes.form}>
<p>
{`This is where new customers can signup and create a new account. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -57,7 +57,7 @@ export const LoginForm: React.FC = () => {
{' with the password '}
<b>demo</b>
{'. To manage your users, '}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
.

View File

@@ -35,7 +35,7 @@ export default function Home() {
{' to start the authentication flow. Once logged in, you will be redirected to the '}
<Link href="/account">account page</Link>
{` which is restricted to users only. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -25,13 +25,16 @@ export const RecoverPasswordForm: React.FC = () => {
} = useForm<FormData>()
const onSubmit = useCallback(async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/forgot-password`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
setSuccess(true)
@@ -52,7 +55,7 @@ export const RecoverPasswordForm: React.FC = () => {
<p>
{`Please enter your email below. You will receive an email message with instructions on
how to reset your password. To manage your all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -32,13 +32,16 @@ export const ResetPasswordForm: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/reset-password`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
const json = await response.json()

File diff suppressed because it is too large Load Diff

View File

@@ -1 +1 @@
NEXT_PUBLIC_CMS_URL=http://localhost:3000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000

View File

@@ -40,7 +40,9 @@ const Account: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
if (user) {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/${user.id}`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/${user.id}`,
{
// Make sure to include cookies with fetch
credentials: 'include',
method: 'PATCH',
@@ -48,7 +50,8 @@ const Account: React.FC = () => {
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
const json = await response.json()
@@ -91,7 +94,7 @@ const Account: React.FC = () => {
<h1>Account</h1>
<p>
{`This is your account dashboard. Here you can update your account information and more. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -38,7 +38,7 @@ const CreateAccount: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users`, {
const response = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, {
method: 'POST',
body: JSON.stringify(data),
headers: {
@@ -78,7 +78,7 @@ const CreateAccount: React.FC = () => {
<form onSubmit={handleSubmit(onSubmit)} className={classes.form}>
<p>
{`This is where new customers can signup and create a new account. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -35,7 +35,7 @@ export default function Home() {
{' to start the authentication flow. Once logged in, you will be redirected to the '}
<Link href="/account">account page</Link>
{` which is restricted to users only. To manage all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -60,7 +60,7 @@ const Login: React.FC = () => {
{' with the password '}
<b>demo</b>
{'. To manage your users, '}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
.

View File

@@ -24,13 +24,16 @@ const RecoverPassword: React.FC = () => {
} = useForm<FormData>()
const onSubmit = useCallback(async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/forgot-password`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
setSuccess(true)
@@ -51,7 +54,7 @@ const RecoverPassword: React.FC = () => {
<p>
{`Please enter your email below. You will receive an email message with instructions on
how to reset your password. To manage your all users, `}
<Link href={`${process.env.NEXT_PUBLIC_CMS_URL}/admin/collections/users`}>
<Link href={`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/admin/collections/users`}>
login to the admin dashboard
</Link>
{'.'}

View File

@@ -31,13 +31,16 @@ const ResetPassword: React.FC = () => {
const onSubmit = useCallback(
async (data: FormData) => {
const response = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/reset-password`, {
const response = await fetch(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,
{
method: 'POST',
body: JSON.stringify(data),
headers: {
'Content-Type': 'application/json',
},
})
},
)
if (response.ok) {
const json = await response.json()

View File

@@ -8,7 +8,7 @@ export const USER = `
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export const gql = async (query): Promise<any> => {
try {
const res = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/graphql`, {
const res = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/graphql`, {
method: 'POST',
credentials: 'include',
headers: {

View File

@@ -16,7 +16,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const create = useCallback<Create>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users`, args)
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users`, args)
setUser(user)
return user
}
@@ -38,7 +38,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const login = useCallback<Login>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/login`, args)
const user = await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/login`, args)
setUser(user)
return user
}
@@ -62,7 +62,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const logout = useCallback<Logout>(async () => {
if (api === 'rest') {
await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/logout`)
await rest(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/logout`)
setUser(null)
return
}
@@ -81,7 +81,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const fetchMe = async () => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/me`,
{},
{
method: 'GET',
@@ -111,7 +111,7 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
async args => {
if (api === 'rest') {
const user = await rest(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/forgot-password`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/forgot-password`,
args,
)
setUser(user)
@@ -132,7 +132,10 @@ export const AuthProvider: React.FC<{ children: React.ReactNode; api?: 'rest' |
const resetPassword = useCallback<ResetPassword>(
async args => {
if (api === 'rest') {
const user = await rest(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/reset-password`, args)
const user = await rest(
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/reset-password`,
args,
)
setUser(user)
return user
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3001
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
MONGODB_URI=mongodb://127.0.0.1/payload-example-auth
DATABASE_URI=mongodb://127.0.0.1/payload-example-auth
PAYLOAD_SECRET=PAYLOAD_AUTH_EXAMPLE_SECRET_KEY
COOKIE_DOMAIN=localhost
PAYLOAD_PUBLIC_SEED=true

View File

@@ -17,6 +17,9 @@
"lint:fix": "eslint --fix --ext .ts,.tsx src"
},
"dependencies": {
"@payloadcms/bundler-webpack": "^1.0.0-beta.5",
"@payloadcms/db-mongodb": "^1.0.0-beta.8",
"@payloadcms/richtext-slate": "^1.0.0-beta.4",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "latest"

View File

@@ -1,6 +1,7 @@
import type { User } from 'payload/generated-types'
import type { FieldHook } from 'payload/types'
import type { User } from '../../payload-types'
// ensure there is always a `user` role
// do not let non-admins change roles
export const protectRoles: FieldHook<User & { id: string }> = async ({ req, data }) => {

View File

@@ -8,23 +8,61 @@
export interface Config {
collections: {
users: User;
};
globals: {};
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {}
}
export interface User {
id: string;
firstName?: string;
lastName?: string;
roles?: ('admin' | 'user')[];
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
id: string
firstName?: string
lastName?: string
roles?: ('admin' | 'user')[]
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string
resetPasswordExpiration?: string
salt?: string
hash?: string
loginAttempts?: number
lockUntil?: string
password?: string
}
export interface PayloadPreference {
id: string
user: {
relationTo: 'users'
value: string | User
}
key?: string
value?:
| {
[k: string]: unknown
}
| unknown[]
| string
| number
| boolean
| null
updatedAt: string
createdAt: string
}
export interface PayloadMigration {
id: string
name?: string
batch?: number
updatedAt: string
createdAt: string
}
declare module 'payload' {
export interface GeneratedTypes {
collections: {
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
}
}

View File

@@ -1,3 +1,6 @@
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { slateEditor } from '@payloadcms/richtext-slate'
import path from 'path'
import { buildConfig } from 'payload/config'
@@ -7,10 +10,15 @@ import BeforeLogin from './components/BeforeLogin'
export default buildConfig({
collections: [Users],
admin: {
bundler: webpackBundler(),
components: {
beforeLogin: [BeforeLogin],
},
},
editor: slateEditor({}),
db: mongooseAdapter({
url: process.env.DATABASE_URI,
}),
cors: [
process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
process.env.PAYLOAD_PUBLIC_SITE_URL || '',

View File

@@ -18,7 +18,6 @@ app.get('/', (_, res) => {
const start = async (): Promise<void> => {
await payload.init({
secret: process.env.PAYLOAD_SECRET,
mongoURL: process.env.MONGODB_URI,
express: app,
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)

View File

@@ -17,9 +17,6 @@
"moduleResolution": "node",
"resolveJsonModule": true,
"paths": {
"payload/generated-types": [
"./src/payload-types.ts"
],
"node_modules/*": [
"./node_modules/*"
]

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
MONGODB_URI=mongodb://127.0.0.1/payload-example-custom-server
DATABASE_URI=mongodb://127.0.0.1/payload-example-custom-server
PAYLOAD_SECRET=PAYLOAD_CUSTOM_SERVER_EXAMPLE_SECRET_KEY
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
NEXT_PUBLIC_SERVER_URL=http://localhost:3000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
PAYLOAD_PUBLIC_SEED=true
PAYLOAD_DROP_DATABASE=true

View File

@@ -4,6 +4,6 @@ module.exports = {
reactStrictMode: true,
swcMinify: true,
images: {
domains: ['localhost', process.env.NEXT_PUBLIC_SERVER_URL],
domains: ['localhost', process.env.NEXT_PUBLIC_PAYLOAD_URL],
},
}

View File

@@ -20,6 +20,9 @@
"lint:fix": "eslint --fix --ext .ts,.tsx src"
},
"dependencies": {
"@payloadcms/bundler-webpack": "^1.0.0-beta.5",
"@payloadcms/db-mongodb": "^1.0.0-beta.8",
"@payloadcms/richtext-slate": "^1.0.0-beta.4",
"dotenv": "^8.2.0",
"escape-html": "^1.0.3",
"express": "^4.17.1",

View File

@@ -0,0 +1,3 @@
module.exports = {
config: () => null,
}

View File

@@ -22,10 +22,6 @@ interface Args {
}
export const getPayloadClient = async ({ initOptions, seed }: Args = {}): Promise<Payload> => {
if (!process.env.MONGODB_URI) {
throw new Error('MONGODB_URI environment variable is missing')
}
if (!process.env.PAYLOAD_SECRET) {
throw new Error('PAYLOAD_SECRET environment variable is missing')
}
@@ -36,7 +32,6 @@ export const getPayloadClient = async ({ initOptions, seed }: Args = {}): Promis
if (!cached.promise) {
cached.promise = payload.init({
mongoURL: process.env.MONGODB_URI,
secret: process.env.PAYLOAD_SECRET,
local: initOptions?.express ? false : true,
...(initOptions || {}),

View File

@@ -8,31 +8,70 @@
export interface Config {
collections: {
pages: Page;
users: User;
};
globals: {};
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {}
}
export interface Page {
id: string;
title: string;
id: string
title: string
richText?: {
[k: string]: unknown;
}[];
slug?: string;
updatedAt: string;
createdAt: string;
[k: string]: unknown
}[]
slug?: string
updatedAt: string
createdAt: string
}
export interface User {
id: string;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
id: string
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string
resetPasswordExpiration?: string
salt?: string
hash?: string
loginAttempts?: number
lockUntil?: string
password?: string
}
export interface PayloadPreference {
id: string
user: {
relationTo: 'users'
value: string | User
}
key?: string
value?:
| {
[k: string]: unknown
}
| unknown[]
| string
| number
| boolean
| null
updatedAt: string
createdAt: string
}
export interface PayloadMigration {
id: string
name?: string
batch?: number
updatedAt: string
createdAt: string
}
declare module 'payload' {
export interface GeneratedTypes {
collections: {
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
}
}

View File

@@ -1,3 +1,6 @@
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { slateEditor } from '@payloadcms/richtext-slate'
import dotenv from 'dotenv'
import path from 'path'
@@ -14,10 +17,25 @@ export default buildConfig({
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL || '',
collections: [Pages],
admin: {
bundler: webpackBundler(),
components: {
beforeLogin: [BeforeLogin],
},
webpack: config => ({
...config,
resolve: {
...config.resolve,
alias: {
...config.resolve.alias,
dotenv: path.resolve(__dirname, './dotenv.js'),
},
},
}),
},
editor: slateEditor({}),
db: mongooseAdapter({
url: process.env.DATABASE_URI,
}),
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,3 @@
NEXT_PUBLIC_CMS_URL=http://localhost:3000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
NEXT_PRIVATE_DRAFT_SECRET=EXAMPLE_DRAFT_SECRET
NEXT_PRIVATE_REVALIDATION_KEY=EXAMPLE_REVALIDATION_KEY

View File

@@ -16,7 +16,7 @@ export const fetchPage = async (
const pageRes: {
docs: Page[]
} = await fetch(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages?where[slug][equals]=${slug}${
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?where[slug][equals]=${slug}${
draft && payloadToken ? '&draft=true' : ''
}`,
{

View File

@@ -3,7 +3,7 @@ import type { Page } from '../../payload-types'
export const fetchPages = async (): Promise<Page[]> => {
const pageRes: {
docs: Page[]
} = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages?depth=0&limit=100`).then(res =>
} = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?depth=0&limit=100`).then(res =>
res.json(),
) // eslint-disable-line function-paren-newline

View File

@@ -18,7 +18,7 @@ export const AdminBarClient: React.FC<PayloadAdminBarProps> = props => {
<PayloadAdminBar
{...props}
logo={<Title />}
cmsURL={process.env.NEXT_PUBLIC_CMS_URL}
cmsURL={process.env.NEXT_PUBLIC_PAYLOAD_URL}
onPreviewExit={async () => {
await fetch(`/api/exit-preview`)
window.location.reload()

View File

@@ -10,7 +10,7 @@ import classes from './index.module.scss'
export async function Header() {
const mainMenu: MainMenu = await fetch(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/globals/main-menu`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/globals/main-menu`,
).then(res => res.json())
const { navItems } = mainMenu

View File

@@ -24,7 +24,7 @@ export async function GET(
}
// validate the Payload token
const userReq = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`, {
const userReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/me`, {
headers: {
Authorization: `JWT ${payloadToken}`,
},

View File

@@ -8,52 +8,94 @@
export interface Config {
collections: {
pages: Page;
users: User;
};
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu;
};
'main-menu': MainMenu
}
}
export interface Page {
id: string;
title: string;
slug?: string;
id: string
title: string
slug?: string
richText: {
[k: string]: unknown;
}[];
updatedAt: string;
createdAt: string;
_status?: 'draft' | 'published';
[k: string]: unknown
}[]
updatedAt: string
createdAt: string
_status?: 'draft' | 'published'
}
export interface User {
id: string;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
id: string
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string
resetPasswordExpiration?: string
salt?: string
hash?: string
loginAttempts?: number
lockUntil?: string
password?: string
}
export interface PayloadPreference {
id: string
user: {
relationTo: 'users'
value: string | User
}
key?: string
value?:
| {
[k: string]: unknown
}
| unknown[]
| string
| number
| boolean
| null
updatedAt: string
createdAt: string
}
export interface PayloadMigration {
id: string
name?: string
batch?: number
updatedAt: string
createdAt: string
}
export interface MainMenu {
id: string;
id: string
navItems?: {
link: {
type?: 'reference' | 'custom';
newTab?: boolean;
type?: 'reference' | 'custom'
newTab?: boolean
reference: {
value: string | Page;
relationTo: 'pages';
};
url: string;
label: string;
};
id?: string;
}[];
updatedAt?: string;
createdAt?: string;
relationTo: 'pages'
value: string | Page
}
url: string
label: string
}
id?: string
}[]
updatedAt?: string
createdAt?: string
}
declare module 'payload' {
export interface GeneratedTypes {
collections: {
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu
}
}
}

View File

@@ -1,2 +1,2 @@
NEXT_PUBLIC_CMS_URL=http://localhost:3000
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
NEXT_PRIVATE_REVALIDATION_KEY=EXAMPLE_REVALIDATION_KEY

View File

@@ -20,7 +20,7 @@ export const AdminBar: React.FC<{
<PayloadAdminBar
{...adminBarProps}
logo={<Title />}
cmsURL={process.env.NEXT_PUBLIC_CMS_URL}
cmsURL={process.env.NEXT_PUBLIC_PAYLOAD_URL}
onAuthChange={setUser}
className={classes.payloadAdminBar}
classNames={{

View File

@@ -7,7 +7,7 @@ import { Gutter } from '../components/Gutter'
import RichText from '../components/RichText'
import type { MainMenu, Page as PageType } from '../payload-types'
import classes from './[slug].module.scss';
import classes from './[slug].module.scss'
const Page: React.FC<
PageType & {
@@ -67,7 +67,7 @@ export const getStaticProps: GetStaticProps = async (context: GetStaticPropsCont
)
// when previewing, send the payload token to bypass draft access control
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages${searchParams}`, {
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages${searchParams}`, {
headers: {
...(preview
? {
@@ -110,7 +110,7 @@ export const getStaticPaths: GetStaticPaths = async () => {
let paths: Paths = []
const pagesReq = await fetch(
`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages?where[_status][equals]=published&depth=0&limit=300`,
`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages?where[_status][equals]=published&depth=0&limit=300`,
)
const pagesData = await pagesReq.json()

View File

@@ -13,7 +13,7 @@ export interface IGlobals {
}
export const getAllGlobals = async (): Promise<IGlobals> => {
const res = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/globals/main-menu?depth=1`)
const res = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/globals/main-menu?depth=1`)
const mainMenu = await res.json()
return {

View File

@@ -20,7 +20,7 @@ const preview = async (req: NextApiRequest, res: NextApiResponse): Promise<void>
}
// validate the Payload token
const userReq = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/users/me`, {
const userReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/users/me`, {
headers: {
Authorization: `JWT ${payloadToken}`,
},

View File

@@ -8,52 +8,94 @@
export interface Config {
collections: {
pages: Page;
users: User;
};
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu;
};
'main-menu': MainMenu
}
}
export interface Page {
id: string;
title: string;
slug?: string;
id: string
title: string
slug?: string
richText: {
[k: string]: unknown;
}[];
updatedAt: string;
createdAt: string;
_status?: 'draft' | 'published';
[k: string]: unknown
}[]
updatedAt: string
createdAt: string
_status?: 'draft' | 'published'
}
export interface User {
id: string;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
id: string
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string
resetPasswordExpiration?: string
salt?: string
hash?: string
loginAttempts?: number
lockUntil?: string
password?: string
}
export interface PayloadPreference {
id: string
user: {
relationTo: 'users'
value: string | User
}
key?: string
value?:
| {
[k: string]: unknown
}
| unknown[]
| string
| number
| boolean
| null
updatedAt: string
createdAt: string
}
export interface PayloadMigration {
id: string
name?: string
batch?: number
updatedAt: string
createdAt: string
}
export interface MainMenu {
id: string;
id: string
navItems?: {
link: {
type?: 'reference' | 'custom';
newTab?: boolean;
type?: 'reference' | 'custom'
newTab?: boolean
reference: {
value: string | Page;
relationTo: 'pages';
};
url: string;
label: string;
};
id?: string;
}[];
updatedAt?: string;
createdAt?: string;
relationTo: 'pages'
value: string | Page
}
url: string
label: string
}
id?: string
}[]
updatedAt?: string
createdAt?: string
}
declare module 'payload' {
export interface GeneratedTypes {
collections: {
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu
}
}
}

View File

@@ -1,4 +1,4 @@
MONGODB_URI=mongodb://127.0.0.1/payload-example-draft-preview
DATABASE_URI=mongodb://127.0.0.1/payload-example-draft-preview
PAYLOAD_SECRET=ENTER-STRING-HERE
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:3000
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3001

View File

@@ -42,7 +42,7 @@ See the [Collections](https://payloadcms.com/docs/configuration/collections) doc
const searchParams = `?where[slug][equals]=${pageSlug}&depth=1${preview ? `&draft=true` : ''}`
// when previewing, send the payload token to bypass draft access control
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_CMS_URL}/api/pages${searchParams}`, {
const pageReq = await fetch(`${process.env.NEXT_PUBLIC_PAYLOAD_URL}/api/pages${searchParams}`, {
headers: {
...preview ? {
Authorization: `JWT ${payloadToken}`,

View File

@@ -18,6 +18,9 @@
"lint:fix": "eslint --fix --ext .ts,.tsx src"
},
"dependencies": {
"@payloadcms/bundler-webpack": "^1.0.0-beta.5",
"@payloadcms/db-mongodb": "^1.0.0-beta.8",
"@payloadcms/richtext-slate": "^1.0.0-beta.4",
"dotenv": "^8.2.0",
"express": "^4.17.1",
"payload": "latest"

View File

@@ -1,5 +1,5 @@
import type { RichTextElement } from 'payload/dist/fields/config/types'
import type { RichTextElement } from '@payloadcms/richtext-slate'
const elements: RichTextElement[] = ['blockquote', 'h2', 'h3', 'h4', 'h5', 'h6', 'link']
const elements: RichTextElement[] = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'link']
export default elements

View File

@@ -1,4 +1,6 @@
import type { RichTextElement, RichTextField, RichTextLeaf } from 'payload/dist/fields/config/types'
import { slateEditor } from '@payloadcms/richtext-slate'
import type { RichTextElement, RichTextLeaf } from '@payloadcms/richtext-slate/dist/types'
import type { RichTextField } from 'payload/types'
import deepMerge from '../../utilities/deepMerge'
import link from '../link'
@@ -25,6 +27,7 @@ const richText: RichText = (
name: 'richText',
type: 'richText',
required: true,
editor: slateEditor({
admin: {
upload: {
collections: {
@@ -34,10 +37,12 @@ const richText: RichText = (
type: 'richText',
name: 'caption',
label: 'Caption',
editor: slateEditor({
admin: {
elements: [...elements],
leaves: [...leaves],
},
}),
},
{
type: 'radio',
@@ -79,6 +84,7 @@ const richText: RichText = (
elements: [...elements, ...(additions.elements || [])],
leaves: [...leaves, ...(additions.leaves || [])],
},
}),
},
overrides,
)

View File

@@ -1,4 +1,4 @@
import type { RichTextLeaf } from 'payload/dist/fields/config/types'
import { RichTextLeaf } from '@payloadcms/richtext-slate'
const defaultLeaves: RichTextLeaf[] = ['bold', 'italic', 'underline']

View File

@@ -8,52 +8,94 @@
export interface Config {
collections: {
pages: Page;
users: User;
};
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu;
};
'main-menu': MainMenu
}
}
export interface Page {
id: string;
title: string;
slug?: string;
id: string
title: string
slug?: string
richText: {
[k: string]: unknown;
}[];
updatedAt: string;
createdAt: string;
_status?: 'draft' | 'published';
[k: string]: unknown
}[]
updatedAt: string
createdAt: string
_status?: 'draft' | 'published'
}
export interface User {
id: string;
updatedAt: string;
createdAt: string;
email: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
salt?: string;
hash?: string;
loginAttempts?: number;
lockUntil?: string;
password?: string;
id: string
updatedAt: string
createdAt: string
email: string
resetPasswordToken?: string
resetPasswordExpiration?: string
salt?: string
hash?: string
loginAttempts?: number
lockUntil?: string
password?: string
}
export interface PayloadPreference {
id: string
user: {
relationTo: 'users'
value: string | User
}
key?: string
value?:
| {
[k: string]: unknown
}
| unknown[]
| string
| number
| boolean
| null
updatedAt: string
createdAt: string
}
export interface PayloadMigration {
id: string
name?: string
batch?: number
updatedAt: string
createdAt: string
}
export interface MainMenu {
id: string;
id: string
navItems?: {
link: {
type?: 'reference' | 'custom';
newTab?: boolean;
type?: 'reference' | 'custom'
newTab?: boolean
reference: {
value: string | Page;
relationTo: 'pages';
};
url: string;
label: string;
};
id?: string;
}[];
updatedAt?: string;
createdAt?: string;
relationTo: 'pages'
value: string | Page
}
url: string
label: string
}
id?: string
}[]
updatedAt?: string
createdAt?: string
}
declare module 'payload' {
export interface GeneratedTypes {
collections: {
pages: Page
users: User
'payload-preferences': PayloadPreference
'payload-migrations': PayloadMigration
}
globals: {
'main-menu': MainMenu
}
}
}

View File

@@ -1,3 +1,6 @@
import { webpackBundler } from '@payloadcms/bundler-webpack'
import { mongooseAdapter } from '@payloadcms/db-mongodb'
import { slateEditor } from '@payloadcms/richtext-slate'
import path from 'path'
import { buildConfig } from 'payload/config'
@@ -9,10 +12,15 @@ import { MainMenu } from './globals/MainMenu'
export default buildConfig({
collections: [Pages, Users],
admin: {
bundler: webpackBundler(),
components: {
beforeLogin: [BeforeLogin],
},
},
editor: slateEditor({}),
db: mongooseAdapter({
url: process.env.DATABASE_URI,
}),
serverURL: process.env.PAYLOAD_PUBLIC_SERVER_URL,
cors: [
process.env.PAYLOAD_PUBLIC_SERVER_URL || '',

View File

@@ -1,7 +1,7 @@
import type { Page } from '../payload-types'
export const examplePage: Partial<Page> = {
title: 'Example Page',
title: 'Example Page (Published)',
slug: 'example-page',
_status: 'published',
richText: [

View File

@@ -19,7 +19,6 @@ app.get('/', (_, res) => {
const start = async (): Promise<void> => {
await payload.init({
secret: process.env.PAYLOAD_SECRET,
mongoURL: process.env.MONGODB_URI,
express: app,
onInit: () => {
payload.logger.info(`Payload Admin URL: ${payload.getAdminURL()}`)

View File

@@ -16,7 +16,6 @@
"sourceMap": true,
"resolveJsonModule": true,
"paths": {
"payload/generated-types": ["./src/payload-types.ts"],
"node_modules/*": ["./node_modules/*"]
},
},

File diff suppressed because it is too large Load Diff

View File

@@ -1,4 +0,0 @@
MONGODB_URI=mongodb://127.0.0.1/payload-example-form-builder
PAYLOAD_SECRET=ENTER-STRING-HERE
PAYLOAD_PUBLIC_SITE_URL=http://localhost:3000
PAYLOAD_PUBLIC_SERVER_URL=http://localhost:8000

View File

@@ -1,8 +0,0 @@
module.exports = {
printWidth: 100,
parser: "typescript",
semi: false,
singleQuote: true,
trailingComma: "all",
arrowParens: "avoid",
};

View File

@@ -1,13 +0,0 @@
import { RichTextElement } from 'payload/dist/fields/config/types';
const elements: RichTextElement[] = [
'blockquote',
'h2',
'h3',
'h4',
'h5',
'h6',
'link',
];
export default elements;

View File

@@ -1,94 +0,0 @@
import { RichTextElement, RichTextField, RichTextLeaf } from 'payload/dist/fields/config/types';
import deepMerge from '../../utilities/deepMerge';
import elements from './elements';
import leaves from './leaves';
import link from '../link';
type RichText = (
overrides?: Partial<RichTextField>,
additions?: {
elements?: RichTextElement[]
leaves?: RichTextLeaf[]
}
) => RichTextField
const richText: RichText = (
overrides,
additions = {
elements: [],
leaves: [],
},
) => deepMerge<RichTextField, Partial<RichTextField>>(
{
name: 'richText',
type: 'richText',
required: true,
admin: {
upload: {
collections: {
media: {
fields: [
{
type: 'richText',
name: 'caption',
label: 'Caption',
admin: {
elements: [
...elements,
],
leaves: [
...leaves,
],
},
},
{
type: 'radio',
name: 'alignment',
label: 'Alignment',
options: [
{
label: 'Left',
value: 'left',
},
{
label: 'Center',
value: 'center',
},
{
label: 'Right',
value: 'right',
},
],
},
{
name: 'enableLink',
type: 'checkbox',
label: 'Enable Link',
},
link({
appearances: false,
disableLabel: true,
overrides: {
admin: {
condition: (_, data) => Boolean(data?.enableLink),
},
},
}),
],
},
},
},
elements: [
...elements,
...additions.elements || [],
],
leaves: [
...leaves,
...additions.leaves || [],
],
},
},
overrides,
);
export default richText;

View File

@@ -1,9 +0,0 @@
import { RichTextLeaf } from 'payload/dist/fields/config/types';
const defaultLeaves: RichTextLeaf[] = [
'bold',
'italic',
'underline',
];
export default defaultLeaves;

View File

@@ -1,23 +0,0 @@
import { Field } from 'payload/types';
import formatSlug from '../utilities/formatSlug';
import deepMerge from '../utilities/deepMerge';
type Slug = (fieldToUse?: string, overrides?: Partial<Field>) => Field
export const slugField: Slug = (fieldToUse = 'title', overrides) => deepMerge<Field, Partial<Field>>(
{
name: 'slug',
label: 'Slug',
type: 'text',
index: true,
admin: {
position: 'sidebar',
},
hooks: {
beforeValidate: [
formatSlug(fieldToUse),
],
},
},
overrides,
);

View File

@@ -1,202 +0,0 @@
/* tslint:disable */
/**
* This file was automatically generated by Payload.
* DO NOT MODIFY IT BY HAND. Instead, modify your source Payload config,
* and re-run `payload generate:types` to regenerate this file.
*/
export interface Config {}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "main-menu".
*/
export interface MainMenu {
id: string;
navItems: {
link: {
type?: 'reference' | 'custom';
newTab?: boolean;
reference: {
value: string | Page;
relationTo: 'pages';
};
url: string;
label: string;
};
id?: string;
}[];
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "pages".
*/
export interface Page {
id: string;
title: string;
layout: {
form: string | Form;
enableIntro?: boolean;
introContent: {
[k: string]: unknown;
}[];
id?: string;
blockName?: string;
blockType: 'formBlock';
}[];
slug?: string;
_status?: 'draft' | 'published';
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "forms".
*/
export interface Form {
id: string;
title: string;
fields: (
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'text';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'textarea';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: string;
options: {
label: string;
value: string;
id?: string;
}[];
required?: boolean;
id?: string;
blockName?: string;
blockType: 'select';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'email';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'state';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'country';
}
| {
name: string;
label?: string;
width?: number;
defaultValue?: number;
required?: boolean;
id?: string;
blockName?: string;
blockType: 'number';
}
| {
name: string;
label?: string;
width?: number;
required?: boolean;
defaultValue?: boolean;
id?: string;
blockName?: string;
blockType: 'checkbox';
}
| {
message?: {
[k: string]: unknown;
}[];
id?: string;
blockName?: string;
blockType: 'message';
}
)[];
submitButtonLabel?: string;
confirmationType?: 'message' | 'redirect';
confirmationMessage: {
[k: string]: unknown;
}[];
redirect: {
url: string;
};
emails: {
emailTo: string;
bcc?: string;
replyTo?: string;
replyToName?: string;
emailFrom?: string;
emailFromName?: string;
subject: string;
message?: {
[k: string]: unknown;
}[];
id?: string;
}[];
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "users".
*/
export interface User {
id: string;
email?: string;
resetPasswordToken?: string;
resetPasswordExpiration?: string;
loginAttempts?: number;
lockUntil?: string;
createdAt: string;
updatedAt: string;
}
/**
* This interface was referenced by `Config`'s JSON-Schema
* via the `definition` "form-submissions".
*/
export interface FormSubmission {
id: string;
form: string | Form;
submissionData: {
field: string;
value: string;
id?: string;
}[];
createdAt: string;
updatedAt: string;
}

View File

@@ -1,31 +0,0 @@
import { buildConfig } from 'payload/config';
import path from 'path';
import FormBuilder from '@payloadcms/plugin-form-builder';
import { Users } from './collections/Users';
import { Pages } from './collections/Pages';
import { MainMenu } from './globals/MainMenu';
export default buildConfig({
collections: [
Pages,
Users,
],
globals: [
MainMenu,
],
cors: [
'http://localhost:3000',
process.env.PAYLOAD_PUBLIC_SITE_URL,
],
typescript: {
outputFile: path.resolve(__dirname, 'payload-types.ts'),
},
plugins: [
FormBuilder({
fields: {
payment: false,
},
}),
],
});

View File

@@ -1,21 +0,0 @@
import { FieldHook } from 'payload/types';
const format = (val: string): string => val.replace(/ /g, '-').replace(/[^\w-]+/g, '').toLowerCase();
const formatSlug = (fallback: string): FieldHook => ({ operation, value, originalDoc, data }) => {
if (typeof value === 'string') {
return format(value);
}
if (operation === 'create') {
const fallbackData = (data && data[fallback]) || (originalDoc && originalDoc[fallback]);
if (fallbackData && typeof fallbackData === 'string') {
return format(fallbackData);
}
}
return value;
};
export default formatSlug;

View File

@@ -0,0 +1 @@
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000

View File

@@ -0,0 +1,8 @@
module.exports = {
printWidth: 100,
parser: 'typescript',
semi: false,
singleQuote: true,
trailingComma: 'all',
arrowParens: 'avoid',
}

View File

@@ -1,14 +1,14 @@
# Form Builder Example Website
# Form Builder Example Front-End
This is a [Next.js](https://nextjs.org/) project bootstrapped with [`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app) that fetches data from [Payload](https://payloadcms.com).
This is a [Next.js](https://nextjs.org) app using the [Pages Router](https://nextjs.org/docs/pages). It was made explicitly for Payload's [Form Builder Example](https://github.com/payloadcms/payload/tree/master/examples/form-builder/payload).
This example repo was made explicitly to demonstrate the power and convenience of the [Form-Builder plugin](https://github.com/payloadcms/plugin-form-builder). Along with the `Form-Builder plugin`, this repo takes advantage of the popular [React Hooks Form](https://react-hook-form.com/) library for easy validation, giving users an easy way to build and manage forms.
> This example uses the Pages Router, the legacy API of Next.js. If your app is using the latest [App Router](https://nextjs.org/docs/app), we will add an example for that soon.
## Getting Started
### Payload
First you'll need a running Payload app. If you have not done so already, open up the `cms` folder and follow the setup instructions. Take note of your server URL, you'll need this in the next step.
First you'll need a running Payload app. There is one made explicitly for this example and [can be found here](https://github.com/payloadcms/payload/tree/master/examples/form-builder/payload). If you have not done so already, clone it down and follow the setup instructions there.
### Next.js App
@@ -16,13 +16,9 @@ First you'll need a running Payload app. If you have not done so already, open u
2. `cd` into this directory and run `yarn` or `npm install`
3. `cp .env.example .env` to copy the example environment variables
4. `yarn dev` or `npm run dev` to start the server
5. `open http://localhost:3000` to see the result
5. `open http://localhost:3001` to see the result
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
Once running, you will find a few seeded example forms on your local environment. Give them a try!
You can also start editing the pages by modifying the documents within your CMS.
Once running you will find a couple seeded pages on your local environment with some basic instructions. You can also start editing the pages by modifying the documents within Payload. See the [Form Builder Example](https://github.com/payloadcms/payload/tree/master/examples/form-builder/payload) for full details.
## Learn More

View File

@@ -1,32 +1,40 @@
import React, { useState } from 'react';
import { CheckboxField } from 'payload-plugin-form-builder/dist/types';
import { UseFormRegister, FieldErrorsImpl, FieldValues } from 'react-hook-form';
import { Check } from '../../../icons/Check';
import { Error } from '../Error';
import { Width } from '../Width';
import React, { useState } from 'react'
import { CheckboxField } from 'payload-plugin-form-builder/dist/types'
import { UseFormRegister, FieldErrorsImpl, FieldValues } from 'react-hook-form'
import { Check } from '../../../icons/Check'
import { Error } from '../Error'
import { Width } from '../Width'
import classes from './index.module.scss';
import classes from './index.module.scss'
export const Checkbox: React.FC<CheckboxField & {
register: UseFormRegister<FieldValues & any>,
setValue: any,
getValues: any,
errors: Partial<FieldErrorsImpl<{
[x: string]: any;
}>>
}> = ({ name, label, width, register, setValue, getValues, required: requiredFromProps, errors }) => {
const [checked, setChecked] = useState(false);
export const Checkbox: React.FC<
CheckboxField & {
register: UseFormRegister<FieldValues & any>
setValue: any
getValues: any
errors: Partial<
FieldErrorsImpl<{
[x: string]: any
}>
>
}
> = ({
name,
label,
width,
register,
setValue,
getValues,
required: requiredFromProps,
errors,
}) => {
const [checked, setChecked] = useState(false)
const isCheckboxChecked = getValues(name);
const isCheckboxChecked = getValues(name)
return (
<Width width={width}>
<div
className={[
classes.checkbox,
checked && classes.checked
].filter(Boolean).join(' ')}
>
<div className={[classes.checkbox, checked && classes.checked].filter(Boolean).join(' ')}>
<div className={classes.container}>
<input
type="checkbox"
@@ -49,5 +57,5 @@ export const Checkbox: React.FC<CheckboxField & {
{requiredFromProps && errors[name] && checked === false && <Error />}
</div>
</Width>
);
};
)
}

View File

@@ -1,19 +1,23 @@
import React from 'react';
import ReactSelect from 'react-select';
import { CountryField } from 'payload-plugin-form-builder/dist/types';
import { Controller, Control, FieldValues, FieldErrorsImpl } from 'react-hook-form';
import { countryOptions } from './options';
import { Error } from '../Error';
import { Width } from '../Width';
import React from 'react'
import ReactSelect from 'react-select'
import { CountryField } from 'payload-plugin-form-builder/dist/types'
import { Controller, Control, FieldValues, FieldErrorsImpl } from 'react-hook-form'
import { countryOptions } from './options'
import { Error } from '../Error'
import { Width } from '../Width'
import classes from './index.module.scss';
import classes from './index.module.scss'
export const Country: React.FC<CountryField & {
export const Country: React.FC<
CountryField & {
control: Control<FieldValues, any>
errors: Partial<FieldErrorsImpl<{
[x: string]: any;
}>>
}> = ({ name, label, width, control, required, errors }) => {
errors: Partial<
FieldErrorsImpl<{
[x: string]: any
}>
>
}
> = ({ name, label, width, control, required, errors }) => {
return (
<Width width={width}>
<div className={classes.select}>
@@ -30,7 +34,7 @@ export const Country: React.FC<CountryField & {
instanceId={name}
options={countryOptions}
value={countryOptions.find(c => c.value === value)}
onChange={(val) => onChange(val.value)}
onChange={val => onChange(val.value)}
className={classes.reactSelect}
classNamePrefix="rs"
/>
@@ -39,5 +43,5 @@ export const Country: React.FC<CountryField & {
{required && errors[name] && <Error />}
</div>
</Width>
);
};
)
}

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