Compare commits
497 Commits
v2.0.2
...
db-postgre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4b9e87bb4d | ||
|
|
ff5e174497 | ||
|
|
34017e1758 | ||
|
|
23d95526ab | ||
|
|
59b87fdb21 | ||
|
|
f2ac1f7d48 | ||
|
|
8d4f39af5e | ||
|
|
c4ac341d75 | ||
|
|
27589482dd | ||
|
|
d7ab4b7062 | ||
|
|
2c8fbf1be3 | ||
|
|
eec88f8f1b | ||
|
|
1481ef97b5 | ||
|
|
a89e89fb80 | ||
|
|
7e7eeb059d | ||
|
|
dc2a502dcc | ||
|
|
a9a5ba82d8 | ||
|
|
e6e8fae1c5 | ||
|
|
a05868a7f3 | ||
|
|
f27cd26575 | ||
|
|
db835ea5c8 | ||
|
|
d8f265fb94 | ||
|
|
d81d4eb075 | ||
|
|
52f89c0136 | ||
|
|
b0083b7c07 | ||
|
|
21649537a6 | ||
|
|
9be34c9599 | ||
|
|
8ca632e541 | ||
|
|
2ef79145a4 | ||
|
|
a0641a445d | ||
|
|
3a2e78f7f3 | ||
|
|
976d69d154 | ||
|
|
66018362fe | ||
|
|
647fe23d1c | ||
|
|
d7c61861f6 | ||
|
|
7caa098023 | ||
|
|
fd54c40400 | ||
|
|
e180131314 | ||
|
|
5902d4542b | ||
|
|
6bc282444e | ||
|
|
4dc6c09347 | ||
|
|
03b9ab0054 | ||
|
|
3c3c93f483 | ||
|
|
5dbfb1a335 | ||
|
|
d411874589 | ||
|
|
8358e2f2d2 | ||
|
|
2c67eff059 | ||
|
|
012b8e6f90 | ||
|
|
fcd4c8d830 | ||
|
|
81ec435363 | ||
|
|
e116fcfbf5 | ||
|
|
c47632dc1d | ||
|
|
0dab68b336 | ||
|
|
483f93bfcf | ||
|
|
4bd01df411 | ||
|
|
c956a85252 | ||
|
|
beed83b231 | ||
|
|
3b1bdcbe41 | ||
|
|
d3d0971275 | ||
|
|
1a99d66cd0 | ||
|
|
52c4a63bf1 | ||
|
|
3446d28602 | ||
|
|
2eb18771a1 | ||
|
|
f6fd5d6742 | ||
|
|
76d6c88261 | ||
|
|
10ebd76fcf | ||
|
|
36d6eb0a69 | ||
|
|
cd1f8dc332 | ||
|
|
e4275aa228 | ||
|
|
ddfcb2f12e | ||
|
|
09f33eae2c | ||
|
|
d3b7c9feec | ||
|
|
5fd3d43000 | ||
|
|
7767679caa | ||
|
|
fdf2e32005 | ||
|
|
773be8744d | ||
|
|
40d5bc0c4a | ||
|
|
fd33c790f2 | ||
|
|
ae7aac7639 | ||
|
|
05cc2873b4 | ||
|
|
171ee121e9 | ||
|
|
4af1d7d812 | ||
|
|
d229fc391a | ||
|
|
46a24a9822 | ||
|
|
06a51b3c9b | ||
|
|
1d4142ccc0 | ||
|
|
f1741beba2 | ||
|
|
9103277a10 | ||
|
|
d84673f400 | ||
|
|
15e23a3adc | ||
|
|
565929adcf | ||
|
|
8bbac60e60 | ||
|
|
15c7f0dbf3 | ||
|
|
05eba56d7d | ||
|
|
ab984b3ea9 | ||
|
|
a54638eb47 | ||
|
|
69af8d9c83 | ||
|
|
64864686c4 | ||
|
|
32c0bef05e | ||
|
|
a77513e94f | ||
|
|
aaf883909c | ||
|
|
cc56da11d6 | ||
|
|
41d9c28073 | ||
|
|
a071b97607 | ||
|
|
cfd9231403 | ||
|
|
71dce62646 | ||
|
|
db376f24ba | ||
|
|
2752483ac7 | ||
|
|
860f867c62 | ||
|
|
5b0adbe9c3 | ||
|
|
fb7d1be2f3 | ||
|
|
687a2e85d0 | ||
|
|
df80483afe | ||
|
|
8781770d83 | ||
|
|
ed1d5a60f7 | ||
|
|
50a0965561 | ||
|
|
c31fa5dd83 | ||
|
|
440eb8d9c6 | ||
|
|
1523b2be41 | ||
|
|
68f55c4064 | ||
|
|
0d3544ea04 | ||
|
|
f152f451dc | ||
|
|
5d92436e39 | ||
|
|
63edecddd8 | ||
|
|
65cdf6bfd0 | ||
|
|
9e831a6a00 | ||
|
|
0b64c5fb66 | ||
|
|
40426a25df | ||
|
|
c91b1e8310 | ||
|
|
06e2fa9d11 | ||
|
|
72249d1ecd | ||
|
|
dc22496103 | ||
|
|
c6925ec29f | ||
|
|
8f46b31249 | ||
|
|
af1c2e924e | ||
|
|
1487250752 | ||
|
|
e3c776523a | ||
|
|
c09e9d96cf | ||
|
|
aabc0650f8 | ||
|
|
4dd4e9aaae | ||
|
|
3b63b7fc3c | ||
|
|
f0e2e78b82 | ||
|
|
a154adf066 | ||
|
|
d86bcc1495 | ||
|
|
2b7043c6e6 | ||
|
|
e0afeeca97 | ||
|
|
76e306ddd8 | ||
|
|
cfc78ed4f5 | ||
|
|
64b0db5a7a | ||
|
|
48600f0c66 | ||
|
|
6d2dd5849d | ||
|
|
6d9353b53f | ||
|
|
1914be75aa | ||
|
|
b17f627e02 | ||
|
|
bef79621ee | ||
|
|
af892ecb0e | ||
|
|
a42e84bbb2 | ||
|
|
470bdb72ff | ||
|
|
5c36be949c | ||
|
|
eb97acd408 | ||
|
|
2567ac58ba | ||
|
|
9ff014bbfe | ||
|
|
e6f0d35985 | ||
|
|
b1e449e005 | ||
|
|
9ae585d23c | ||
|
|
9de3320933 | ||
|
|
5d429fa7ae | ||
|
|
dc8f1925f0 | ||
|
|
15f650afde | ||
|
|
c945384d63 | ||
|
|
dfada1b238 | ||
|
|
229bdda2c1 | ||
|
|
a1d51fb410 | ||
|
|
46430f5598 | ||
|
|
e41899cd27 | ||
|
|
890af8be05 | ||
|
|
8bfae6b932 | ||
|
|
ace3e577f6 | ||
|
|
9198245ad9 | ||
|
|
f0095937ba | ||
|
|
0bbd7137cd | ||
|
|
ffed34cf27 | ||
|
|
040f3a34d1 | ||
|
|
0985825b08 | ||
|
|
c18d3b5f0e | ||
|
|
e9e25ceac9 | ||
|
|
35aed59a1a | ||
|
|
26002173b1 | ||
|
|
41d968771e | ||
|
|
26c34541d2 | ||
|
|
263d40d169 | ||
|
|
6ced11d44d | ||
|
|
be049cea00 | ||
|
|
491e50c236 | ||
|
|
ad253db691 | ||
|
|
aff5fdff8a | ||
|
|
aa97bebbd4 | ||
|
|
a2410ea9fc | ||
|
|
de20ef1e8d | ||
|
|
08f7497040 | ||
|
|
74e99ce251 | ||
|
|
b5c56efb4b | ||
|
|
4ff6d63c94 | ||
|
|
c90d1faa7f | ||
|
|
1848b120ce | ||
|
|
62679baa91 | ||
|
|
2de36550ae | ||
|
|
61ea5becbb | ||
|
|
5d9384f530 | ||
|
|
d75ffa0ea7 | ||
|
|
26967fb924 | ||
|
|
830d9867b6 | ||
|
|
2f86c196e1 | ||
|
|
86a35ed441 | ||
|
|
70e068b182 | ||
|
|
4ac01a7fa3 | ||
|
|
8058a6d800 | ||
|
|
252b04097f | ||
|
|
23066aec71 | ||
|
|
b9a595b00c | ||
|
|
ea49d74941 | ||
|
|
f5f41f929e | ||
|
|
61151c9c5d | ||
|
|
c12c1a7472 | ||
|
|
7afa1e999d | ||
|
|
71c41dbe03 | ||
|
|
a161dc7bb6 | ||
|
|
6c17222a6a | ||
|
|
1ebb9f3915 | ||
|
|
eab04d9b4d | ||
|
|
1758b6c449 | ||
|
|
bca1be8cb6 | ||
|
|
1e197933dd | ||
|
|
4eb929d57c | ||
|
|
198209c2a4 | ||
|
|
54f19ce1e3 | ||
|
|
d32f3ade1b | ||
|
|
bf189abc91 | ||
|
|
69a379e49f | ||
|
|
493fc3ed68 | ||
|
|
138e495e1a | ||
|
|
8fe619a221 | ||
|
|
5195a80dba | ||
|
|
909cf90fa2 | ||
|
|
c1d1a00d4a | ||
|
|
ae68093f35 | ||
|
|
0f2f355a01 | ||
|
|
0101aa60d9 | ||
|
|
c823ee07cd | ||
|
|
1f12f9b480 | ||
|
|
ec31ab3a2c | ||
|
|
a7bea35d69 | ||
|
|
64a4f19539 | ||
|
|
c35661e16e | ||
|
|
69b6179521 | ||
|
|
3d2e167e78 | ||
|
|
aa1955221c | ||
|
|
7a9b11e2c4 | ||
|
|
a82c0d0e50 | ||
|
|
35a6daa10d | ||
|
|
bf5db4e44a | ||
|
|
a87e8aa82b | ||
|
|
e00d87a791 | ||
|
|
b61babca73 | ||
|
|
e403a0492e | ||
|
|
54a76e1401 | ||
|
|
91f6e36420 | ||
|
|
9e74fe558f | ||
|
|
ac8bcfac23 | ||
|
|
91b0a691ed | ||
|
|
3ced6ec2a0 | ||
|
|
650fe159ee | ||
|
|
b92657fb39 | ||
|
|
17dbe066c1 | ||
|
|
5acc88ee9a | ||
|
|
d4983af3fc | ||
|
|
6f2dcfd44e | ||
|
|
3df6435353 | ||
|
|
3ef03364be | ||
|
|
5396af9bfc | ||
|
|
56eddf3a93 | ||
|
|
6dd900e6b9 | ||
|
|
441a26b79c | ||
|
|
471d5ca17f | ||
|
|
536f995ab4 | ||
|
|
bb3c97828e | ||
|
|
c4d32d5418 | ||
|
|
8522fd9f27 | ||
|
|
ee93118688 | ||
|
|
47f9b89175 | ||
|
|
891fc55e25 | ||
|
|
988755f202 | ||
|
|
b5483a46f6 | ||
|
|
04fd2d6e82 | ||
|
|
4cdc7cf3c4 | ||
|
|
fbaa1028e6 | ||
|
|
df26e19c16 | ||
|
|
98501cf4c0 | ||
|
|
d0ac142871 | ||
|
|
d60c66ebd6 | ||
|
|
a515bdae56 | ||
|
|
cc40853903 | ||
|
|
121d69faf9 | ||
|
|
0a2d7c858a | ||
|
|
0962e1e563 | ||
|
|
a324768b3f | ||
|
|
0973ee512e | ||
|
|
f74e492448 | ||
|
|
e567627809 | ||
|
|
56965bc0ed | ||
|
|
e43d6520c5 | ||
|
|
1123909960 | ||
|
|
bc1853c2e7 | ||
|
|
318b734f96 | ||
|
|
2734b1d54a | ||
|
|
82510c1574 | ||
|
|
0a2b02f206 | ||
|
|
41ee127de8 | ||
|
|
9ddec59ddd | ||
|
|
b72b22c628 | ||
|
|
a685f30245 | ||
|
|
173ec6f0f8 | ||
|
|
349ab5343e | ||
|
|
cf97adab7c | ||
|
|
b6fc940f18 | ||
|
|
2fb685c0fe | ||
|
|
54be5847f7 | ||
|
|
bf4f37b514 | ||
|
|
9e577e7214 | ||
|
|
69185c06c2 | ||
|
|
e561016d07 | ||
|
|
9db4dadce3 | ||
|
|
fa40d511c2 | ||
|
|
ebfb86866f | ||
|
|
be853a0657 | ||
|
|
c880342099 | ||
|
|
d09bbd2171 | ||
|
|
c1823f719a | ||
|
|
39686e3f05 | ||
|
|
482973559d | ||
|
|
600dbd72f4 | ||
|
|
785337dc5d | ||
|
|
14a35f35c3 | ||
|
|
ed2e176285 | ||
|
|
2d79280999 | ||
|
|
8b5084ab43 | ||
|
|
b19356597b | ||
|
|
0bd412edbd | ||
|
|
1a6ba25e5d | ||
|
|
26d0cd18a1 | ||
|
|
31653fe76e | ||
|
|
a6d52223d5 | ||
|
|
1bf7c4084c | ||
|
|
419a3eef53 | ||
|
|
f62531bafd | ||
|
|
dc815dad14 | ||
|
|
bde2ce9b53 | ||
|
|
041af0100c | ||
|
|
2e18c5b8cf | ||
|
|
53f0c526f7 | ||
|
|
dc5c4eced0 | ||
|
|
0d8b6d03ed | ||
|
|
cfa364280f | ||
|
|
7a293563fb | ||
|
|
9359954233 | ||
|
|
9fcc05676e | ||
|
|
1e95f5de49 | ||
|
|
f8983e9e5c | ||
|
|
aab71f03b3 | ||
|
|
447d88bf82 | ||
|
|
897e94f2f4 | ||
|
|
87936e5b52 | ||
|
|
5e02762715 | ||
|
|
0785820539 | ||
|
|
bb6d545aae | ||
|
|
4cdc94d92f | ||
|
|
c28dca6fc0 | ||
|
|
95e630201a | ||
|
|
84100be7eb | ||
|
|
0c7007ae9a | ||
|
|
3e7e3669fe | ||
|
|
1d3bb9c287 | ||
|
|
cacc624f5a | ||
|
|
04dd824f0a | ||
|
|
dc929732b1 | ||
|
|
a47fd23199 | ||
|
|
d205da0aa4 | ||
|
|
c414f12527 | ||
|
|
d9418c9fe3 | ||
|
|
65e2ba9bd0 | ||
|
|
b3f808644f | ||
|
|
1e30435525 | ||
|
|
156d25741b | ||
|
|
de3ee812cd | ||
|
|
234fb33864 | ||
|
|
c168bb5201 | ||
|
|
0ce5d774cb | ||
|
|
d2c2bbd711 | ||
|
|
88193adebb | ||
|
|
eac44f9496 | ||
|
|
6400095f1f | ||
|
|
b57267e60a | ||
|
|
79541b6ba7 | ||
|
|
0420098e94 | ||
|
|
9f80634be4 | ||
|
|
25ecb27aed | ||
|
|
2ff2efd4b2 | ||
|
|
ff7a29179d | ||
|
|
8403f8ac2a | ||
|
|
df0d4fa726 | ||
|
|
2a4bb5a11d | ||
|
|
2b6c5e42b5 | ||
|
|
a1a4765a94 | ||
|
|
64d0bc7a16 | ||
|
|
b1fb43baf5 | ||
|
|
bb309ca843 | ||
|
|
760662263f | ||
|
|
bce5205cf1 | ||
|
|
0b21726af6 | ||
|
|
04a7d256c5 | ||
|
|
8a9915b58a | ||
|
|
820e867804 | ||
|
|
699314a781 | ||
|
|
86552e62ff | ||
|
|
13769d3cdc | ||
|
|
158ae0de30 | ||
|
|
04056513d7 | ||
|
|
2b7e6dda2f | ||
|
|
b11464542a | ||
|
|
b97568f394 | ||
|
|
18e8839b8c | ||
|
|
f5e5bfae81 | ||
|
|
b27ab75e07 | ||
|
|
5799e4015f | ||
|
|
2f72ed78e1 | ||
|
|
5f3f038a6b | ||
|
|
5b29852c0a | ||
|
|
9616e43035 | ||
|
|
b918425e72 | ||
|
|
9ed5f5b6fc | ||
|
|
1721d118a8 | ||
|
|
8dc400c65a | ||
|
|
a5ac793443 | ||
|
|
8d6d995d78 | ||
|
|
4652255d4f | ||
|
|
a274f2e5ca | ||
|
|
ed4528096a | ||
|
|
f7946af404 | ||
|
|
26ead270a2 | ||
|
|
c45c784c58 | ||
|
|
6b6977cc00 | ||
|
|
41a6abd2e4 | ||
|
|
d59ccc0f34 | ||
|
|
870946d01b | ||
|
|
3bf68ef9d4 | ||
|
|
60d7d51a0a | ||
|
|
61deb2c873 | ||
|
|
0ae27d4212 | ||
|
|
3c96622313 | ||
|
|
8066ce6f49 | ||
|
|
b7f9ffc51a | ||
|
|
4a873a5ae3 | ||
|
|
c080deb0b8 | ||
|
|
8cefa8181c | ||
|
|
a34dd651b1 | ||
|
|
a86041836f | ||
|
|
6dbd760a2e | ||
|
|
4181a84e9b | ||
|
|
b4d5168409 | ||
|
|
74756c0703 | ||
|
|
dce57d6fdd | ||
|
|
d55df67642 | ||
|
|
769d9063d5 | ||
|
|
8f95a23df9 | ||
|
|
9816c33015 | ||
|
|
1d14c976f2 | ||
|
|
63c436e0ac | ||
|
|
a4700d7a9d | ||
|
|
e5a1fe0771 | ||
|
|
b101ff86a9 | ||
|
|
0c5a6044a0 | ||
|
|
6fc7c0b9ad | ||
|
|
9459e82161 | ||
|
|
62501eb3b8 | ||
|
|
df000b7508 | ||
|
|
c04bde6725 | ||
|
|
1fe8ae39cb | ||
|
|
e2049b9564 | ||
|
|
49d9836ab4 | ||
|
|
4ed38575bf | ||
|
|
ef166cd70d | ||
|
|
d45665f092 | ||
|
|
10bae6dab7 | ||
|
|
ad25c86fdd | ||
|
|
f064ff35f3 | ||
|
|
55b44b41bf | ||
|
|
1f3e9b22f4 |
@@ -10,3 +10,9 @@ cdaa0acd61d3001407609915bd573b78565d5571
|
||||
|
||||
# prettier write again
|
||||
dfac7395fed95fc5d8ebca21b786ce70821942bb
|
||||
|
||||
# lint and format plugin-cloud
|
||||
fb7d1be2f3325d076b7c967b1730afcef37922c2
|
||||
|
||||
# lint and format create-payload-app
|
||||
5fd3d430001efe86515262ded5e26f00c1451181
|
||||
|
||||
5
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
5
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
@@ -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.
|
||||
|
||||
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -2,7 +2,7 @@
|
||||
|
||||
<!-- Please include a summary of the pull request and any related issues it fixes. Please also include relevant motivation and context. -->
|
||||
|
||||
- [ ] I have read and understand the [CONTRIBUTING.md](../CONTRIBUTING.md) document in this repository.
|
||||
- [ ] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
|
||||
|
||||
## Type of change
|
||||
|
||||
|
||||
174
.github/workflows/main.yml
vendored
174
.github/workflows/main.yml
vendored
@@ -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,21 @@ jobs:
|
||||
- name: Generate GraphQL schema file
|
||||
run: pnpm dev:generate-graphql-schema graphql-schema-gen
|
||||
|
||||
# DB Adapters
|
||||
|
||||
build-db-mongodb:
|
||||
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,12 +203,18 @@ jobs:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Build db-mongodb
|
||||
run: pnpm turbo run build --filter=db-mongodb
|
||||
- name: Build ${{ matrix.pkg }}
|
||||
run: pnpm turbo run build --filter=${{ matrix.pkg }}
|
||||
|
||||
build-db-postgres:
|
||||
plugins:
|
||||
runs-on: ubuntu-latest
|
||||
needs: core-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pkg:
|
||||
- plugin-cloud
|
||||
- create-payload-app
|
||||
|
||||
steps:
|
||||
- name: Use Node.js 18
|
||||
@@ -214,137 +234,9 @@ jobs:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Build db-postgres
|
||||
run: pnpm turbo run build --filter=db-postgres
|
||||
- name: Build ${{ matrix.pkg }}
|
||||
run: pnpm turbo run build --filter=${{ matrix.pkg }}
|
||||
|
||||
# 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: Test ${{ matrix.pkg }}
|
||||
run: pnpm --filter ${{ matrix.pkg }} run test
|
||||
if: matrix.pkg != 'create-payload-app' # degit doesn't work within GitHub Actions
|
||||
|
||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -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",
|
||||
|
||||
22
CHANGELOG.md
22
CHANGELOG.md
@@ -61,7 +61,19 @@ npm install --save @payloadcms/db-mongodb @payloadcms/richtext-slate @payloadcms
|
||||
|
||||
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
|
||||
@@ -69,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:
|
||||
|
||||
@@ -109,6 +121,12 @@ This means that in some fringe cases, if you are creating a doc and then instant
|
||||
|
||||
To avoid any issues, you can pass the `req.transactionID` through to your Local API calls, so that your Local API calls are included as part of the parent transaction.
|
||||
|
||||
### ⚠️ Locales now have more functionality, and in some places, you might need to update custom code
|
||||
|
||||
Payload's locales have become more powerful and now allow you to customize more aspects per locale such as a human-friendly label and if the locale is RTL or not.
|
||||
|
||||
This means that certain functions now return a different shape, such as `useLocale`. This hook used to return a string of the locale code you are currently editing, but it now returns an object with type of `Locale`.
|
||||
|
||||
### ⚠️ Admin panel CSS classes may have changed
|
||||
|
||||
The revisions we've made in 2.0 required changes to both HTML and CSS within the admin panel. For this reason, if you were loading custom CSS into the admin panel to customize the look and feel, your stylesheets may need to be updated. If your CSS is targeting elements on the page using HTML selectors or class names, you may need to update these selectors based on the current markup. It may also be necessary to update your style definitions if the core Payload component you are targeting has undergone significant change.
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
<a target="_blank" href="https://payloadcms.com/docs/getting-started/what-is-payload" rel="dofollow"><strong>Explore the Docs</strong></a> · <a target="_blank" href="https://payloadcms.com/community-help" rel="dofollow"><strong>Community Help</strong></a> · <a target="_blank" href="https://demo.payloadcms.com/" rel="dofollow"><strong>Try Live Demo</strong></a> · <a target="_blank" href="https://github.com/payloadcms/payload/discussions/1539" rel="dofollow"><strong>Roadmap</strong></a> · <a target="_blank" href="https://www.g2.com/products/payload-cms/reviews#reviews" rel="dofollow"><strong>View G2 Reviews</strong></a>
|
||||
</h4>
|
||||
<hr/>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 🎉 <strong>Payload 2.0 is now available!<strong> Read more in the <a target="_blank" href="https://payloadcms.com/blog/payload-2-0" rel="dofollow"><strong>announcement post</strong></a>.
|
||||
|
||||
<h3>Benefits over a regular CMS</h3>
|
||||
<ul>
|
||||
<li>Don’t hit some third-party SaaS API, hit your own API</li>
|
||||
@@ -95,6 +99,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).
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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/main/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',
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -343,12 +399,12 @@ Your custom view components will be given all the props that a React Router `<Ro
|
||||
|
||||
#### Example
|
||||
|
||||
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/master/test/admin/components/views). There, you'll find two custom views:
|
||||
You can find examples of custom views in the [Payload source code `/test/admin/components/views` folder](https://github.com/payloadcms/payload/tree/main/test/admin/components/views). There, you'll find two custom views:
|
||||
|
||||
1. A custom view that uses the `DefaultTemplate`, which is the built-in Payload template that displays the sidebar and "eyebrow nav"
|
||||
1. A custom view that uses the `MinimalTemplate` - which is just a centered template used for things like logging in or out
|
||||
|
||||
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/master/test/admin/config.ts).
|
||||
To see how to pass in your custom views to create custom views of your own, take a look at the `admin.components.views` property of the [Payload test admin config](https://github.com/payloadcms/payload/blob/main/test/admin/config.ts).
|
||||
|
||||
### Fields
|
||||
|
||||
|
||||
@@ -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.",
|
||||
},
|
||||
],
|
||||
[
|
||||
|
||||
@@ -28,25 +28,25 @@ When bundled, it is code-split, highly performant (even with 100+ fields), and w
|
||||
|
||||
All options for the Admin panel are defined in your base Payload config file.
|
||||
|
||||
| Option | Description |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `user` | The `slug` of a Collection that you want be used to log in to the Admin dashboard. [More](/docs/admin/overview#the-admin-user-collection) |
|
||||
| `buildPath` | Specify an absolute path for where to store the built Admin panel bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
|
||||
| `meta` | Base meta data to use for the Admin panel. Included properties are `titleSuffix`, `ogImage`, and `favicon`. |
|
||||
| `disable` | If set to `true`, the entire Admin panel will be disabled. |
|
||||
| `indexHTML` | Optionally replace the entirety of the `index.html` file used by the Admin panel. Reference the [base index.html file](https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/index.html) to ensure your replacement has the appropriate HTML elements. |
|
||||
| `css` | Absolute path to a stylesheet that you can use to override / customize the Admin panel styling. [More](/docs/admin/customizing-css). |
|
||||
| `scss` | Absolute path to a Sass variables / mixins stylesheet meant to override Payload styles to make for an easy re-skinning of the Admin panel. [More](/docs/admin/customizing-css#overriding-scss-variables). |
|
||||
| `dateFormat` | Global date format that will be used for all dates in the Admin panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More](/docs/authentication/config). |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
|
||||
| `components` | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components) |
|
||||
| `webpack` | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack) |
|
||||
| `vite` | Customize the Vite config that's used to generate the Admin panel. [More](/docs/admin/vite) |
|
||||
| **`bundler`** | The bundler that you would like to use to bundle the admin panel. Officially supported bundlers: [Webpack](/docs/admin/webpack) and [Vite](/docs/admin/vite). |
|
||||
| **`logoutRoute`** | The route for the `logout` page. |
|
||||
| **`inactivityRoute`** | The route for the `logout` inactivity page. |
|
||||
| Option | Description |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `bundler` | The bundler that you would like to use to bundle the admin panel. Officially supported bundlers: [Webpack](/docs/admin/webpack) and [Vite](/docs/admin/vite). |
|
||||
| `user` | The `slug` of a Collection that you want be used to log in to the Admin dashboard. [More](/docs/admin/overview#the-admin-user-collection) |
|
||||
| `buildPath` | Specify an absolute path for where to store the built Admin panel bundle used in production. Defaults to `path.resolve(process.cwd(), 'build')`. |
|
||||
| `meta` | Base meta data to use for the Admin panel. Included properties are `titleSuffix`, `ogImage`, and `favicon`. |
|
||||
| `disable` | If set to `true`, the entire Admin panel will be disabled. |
|
||||
| `indexHTML` | Optionally replace the entirety of the `index.html` file used by the Admin panel. Reference the [base index.html file](https://github.com/payloadcms/payload/blob/main/packages/payload/src/admin/index.html) to ensure your replacement has the appropriate HTML elements. |
|
||||
| `css` | Absolute path to a stylesheet that you can use to override / customize the Admin panel styling. [More](/docs/admin/customizing-css). |
|
||||
| `scss` | Absolute path to a Sass variables / mixins stylesheet meant to override Payload styles to make for an easy re-skinning of the Admin panel. [More](/docs/admin/customizing-css#overriding-scss-variables). |
|
||||
| `dateFormat` | Global date format that will be used for all dates in the Admin panel. Any valid [date-fns](https://date-fns.org/) format pattern can be used. |
|
||||
| `avatar` | Set account profile picture. Options: `gravatar`, `default` or a custom React component. |
|
||||
| `autoLogin` | Used to automate admin log-in for dev and demonstration convenience. [More](/docs/authentication/config). |
|
||||
| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). |
|
||||
| `components` | Component overrides that affect the entirety of the Admin panel. [More](/docs/admin/components) |
|
||||
| `webpack` | Customize the Webpack config that's used to generate the Admin panel. [More](/docs/admin/webpack) |
|
||||
| `vite` | Customize the Vite config that's used to generate the Admin panel. [More](/docs/admin/vite) |
|
||||
| `logoutRoute` | The route for the `logout` page. |
|
||||
| `inactivityRoute` | The route for the `logout` inactivity page. |
|
||||
|
||||
### The Admin User Collection
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ After a user logs in, they can change their language selection in the `/account`
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
If there is a language that Payload does not yet support, we accept code
|
||||
[contributions](https://github.com/payloadcms/payload/blob/main/contributing.md).
|
||||
[contributions](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md).
|
||||
</Banner>
|
||||
|
||||
### Node Express
|
||||
|
||||
@@ -19,48 +19,53 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
||||
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
||||
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
||||
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
||||
| `admin` | Base Payload admin configuration. Specify custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). |
|
||||
| `editor` | Default richText editor which will be used by richText fields. |
|
||||
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
||||
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
||||
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
||||
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
||||
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
||||
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
||||
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
||||
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
||||
| `debug` | Enable to expose more detailed error information. |
|
||||
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
||||
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
||||
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
||||
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
||||
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
| Option | Description |
|
||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `admin` \* | Base Payload admin configuration. Specify bundler*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
|
||||
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
|
||||
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
|
||||
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
||||
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
||||
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
||||
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
||||
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
||||
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
||||
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
||||
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
||||
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
||||
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
||||
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
||||
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
||||
| `debug` | Enable to expose more detailed error information. |
|
||||
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
||||
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
||||
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
||||
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
||||
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
#### Simple example
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { mongooseAdapter } from '@payloadcms/db-mongodb'
|
||||
import { postgresAdapter } from '@payloadcms/db-postgres'
|
||||
import { postgresAdapter } from '@payloadcms/db-postgres' // beta
|
||||
|
||||
import { viteBundler } from '@payloadcms/bundler-vite'
|
||||
import { webpackBundler } from '@payloadcms/bundler-webpack'
|
||||
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical'
|
||||
import { lexicalEditor } from '@payloadcms/richtext-lexical' // beta
|
||||
import { slateEditor } from '@payloadcms/richtext-slate'
|
||||
|
||||
export default buildConfig({
|
||||
bundler: webpackBundler() // or viteBundler(),
|
||||
admin: {
|
||||
bundler: webpackBundler(), // or viteBundler()
|
||||
},
|
||||
db: mongooseAdapter({}) // or postgresAdapter({}),
|
||||
editor: lexicalEditor({}) // or slateEditor({})
|
||||
collections: [
|
||||
|
||||
@@ -8,6 +8,16 @@ desc: Payload features first-party database migrations all done in TypeScript.
|
||||
|
||||
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>
|
||||
|
||||
@@ -11,7 +11,7 @@ keywords: documentation, getting started, guide, Content Management System, cms,
|
||||
Payload requires the following software:
|
||||
|
||||
- Yarn or NPM
|
||||
- Node.js version 14+
|
||||
- Node.js version 16+
|
||||
- Any [compatible database](/docs/database/overview) (MongoDB or Postgres)
|
||||
|
||||
<Banner type="warning">
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: headless cms, typescript, documentation, Content Management System, cm
|
||||
|
||||
When working with GraphQL it is useful to have the schema for development of other projects that need to call on your GraphQL endpoint. In Payload the schema is controlled by your collections and globals and is made available to the developer or third parties, it is not necessary for developers using Payload to write schema types manually.
|
||||
|
||||
### Schema generatation script
|
||||
### Schema generation script
|
||||
|
||||
Run the following command in a Payload project to generate your project's GraphQL schema from Payload:
|
||||
|
||||
|
||||
@@ -88,13 +88,14 @@ This package provides the following functions:
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`subscribe`** | Subscribes to the Admin panel's `window.postMessage` events and calls the provided callback function. |
|
||||
| **`unsubscribe`** | Unsubscribes from the Admin panel's `window.postMessage` events. |
|
||||
| **`ready`** | Sends a `window.postMessage` event to the Admin panel to indicate that the front-end is ready to receive messages. |
|
||||
|
||||
The `subscribe` function takes the following args:
|
||||
|
||||
| Path | Description |
|
||||
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`callback`** \* | A callback function that is called with `data` every time a change is made to the document. |
|
||||
| **`serverURL`** \* | The URL of your Payload server. git s |
|
||||
| **`serverURL`** \* | The URL of your Payload server. |
|
||||
| **`initialData`** | The initial data of the document. The live data will be merged in as changes are made. |
|
||||
| **`depth`** | The depth of the relationships to fetch. Defaults to `0`. |
|
||||
|
||||
@@ -103,18 +104,23 @@ With these functions, you can build your own hook using your front-end framework
|
||||
```tsx
|
||||
import { subscribe, unsubscribe } from '@payloadcms/live-preview';
|
||||
|
||||
// Build your own hook to subscribe to the live preview events
|
||||
// This function will handle everything for you like
|
||||
// 1. subscribing to `window.postMessage` events
|
||||
// 2. merging initial page data with incoming form state
|
||||
// 3. populating relationships and uploads
|
||||
// To build your own hook, subscribe to Live Preview events using the`subscribe` function
|
||||
// It handles everything from:
|
||||
// 1. Listening to `window.postMessage` events
|
||||
// 2. Merging initial data with active form state
|
||||
// 3. Populating relationships and uploads
|
||||
// 4. Calling the `onChange` callback with the result
|
||||
// Your hook should also:
|
||||
// 1. Tell the Admin panel when it is ready to receive messages
|
||||
// 2. Handle the results of the `onChange` callback to update the UI
|
||||
// 3. Unsubscribe from the `window.postMessage` events when it unmounts
|
||||
```
|
||||
|
||||
Here is an example of what the same `useLivePreview` React hook from above looks like under the hood:
|
||||
|
||||
```tsx
|
||||
import { subscribe, unsubscribe } from '@payloadcms/live-preview'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { subscribe, unsubscribe, ready } from '@payloadcms/live-preview'
|
||||
import { useCallback, useEffect, useState, useRef } from 'react'
|
||||
|
||||
export const useLivePreview = <T extends any>(props: {
|
||||
depth?: number
|
||||
@@ -127,13 +133,18 @@ export const useLivePreview = <T extends any>(props: {
|
||||
const { depth = 0, initialData, serverURL } = props
|
||||
const [data, setData] = useState<T>(initialData)
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true)
|
||||
const hasSentReadyMessage = useRef<boolean>(false)
|
||||
|
||||
const onChange = useCallback((mergedData) => {
|
||||
// When a change is made, the `onChange` callback will be called with the merged data
|
||||
// Set this merged data into state so that React will re-render the UI
|
||||
setData(mergedData)
|
||||
setIsLoading(false)
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
// Listen for `window.postMessage` events from the Admin panel
|
||||
// When a change is made, the `onChange` callback will be called with the merged data
|
||||
const subscription = subscribe({
|
||||
callback: onChange,
|
||||
depth,
|
||||
@@ -141,6 +152,17 @@ export const useLivePreview = <T extends any>(props: {
|
||||
serverURL,
|
||||
})
|
||||
|
||||
// Once subscribed, send a `ready` message back up to the Admin panel
|
||||
// This will indicate that the front-end is ready to receive messages
|
||||
if (!hasSentReadyMessage.current) {
|
||||
hasSentReadyMessage.current = true
|
||||
|
||||
ready({
|
||||
serverURL
|
||||
})
|
||||
}
|
||||
|
||||
// When the component unmounts, unsubscribe from the `window.postMessage` events
|
||||
return () => {
|
||||
unsubscribe(subscription)
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: live preview, preview, live, iframe, iframe preview, visual editing, d
|
||||
|
||||
**With Live Preview you can render your front-end application directly within the Admin panel. As you type, your changes take effect in real-time. No need to save a draft or publish your changes.**
|
||||
|
||||
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin panel communicates with your app through `window.postMessage` events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
|
||||
Live Preview works by rendering an iframe on the page that loads your front-end application. The Admin panel communicates with your app through [`window.postMessage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/postMessage) events. These events are emitted every time a change is made to the document. Your app then listens for these events and re-renders itself with the data it receives.
|
||||
|
||||
{/* IMAGE OF LIVE PREVIEW HERE */}
|
||||
|
||||
@@ -84,8 +84,8 @@ Here is an example of using a function that returns a dynamic URL:
|
||||
documentInfo,
|
||||
locale
|
||||
}) => `${data.tenant.url}${ // Multi-tenant top-level domain
|
||||
documentInfo.slug === 'posts' ? `/posts/${data.slug}` : `/${data.slug}
|
||||
`}?locale=${locale}`, // Localization query param
|
||||
documentInfo.slug === 'posts' ? `/posts/${data.slug}` : `${data.slug !== 'home' : `/${data.slug}` : ''}`
|
||||
}${locale ? `?locale=${locale?.code}` : ''}`, // Localization query param
|
||||
collections: ['pages'],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -131,6 +131,7 @@ const result = await payload.find({
|
||||
depth: 2,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
pagination: false, // If you want to disable pagination count, etc.
|
||||
where: {}, // pass a `where` query here
|
||||
sort: '-title',
|
||||
locale: 'en',
|
||||
@@ -412,7 +413,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({
|
||||
|
||||
@@ -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>
|
||||
|
||||
294
docs/plugins/build-your-own.mdx
Normal file
294
docs/plugins/build-your-own.mdx
Normal 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're already familiar with Payload then you'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'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're starting from scratch, you can easily setup a dev environment like this:
|
||||
|
||||
```
|
||||
mkdir dev
|
||||
cd dev
|
||||
npx create-payload-app
|
||||
```
|
||||
|
||||
If you'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'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'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'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'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'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'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'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'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.
|
||||
@@ -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
|
||||
|
||||
@@ -59,3 +59,7 @@ All Payload APIs support the pagination controls below. With them, you can creat
|
||||
| ------- | --------------------------------------- |
|
||||
| `limit` | Limits the number of documents returned |
|
||||
| `page` | Get a specific page number |
|
||||
|
||||
### Disabling pagination within Local API
|
||||
|
||||
For `find` operations within the Local API, you can disable pagination to retrieve all documents from a collection by passing `pagination: false` to the `find` local operation. This is not supported in REST or GraphQL, however, because it could potentially lead to malicious activity.
|
||||
@@ -1 +1 @@
|
||||
NEXT_PUBLIC_CMS_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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}`,
|
||||
},
|
||||
|
||||
@@ -39,15 +39,18 @@ 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}`, {
|
||||
// Make sure to include cookies with fetch
|
||||
credentials: 'include',
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
},
|
||||
})
|
||||
)
|
||||
|
||||
if (response.ok) {
|
||||
const json = await response.json()
|
||||
|
||||
@@ -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>
|
||||
{'.'}
|
||||
|
||||
@@ -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>
|
||||
{'.'}
|
||||
|
||||
@@ -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>
|
||||
.
|
||||
|
||||
@@ -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>
|
||||
{'.'}
|
||||
|
||||
@@ -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`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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>
|
||||
{'.'}
|
||||
|
||||
@@ -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`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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
@@ -1 +1 @@
|
||||
NEXT_PUBLIC_CMS_URL=http://localhost:3000
|
||||
NEXT_PUBLIC_PAYLOAD_URL=http://localhost:3000
|
||||
|
||||
@@ -40,15 +40,18 @@ 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}`, {
|
||||
// Make sure to include cookies with fetch
|
||||
credentials: 'include',
|
||||
method: 'PATCH',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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',
|
||||
body: JSON.stringify(data),
|
||||
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>
|
||||
{'.'}
|
||||
|
||||
@@ -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>
|
||||
{'.'}
|
||||
|
||||
@@ -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>
|
||||
{'.'}
|
||||
|
||||
@@ -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>
|
||||
.
|
||||
|
||||
@@ -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`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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>
|
||||
{'.'}
|
||||
|
||||
@@ -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`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify(data),
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
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()
|
||||
|
||||
@@ -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: {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"ext": "ts",
|
||||
"exec": "ts-node src/server.ts"
|
||||
"exec": "ts-node src/server.ts -- -I",
|
||||
"stdin": false
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/bundler-webpack": "latest",
|
||||
"@payloadcms/db-mongodb": "latest",
|
||||
"@payloadcms/richtext-slate": "latest",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
@@ -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()}`)
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
"moduleResolution": "node",
|
||||
"resolveJsonModule": true,
|
||||
"paths": {
|
||||
"payload/generated-types": [
|
||||
"./src/payload-types.ts"
|
||||
],
|
||||
"node_modules/*": [
|
||||
"./node_modules/*"
|
||||
]
|
||||
@@ -36,4 +33,4 @@
|
||||
"ts-node": {
|
||||
"transpileOnly": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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],
|
||||
},
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
{
|
||||
"watch": ["server.ts"],
|
||||
"exec": "ts-node --project tsconfig.server.json src/server.ts",
|
||||
"ext": "js ts"
|
||||
"exec": "ts-node --project tsconfig.server.json src/server.ts -- -I",
|
||||
"ext": "js ts",
|
||||
"stdin": false
|
||||
}
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/bundler-webpack": "latest",
|
||||
"@payloadcms/db-mongodb": "latest",
|
||||
"@payloadcms/richtext-slate": "latest",
|
||||
"dotenv": "^8.2.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"express": "^4.17.1",
|
||||
|
||||
3
examples/custom-server/src/dotenv.js
Normal file
3
examples/custom-server/src/dotenv.js
Normal file
@@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
config: () => null,
|
||||
}
|
||||
@@ -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 || {}),
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
@@ -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' : ''
|
||||
}`,
|
||||
{
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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={{
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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}`,
|
||||
},
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}`,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"ext": "ts",
|
||||
"exec": "ts-node src/server.ts"
|
||||
"exec": "ts-node src/server.ts -- -I",
|
||||
"stdin": false
|
||||
}
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
"lint:fix": "eslint --fix --ext .ts,.tsx src"
|
||||
},
|
||||
"dependencies": {
|
||||
"@payloadcms/bundler-webpack": "latest",
|
||||
"@payloadcms/db-mongodb": "latest",
|
||||
"@payloadcms/richtext-slate": "latest",
|
||||
"dotenv": "^8.2.0",
|
||||
"express": "^4.17.1",
|
||||
"payload": "latest"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,60 +27,64 @@ const richText: RichText = (
|
||||
name: 'richText',
|
||||
type: 'richText',
|
||||
required: true,
|
||||
admin: {
|
||||
upload: {
|
||||
collections: {
|
||||
media: {
|
||||
fields: [
|
||||
{
|
||||
type: 'richText',
|
||||
name: 'caption',
|
||||
label: 'Caption',
|
||||
admin: {
|
||||
elements: [...elements],
|
||||
leaves: [...leaves],
|
||||
editor: slateEditor({
|
||||
admin: {
|
||||
upload: {
|
||||
collections: {
|
||||
media: {
|
||||
fields: [
|
||||
{
|
||||
type: 'richText',
|
||||
name: 'caption',
|
||||
label: 'Caption',
|
||||
editor: slateEditor({
|
||||
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),
|
||||
},
|
||||
{
|
||||
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 || [])],
|
||||
},
|
||||
elements: [...elements, ...(additions.elements || [])],
|
||||
leaves: [...leaves, ...(additions.leaves || [])],
|
||||
},
|
||||
}),
|
||||
},
|
||||
overrides,
|
||||
)
|
||||
|
||||
@@ -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']
|
||||
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 || '',
|
||||
|
||||
@@ -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: [
|
||||
|
||||
@@ -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()}`)
|
||||
|
||||
@@ -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
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"ext": "ts",
|
||||
"exec": "ts-node src/server.ts"
|
||||
"exec": "ts-node src/server.ts -- -I",
|
||||
"stdin": false
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -1,8 +0,0 @@
|
||||
module.exports = {
|
||||
printWidth: 100,
|
||||
parser: "typescript",
|
||||
semi: false,
|
||||
singleQuote: true,
|
||||
trailingComma: "all",
|
||||
arrowParens: "avoid",
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ext": "ts",
|
||||
"exec": "ts-node src/server.ts"
|
||||
}
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -1,9 +0,0 @@
|
||||
import { RichTextLeaf } from 'payload/dist/fields/config/types';
|
||||
|
||||
const defaultLeaves: RichTextLeaf[] = [
|
||||
'bold',
|
||||
'italic',
|
||||
'underline',
|
||||
];
|
||||
|
||||
export default defaultLeaves;
|
||||
@@ -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,
|
||||
);
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
}),
|
||||
],
|
||||
});
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user