Compare commits
1139 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fafec05309 | ||
|
|
76a71c1af5 | ||
|
|
2854bfebf7 | ||
|
|
d6bfba72a6 | ||
|
|
2b0f65a27f | ||
|
|
4b60845c67 | ||
|
|
562cd18622 | ||
|
|
584d865d34 | ||
|
|
5b7756e266 | ||
|
|
cfeeb9758f | ||
|
|
51058f65e5 | ||
|
|
6bc4dde23c | ||
|
|
40d6fe0b09 | ||
|
|
9881d322f3 | ||
|
|
1877d2247c | ||
|
|
1bf81f56ce | ||
|
|
606c3cf021 | ||
|
|
d112159d93 | ||
|
|
79393e8cf0 | ||
|
|
5b79067cc1 | ||
|
|
04851d0dc9 | ||
|
|
7c47e4b0d3 | ||
|
|
b734a1c422 | ||
|
|
9b22c4b654 | ||
|
|
03c2b36b84 | ||
|
|
868823d9e1 | ||
|
|
365b91e1b4 | ||
|
|
221356f6b9 | ||
|
|
1db1de1116 | ||
|
|
801f60939b | ||
|
|
dfdd334d16 | ||
|
|
a8e47088bb | ||
|
|
29d8bf0927 | ||
|
|
8a32909dcd | ||
|
|
c0eed02924 | ||
|
|
1d4df99ea7 | ||
|
|
b36deb4640 | ||
|
|
0c2e41c4be | ||
|
|
d9dd78ad00 | ||
|
|
06711be846 | ||
|
|
bf0b114b70 | ||
|
|
68b220ff73 | ||
|
|
f84b4323e2 | ||
|
|
064af8acc7 | ||
|
|
b22d157bd2 | ||
|
|
0112f4c4ab | ||
|
|
6670915323 | ||
|
|
49f117e220 | ||
|
|
8df4b15116 | ||
|
|
766b1b5286 | ||
|
|
3c9dab3b9d | ||
|
|
7d156ef555 | ||
|
|
1aa38f8fdd | ||
|
|
a2d9ef3ca6 | ||
|
|
9fbd7476fb | ||
|
|
f627277479 | ||
|
|
0d17d4f38e | ||
|
|
7e98cf94f3 | ||
|
|
6893231f85 | ||
|
|
8206c0fe8b | ||
|
|
837dcccefe | ||
|
|
3e05598b56 | ||
|
|
8128de64df | ||
|
|
b83d788d3c | ||
|
|
6e62aab66e | ||
|
|
5de3515fc8 | ||
|
|
65ac61f300 | ||
|
|
10b8d492b3 | ||
|
|
09c6cad3e8 | ||
|
|
e4df1293d2 | ||
|
|
ce84174554 | ||
|
|
ba9d6336ac | ||
|
|
e90c2c4cb7 | ||
|
|
8f086e315c | ||
|
|
542b5362d3 | ||
|
|
8626dc6b1a | ||
|
|
a110ba2dc0 | ||
|
|
85d2467d73 | ||
|
|
99f38098dd | ||
|
|
b1123a4978 | ||
|
|
4af8d56479 | ||
|
|
16118960aa | ||
|
|
2c5a737715 | ||
|
|
5fa77d40b9 | ||
|
|
e9106882f7 | ||
|
|
42f0db4251 | ||
|
|
c3533dac2a | ||
|
|
8d52e5f078 | ||
|
|
116e9ffe81 | ||
|
|
967f217346 | ||
|
|
da2a94d0b2 | ||
|
|
6c2b726fe1 | ||
|
|
4dd703a6bf | ||
|
|
762b572c51 | ||
|
|
6ca371cb8b | ||
|
|
0d8d7f358d | ||
|
|
51c2ab1672 | ||
|
|
a88f86cc3f | ||
|
|
451c8c7548 | ||
|
|
528645d407 | ||
|
|
70cf8487e7 | ||
|
|
aa09e566e0 | ||
|
|
c3d6e1b490 | ||
|
|
6580f43e53 | ||
|
|
56d7745139 | ||
|
|
ee1c7db915 | ||
|
|
b682c76dc7 | ||
|
|
0d035a9c23 | ||
|
|
8310950f7b | ||
|
|
120e2936fe | ||
|
|
884f7991c4 | ||
|
|
9664e4b96f | ||
|
|
63cd7fbd0c | ||
|
|
346a48f871 | ||
|
|
8fe3e59e76 | ||
|
|
74d6156e8d | ||
|
|
e834424a4c | ||
|
|
465d8b0245 | ||
|
|
25e9c1a50a | ||
|
|
d601cdd29e | ||
|
|
5646ce9d8f | ||
|
|
f7cacbe932 | ||
|
|
abe38520aa | ||
|
|
46a5f41721 | ||
|
|
2aea4150a0 | ||
|
|
4b2b4c3f9f | ||
|
|
b655809903 | ||
|
|
2e60830f6a | ||
|
|
752b5456b9 | ||
|
|
35f7677d48 | ||
|
|
a3b7da25bc | ||
|
|
596eea1f0a | ||
|
|
725aa3183d | ||
|
|
cf49f53809 | ||
|
|
20c7e37345 | ||
|
|
38e962f2cb | ||
|
|
3efb651589 | ||
|
|
589eb3fa15 | ||
|
|
87554e9b16 | ||
|
|
2e73938534 | ||
|
|
acf2564c73 | ||
|
|
91dba7be88 | ||
|
|
b49591c236 | ||
|
|
8458a98eff | ||
|
|
a518480292 | ||
|
|
a324feae9d | ||
|
|
551f1bd09f | ||
|
|
d5dfe4224d | ||
|
|
f1fc305ac4 | ||
|
|
37ca5d827b | ||
|
|
1aa257df4b | ||
|
|
e4843061f0 | ||
|
|
3c72f3303c | ||
|
|
60f5522e67 | ||
|
|
576af01b6f | ||
|
|
8b767a166a | ||
|
|
684c1a81a4 | ||
|
|
7a72f2f88d | ||
|
|
21ddcf07f7 | ||
|
|
03b1ee0896 | ||
|
|
e30871a96f | ||
|
|
3677cf688d | ||
|
|
863be3d852 | ||
|
|
2b4cf08f3a | ||
|
|
bd017bf56b | ||
|
|
ce7acff6d6 | ||
|
|
536d7017ee | ||
|
|
7c03e5510c | ||
|
|
ceb9b87783 | ||
|
|
42afa6b48a | ||
|
|
3c7d57a73b | ||
|
|
dcfd06c425 | ||
|
|
23be263dd2 | ||
|
|
f978299868 | ||
|
|
dbb0137ea0 | ||
|
|
51108c02ea | ||
|
|
69b97bbc59 | ||
|
|
f2399bc05a | ||
|
|
93a85dd937 | ||
|
|
8ee9724277 | ||
|
|
7c446ec71a | ||
|
|
f2451d03c1 | ||
|
|
0986282f13 | ||
|
|
d3638bcb24 | ||
|
|
f386d1caad | ||
|
|
480c7b3e21 | ||
|
|
908d5747a8 | ||
|
|
9ec2a40274 | ||
|
|
a080a6294c | ||
|
|
9be854a1a4 | ||
|
|
c76dc77e64 | ||
|
|
a42f17ca41 | ||
|
|
ed136fbc51 | ||
|
|
e3ff4c46cb | ||
|
|
6125b66286 | ||
|
|
8285bac2f5 | ||
|
|
61bb0fae53 | ||
|
|
47b9af970b | ||
|
|
731c85337b | ||
|
|
4b59fda56f | ||
|
|
2361221198 | ||
|
|
d931ba9b50 | ||
|
|
51fd1db4eb | ||
|
|
dbd4dd215a | ||
|
|
c716954e89 | ||
|
|
5be247da0a | ||
|
|
b47e84369c | ||
|
|
fe7ddf3e0f | ||
|
|
2fc9288870 | ||
|
|
f9de807daa | ||
|
|
e85ce4eaf2 | ||
|
|
5fc36333b9 | ||
|
|
2809cb910c | ||
|
|
782f8ca047 | ||
|
|
8bdbd6b073 | ||
|
|
7fbd5adaa2 | ||
|
|
324ca171a3 | ||
|
|
bbf114b822 | ||
|
|
a2a8ac9549 | ||
|
|
ae384306eb | ||
|
|
9c4e003315 | ||
|
|
9bb5470342 | ||
|
|
2f209e3e9b | ||
|
|
314ddbd44c | ||
|
|
3b78ab04c7 | ||
|
|
bb21f51f74 | ||
|
|
666c2383ba | ||
|
|
2703853edb | ||
|
|
f728fca036 | ||
|
|
368103d76d | ||
|
|
3a2462baba | ||
|
|
bd2bfbbb93 | ||
|
|
1300fc864c | ||
|
|
ef2d17922b | ||
|
|
b63dd40512 | ||
|
|
fb82567f03 | ||
|
|
b2c443e866 | ||
|
|
07d0324a6d | ||
|
|
c1e92ad27d | ||
|
|
28e481c2e2 | ||
|
|
1ceea645b6 | ||
|
|
578e5e7e58 | ||
|
|
463d00732f | ||
|
|
698a8abe6e | ||
|
|
776877291f | ||
|
|
1c25d965ac | ||
|
|
bc41f81303 | ||
|
|
648c38414e | ||
|
|
02b972e1ed | ||
|
|
dd38a08746 | ||
|
|
315b0059da | ||
|
|
4d3ea70d2b | ||
|
|
29a0dcffc7 | ||
|
|
1732bb877c | ||
|
|
fc1fac08c8 | ||
|
|
1d03de333c | ||
|
|
74f086a460 | ||
|
|
6e93e3e25d | ||
|
|
d53d0cb439 | ||
|
|
3f185cb18b | ||
|
|
7963e7540f | ||
|
|
85316879cd | ||
|
|
69c4760f37 | ||
|
|
7d04cf14fb | ||
|
|
9072096495 | ||
|
|
f6cfe15807 | ||
|
|
e1bad04279 | ||
|
|
dda3341537 | ||
|
|
6e27795756 | ||
|
|
54fac4a5d7 | ||
|
|
2697974694 | ||
|
|
a9b5dffa00 | ||
|
|
095ccf7194 | ||
|
|
4f5b811383 | ||
|
|
776cad427d | ||
|
|
d365ba5303 | ||
|
|
31c0ab7ab7 | ||
|
|
09974fa686 | ||
|
|
03cbab6c08 | ||
|
|
bbe5bff389 | ||
|
|
f857da964b | ||
|
|
d36916b400 | ||
|
|
c0568f92e4 | ||
|
|
b17891c170 | ||
|
|
164d6e93d0 | ||
|
|
733ca324d2 | ||
|
|
fb4f822d34 | ||
|
|
7b21eaf12d | ||
|
|
02a4e17e41 | ||
|
|
5f30dbb1a5 | ||
|
|
219f50b0bc | ||
|
|
ccd6ca298e | ||
|
|
967f2ace0e | ||
|
|
2c36468431 | ||
|
|
8dbf0a2bd8 | ||
|
|
967899229f | ||
|
|
1d58007606 | ||
|
|
56a1dee3d6 | ||
|
|
28572a978e | ||
|
|
acfb9bca45 | ||
|
|
6f82cefdc5 | ||
|
|
d0ea57120c | ||
|
|
277beb6587 | ||
|
|
802deaca03 | ||
|
|
3c6461f757 | ||
|
|
a0bb13a412 | ||
|
|
870838e756 | ||
|
|
8f6f13dc93 | ||
|
|
13179a9498 | ||
|
|
0ba22c3aaf | ||
|
|
311f77dd25 | ||
|
|
8382faa0af | ||
|
|
9c5107e86d | ||
|
|
14a6b40bcc | ||
|
|
07506ae4d9 | ||
|
|
6abcca1215 | ||
|
|
02f27f3de6 | ||
|
|
fbf3a2a1b4 | ||
|
|
c80f68af94 | ||
|
|
85b3d579d3 | ||
|
|
bf6522898d | ||
|
|
ddb34c3d83 | ||
|
|
010ea4305b | ||
|
|
c33b226660 | ||
|
|
8670d387d6 | ||
|
|
a684b8f8bf | ||
|
|
8270d8a228 | ||
|
|
48941dce07 | ||
|
|
d6aa06a8af | ||
|
|
7a0511610e | ||
|
|
451ffcd982 | ||
|
|
fb2fcf3f66 | ||
|
|
b97a0881f1 | ||
|
|
f9b3486ed1 | ||
|
|
8cc900e11f | ||
|
|
904c365b75 | ||
|
|
362a4ccece | ||
|
|
750c6c32fa | ||
|
|
439caf815f | ||
|
|
0406548fe6 | ||
|
|
4fb8b0fa28 | ||
|
|
a0fd26602e | ||
|
|
6d8eafd072 | ||
|
|
286193b4ab | ||
|
|
1808a9b663 | ||
|
|
0683dd22dd | ||
|
|
7fcde11fa0 | ||
|
|
90dab3c445 | ||
|
|
e942a18e5a | ||
|
|
d397fe9af7 | ||
|
|
cf6f0bfb8b | ||
|
|
b628a19e35 | ||
|
|
4592d981a7 | ||
|
|
f6db81e431 | ||
|
|
274edc74a7 | ||
|
|
12edb1cc4b | ||
|
|
269b203ef8 | ||
|
|
ed230a42e0 | ||
|
|
c251801b1a | ||
|
|
8c242450e5 | ||
|
|
e67ca20108 | ||
|
|
c117b32147 | ||
|
|
1c5737b68a | ||
|
|
db7acb4edd | ||
|
|
72be80abc4 | ||
|
|
023719d775 | ||
|
|
431b04075f | ||
|
|
5e02985206 | ||
|
|
b80478d4b4 | ||
|
|
fc7fa8debd | ||
|
|
a4fd0df69c | ||
|
|
cb9ca3e4c9 | ||
|
|
5a6447805f | ||
|
|
52ae6f06a1 | ||
|
|
799699894c | ||
|
|
e0c0b2fdf6 | ||
|
|
506bf646ba | ||
|
|
e6c94c4f36 | ||
|
|
3f9bbe90bd | ||
|
|
042e58ea29 | ||
|
|
7fa27686bb | ||
|
|
e3e2d513df | ||
|
|
086feafcb7 | ||
|
|
f9b8e2dbc5 | ||
|
|
5eafbefa9f | ||
|
|
cfadaf781c | ||
|
|
dab5481fc5 | ||
|
|
1a681dd97b | ||
|
|
2074f63333 | ||
|
|
959a5d78c7 | ||
|
|
995054d46b | ||
|
|
d187b809d7 | ||
|
|
81d69d1b64 | ||
|
|
faef4d5f8e | ||
|
|
cd548a6e2d | ||
|
|
78316d4ddc | ||
|
|
a45ab8bd76 | ||
|
|
cd861c22b7 | ||
|
|
15442a9cc7 | ||
|
|
3c04d43eae | ||
|
|
63e23bab89 | ||
|
|
e8a24fd2e5 | ||
|
|
aee6ca05cc | ||
|
|
0f8051b577 | ||
|
|
9d489ed57f | ||
|
|
ae88bade03 | ||
|
|
4be43527e8 | ||
|
|
823d0228c9 | ||
|
|
2d0441a72e | ||
|
|
6ceb791891 | ||
|
|
cd9e0400ac | ||
|
|
b9a5bb3b8e | ||
|
|
1387ba9ae0 | ||
|
|
3dd70483c6 | ||
|
|
ec2933c49a | ||
|
|
7eec16ee61 | ||
|
|
ff89b8f782 | ||
|
|
588a7d0a5b | ||
|
|
19ce0d79ef | ||
|
|
7f2c3d1d0a | ||
|
|
13cc669e2c | ||
|
|
4d515a0d5b | ||
|
|
11a6ce6d3a | ||
|
|
048dd89bbc | ||
|
|
48625e0e34 | ||
|
|
013c96f0db | ||
|
|
5fa8f69e10 | ||
|
|
fb89793703 | ||
|
|
67098f7a3e | ||
|
|
299ae4fce5 | ||
|
|
09ba58a432 | ||
|
|
f9f6ec47d9 | ||
|
|
b76c25c9e7 | ||
|
|
192dac38f8 | ||
|
|
3a6acf322b | ||
|
|
a9cd23a883 | ||
|
|
b6dec7af1c | ||
|
|
546b7dc20a | ||
|
|
7cab14353d | ||
|
|
888bbf28e0 | ||
|
|
de5ceb2aca | ||
|
|
95719a978c | ||
|
|
dd16bcffd2 | ||
|
|
02410a0be3 | ||
|
|
14f2fbbce7 | ||
|
|
8eea0d6cf4 | ||
|
|
752a657a4f | ||
|
|
0ca5851a3c | ||
|
|
4bb0bdc4e6 | ||
|
|
6865634a6e | ||
|
|
07eb8dd7d2 | ||
|
|
789537cc8c | ||
|
|
8bbb1a16e3 | ||
|
|
0ff81573b5 | ||
|
|
90284ff626 | ||
|
|
e4fc1ff47c | ||
|
|
73c7ba4fe5 | ||
|
|
72a8b1eebe | ||
|
|
c14122a007 | ||
|
|
6ca12b1cc0 | ||
|
|
e8dc7d462e | ||
|
|
c2ca499516 | ||
|
|
1c8cf24ba6 | ||
|
|
49e4e0c6e7 | ||
|
|
bc2e843a83 | ||
|
|
ad25b096b6 | ||
|
|
1b85f194c5 | ||
|
|
cffc9971c4 | ||
|
|
3a6a97618c | ||
|
|
38e917a3df | ||
|
|
3825041393 | ||
|
|
0fedbabe9e | ||
|
|
c5cb08c5b8 | ||
|
|
833899c893 | ||
|
|
1f480c4cd5 | ||
|
|
b74a59947d | ||
|
|
21b8da7f41 | ||
|
|
fb2fd3e9b7 | ||
|
|
c0ff75c164 | ||
|
|
e1a6e08aa1 | ||
|
|
ac4cc5548a | ||
|
|
e0e1b09b77 | ||
|
|
fe86707c53 | ||
|
|
2ed7e325b8 | ||
|
|
e09ebfffa0 | ||
|
|
a8766d00a8 | ||
|
|
ef9606bf5b | ||
|
|
10dd819863 | ||
|
|
c14db9f94d | ||
|
|
c8594a7e7a | ||
|
|
959567aade | ||
|
|
7a8c7f3429 | ||
|
|
4d578f1bfd | ||
|
|
eabfd91655 | ||
|
|
a4c6c4891e | ||
|
|
11c15720d4 | ||
|
|
24e92cfe69 | ||
|
|
c0ab499a77 | ||
|
|
abf74f1a90 | ||
|
|
8e814b1edd | ||
|
|
4b243c9007 | ||
|
|
8d65ba1efd | ||
|
|
5f1b0c21eb | ||
|
|
af164159fb | ||
|
|
39e303add6 | ||
|
|
9b5c889187 | ||
|
|
dd9c15c672 | ||
|
|
92e9602329 | ||
|
|
dbf976ee5e | ||
|
|
927b3fb6d3 | ||
|
|
5e84ca3ce7 | ||
|
|
3b2daa1992 | ||
|
|
a19c42f1bd | ||
|
|
fc82661b54 | ||
|
|
4e95a39132 | ||
|
|
5a637a8b09 | ||
|
|
75e776ddb4 | ||
|
|
e1553c2fc8 | ||
|
|
db6d35bc03 | ||
|
|
d5bf957c8e | ||
|
|
566c45b0b4 | ||
|
|
39ee306630 | ||
|
|
748475f785 | ||
|
|
bf9929e9a9 | ||
|
|
9aa1b8ec47 | ||
|
|
ccc92fdb75 | ||
|
|
657aa65e99 | ||
|
|
abebde6b12 | ||
|
|
1df3d149e0 | ||
|
|
8832d08a22 | ||
|
|
51dc66b5d9 | ||
|
|
aae6d716e5 | ||
|
|
32b38439e3 | ||
|
|
fd8ea88488 | ||
|
|
8d1df96637 | ||
|
|
c1f205c2cf | ||
|
|
e9c796e42c | ||
|
|
b459277c72 | ||
|
|
28ecb0c5eb | ||
|
|
1356b4db40 | ||
|
|
4e1748fb8a | ||
|
|
959f01739c | ||
|
|
85dee9a7bc | ||
|
|
057522c5bd | ||
|
|
9a8c6deafb | ||
|
|
7daddf864d | ||
|
|
ef826c88ec | ||
|
|
42fbd96040 | ||
|
|
889a55ad99 | ||
|
|
3c205bcaba | ||
|
|
a1ddd2e2e3 | ||
|
|
5a07b788c7 | ||
|
|
5d84a98d7b | ||
|
|
b92ad4a2d6 | ||
|
|
b10e842e89 | ||
|
|
bc7d4d8f0e | ||
|
|
12c0e09c65 | ||
|
|
c447421b05 | ||
|
|
0779f8d73d | ||
|
|
ace032ef89 | ||
|
|
c5f9fa0d97 | ||
|
|
ada9a89cd2 | ||
|
|
27e538c8c6 | ||
|
|
8bfe63d5b2 | ||
|
|
65bbf54b4a | ||
|
|
8d31ed6d39 | ||
|
|
a7f72babe1 | ||
|
|
87a60325cf | ||
|
|
0f38a0dcf6 | ||
|
|
812ab9f868 | ||
|
|
ea893671d5 | ||
|
|
474a3cbf7a | ||
|
|
066f5f6d2c | ||
|
|
c661ac2e8a | ||
|
|
cb005d58eb | ||
|
|
6c82c1e04f | ||
|
|
feebf203b8 | ||
|
|
40033c64fb | ||
|
|
ffdbe3c965 | ||
|
|
6e740dbfc1 | ||
|
|
f6eb0202fe | ||
|
|
38aa4c45c4 | ||
|
|
122aa94bdb | ||
|
|
5aa203d020 | ||
|
|
aac066d609 | ||
|
|
70fe14f7af | ||
|
|
de2ae5ec15 | ||
|
|
45b36ce56d | ||
|
|
f7a2ae7e55 | ||
|
|
0247e2d106 | ||
|
|
237aff9c85 | ||
|
|
51911cdfdf | ||
|
|
f64b2b1321 | ||
|
|
8caedb19dd | ||
|
|
e2c65e3fa5 | ||
|
|
523d9d4952 | ||
|
|
4cd228a367 | ||
|
|
44651e6ecc | ||
|
|
b0b82e1f57 | ||
|
|
619b49f6f1 | ||
|
|
ce3bb96ff7 | ||
|
|
a4de51adaa | ||
|
|
861a0fdff9 | ||
|
|
c1e8b20f1b | ||
|
|
ac54b11f9d | ||
|
|
cf17760735 | ||
|
|
31488ffdd6 | ||
|
|
8c4f890af0 | ||
|
|
5ac436e184 | ||
|
|
387cec9838 | ||
|
|
a3cc3c3429 | ||
|
|
bf620fe16f | ||
|
|
ebd16e8fdf | ||
|
|
ee06515ca9 | ||
|
|
d0abf19037 | ||
|
|
0d6a27cc69 | ||
|
|
164b868dc2 | ||
|
|
c87fd2b649 | ||
|
|
c4cc283bcd | ||
|
|
cbfabeeb9d | ||
|
|
e84c43a4f6 | ||
|
|
83720c8277 | ||
|
|
5888fb9b3f | ||
|
|
985eb59893 | ||
|
|
2a4db3896e | ||
|
|
9ea1512df9 | ||
|
|
15b6bb3d75 | ||
|
|
d9d2b6c383 | ||
|
|
8a8c392095 | ||
|
|
b4a20741b2 | ||
|
|
007d38be04 | ||
|
|
40224ed1bc | ||
|
|
f3f246848a | ||
|
|
a6917d8952 | ||
|
|
a60b5acb65 | ||
|
|
753de21b12 | ||
|
|
3eb85b1554 | ||
|
|
7109bfde52 | ||
|
|
686a616b4c | ||
|
|
7e8869858c | ||
|
|
a16bad0cc0 | ||
|
|
32a0778fc4 | ||
|
|
6a7663beb5 | ||
|
|
06fc8cbf4d | ||
|
|
79d047e64f | ||
|
|
ab27b1bfd1 | ||
|
|
42ebf68932 | ||
|
|
5c5f1f9735 | ||
|
|
3965613154 | ||
|
|
8ac0906ff0 | ||
|
|
62879a5bc4 | ||
|
|
ff4d1f6ac2 | ||
|
|
1930bc260e | ||
|
|
fa32c27716 | ||
|
|
ebdfd8f69a | ||
|
|
2af0c04c8a | ||
|
|
cfb3632cbc | ||
|
|
c076c77db4 | ||
|
|
f9bcf359a1 | ||
|
|
bf2e5c70f8 | ||
|
|
ad3141dc00 | ||
|
|
e0eb93bf83 | ||
|
|
7a99b2544a | ||
|
|
2089136671 | ||
|
|
e36f775273 | ||
|
|
060c3805e5 | ||
|
|
3c3e1f17ef | ||
|
|
8abc9cfbc7 | ||
|
|
7bb0984a12 | ||
|
|
586b25a54c | ||
|
|
c655ceac9e | ||
|
|
d4c1e0deb0 | ||
|
|
e2ed0ccaea | ||
|
|
4999fbaee6 | ||
|
|
f80ad26081 | ||
|
|
b4a7e912b2 | ||
|
|
0a87f106ec | ||
|
|
b0a66ce6d8 | ||
|
|
8c7e37c56a | ||
|
|
9f30553813 | ||
|
|
11532857d2 | ||
|
|
c975a6c8ba | ||
|
|
6096044fe0 | ||
|
|
3ebe7b4a7e | ||
|
|
a1fd1e07f0 | ||
|
|
9029dab015 | ||
|
|
e9e084d933 | ||
|
|
93129f8989 | ||
|
|
7e676b4b8d | ||
|
|
f9cb02026e | ||
|
|
3a2a41d2b6 | ||
|
|
ee658a6e9b | ||
|
|
b7d56b6fce | ||
|
|
d2254c1255 | ||
|
|
4d259a69f2 | ||
|
|
8c50ae6071 | ||
|
|
40ecd206e6 | ||
|
|
9fed4f1c49 | ||
|
|
ecac445fb2 | ||
|
|
c4742e5c30 | ||
|
|
55aec55ef2 | ||
|
|
8e95383afe | ||
|
|
e072dad30c | ||
|
|
30688bbe41 | ||
|
|
4c22b2a7d9 | ||
|
|
d5cd9709f7 | ||
|
|
dddbec2682 | ||
|
|
cfc5533920 | ||
|
|
caa4c07e3e | ||
|
|
e6ac872b0d | ||
|
|
d42b5d4989 | ||
|
|
6d72d66656 | ||
|
|
3a8e730b9c | ||
|
|
ac2e174643 | ||
|
|
777794583c | ||
|
|
cff6608996 | ||
|
|
972dd3e174 | ||
|
|
3bc67e338b | ||
|
|
4cd2c8c1d9 | ||
|
|
224b68dbf2 | ||
|
|
851983af15 | ||
|
|
96a90bbca4 | ||
|
|
922887fe77 | ||
|
|
0bebb4e7ef | ||
|
|
2e4f7ab35c | ||
|
|
a828ec7c3c | ||
|
|
a4514c790b | ||
|
|
b162285f13 | ||
|
|
bdb2f8939a | ||
|
|
66465897a9 | ||
|
|
43e9c32ec6 | ||
|
|
6032605341 | ||
|
|
e40fe65272 | ||
|
|
2ba355c76f | ||
|
|
b321b07ad5 | ||
|
|
a41e295e42 | ||
|
|
4b0d4f4cd5 | ||
|
|
ade4c011d3 | ||
|
|
2b654882fd | ||
|
|
58abeecb11 | ||
|
|
1f0a1c796a | ||
|
|
dd56ceb700 | ||
|
|
090906c559 | ||
|
|
65b8fd27af | ||
|
|
e6ed676117 | ||
|
|
827428d6b5 | ||
|
|
02f9be2c4a | ||
|
|
aefb655769 | ||
|
|
5214b331e0 | ||
|
|
b5880f26af | ||
|
|
59e5a457ef | ||
|
|
0dbc4fa213 | ||
|
|
d51e93b86e | ||
|
|
071462b33b | ||
|
|
f2d11cfcaf | ||
|
|
90c9bf879f | ||
|
|
e813394eb4 | ||
|
|
8c65f6a938 | ||
|
|
e968f4067c | ||
|
|
1fd61fb989 | ||
|
|
eb9d860af3 | ||
|
|
12ed655881 | ||
|
|
c1df7674b2 | ||
|
|
30088ec20b | ||
|
|
7720f452d3 | ||
|
|
678614b62b | ||
|
|
888b3a2672 | ||
|
|
fa86fb7e3f | ||
|
|
2a44cad2d0 | ||
|
|
5f0574e15c | ||
|
|
bd4b834b74 | ||
|
|
1614bcdc0b | ||
|
|
93f684e5b6 | ||
|
|
9f2e51ea8c | ||
|
|
c1caa6318e | ||
|
|
4d5fcfcdad | ||
|
|
39aec8caa3 | ||
|
|
1c8209c54a | ||
|
|
742d21f1c9 | ||
|
|
c70d59c8d2 | ||
|
|
2d74bb00f2 | ||
|
|
6ae6b9268f | ||
|
|
b7aaa53a8a | ||
|
|
3a3def5e76 | ||
|
|
44d55e39f3 | ||
|
|
af4ed27d15 | ||
|
|
eb98810cef | ||
|
|
dfa47a0e0f | ||
|
|
f81fa55289 | ||
|
|
ab7b14d81e | ||
|
|
69309a1f88 | ||
|
|
abdd1634e4 | ||
|
|
e4d2549984 | ||
|
|
2edabef78f | ||
|
|
9c5d7b2f2c | ||
|
|
453a9036be | ||
|
|
b0ef5fb06d | ||
|
|
27352f7230 | ||
|
|
58c454b628 | ||
|
|
3058eb5617 | ||
|
|
76745bf19a | ||
|
|
7c6ff89ab6 | ||
|
|
8d26d6d863 | ||
|
|
52589f7c59 | ||
|
|
46b750b3ec | ||
|
|
caee0c07d7 | ||
|
|
4cb3e32ff1 | ||
|
|
fb41d245e6 | ||
|
|
1ab8ccdc99 | ||
|
|
3d854f7724 | ||
|
|
e7908b7f37 | ||
|
|
6981098329 | ||
|
|
8b778b6407 | ||
|
|
993a8a1f90 | ||
|
|
25c5b784e1 | ||
|
|
9b613ee202 | ||
|
|
84b36fed6f | ||
|
|
f351039d48 | ||
|
|
339cee416a | ||
|
|
e39c5e3ec0 | ||
|
|
517e359399 | ||
|
|
1c2eec405b | ||
|
|
398f40ea68 | ||
|
|
1efc6f53d3 | ||
|
|
5ff01f529f | ||
|
|
2a678b9686 | ||
|
|
922122492e | ||
|
|
7fb0e654cd | ||
|
|
3c435daf65 | ||
|
|
198b077257 | ||
|
|
d72237adf3 | ||
|
|
65ce21a238 | ||
|
|
59dfd9b9bd | ||
|
|
268b5dd54e | ||
|
|
c0ac155a71 | ||
|
|
5d71d4bf6e | ||
|
|
bbc926bccc | ||
|
|
c83ad752ca | ||
|
|
9ae5b47296 | ||
|
|
6dc688cefd | ||
|
|
989409a1ab | ||
|
|
ead6229d55 | ||
|
|
69147a51d6 | ||
|
|
6023559142 | ||
|
|
51bd6d5ce0 | ||
|
|
690ec7ce24 | ||
|
|
ff8dc859cd | ||
|
|
06230398d7 | ||
|
|
c0e21c2406 | ||
|
|
fc23b49998 | ||
|
|
e80ead17a8 | ||
|
|
a88c352e72 | ||
|
|
338c4e2fb1 | ||
|
|
8b08e5a1f9 | ||
|
|
b3f2c79d87 | ||
|
|
bd4da37f23 | ||
|
|
eec4b3ace5 | ||
|
|
9feca3c4cc | ||
|
|
4a49640c3f | ||
|
|
32e2211dbe | ||
|
|
fcc247ffd6 | ||
|
|
d13732b44e | ||
|
|
50f74fbeda | ||
|
|
4855ba07c5 | ||
|
|
1e0c5be5b3 | ||
|
|
21c15ae559 | ||
|
|
9e7a15c1be | ||
|
|
f66dd613e3 | ||
|
|
3c70a15bb6 | ||
|
|
a1f40c73c9 | ||
|
|
98171abed5 | ||
|
|
9b949da47c | ||
|
|
caa5cefe53 | ||
|
|
1befe0ce57 | ||
|
|
63ca5126cf | ||
|
|
a4105266b4 | ||
|
|
148fc817cd | ||
|
|
213849fb32 | ||
|
|
412064d77f | ||
|
|
700e3a159f | ||
|
|
ea069c0c51 | ||
|
|
de2ef90043 | ||
|
|
ed6394300f | ||
|
|
8ae0d045e3 | ||
|
|
70745cea5d | ||
|
|
6f62429382 | ||
|
|
c0a942aa4a | ||
|
|
e3c5a6c294 | ||
|
|
66dac29ee6 | ||
|
|
1f9b4e2296 | ||
|
|
2c6844c327 | ||
|
|
3bb262fd66 | ||
|
|
47bb5d6c61 | ||
|
|
4851b6bae0 | ||
|
|
433b3e8c21 | ||
|
|
35dc687be6 | ||
|
|
dc0f8deb06 | ||
|
|
ed998598df | ||
|
|
a53682acee | ||
|
|
d04db59880 | ||
|
|
34582da561 | ||
|
|
dff840c49b | ||
|
|
8cfa550954 | ||
|
|
fc7709da51 | ||
|
|
0a4766a61e | ||
|
|
671adc7e0e | ||
|
|
cc7257efd5 | ||
|
|
773fb57c71 | ||
|
|
5a93683a26 | ||
|
|
0af29ff4db | ||
|
|
d8cce02e97 | ||
|
|
b06ca700be | ||
|
|
5f620a2325 | ||
|
|
01d1f43d45 | ||
|
|
6903d7f52f | ||
|
|
bb565f9450 | ||
|
|
918f736141 | ||
|
|
a5c76d4bd5 | ||
|
|
d6d4906148 | ||
|
|
a054cf098c | ||
|
|
c0710a3b74 | ||
|
|
ae05392625 | ||
|
|
3fb2e5d25e | ||
|
|
af7b42e531 | ||
|
|
679331873c | ||
|
|
4460ad0577 | ||
|
|
1ea6e8b4f3 | ||
|
|
f018fc04b0 | ||
|
|
69026c5779 | ||
|
|
b847d85e60 | ||
|
|
d3d367c635 | ||
|
|
8de92dc6b9 | ||
|
|
dabc0bbe80 | ||
|
|
3f30b2f489 | ||
|
|
84e03893fd | ||
|
|
b4ffeaf034 | ||
|
|
a470706c2e | ||
|
|
5e7d731ddd | ||
|
|
2e833a6efd | ||
|
|
1cde647a2a | ||
|
|
047efe02ff | ||
|
|
441eb2c20c | ||
|
|
0f45014dce | ||
|
|
1acf615fc7 | ||
|
|
f1c342e05e | ||
|
|
96002dbda5 | ||
|
|
93d0a9b3d4 | ||
|
|
571495c3e0 | ||
|
|
9b71aa17b3 | ||
|
|
03dcf743e8 | ||
|
|
dadaf32e4d | ||
|
|
086117d703 | ||
|
|
ea9943e135 | ||
|
|
bda03d7a84 | ||
|
|
665d3da651 | ||
|
|
faab09b76f | ||
|
|
33401f4064 | ||
|
|
9e9dfbcb10 | ||
|
|
73af283e1c | ||
|
|
6c25ad9cc2 | ||
|
|
c247f3130c | ||
|
|
4194632318 | ||
|
|
8f84f9e140 | ||
|
|
21420f16df | ||
|
|
ee682270a4 | ||
|
|
6923128774 | ||
|
|
5cabd8e4c0 | ||
|
|
84bc5ab299 | ||
|
|
9483ccb120 | ||
|
|
d8c700975f | ||
|
|
aee7d36f1d | ||
|
|
febbea5550 | ||
|
|
ee54c1481c | ||
|
|
78af86f9d1 | ||
|
|
82961767e3 | ||
|
|
7583289d24 | ||
|
|
d40e136947 | ||
|
|
ed7cfff45c | ||
|
|
a10376372a | ||
|
|
f6e749734a | ||
|
|
62c9efbc54 | ||
|
|
84e1417b71 | ||
|
|
bf1242aafa | ||
|
|
001a68f45c | ||
|
|
a823e75d2b | ||
|
|
c21c6b8013 | ||
|
|
e42d103af3 | ||
|
|
84e00bf7b3 | ||
|
|
25e5ab7cee | ||
|
|
5a7972fbf8 | ||
|
|
74e10b1788 | ||
|
|
6c3bc6fb34 | ||
|
|
b8ca2c56d9 | ||
|
|
c9e7c1b3bc | ||
|
|
dacf1a85fd | ||
|
|
6567454ae4 | ||
|
|
06fd7e7776 | ||
|
|
cac4b92a02 | ||
|
|
7d27431312 | ||
|
|
206d0c2c2a | ||
|
|
38b8423150 | ||
|
|
ea8b1ba10c | ||
|
|
1bbf099fe0 | ||
|
|
5fae18e940 | ||
|
|
f4d20a9aed | ||
|
|
27dd945544 | ||
|
|
7c74507bca | ||
|
|
c18ea7c856 | ||
|
|
681d75e43e | ||
|
|
c11bcd1416 | ||
|
|
82501319ce | ||
|
|
b379001f00 | ||
|
|
fe1dfa3e23 | ||
|
|
d97c9fd2ee | ||
|
|
fde79a1b3c | ||
|
|
59781b9eef | ||
|
|
27ab978565 | ||
|
|
f7d664fdcf | ||
|
|
4d74d7a994 | ||
|
|
6a3ee4debe | ||
|
|
a0181a0eee | ||
|
|
1c3a257244 | ||
|
|
7727496548 | ||
|
|
ecfb363169 | ||
|
|
4579a2adc1 | ||
|
|
57ba307c3b | ||
|
|
54dadbeae5 | ||
|
|
2a8bc31e4a | ||
|
|
d6fcd19bd1 | ||
|
|
e0d4b3fef2 | ||
|
|
3552d6a340 | ||
|
|
e330d8874b | ||
|
|
d919abbda4 | ||
|
|
8e6b2c4f9d | ||
|
|
420ed6738e | ||
|
|
49fa5cb23a | ||
|
|
ec9196e33c | ||
|
|
883daf7b46 | ||
|
|
7b92211eca | ||
|
|
192c9fe981 | ||
|
|
9f4ce8d756 | ||
|
|
abaa22950c | ||
|
|
e23481a011 | ||
|
|
8a8741a792 | ||
|
|
206b757629 | ||
|
|
238badabb4 | ||
|
|
e86a6efe45 | ||
|
|
37bc8826f7 | ||
|
|
3d4dfbcf7a | ||
|
|
2de435f43a | ||
|
|
ff4a6a1ea1 | ||
|
|
55df622007 | ||
|
|
baf5b10d23 | ||
|
|
794b6e8783 | ||
|
|
df41201134 | ||
|
|
95e9300d10 | ||
|
|
ad2a54bb78 | ||
|
|
d417e50d52 | ||
|
|
16c41d36cf | ||
|
|
4e019e44b0 | ||
|
|
d7e7ee9a52 | ||
|
|
e7a16364c0 | ||
|
|
a46c220489 | ||
|
|
830af2389e | ||
|
|
332b5d1dad | ||
|
|
3cde636d47 | ||
|
|
c0293719d9 | ||
|
|
bd4ed5b99b | ||
|
|
0527e6f3ea | ||
|
|
ff3ab18d16 | ||
|
|
691730974e | ||
|
|
46a29f54fc | ||
|
|
95127c94a6 | ||
|
|
88a0c56f40 | ||
|
|
6bd5907ad7 | ||
|
|
801068c8fe | ||
|
|
4516c3670e | ||
|
|
73b8ba3d4a | ||
|
|
9567328d28 | ||
|
|
35abe811c1 | ||
|
|
6bc1758dc0 | ||
|
|
341c163b36 | ||
|
|
468b0d2a55 | ||
|
|
f873fa8d99 | ||
|
|
59de4f7e82 | ||
|
|
f02bbe6308 | ||
|
|
e5835ae4f6 | ||
|
|
309569c581 | ||
|
|
a88dddab22 | ||
|
|
b5048a3323 | ||
|
|
3ec6b3d846 | ||
|
|
d0dacdbde0 | ||
|
|
8d643fb29d | ||
|
|
e5ffb1e92d | ||
|
|
087eeb01a2 | ||
|
|
542ea8eb81 | ||
|
|
60bb2652f0 | ||
|
|
7b769caf78 | ||
|
|
0796d5394d | ||
|
|
0be4285305 | ||
|
|
e366624440 | ||
|
|
c755143cc0 | ||
|
|
020a2797d5 | ||
|
|
389ee261d4 | ||
|
|
13fd974a2d | ||
|
|
d492870924 | ||
|
|
57f5f5ec43 | ||
|
|
0d06b8c178 | ||
|
|
9af4c1dde7 | ||
|
|
5b70ebd119 | ||
|
|
0dfed3b30a | ||
|
|
915f1e2b3a | ||
|
|
2e765a1e05 | ||
|
|
26717c9ce4 | ||
|
|
fc35d845e7 | ||
|
|
6580fc7f91 | ||
|
|
1b8ab36123 | ||
|
|
b8c0482cda | ||
|
|
100da03647 | ||
|
|
016beb6eec | ||
|
|
f85d366500 | ||
|
|
a5670c3163 | ||
|
|
4202fc2933 | ||
|
|
e913fbe4ea | ||
|
|
0fbfe149df | ||
|
|
07b2ccad61 | ||
|
|
f715146aa3 | ||
|
|
efe4f6d861 | ||
|
|
8eaf05efef | ||
|
|
6c7282ec37 | ||
|
|
d9d05f3644 | ||
|
|
d88daa433e | ||
|
|
4d6eba8d21 | ||
|
|
28d9f9009c | ||
|
|
91e33ad1ee | ||
|
|
4359564e2f | ||
|
|
420eef4d91 | ||
|
|
d2f281d318 | ||
|
|
44b31a9e58 |
@@ -11,7 +11,7 @@ module.exports = {
|
||||
'@typescript-eslint',
|
||||
],
|
||||
extends: [
|
||||
'@trbl',
|
||||
'./eslint-config',
|
||||
],
|
||||
settings: {
|
||||
'import/resolver': {
|
||||
@@ -57,6 +57,7 @@ module.exports = {
|
||||
{
|
||||
ignore: [
|
||||
'payload-config',
|
||||
'payload/generated-types',
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
42
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Bug Report
|
||||
description: Create a bug report for Payload
|
||||
labels: ["possible-bug"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
*Note:* Feature requests should be opened as [discussions](https://github.com/payloadcms/payload/discussions/new?category=feature-requests-ideas).
|
||||
- type: input
|
||||
id: reproduction-link
|
||||
attributes:
|
||||
label: Link to reproduction
|
||||
description: Please add a link to a reproduction. See the fork [reproduction-guide](https://github.com/payloadcms/payload/blob/master/.github/reproduction-guide.md) for more information.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: To Reproduce
|
||||
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the Bug
|
||||
validations:
|
||||
required: true
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: Payload Version
|
||||
description: What version of Payload are you running?
|
||||
validations:
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
|
||||
22
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
22
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
@@ -1,22 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Create a bug report for Payload
|
||||
labels: 'possible-bug'
|
||||
---
|
||||
|
||||
# Bug Report
|
||||
|
||||
<!--- Provide a general summary of the issue in the Title above -->
|
||||
|
||||
## Steps to Reproduce
|
||||
|
||||
<!--- Steps to reproduce this bug. Include any code, if relevant -->
|
||||
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
## Other Details
|
||||
|
||||
<!--- Payload version, browser, etc -->
|
||||
<!--- Possible solution if you're familiar with the code -->
|
||||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
@@ -1,8 +1,5 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Security Vulnerability
|
||||
url: https://github.com/payloadcms/payload/blob/master/SECURITY.md
|
||||
about: See instructions to privately disclose any security concerns
|
||||
- name: Feature Request
|
||||
url: https://github.com/payloadcms/payload/discussions
|
||||
about: Suggest an idea to improve Payload in our GitHub Discussions
|
||||
|
||||
58
.github/reproduction-guide.md
vendored
Normal file
58
.github/reproduction-guide.md
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
# Reproduction Guide
|
||||
|
||||
1. [fork](https://github.com/payloadcms/payload/fork) this repo
|
||||
2. run `yarn` to install dependencies
|
||||
3. open up the `test/_community` directory
|
||||
4. add any necessary `collections/globals/fields` in this directory to recreate the issue you are experiencing
|
||||
5. run `yarn dev _community` to start the admin panel
|
||||
|
||||
**NOTE:** The goal is to isolate the problem by reducing the number of `collections/globals/fields` you add to the `test/_community` folder. This folder is _not_ meant for you to copy your project into, but rather recreate the issue you are experiencing with minimal config.
|
||||
|
||||
## Example test directory file tree
|
||||
```text
|
||||
.
|
||||
├── config.ts
|
||||
├── int.spec.ts
|
||||
├── e2e.spec.ts
|
||||
└── payload-types.ts
|
||||
```
|
||||
|
||||
- `config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example
|
||||
- `int.spec.ts` [Optional] - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix.
|
||||
- `e2e.spec.ts` [Optional] - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests.
|
||||
- `payload-types.ts` - Generated types from `config.ts`. Generate this file by running `yarn dev:generate-types _community`.
|
||||
|
||||
The directory split up in this way specifically to reduce friction when creating tests and to add the ability to boot up Payload with that specific config. You should modify the files in `test/_community` to get started.
|
||||
|
||||
<br />
|
||||
|
||||
## Testing is optional but encouraged
|
||||
An issue does not need to have failing tests — reproduction steps with your forked repo are enough at this point. Some people like to dive deeper and we want to give you the guidance/tools to do so. Read more below:
|
||||
|
||||
### Running integration tests (Payload API tests)
|
||||
First install [Jest Runner for VSVode](https://marketplace.visualstudio.com/items?itemName=firsttris.vscode-jest-runner).
|
||||
|
||||
There are a couple ways run integration tests:
|
||||
|
||||
- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/github/int-debug.png" />
|
||||
|
||||
- **Manually** - you can run all int tests in the `/test/_community/int.spec.ts` file by running the following command:
|
||||
|
||||
```bash
|
||||
yarn test:int _community
|
||||
```
|
||||
|
||||
### Running E2E tests (Admin Panel UI tests)
|
||||
The easiest way to run E2E tests is to install
|
||||
- [Playwright Test for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright)
|
||||
- [Playwright Runner](https://marketplace.visualstudio.com/items?itemName=ortoni.ortoni)
|
||||
|
||||
Once they are installed you can open the `testing` tab in vscode sidebar and drill down to the test you want to run, i.e. `/test/_community/e2e.spec.ts`
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/github/e2e-debug.png" />
|
||||
|
||||
|
||||
#### Notes
|
||||
- It is recommended to add the test credentials (located in `test/credentials.ts`) to your autofill for `localhost:3000/admin` as this will be required on every nodemon restart. The default credentials are `dev@payloadcms.com` as email and `test` as password.
|
||||
122
.github/workflows/tests.yml
vendored
122
.github/workflows/tests.yml
vendored
@@ -2,9 +2,9 @@ name: build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, edited, synchronize]
|
||||
types: [opened, reopened, synchronize]
|
||||
push:
|
||||
branches: ['master']
|
||||
branches: ["master"]
|
||||
|
||||
jobs:
|
||||
build_yarn:
|
||||
@@ -14,47 +14,51 @@ jobs:
|
||||
node-version: [14.x, 16.x, 18.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
scope: '@payloadcms'
|
||||
always-auth: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: yarn
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- run: yarn build
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
scope: "@payloadcms"
|
||||
always-auth: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-build-${{ env.cache-name }}-
|
||||
${{ runner.os }}-build-
|
||||
${{ runner.os }}-
|
||||
- run: yarn
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- run: yarn build
|
||||
|
||||
- name: Component Tests
|
||||
run: yarn test:components
|
||||
- name: Integration Tests
|
||||
run: yarn test:int
|
||||
- name: Component Tests
|
||||
run: yarn test:components
|
||||
- name: Integration Tests
|
||||
run: yarn test:int
|
||||
|
||||
- name: Generate Payload Types
|
||||
run: yarn dev:generate-types fields
|
||||
- name: Generate Payload Types
|
||||
run: yarn dev:generate-types fields
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: E2E Tests
|
||||
run: yarn test:e2e --bail
|
||||
- name: Generate GraphQL schema file
|
||||
run: yarn dev:generate-graphql-schema graphql-schema-gen
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install --with-deps
|
||||
- name: E2E Tests
|
||||
run: yarn test:e2e --bail
|
||||
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: test-results
|
||||
path: test-results/
|
||||
retention-days: 30
|
||||
|
||||
# - uses: actions/upload-artifact@v2
|
||||
# if: always()
|
||||
# with:
|
||||
# name: playwright-report
|
||||
# path: playwright-report/
|
||||
# retention-days: 30
|
||||
install_npm:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
@@ -62,23 +66,23 @@ jobs:
|
||||
node-version: [16.x]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
scope: '@payloadcms'
|
||||
always-auth: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-${{ env.cache-name }}-
|
||||
${{ runner.os }}-npm-
|
||||
${{ runner.os }}-
|
||||
- run: npm install --legacy-peer-deps
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
- uses: actions/checkout@v2
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
registry-url: https://registry.npmjs.org
|
||||
scope: "@payloadcms"
|
||||
always-auth: true
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: ${{ runner.os }}-node-npm-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-npm-${{ env.cache-name }}-
|
||||
${{ runner.os }}-npm-
|
||||
${{ runner.os }}-
|
||||
- run: npm install
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -2,6 +2,7 @@ coverage
|
||||
package-lock.json
|
||||
dist
|
||||
.idea
|
||||
test-results
|
||||
|
||||
# Created by https://www.gitignore.io/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
|
||||
@@ -163,7 +164,7 @@ GitHub.sublime-settings
|
||||
# CMake
|
||||
cmake-build-debug/
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# MongoDB Explorer plugin:
|
||||
.idea/**/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"verbose": true,
|
||||
"git": {
|
||||
"commitMessage": "chore(release): v${version}",
|
||||
"requireCleanWorkingDir": true
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"preReleaseId": "beta",
|
||||
"verbose": true,
|
||||
"git": {
|
||||
"requireCleanWorkingDir": false,
|
||||
"commit": false,
|
||||
@@ -7,11 +7,11 @@
|
||||
"tag": false
|
||||
},
|
||||
"github": {
|
||||
"release": false
|
||||
"release": true
|
||||
},
|
||||
"npm": {
|
||||
"skipChecks": true,
|
||||
"tag": "beta"
|
||||
"tag": "canary"
|
||||
},
|
||||
"hooks": {
|
||||
"before:init": ["yarn", "yarn clean", "yarn test"]
|
||||
40
.vscode/launch.json
vendored
40
.vscode/launch.json
vendored
@@ -5,42 +5,18 @@
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Debug Jest Tests",
|
||||
"type": "node",
|
||||
"command": "yarn run dev _community",
|
||||
"name": "Run Dev Community",
|
||||
"request": "launch",
|
||||
"runtimeArgs": [
|
||||
"--inspect-brk",
|
||||
"${workspaceRoot}/node_modules/.bin/jest",
|
||||
"--runInBand"
|
||||
],
|
||||
"env": {
|
||||
"PAYLOAD_CONFIG_PATH": "demo/payload.config.ts"
|
||||
},
|
||||
"console": "integratedTerminal",
|
||||
"internalConsoleOptions": "neverOpen",
|
||||
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/babel-node",
|
||||
"port": 9229,
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
]
|
||||
"type": "node-terminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"type": "node",
|
||||
"command": "yarn run dev fields",
|
||||
"name": "Run Dev Fields",
|
||||
"request": "launch",
|
||||
"name": "Launch Program",
|
||||
"env": {
|
||||
"BABEL_ENV": "development"
|
||||
},
|
||||
"program": "${workspaceFolder}/test/dev.js",
|
||||
"skipFiles": [
|
||||
"<node_internals>/**"
|
||||
],
|
||||
"runtimeArgs": [
|
||||
"--nolazy"
|
||||
],
|
||||
"args": [
|
||||
"fields"
|
||||
]
|
||||
"type": "node-terminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
2861
CHANGELOG.md
2861
CHANGELOG.md
File diff suppressed because it is too large
Load Diff
64
ISSUE_GUIDE.md
Normal file
64
ISSUE_GUIDE.md
Normal file
@@ -0,0 +1,64 @@
|
||||
# Reporting an issue
|
||||
|
||||
To report an issue, please follow the steps below:
|
||||
|
||||
1. Fork this repository
|
||||
2. Add necessary collections/globals/fields to the `test/_community` directory to recreate the issue you are experiencing
|
||||
3. Create an issue and add a link to your forked repo
|
||||
|
||||
**The goal is to isolate the problem by reducing the number of fields/collections you add to the test/_community folder. This folder is not meant for you to copy your project into, but to recreate the issue you are experiencing with minimal config.**
|
||||
|
||||
## Test directory file tree explanation
|
||||
```text
|
||||
.
|
||||
├── config.ts
|
||||
├── int.spec.ts
|
||||
├── e2e.spec.ts
|
||||
└── payload-types.ts
|
||||
```
|
||||
|
||||
- `config.ts` - This is the _granular_ Payload config for testing. It should be as lightweight as possible. Reference existing configs for an example
|
||||
- `int.spec.ts` [Optional] - This is the test file run by jest. Any test file must have a `*int.spec.ts` suffix.
|
||||
- `e2e.spec.ts` [Optional] - This is the end-to-end test file that will load up the admin UI using the above config and run Playwright tests.
|
||||
- `payload-types.ts` - Generated types from `config.ts`. Generate this file by running `yarn dev:generate-types _community`.
|
||||
|
||||
The directory split up in this way specifically to reduce friction when creating tests and to add the ability to boot up Payload with that specific config. You should modify the files in `test/_community` to get started.
|
||||
|
||||
## How to start test collection admin UI
|
||||
To start the admin panel so you can manually recreate your issue, you can run the following command:
|
||||
|
||||
```bash
|
||||
# This command will start up Payload using your config
|
||||
# NOTE: it will wipe the test database on restart
|
||||
yarn dev _community
|
||||
```
|
||||
|
||||
|
||||
## Testing is optional but encouraged
|
||||
An issue does not need to have failing tests — reproduction steps with your forked repo are enough at this point. Some people like to dive deeper and we want to give you the guidance/tools to do so. Read more below.
|
||||
|
||||
### How to run integration tests (Payload API tests)
|
||||
There are a couple ways to do this:
|
||||
|
||||
- **Granularly** - you can run individual tests in vscode by installing the Jest Runner plugin and using that to run individual tests. Clicking the `debug` button will run the test in debug mode allowing you to set break points.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/github/int-debug.png" />
|
||||
|
||||
- **Manually** - you can run all int tests in the `/test/_community/int.spec.ts` file by running the following command:
|
||||
|
||||
```bash
|
||||
yarn test:int _community
|
||||
```
|
||||
|
||||
### How to run E2E tests (Admin Panel UI tests)
|
||||
The easiest way to run E2E tests is to install
|
||||
- [Playwright Test for VSCode](https://marketplace.visualstudio.com/items?itemName=ms-playwright.playwright)
|
||||
- [Playwright Runner](https://marketplace.visualstudio.com/items?itemName=ortoni.ortoni)
|
||||
|
||||
Once they are installed you can open the `testing` tab in vscode sidebar and drill down to the test you want to run, i.e. `/test/_community/e2e.spec.ts`
|
||||
|
||||
<img src="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/github/e2e-debug.png" />
|
||||
|
||||
|
||||
#### Notes
|
||||
- It is recommended to add the test credentials (located in `test/credentials.ts`) to your autofill for `localhost:3000/admin` as this will be required on every nodemon restart. The default credentials are `dev@payloadcms.com` as email and `test` as password.
|
||||
131
README.md
131
README.md
@@ -1,30 +1,70 @@
|
||||
<h1 align="center">Payload</h1>
|
||||
<p align="center">A free and open-source TypeScript headless CMS & application framework built with Express, MongoDB and React.</p>
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT">
|
||||
<img src="https://img.shields.io/badge/License-MIT-blue.svg" />
|
||||
</a>
|
||||
<a href="https://github.com/payloadcms/payload/actions">
|
||||
<img src="https://github.com/payloadcms/payload/workflows/build/badge.svg" />
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/payload">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/payload" />
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/intent/tweet?text=Payload%20-%20A%20self-hosted%2C%20headless%20JavaScript%20CMS%20%26%20application%20framework&url=https%3A%2F%2Fgithub.com%2Fpayloadcms%2Fpayload">
|
||||
<img alt="Tweet Payload" src="https://img.shields.io/twitter/url/http/shields.io.svg?style=social" />
|
||||
</a>
|
||||
|
||||
<a href="https://discord.com/invite/r6sCXqVk3v">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/967097582721572934?label=Discord&color=7289da" />
|
||||
<p style="border: none; margin-bottom:0; padding-bottom: 0;" align="center">
|
||||
<a href="https://payloadcms.com">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/payload-logo-light.svg">
|
||||
<img width="350" alt="Payload Logo" src="https://raw.githubusercontent.com/payloadcms/payload/master/src/admin/assets/images/payload-logo-dark.svg">
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<h3 align="center">The most powerful TypeScript CMS</h3>
|
||||
<p align="center">Code-first Headless CMS that bridges the gap between CMS and application framework</p>
|
||||
|
||||
<h3 align="center">
|
||||
<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://demo.payloadcms.com/" rel="dofollow"><strong>Try Live Demo</strong></a>
|
||||
<br />
|
||||
</h3>
|
||||
|
||||
<br />
|
||||
|
||||
<p align="center">
|
||||
<a href="https://opensource.org/licenses/MIT">
|
||||
<img src="https://img.shields.io/badge/License-MIT-blue.svg?style=flat-square" />
|
||||
</a>
|
||||
|
||||
<a href="https://github.com/payloadcms/payload/actions">
|
||||
<img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/payloadcms/payload/tests.yml?style=flat-square">
|
||||
</a>
|
||||
|
||||
<a href="https://github.com/payloadcms/payload/commits">
|
||||
<img src="https://img.shields.io/github/commit-activity/m/payloadcms/payload?style=flat-square" alt="git commit activity"/>
|
||||
</a>
|
||||
|
||||
<a href="https://discord.gg/payload">
|
||||
<img alt="Discord" src="https://img.shields.io/discord/967097582721572934?label=Discord&color=7289da&style=flat-square" />
|
||||
</a>
|
||||
|
||||
<a href="https://www.npmjs.com/package/payload">
|
||||
<img alt="npm" src="https://img.shields.io/npm/v/payload?style=flat-square" />
|
||||
</a>
|
||||
|
||||
<a href="https://twitter.com/payloadcms">
|
||||
<img src="https://img.shields.io/badge/follow-payloadcms-1DA1F2?logo=twitter&style=flat-square" alt="Payload Twitter" />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<br />
|
||||
|
||||
<a href="https://payloadcms.com">
|
||||
<img src="https://payloadcms.com/images/og-image.jpg" alt="Payload headless CMS Admin panel built with React" />
|
||||
<img src="https://cms.payloadcms.com/media/payload-github-header.jpg" alt="Payload headless CMS Admin panel built with React" />
|
||||
</a>
|
||||
|
||||
### Features
|
||||
<br />
|
||||
|
||||
## ⭐ Why Payload?
|
||||
|
||||
Payload is a CMS that has been designed for developers from the ground up to deliver them what they need to build great digital products. If you know JavaScript, you know Payload. It's a _code-first_ CMS, which allows us to do a lot of things right:
|
||||
|
||||
- Payload gives you everything you need, but then steps back and lets you build what you want in JavaScript or TypeScript - with no unnecessary complexity brought by GUIs. You'll understand how your CMS works because you will have written it exactly how you want it.
|
||||
- Bring your own Express server and do whatever you need on top of Payload. Payload doesn't impose anything on you or your app.
|
||||
- Completely control the Admin panel by using your own React components. Swap out fields or even entire views with ease.
|
||||
- Use your data however and wherever you need thanks to auto-generated, yet fully extensible REST, GraphQL, and Local Node APIs.
|
||||
|
||||
<a target="_blank" href="https://payloadcms.com/" rel="dofollow"><strong>Read more on our website</strong></a>
|
||||
|
||||
## ✨ Features
|
||||
|
||||
- Completely free and open-source
|
||||
- [GraphQL](https://payloadcms.com/docs/graphql/overview), [REST](https://payloadcms.com/docs/rest-api/overview), and [Local](https://payloadcms.com/docs/local-api/overview) APIs
|
||||
@@ -44,41 +84,56 @@
|
||||
- Intensely fast API
|
||||
- Highly secure thanks to HTTP-only cookies, CSRF protection, and more
|
||||
|
||||
### Code-first
|
||||
<a target="_blank" href="https://github.com/payloadcms/payload/discussions"><strong>Request Feature</strong></a>
|
||||
|
||||
Payload is a CMS that has been designed for developers from the ground up to deliver them what they need to build great digital products. If you know JavaScript, you know Payload. It's a _code-first_ CMS, which allows us to do a lot of things right:
|
||||
|
||||
- Payload gives you everything you need, but then steps back and lets you build what you want in JavaScript or TypeScript - with no unnecessary complexity brought by GUIs. You'll understand how your CMS works because you will have written it exactly how you want it.
|
||||
- Bring your own Express server and do whatever you need on top of Payload. Payload doesn't impose anything on you or your app.
|
||||
- Completely control the Admin panel by using your own React components. Swap out fields or even entire views with ease.
|
||||
- Use your data however and wherever you need thanks to auto-generated, yet fully extensible REST, GraphQL, and Local Node APIs.
|
||||
|
||||
### Quick Start
|
||||
## 🚀 Quick Start
|
||||
|
||||
Before beginning to work with Payload, make sure you have all of the [required software](https://payloadcms.com/docs/getting-started/installation).
|
||||
|
||||
From there, the easiest way to get started with Payload is to use the `create-payload-app` package:
|
||||
|
||||
```
|
||||
```text
|
||||
npx create-payload-app
|
||||
```
|
||||
|
||||
Alternatively, it only takes about five minutes to [create an app from scratch](https://payloadcms.com/docs/getting-started/installation#from-scratch).
|
||||
|
||||
### Documentation
|
||||
## 🗒️ Documentation
|
||||
|
||||
Check out the [Payload website](https://payloadcms.com/docs/getting-started/what-is-payload) to find in-depth documentation for everything that Payload offers.
|
||||
|
||||
### Contributing
|
||||
## 🙋 Contributing
|
||||
|
||||
If you want to add contributions to this repository, please follow the instructions in [contributing.md](./contributing.md).
|
||||
|
||||
### Other Resources
|
||||
## 📚 Examples and Templates
|
||||
|
||||
##### Discussions
|
||||
The examples directory is a great resource for learning how to setup Payload in a variety of different ways. There are also a number of templates to help get you going very quickly. If you maintain your own template, consider adding the `payload-template` topic to your GitHub repository for others to find.
|
||||
|
||||
There are lots of good conversations and resources in our [GitHub Discussions board](https://github.com/payloadcms/payload/discussions). If you're struggling with something, chances are, someone's already solved what you're up against. Searching Discussions will often provide very helpful tips and tricks.
|
||||
- [Examples Directory](./examples)
|
||||
- [Official Templates](https://github.com/orgs/payloadcms/repositories?q=topic%3Apayload-template)
|
||||
- [Community Templates](https://github.com/topics/payload-template)
|
||||
|
||||
##### Discord
|
||||
## 🔌 Plugins
|
||||
|
||||
Join [Payload's Discord channel](https://discord.com/invite/r6sCXqVk3v) to interact with Payload developers in realtime.
|
||||
Payload is highly extensible and allows you to install or distribute plugins that add or remove functionality. There are both officially-supported and community-supported plugins available. If you maintain your own plugin, consider adding the `payload-plugin` topic to your GitHub repository for others to find.
|
||||
|
||||
- [Official Plugins](https://github.com/orgs/payloadcms/repositories?q=topic%3Apayload-plugin)
|
||||
- [Community Plugins](https://github.com/topics/payload-plugin)
|
||||
|
||||
## 🚨 Need help?
|
||||
|
||||
There are lots of good conversations and resources in our Github Discussions board and our Discord Server. If you're struggling with something, chances are, someone's already solved what you're up against. :point_down:
|
||||
|
||||
- [GitHub Discussions](https://github.com/payloadcms/payload/discussions)
|
||||
- [GitHub Issues](https://github.com/payloadcms/payload/issues)
|
||||
- [Discord](https://t.co/30APlsQUPB)
|
||||
- [Community Help](https://payloadcms.com/community-help)
|
||||
|
||||
## ⭐ Like what we're doing? Give us a star
|
||||
|
||||

|
||||
|
||||
## 👏 Thanks to all our contributors
|
||||
|
||||
<img align="left" src="https://contributors-img.web.app/image?repo=payloadcms/payload"/>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
const config = require('./src/babel.config');
|
||||
|
||||
module.exports = config;
|
||||
3
babel.js
3
babel.js
@@ -1,3 +0,0 @@
|
||||
const babelConfig = require('./dist/babel.config');
|
||||
|
||||
exports.config = babelConfig;
|
||||
5
components/elements.js
Normal file
5
components/elements.js
Normal file
@@ -0,0 +1,5 @@
|
||||
exports.Button = require('../dist/admin/components/elements/Button').default;
|
||||
exports.Card = require('../dist/admin/components/elements/Card').default;
|
||||
exports.Eyebrow = require('../dist/admin/components/elements/Eyebrow').default;
|
||||
exports.Nav = require('../dist/admin/components/elements/Nav').default;
|
||||
exports.Gutter = require('../dist/admin/components/elements/Gutter').Gutter;
|
||||
1
components/fields/Json.ts
Normal file
1
components/fields/Json.ts
Normal file
@@ -0,0 +1 @@
|
||||
export type { Props } from '../../dist/admin/components/forms/field-types/JSON/types';
|
||||
42
components/forms.js
Normal file
42
components/forms.js
Normal file
@@ -0,0 +1,42 @@
|
||||
exports.useForm = require('../dist/admin/components/forms/Form/context').useForm;
|
||||
|
||||
/**
|
||||
* @deprecated useWatchForm is no longer preferred. If you need all form fields, prefer `useAllFormFields`.
|
||||
*/
|
||||
exports.useWatchForm = require('../dist/admin/components/forms/Form/context').useWatchForm;
|
||||
|
||||
exports.useFormFields = require('../dist/admin/components/forms/Form/context').useFormFields;
|
||||
|
||||
exports.useAllFormFields = require('../dist/admin/components/forms/Form/context').useAllFormFields;
|
||||
|
||||
exports.useFormSubmitted = require('../dist/admin/components/forms/Form/context').useFormSubmitted;
|
||||
|
||||
exports.useFormProcessing = require('../dist/admin/components/forms/Form/context').useFormProcessing;
|
||||
|
||||
exports.useFormModified = require('../dist/admin/components/forms/Form/context').useFormModified;
|
||||
|
||||
exports.useField = require('../dist/admin/components/forms/useField').default;
|
||||
|
||||
/**
|
||||
* @deprecated This method is now called useField. The useFieldType alias will be removed in an upcoming version.
|
||||
*/
|
||||
exports.useFieldType = require('../dist/admin/components/forms/useField').default;
|
||||
|
||||
exports.Form = require('../dist/admin/components/forms/Form').default;
|
||||
|
||||
exports.Text = require('../dist/admin/components/forms/field-types/Text').default;
|
||||
exports.TextInput = require('../dist/admin/components/forms/field-types/Text/Input').default;
|
||||
|
||||
exports.Group = require('../dist/admin/components/forms/field-types/Group').default;
|
||||
|
||||
exports.Select = require('../dist/admin/components/forms/field-types/Select').default;
|
||||
exports.SelectInput = require('../dist/admin/components/forms/field-types/Select/Input').default;
|
||||
|
||||
exports.Checkbox = require('../dist/admin/components/forms/field-types/Checkbox').default;
|
||||
exports.Submit = require('../dist/admin/components/forms/Submit').default;
|
||||
exports.Label = require('../dist/admin/components/forms/Label').default;
|
||||
|
||||
exports.reduceFieldsToValues = require('../dist/admin/components/forms/Form/reduceFieldsToValues').default;
|
||||
exports.getSiblingData = require('../dist/admin/components/forms/Form/getSiblingData').default;
|
||||
|
||||
exports.withCondition = require('../dist/admin/components/forms/withCondition').default;
|
||||
1
components/hooks.js
Normal file
1
components/hooks.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.useStepNav = require('../dist/admin/components/elements/StepNav').useStepNav;
|
||||
2
components/icons.js
Normal file
2
components/icons.js
Normal file
@@ -0,0 +1,2 @@
|
||||
exports.Chevron = require('../dist/admin/components/icons/Chevron').default;
|
||||
exports.X = require('../dist/admin/components/icons/X').default;
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as Chevron } from '../src/admin/components/icons/Chevron';
|
||||
export { default as X } from '../src/admin/components/icons/X';
|
||||
export { default as Chevron } from '../dist/admin/components/icons/Chevron';
|
||||
export { default as X } from '../dist/admin/components/icons/X';
|
||||
|
||||
1
components/preferences.js
Normal file
1
components/preferences.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.usePreferences = require('../dist/admin/components/utilities/Preferences').usePreferences;
|
||||
3
components/rich-text.js
Normal file
3
components/rich-text.js
Normal file
@@ -0,0 +1,3 @@
|
||||
exports.LeafButton = require('../dist/admin/components/forms/field-types/RichText/leaves/Button').default;
|
||||
exports.ElementButton = require('../dist/admin/components/forms/field-types/RichText/elements/Button').default;
|
||||
exports.toggleElement = require('../dist/admin/components/forms/field-types/RichText/elements/toggle').default;
|
||||
2
components/templates.js
Normal file
2
components/templates.js
Normal file
@@ -0,0 +1,2 @@
|
||||
exports.DefaultTemplate = require('../dist/admin/components/templates/Default').default;
|
||||
exports.MinimalTemplate = require('../dist/admin/components/templates/Minimal').default;
|
||||
7
components/utilities.js
Normal file
7
components/utilities.js
Normal file
@@ -0,0 +1,7 @@
|
||||
exports.Meta = require('../dist/admin/components/utilities/Meta').default;
|
||||
exports.useLocale = require('../dist/admin/components/utilities/Locale').useLocale;
|
||||
exports.useDocumentInfo = require('../dist/admin/components/utilities/DocumentInfo').useDocumentInfo;
|
||||
exports.useConfig = require('../dist/admin/components/utilities/Config').useConfig;
|
||||
exports.useAuth = require('../dist/admin/components/utilities/Auth').useAuth;
|
||||
exports.useEditDepth = require('../dist/admin/components/utilities/EditDepth').useEditDepth;
|
||||
exports.useTheme = require('../dist/admin/components/utilities/Theme').useTheme;
|
||||
1
components/views/Cell.js
Normal file
1
components/views/Cell.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.Cell = require('../../dist/admin/components/views/collections/List/Cell').default;
|
||||
1
components/views/Dashboard.js
Normal file
1
components/views/Dashboard.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.Dashboard = required('../../dist/admin/components/views/Dashboard/Default').default;
|
||||
1
components/views/Edit.js
Normal file
1
components/views/Edit.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.Edit = require('../../dist/admin/components/views/collections/Edit/Default').default;
|
||||
1
components/views/List.js
Normal file
1
components/views/List.js
Normal file
@@ -0,0 +1 @@
|
||||
exports.List = require('../../dist/admin/components/views/collections/List/Default').default;
|
||||
@@ -1,2 +1,2 @@
|
||||
export { default as List } from '../../dist/admin/components/views/collections/List/Default';
|
||||
export type { Props } from '../../dist/admin/components/views/collections/Edit/types';
|
||||
export type { Props } from '../../dist/admin/components/views/collections/List/types';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing to Payload CMS
|
||||
# Contributing to Payload
|
||||
|
||||
Below you'll find a set of guidelines for how to contribute to Payload CMS.
|
||||
Below you'll find a set of guidelines for how to contribute to Payload.
|
||||
|
||||
## Opening issues
|
||||
|
||||
@@ -22,7 +22,7 @@ If you're an incredibly awesome person and want to help us make Payload even bet
|
||||
|
||||
### Before Starting
|
||||
|
||||
To help us work on new features, you can create a new feature request post in [GitHub Discussion](https://github.com/payloadcms/payload/discussions) or discuss it in our [Discord](https://discord.com/invite/r6sCXqVk3v). New functionality often has large implications across the entire Payload repo, so it is best to discuss the architecture and approach before starting work on a pull request.
|
||||
To help us work on new features, you can create a new feature request post in [GitHub Discussion](https://github.com/payloadcms/payload/discussions) or discuss it in our [Discord](https://discord.com/invite/payload). New functionality often has large implications across the entire Payload repo, so it is best to discuss the architecture and approach before starting work on a pull request.
|
||||
|
||||
### Code
|
||||
|
||||
@@ -49,7 +49,11 @@ The directory split up in this way specifically to reduce friction when creating
|
||||
|
||||
The following command will start Payload with your config: `yarn dev my-test-dir`. This command will start up Payload using your config and refresh a test database on every restart.
|
||||
|
||||
When switching between test directories, you will want to remove your `node_modules/.cache ` manually or by running `yarn clean:cache`.
|
||||
If you wish to use to your own Mongo database for the `test` directory instead of using the in memory database, all you need to do is add the following env vars to the `test/dev.ts` file:
|
||||
|
||||
- `process.env.NODE_ENV`
|
||||
- `process.env.PAYLOAD_TEST_MONGO_URL`
|
||||
- Simply set `process.env.NODE_ENV` to `test` and set `process.env.PAYLOAD_TEST_MONGO_URL` to your mongo url e.g. `mongodb://127.0.0.1/your-test-db`.
|
||||
|
||||
NOTE: It is recommended to add the test credentials (located in `test/credentials.ts`) to your autofill for `localhost:3000/admin` as this will be required on every nodemon restart. The default credentials are `dev@payloadcms.com` as E-Mail and `test` as password.
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ If a Collection supports [`Authentication`](/docs/authentication/overview), the
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Posts: CollectionConfig = {
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: "posts",
|
||||
// highlight-start
|
||||
access: {
|
||||
@@ -42,8 +42,6 @@ const Posts: CollectionConfig = {
|
||||
},
|
||||
// highlight-end
|
||||
};
|
||||
|
||||
export default Categories;
|
||||
```
|
||||
|
||||
### Create
|
||||
|
||||
@@ -20,7 +20,7 @@ Field Access Control is specified with functions inside a field's config. All fi
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Posts: CollectionConfig = {
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
@@ -67,6 +67,8 @@ Returns a boolean which allows or denies the ability to read a field's value. If
|
||||
|
||||
Returns a boolean which allows or denies the ability to update a field's value. If `false` is returned, any passed values will be discarded.
|
||||
|
||||
If `false` is returned and you attempt to update the field's value, the operation will **not** throw an error however the field will be omitted from the update operation and the value will remain unchanged.
|
||||
|
||||
**Available argument properties:**
|
||||
|
||||
| Option | Description |
|
||||
|
||||
@@ -38,7 +38,7 @@ const defaultPayloadAccess = ({ req: { user } }) => {
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Note:</strong><br/>
|
||||
In the Local API, all Access Control functions are skipped by default, allowing your server to do whatever it needs. But, you can opt back in by setting the option <strong>overrideAccess</strong> to <strong>true</strong>.
|
||||
In the Local API, all Access Control functions are skipped by default, allowing your server to do whatever it needs. But, you can opt back in by setting the option <strong>overrideAccess</strong> to <strong>false</strong>.
|
||||
</Banner>
|
||||
|
||||
### Access Control Types
|
||||
|
||||
@@ -11,32 +11,30 @@ While designing the Payload Admin panel, we determined it should be as minimal a
|
||||
To swap in your own React component, first, consult the list of available component overrides below. Determine the scope that corresponds to what you are trying to accomplish, and then author your React component accordingly.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
Custom components will automatically be provided with all props that the
|
||||
default component would accept.
|
||||
<strong>Tip:</strong><br />
|
||||
Custom components will automatically be provided with all props that the default component would accept.
|
||||
</Banner>
|
||||
|
||||
### Base Component Overrides
|
||||
|
||||
You can override a set of admin panel-wide components by providing a component to your base Payload config's `admin.components` property. The following options are available:
|
||||
|
||||
| Path | Description |
|
||||
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Nav`** | Contains the sidebar and mobile Nav in its entirety. |
|
||||
| **`logout.Button`** | A custom React component.
|
||||
| **`BeforeDashboard`** | Array of components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
|
||||
| **`AfterDashboard`** | Array of components to inject into the built-in Dashboard, _after_ the default dashboard contents. [Demo](https://github.com/payloadcms/payload/tree/master/test/admin/components/AfterDashboard/index.tsx) |
|
||||
| **`BeforeLogin`** | Array of components to inject into the built-in Login, _before_ the default login form. |
|
||||
| **`AfterLogin`** | Array of components to inject into the built-in Login, _after_ the default login form. |
|
||||
| **`BeforeNavLinks`** | Array of components to inject into the built-in Nav, _before_ the links themselves. |
|
||||
| **`AfterNavLinks`** | Array of components to inject into the built-in Nav, _after_ the links. |
|
||||
| **`views.Account`** | The Account view is used to show the currently logged in user's Account page. |
|
||||
| **`views.Dashboard`** | The main landing page of the Admin panel. |
|
||||
| **`graphics.Icon`** | Used as a graphic within the `Nav` component. Often represents a condensed version of a full logo. |
|
||||
| **`graphics.Logo`** | The full logo to be used in contexts like the `Login` view. |
|
||||
| **`routes`** | Define your own routes to add to the Payload Admin UI. [More](#custom-routes) |
|
||||
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
||||
| Path | Description |
|
||||
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Nav`** | Contains the sidebar and mobile Nav in its entirety. |
|
||||
| **`logout.Button`** | A custom React component. |
|
||||
| **`BeforeDashboard`** | Array of components to inject into the built-in Dashboard, _before_ the default dashboard contents. |
|
||||
| **`AfterDashboard`** | Array of components to inject into the built-in Dashboard, _after_ the default dashboard contents. [Demo](https://github.com/payloadcms/payload/tree/master/test/admin/components/AfterDashboard/index.tsx) |
|
||||
| **`BeforeLogin`** | Array of components to inject into the built-in Login, _before_ the default login form. |
|
||||
| **`AfterLogin`** | Array of components to inject into the built-in Login, _after_ the default login form. |
|
||||
| **`BeforeNavLinks`** | Array of components to inject into the built-in Nav, _before_ the links themselves. |
|
||||
| **`AfterNavLinks`** | Array of components to inject into the built-in Nav, _after_ the links. |
|
||||
| **`views.Account`** | The Account view is used to show the currently logged in user's Account page. |
|
||||
| **`views.Dashboard`** | The main landing page of the Admin panel. |
|
||||
| **`graphics.Icon`** | Used as a graphic within the `Nav` component. Often represents a condensed version of a full logo. |
|
||||
| **`graphics.Logo`** | The full logo to be used in contexts like the `Login` view. |
|
||||
| **`routes`** | Define your own routes to add to the Payload Admin UI. [More](#custom-routes) |
|
||||
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
||||
|
||||
#### Full example:
|
||||
|
||||
@@ -77,18 +75,117 @@ _For more examples regarding how to customize components, look at the following
|
||||
|
||||
You can override components on a Collection-by-Collection basis via each Collection's `admin` property.
|
||||
|
||||
| Path | Description |
|
||||
| ---------------- | ------------------------------------------------------------------------------------------------ |
|
||||
| **`views.Edit`** | Used while a document within this Collection is being edited. |
|
||||
| **`views.List`** | The `List` view is used to render a paginated, filterable table of Documents in this Collection. |
|
||||
| Path | Description |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`views.Edit`** | Used while a document within this Collection is being edited. |
|
||||
| **`views.List`** | The `List` view is used to render a paginated, filterable table of Documents in this Collection. |
|
||||
| **`edit.SaveButton`** | Replace the default `Save` button with a custom component. Drafts must be disabled |
|
||||
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a custom component. Drafts must be enabled and autosave must be disabled. |
|
||||
| **`edit.PublishButton`** | Replace the default `Publish` button with a custom component. Drafts must be enabled. |
|
||||
| **`edit.PreviewButton`** | Replace the default `Preview` button with a custom component. |
|
||||
| **`BeforeList`** | Array of components to inject _before_ the built-in List view |
|
||||
| **`BeforeListTable`** | Array of components to inject _before_ the built-in List view's table |
|
||||
| **`AfterListTable`** | Array of components to inject _after_ the built-in List view's table |
|
||||
| **`AfterList`** | Array of components to inject _after_ the built-in List view |
|
||||
|
||||
#### Examples
|
||||
|
||||
```tsx
|
||||
// Custom Buttons
|
||||
|
||||
import * as React from "react";
|
||||
import {
|
||||
CustomSaveButtonProps,
|
||||
CustomSaveDraftButtonProps,
|
||||
CustomPublishButtonProps,
|
||||
CustomPreviewButtonProps,
|
||||
} from "payload/types";
|
||||
|
||||
export const CustomSaveButton: CustomSaveButtonProps = ({
|
||||
DefaultButton,
|
||||
label,
|
||||
}) => {
|
||||
return <DefaultButton label={label} />;
|
||||
};
|
||||
|
||||
export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
|
||||
DefaultButton,
|
||||
disabled,
|
||||
label,
|
||||
saveDraft,
|
||||
}) => {
|
||||
return (
|
||||
<DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
|
||||
);
|
||||
};
|
||||
|
||||
export const CustomPublishButton: CustomPublishButtonProps = ({
|
||||
DefaultButton,
|
||||
disabled,
|
||||
label,
|
||||
publish,
|
||||
}) => {
|
||||
return <DefaultButton label={label} disabled={disabled} publish={publish} />;
|
||||
};
|
||||
|
||||
export const CustomPreviewButton: CustomPreviewButtonProps = ({
|
||||
DefaultButton,
|
||||
disabled,
|
||||
label,
|
||||
preview,
|
||||
}) => {
|
||||
return <DefaultButton label={label} disabled={disabled} preview={preview} />;
|
||||
};
|
||||
```
|
||||
|
||||
##### Custom Collection List View Example
|
||||
|
||||
Collection.ts
|
||||
|
||||
```tsx
|
||||
import { MyListComponent } from './MyListComponent';
|
||||
export const MyCollection: CollectionConfig = {
|
||||
slug: 'mycollection',
|
||||
admin: {
|
||||
components: {
|
||||
views: {
|
||||
List: MyListComponent,
|
||||
},
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
...
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
MyListComponent.tsx
|
||||
|
||||
```tsx
|
||||
import React from "react";
|
||||
import { List, type Props } from "payload/components/views/List"; // Payload's default List view component and its props
|
||||
export const MyListComponent: React.FC<Props> = (props) => (
|
||||
<div>
|
||||
<p>
|
||||
Some text before the default list view component. If you just want to do
|
||||
that, you can also use the admin.components.list.BeforeList hook
|
||||
</p>
|
||||
<List {...props} />
|
||||
</div>
|
||||
);
|
||||
```
|
||||
|
||||
### Globals
|
||||
|
||||
As with Collections, You can override components on a global-by-global basis via their `admin` property.
|
||||
|
||||
| Path | Description |
|
||||
| ---------------- | --------------------------------------- |
|
||||
| **`views.Edit`** | Used while this Global is being edited. |
|
||||
| Path | Description |
|
||||
| -------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`views.Edit`** | Used while this Global is being edited. |
|
||||
| **`edit.SaveButton`** | Replace the default `Save` button with a custom component. Drafts must be disabled |
|
||||
| **`edit.SaveDraftButton`** | Replace the default `Save Draft` button with a custom component. Drafts must be enabled and autosave must be disabled. |
|
||||
| **`edit.PublishButton`** | Replace the default `Publish` button with a custom component. Drafts must be enabled. |
|
||||
| **`edit.PreviewButton`** | Replace the default `Preview` button with a custom component. |
|
||||
|
||||
### Fields
|
||||
|
||||
@@ -163,7 +260,8 @@ const CustomTextField: React.FC<Props> = ({ path }) => {
|
||||
|
||||
<Banner type="success">
|
||||
For more information regarding the hooks that are available to you while you
|
||||
build custom components, including the <strong>useField</strong> hook, <a href="/docs/admin/hooks" style={{ color: "black" }}>click here</a>.
|
||||
build custom components, including the <strong>useField</strong> hook, [click
|
||||
here](/docs/admin/hooks).
|
||||
</Banner>
|
||||
|
||||
## Custom routes
|
||||
@@ -232,19 +330,20 @@ To make use of Payload SCSS variables / mixins to use directly in your own compo
|
||||
When developing custom components you can support multiple languages to be consistent with Payload's i18n support. The best way to do this is to add your translation resources to the [i18n configuration](https://payloadcms.com/docs/configuration/i18n) and import `useTranslation` from `react-i18next` in your components.
|
||||
|
||||
For example:
|
||||
|
||||
```tsx
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { useTranslation } from "react-i18next";
|
||||
|
||||
const CustomComponent: React.FC = () => {
|
||||
// highlight-start
|
||||
const { t, i18n } = useTranslation('namespace1');
|
||||
const { t, i18n } = useTranslation("namespace1");
|
||||
// highlight-end
|
||||
|
||||
return (
|
||||
<ul>
|
||||
<li>{ t('key', { variable: 'value' }) }</li>
|
||||
<li>{ t('namespace2:key', { variable: 'value' }) }</li>
|
||||
<li>{ i18n.language }</li>
|
||||
<li>{t("key", { variable: "value" })}</li>
|
||||
<li>{t("namespace2:key", { variable: "value" })}</li>
|
||||
<li>{i18n.language}</li>
|
||||
</ul>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -166,7 +166,6 @@ The `useDocumentInfo` hook provides lots of information about the document curre
|
||||
|---------------------------|--------------------------------------------------------------------------------------------------------------------| |
|
||||
| **`collection`** | If the doc is a collection, its collection config will be returned |
|
||||
| **`global`** | If the doc is a global, its global config will be returned |
|
||||
| **`type`** | The type of document being edited (collection or global) |
|
||||
| **`id`** | If the doc is a collection, its ID will be returned |
|
||||
| **`preferencesKey`** | The `preferences` key to use when interacting with document-level user preferences |
|
||||
| **`versions`** | Versions of the current doc |
|
||||
@@ -226,14 +225,15 @@ const Greeting: React.FC = () => {
|
||||
|
||||
Useful to retrieve info about the currently logged in user as well as methods for interacting with it. It sends back an object with the following properties:
|
||||
|
||||
| Property | Description |
|
||||
|---------------------|-----------------------------------------------------------------------------------------|
|
||||
| **`user`** | The currently logged in user |
|
||||
| **`logOut`** | A method to log out the currently logged in user |
|
||||
| **`refreshCookie`** | A method to trigger the silent refreshing of a user's auth token |
|
||||
| **`setToken`** | Set the token of the user, to be decoded and used to reset the user and token in memory |
|
||||
| **`token`** | The logged in user's token (useful for creating preview links, etc.) |
|
||||
| **`permissions`** | The permissions of the current user |
|
||||
| Property | Description |
|
||||
|--------------------------|-----------------------------------------------------------------------------------------|
|
||||
| **`user`** | The currently logged in user |
|
||||
| **`logOut`** | A method to log out the currently logged in user |
|
||||
| **`refreshCookie`** | A method to trigger the silent refreshing of a user's auth token |
|
||||
| **`setToken`** | Set the token of the user, to be decoded and used to reset the user and token in memory |
|
||||
| **`token`** | The logged in user's token (useful for creating preview links, etc.) |
|
||||
| **`refreshPermissions`** | Load new permissions (useful when content that effects permissions has been changed) |
|
||||
| **`permissions`** | The permissions of the current user |
|
||||
|
||||
```tsx
|
||||
import { useAuth } from 'payload/components/utilities';
|
||||
|
||||
@@ -11,49 +11,54 @@ Payload dynamically generates a beautiful, fully functional React admin panel to
|
||||
The Payload Admin panel is built with Webpack, code-split, highly performant (even with 100+ fields), and written fully in TypeScript.
|
||||
|
||||
<Banner type="success">
|
||||
The Admin panel is meant to be simple enough to give you a starting point but not bring too much complexity, so that you can easily customize it to suit the needs of your application and your editors.
|
||||
The Admin panel is meant to be simple enough to give you a starting point but
|
||||
not bring too much complexity, so that you can easily customize it to suit the
|
||||
needs of your application and your editors.
|
||||
</Banner>
|
||||
|
||||

|
||||
|
||||
*Screenshot of the Admin panel while editing a document from an example `AllFields` collection*
|
||||
_Screenshot of the Admin panel while editing a document from an example `AllFields` collection_
|
||||
|
||||
## Admin Options
|
||||
|
||||
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) |
|
||||
| `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. |
|
||||
| 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/master/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. |
|
||||
| `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) | |
|
||||
| **`logoutRoute`** | The route for the `logout` page. |
|
||||
| **`inactivityRoute`** | The route for the `logout` inactivity page. |
|
||||
|
||||
| `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. |
|
||||
| `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) |
|
||||
| **`logoutRoute`** | The route for the `logout` page. |
|
||||
| **`inactivityRoute`** | The route for the `logout` inactivity page. |
|
||||
|
||||
### The Admin User Collection
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br />
|
||||
The Payload Admin panel can only be used by one Collection that supports <a href="/docs/authentication/overview">Authentication</a>.
|
||||
<strong>Important:</strong>
|
||||
<br />
|
||||
The Payload Admin panel can only be used by one Collection that supports
|
||||
[Authentication](/docs/authentication/overview).
|
||||
</Banner>
|
||||
|
||||
To specify which Collection to use to log in to the Admin panel, pass the `admin` options a `user` key equal to the slug of the Collection that you'd like to use.
|
||||
|
||||
`payload.config.js`:
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config';
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
const config = buildConfig({
|
||||
admin: {
|
||||
user: 'admins', // highlight-line
|
||||
user: "admins", // highlight-line
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
@@ -56,7 +56,7 @@ You may rely on server-only packages such as the above to perform logic in acces
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import createStripeSubscription from './hooks/createStripeSubscription';
|
||||
|
||||
const Subscription: CollectionConfig = {
|
||||
export const Subscription: CollectionConfig = {
|
||||
slug: 'subscriptions',
|
||||
hooks: {
|
||||
beforeChange: [
|
||||
@@ -71,8 +71,6 @@ const Subscription: CollectionConfig = {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
export default Subscription;
|
||||
```
|
||||
|
||||
The collection above features a `beforeChange` hook that creates a Stripe subscription whenever a Subscription document is created in Payload.
|
||||
|
||||
@@ -17,7 +17,7 @@ To enable Authentication on a collection, define an `auth` property and set it t
|
||||
| **`useAPIKey`** | Payload Authentication provides for API keys to be set on each user within an Authentication-enabled Collection. [More](/docs/authentication/config#api-keys) |
|
||||
| **`tokenExpiration`** | How long (in seconds) to keep the user logged in. JWTs and HTTP-only cookies will both expire at the same time. |
|
||||
| **`maxLoginAttempts`** | Only allow a user to attempt logging in X amount of times. Automatically locks out a user from authenticating if this limit is passed. Set to `0` to disable. |
|
||||
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
|
||||
| **`lockTime`** | Set the time (in milliseconds) that a user should be locked out if they fail authentication more times than `maxLoginAttempts` allows for. |
|
||||
| **`depth`** | How many levels deep a `user` document should be populated when creating the JWT and binding the `user` to the express `req`. Defaults to `0` and should only be modified if absolutely necessary, as this will affect performance. |
|
||||
| **`cookies`** | Set cookie options, including `secure`, `sameSite`, and `domain`. For advanced users. |
|
||||
| **`forgotPassword`** | Customize the way that the `forgotPassword` operation functions. [More](/docs/authentication/config#forgot-password) |
|
||||
@@ -29,10 +29,12 @@ To enable Authentication on a collection, define an `auth` property and set it t
|
||||
|
||||
To integrate with third-party APIs or services, you might need the ability to generate API keys that can be used to identify as a certain user within Payload.
|
||||
|
||||
In Payload, users are essentially documents within a collection. Just like you can authenticate as a user with an email and password, which is considered as our default local auth strategy, you can also authenticate as a user with an API key. API keys are generated on a user-by-user basis, similar to email and passwords, and are meant to represent a single user.
|
||||
|
||||
For example, if you have a third-party service or external app that needs to be able to perform protected actions at its discretion, you have two options:
|
||||
|
||||
1. Create a user for the third-party app, and log in each time to receive a token before you attempt to access any protected actions
|
||||
1. Enable API key support for the Collection, where you can generate a non-expiring API key per user in the collection
|
||||
1. Enable API key support for the Collection, where you can generate a non-expiring API key per user in the collection. This is particularly useful as you can create a "user" that reflects an integration with a specific external service and assign a "role" or specific access only needed by that service/integration. Alternatively, you could create a "super admin" user and assign an API key to that user so that any requests made with that API key are considered as being made by that super user.
|
||||
|
||||
Technically, both of these options will work for third-party integrations but the second option with API key is simpler, because it reduces the amount of work that your integrations need to do to be authenticated properly.
|
||||
|
||||
@@ -43,21 +45,23 @@ To enable API keys on a collection, set the `useAPIKey` auth option to `true`. F
|
||||
is compromised, your API keys will not be.
|
||||
</Banner>
|
||||
|
||||
##### Authenticating via API Key
|
||||
#### Authenticating via API Key
|
||||
|
||||
To utilize your API key while interacting with the REST or GraphQL API, add the `Authorization` header.
|
||||
To authenticate REST or GraphQL API requests using an API key, set the `Authorization` header. The header is case-sensitive and needs the slug of the `auth.useAPIKey` enabled collection, then " API-Key ", followed by the `apiKey` that has been assigned. Payload's built-in middleware will then assign the user document to `req.user` and handle requests with the proper access control. By doing this, Payload recognizes the request being made as a request by the user associated with that API key.
|
||||
|
||||
**For example, using Fetch:**
|
||||
|
||||
```ts
|
||||
import User from '../collections/User';
|
||||
|
||||
const response = await fetch("http://localhost:3000/api/pages", {
|
||||
headers: {
|
||||
Authorization: `${collection.labels.singular} API-Key ${YOUR_API_KEY}`,
|
||||
Authorization: `${User.slug} API-Key ${YOUR_API_KEY}`,
|
||||
},
|
||||
});
|
||||
```
|
||||
|
||||
Note: The label portion of the header is case-sensitive and will likely have a capitalized first character unless the label has been customized.
|
||||
Payload ensures that the same, uniform access control is used across all authentication strategies. This enables you to utilize your existing access control configurations with both API keys and the standard email/password authentication. This consistency can aid in maintaining granular control over your API keys.
|
||||
|
||||
### Forgot Password
|
||||
|
||||
@@ -82,7 +86,7 @@ Example:
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Customers: CollectionConfig = {
|
||||
export const Customers: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
auth: {
|
||||
forgotPassword: {
|
||||
@@ -156,7 +160,7 @@ Example:
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
|
||||
const Customers: CollectionConfig = {
|
||||
export const Customers: CollectionConfig = {
|
||||
slug: 'customers',
|
||||
auth: {
|
||||
verify: {
|
||||
|
||||
@@ -94,7 +94,7 @@ Example response:
|
||||
|
||||
```graphql
|
||||
query {
|
||||
Me[collection-singular-label] {
|
||||
me[collection-singular-label] {
|
||||
user {
|
||||
email
|
||||
}
|
||||
|
||||
@@ -6,6 +6,11 @@ desc: Payload provides highly secure user Authentication out of the box, and you
|
||||
keywords: authentication, config, configuration, overview, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<YouTube
|
||||
id="CT4KafeJjTI"
|
||||
title="Simplified Authentication for Headless CMS: Unlocking Reusability in One Line"
|
||||
/>
|
||||
|
||||
<Banner>
|
||||
Payload provides for highly secure and customizable user Authentication out of the box, which allows for users to identify themselves to Payload.
|
||||
</Banner>
|
||||
@@ -35,8 +40,8 @@ Simple example collection:
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Admins: CollectionConfig = {
|
||||
slug:
|
||||
export const Admins: CollectionConfig = {
|
||||
slug: 'admins',
|
||||
// highlight-start
|
||||
auth: {
|
||||
tokenExpiration: 7200, // How many seconds to keep the user logged in
|
||||
|
||||
@@ -11,38 +11,48 @@ Because Payload uses your existing Express server, you are free to add whatever
|
||||
This approach has a ton of benefits - it's great for isolation of concerns and limiting scope, but it also means that your additional routes won't have access to Payload's user authentication.
|
||||
|
||||
<Banner type="success">
|
||||
You can make full use of Payload's built-in authentication within your own custom Express endpoints by adding Payload's authentication middleware.
|
||||
You can make full use of Payload's built-in authentication within your own
|
||||
custom Express endpoints by adding Payload's authentication middleware.
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
Payload must be initialized before the `payload.authenticate` middleware can
|
||||
be used. This is done by calling `payload.init()` prior to adding the
|
||||
middleware.
|
||||
</Banner>
|
||||
|
||||
Example in `server.js`:
|
||||
|
||||
```ts
|
||||
import express from 'express';
|
||||
import payload from 'payload';
|
||||
import express from "express";
|
||||
import payload from "payload";
|
||||
|
||||
const app = express();
|
||||
|
||||
payload.init({
|
||||
secret: 'PAYLOAD_SECRET_KEY',
|
||||
mongoURL: 'mongodb://localhost/payload',
|
||||
express: app,
|
||||
});
|
||||
const start = async () => {
|
||||
await payload.init({
|
||||
secret: "PAYLOAD_SECRET_KEY",
|
||||
mongoURL: "mongodb://localhost/payload",
|
||||
express: app,
|
||||
});
|
||||
|
||||
const router = express.Router();
|
||||
const router = express.Router();
|
||||
|
||||
router.use(payload.authenticate); // highlight-line
|
||||
// Note: Payload must be initialized before the `payload.authenticate` middleware can be used
|
||||
router.use(payload.authenticate); // highlight-line
|
||||
|
||||
router.get('/', (req, res) => {
|
||||
if (req.user) {
|
||||
return res.send(`Authenticated successfully as ${req.user.email}.`);
|
||||
}
|
||||
router.get("/", (req, res) => {
|
||||
if (req.user) {
|
||||
return res.send(`Authenticated successfully as ${req.user.email}.`);
|
||||
}
|
||||
|
||||
return res.send('Not authenticated');
|
||||
});
|
||||
return res.send("Not authenticated");
|
||||
});
|
||||
|
||||
app.use('/some-route-here', router);
|
||||
app.use("/some-route-here", router);
|
||||
|
||||
app.listen(3000, async () => {
|
||||
payload.logger.info(`listening on ${3000}...`);
|
||||
});
|
||||
app.listen(3000);
|
||||
};
|
||||
|
||||
start();
|
||||
```
|
||||
|
||||
62
docs/cloud/configuration.mdx
Normal file
62
docs/cloud/configuration.mdx
Normal file
@@ -0,0 +1,62 @@
|
||||
---
|
||||
title: Project Configuration
|
||||
label: Configuration
|
||||
order: 20
|
||||
desc: Quickly configure and deploy your Payload Cloud project in a few simple steps.
|
||||
keywords: configuration, config, settings, project, cloud, payload cloud, deploy, deployment
|
||||
---
|
||||
|
||||
### Select your plan
|
||||
|
||||
Once you have created a project, you will need to select your plan. This will determine the resources that are allocated to your project and the features that are available to you.
|
||||
|
||||
<Banner type="success">
|
||||
Note: All Payload Cloud teams that deploy a project require a card on file.
|
||||
This helps us prevent fraud and abuse on our platform. If you select a plan
|
||||
with a free trial, you will not be charged until your trial period is over.
|
||||
We’ll remind you 7 days before your trial ends and you can cancel anytime.
|
||||
</Banner>
|
||||
|
||||
### Project Details
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Region** | Select the region closest to your audience. This will ensure the fastest communication between your data and your client. |
|
||||
| **Project Name** | A name for your project. You can change this at any time. |
|
||||
| **Project Slug** | Choose a unique slug to identify your project. This needs to be unique for your team and you can change it any time. |
|
||||
| **Team** | Select the team you want to create the project under. If this is your first project, a personal team will be created for you automatically. You can modify your team settings and invite new members at any time from the Team Settings page. |
|
||||
|
||||
### Build Settings
|
||||
|
||||
If you are deploying a new project from a template, the following settings will be automatically configured for you. If you are using your own repository, you need to make sure your build settings are accurate for your project to deploy correctly.
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **Root Directory** | The folder where your `package.json` file lives. |
|
||||
| **Install Command** | The command used to install your modules, for example: `yarn install` or `npm install` |
|
||||
| **Build Command** | The command used to build your application, for example: `yarn build` or `npm run build` |
|
||||
| **Serve Command** | The command used to serve your application, for example: `yarn serve` or `npm run serve` |
|
||||
| **Branch to Deploy** | Select the branch of your repository that you want to deploy from. This is the branch that will be used to build your project when you commit new changes. |
|
||||
| **Default Domain** | Set a default domain for your project. This must be unique and you will not able to change it. You can always add a custom domain later in your project settings. |
|
||||
|
||||
### Environment Variables
|
||||
|
||||
Any of the features in Payload Cloud that require environment variables will automatically be provided to your application. If your app requires any custom environment variables, you can set them here.
|
||||
|
||||
<Banner type="warning">
|
||||
Note: For security reasons, any variables you wish to provide to the Admin
|
||||
panel must be prefixed with `PAYLOAD_PUBLIC_`. Learn more
|
||||
[here](https://payloadcms.com/docs/admin/webpack#admin-environment-vars).
|
||||
</Banner>
|
||||
|
||||
### Payment
|
||||
|
||||
Payment methods can be set per project and can be updated any time. You can use team’s default payment method, or add a new one. Modify your payment methods in your Project settings / Team settings.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Note:</strong> All Payload Cloud teams that deploy a project require a
|
||||
card on file. This helps us prevent fraud and abuse on our platform. If you
|
||||
select a plan with a free trial, you will not be charged until your trial
|
||||
period is over. We’ll remind you 7 days before your trial ends and you can
|
||||
cancel anytime.
|
||||
</Banner>
|
||||
53
docs/cloud/creating-a-project.mdx
Normal file
53
docs/cloud/creating-a-project.mdx
Normal file
@@ -0,0 +1,53 @@
|
||||
---
|
||||
title: Getting Started
|
||||
label: Getting Started
|
||||
order: 10
|
||||
desc: Get started with Payload Cloud, a deployment solution specifically designed for Node + MongoDB applications.
|
||||
keywords: cloud, hosted, database, storage, email, deployment, serverless, node, mongodb, s3, aws, cloudflare, atlas, resend, payload, cms
|
||||
---
|
||||
|
||||
A deployment solution specifically designed for Node.js + MongoDB applications, offering seamless deployment of your entire stack in one place. You can get started in minutes with a one-click template or bring your own codebase with you.
|
||||
|
||||
Payload Cloud offers various plans tailored to meet your specific needs, including a MongoDB Atlas database, S3 file storage, and email delivery powered by [Resend](https://resend.com). To see a full breakdown of features and plans, see our [Cloud Pricing page](https://payloadcms.com/cloud-pricing).
|
||||
|
||||
To get started, you first need to create an account. Head over to [the login screen](https://payloadcms.com/login) and **Register for Free**.
|
||||
|
||||
<Banner type="success">
|
||||
To create your first project, you can either select [a
|
||||
template](#starting-from-a-template) or [import an existing
|
||||
project](#importing-from-an-existing-codebase) from GitHub.
|
||||
</Banner>
|
||||
|
||||
## Starting from a Template
|
||||
|
||||
Templates come preconfigured and provide a one-click solution to quickly deploy a new application.
|
||||
|
||||

|
||||
_Creating a new project from a template._
|
||||
|
||||
After creating an account, select your desired template from the Projects page. At this point, you need to connect to authorize the Payload Cloud application with your GitHub account. Click Continue with GitHub and follow the prompts to authorize the app.
|
||||
|
||||
Next, select your `GitHub Scope`. If you belong to multiple organizations, they will show up here. If you do not see the organization you are looking for, you may need to adjust your GitHub app permissions.
|
||||
|
||||
After selecting your scope, create a unique `repository name` and select whether you want your repository to be public or private on GitHub.
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong> Public repositories can be accessed by anyone online,
|
||||
while private repositories grant access only to you and anyone you explicitly
|
||||
authorize.
|
||||
</Banner>
|
||||
|
||||
Once you are ready, click **Create Project**. This will clone the selected template to a new repository in your GitHub account, and take you to the configuration page to set up your project for deployment.
|
||||
|
||||
## Importing from an Existing Codebase
|
||||
|
||||
Payload Cloud works for any Node.js + MongoDB app. From the New Project page, select **import an existing Git codebase**. Choose the organization and select the repository you want to import. From here, you will be taken to the configuration page to set up your project for deployment.
|
||||
|
||||

|
||||
_Creating a new project from an existing repository._
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong> In order to make use of the features of Payload Cloud
|
||||
in your own codebase, you will need to add the [Cloud
|
||||
Plugin](https://github.com/payloadcms/plugin-cloud) to your Payload app.
|
||||
</Banner>
|
||||
110
docs/cloud/projects.mdx
Normal file
110
docs/cloud/projects.mdx
Normal file
@@ -0,0 +1,110 @@
|
||||
---
|
||||
title: Cloud Projects
|
||||
label: Projects
|
||||
order: 40
|
||||
desc: Manage your Payload Cloud projects.
|
||||
keywords: cloud, payload cloud, projects, project, overview, database, file storage, build settings, environment variables, custom domains, email, developing locally
|
||||
---
|
||||
|
||||
### Overview
|
||||
|
||||
<Banner>
|
||||
The overview tab shows your most recent deployment, along with build and
|
||||
deployment logs. From here, you can see your live URL, deployment details like
|
||||
timestamps and commit hash, as well as the status of your deployment. You can
|
||||
also trigger a redeployment manually, which will rebuild your project using
|
||||
the current configuration.
|
||||
</Banner>
|
||||
|
||||

|
||||
_A screenshot of the Overview page for a Cloud project._
|
||||
|
||||
### Database
|
||||
|
||||
Your Payload Cloud project comes with a MongoDB serverless Atlas DB instance or a Dedicated Atlas cluster, depending on your plan. To interact with your cloud database, you will be provided with a MongoDB connection string. This can be found under the **Database** tab of your project.
|
||||
|
||||
`mongodb+srv://your_connection_string`
|
||||
|
||||
### File Storage
|
||||
|
||||
Payload Cloud gives you S3 file storage backed by Cloudflare as a CDN, and this plugin extends Payload so that all of your media will be stored in S3 rather than locally.
|
||||
|
||||
AWS Cognito is used for authentication to your S3 bucket. The [Payload Cloud Plugin](https://github.com/payloadcms/plugin-cloud) will automatically pick up these values. These values are only if you'd like to access your files directly, outside of Payload Cloud.
|
||||
|
||||
### Build Settings
|
||||
|
||||
You can update settings from your Project’s Settings tab. Changes to your build settings will trigger a redeployment of your project.
|
||||
|
||||
### Environment Variables
|
||||
|
||||
From the Environment Variables page of the Settings tab, you can add, update and delete variables for use in your project. Like build settings, these changes will trigger a redeployment of your project.
|
||||
|
||||
<Banner>
|
||||
Note: For security reasons, any variables you wish to provide to the Admin
|
||||
panel must be prefixed with `PAYLOAD_PUBLIC_`. Learn more
|
||||
[here](https://payloadcms.com/docs/admin/webpack#admin-environment-vars).
|
||||
</Banner>
|
||||
### Custom Domains
|
||||
|
||||
With Payload Cloud, you can add custom domain names to your project. To do so, first go to the Domains page of the Settings tab of your project. Here you can see your default domain. To add a new domain, type in the domain name you wish to use.
|
||||
|
||||
<Banner>
|
||||
Note: do not include the protocol (http:// or https://) or any routes (/page).
|
||||
Only include the domain name and extension, and optionally a subdomain. -
|
||||
your-domain.com - backend.your-domain.com
|
||||
</Banner>
|
||||
|
||||
Once you click save, a DNS record will be generated for your domain name to point to your live project. Add this record into your DNS provider’s records, and once the records are resolving properly (this can take 1hr to 48hrs in some cases), your domain will now to point to your live project.
|
||||
|
||||
You will also need to configure your Payload project to use your specified domain. In your `payload.config.ts` file, specify your `serverURL` with your domain:
|
||||
|
||||
```ts
|
||||
export default buildConfig({
|
||||
serverURL: "https://example.com",
|
||||
// the rest of your config,
|
||||
});
|
||||
```
|
||||
|
||||
### Email
|
||||
|
||||
Powered by [Resend](https://resend.com), Payload Cloud comes with integrated email support out of the box. No configuration is needed, and you can use `payload.sendEmail()` to send email right from your Payload app. To learn more about sending email with Payload, checkout the [Email Configuration](https://payloadcms.com/docs/email/overview) overview.
|
||||
|
||||
If you are on the Pro or Enterprise plan, you can add your own custom Email domain name. From the Email page of your project’s Settings, add the domain you wish to use for email delivery. This will generate a set of DNS records. Add these records to your DNS provider and click verify to check that your records are resolving properly. Once verified, your emails will now be sent from your custom domain name.
|
||||
|
||||
### Developing Locally
|
||||
|
||||
To make changes to your project, you will need to clone the repository defined in your project settings to your local machine. In order to run your project locally, you will need configure your local environment first. Refer to your repository’s `README.md` file to see the steps needed for your specific template.
|
||||
|
||||
From there, you are ready to make updates to your project. When you are ready to make your changes live, commit your changes to the branch you specified in your Project settings, and your application will automatically trigger a redeploy and build from your latest commit.
|
||||
|
||||
### Cloud Plugin
|
||||
|
||||
Projects generated from a template will come pre-configured with the official Cloud Plugin, but if you are using your own repository you will need to add this into your project. To do so, add the plugin to your Payload config:
|
||||
|
||||
`yarn add @payloadcms/plugin-cloud`
|
||||
|
||||
```js
|
||||
import { payloadCloud } from "@payloadcms/plugin-cloud";
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
export default buildConfig({
|
||||
plugins: [payloadCloud()],
|
||||
// rest of config
|
||||
});
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
**Note:** If your Payload config already has an email with transport, this
|
||||
will take precedence over Payload Cloud's email service.
|
||||
</Banner>
|
||||
|
||||
##### **Optional configuration**
|
||||
|
||||
If you wish to opt-out of any Payload cloud features, the plugin also accepts options to do so.
|
||||
|
||||
```js
|
||||
payloadCloud({
|
||||
storage: false, // Disable file storage
|
||||
email: false, // Disable email delivery
|
||||
});
|
||||
```
|
||||
35
docs/cloud/teams.mdx
Normal file
35
docs/cloud/teams.mdx
Normal file
@@ -0,0 +1,35 @@
|
||||
---
|
||||
title: Cloud Teams
|
||||
label: Teams
|
||||
order: 30
|
||||
desc: Manage your Payload Cloud team and billing settings.
|
||||
keywords: team, teams, billing, subscription, payment, plan, plans, cloud, payload cloud
|
||||
---
|
||||
|
||||
<Banner>
|
||||
Within Payload Cloud, the team management feature offers you the ability to
|
||||
manage your organization, team members, billing, and subscription settings.
|
||||
</Banner>
|
||||
|
||||

|
||||
_A screenshot of the Team Settings page._
|
||||
|
||||
### Members
|
||||
|
||||
Each team has members that can interact with your projects. You can invite multiple people to your team and each individual can belong to more than one team. You can assign them either `owner` or `user` permissions. Owners are able to make admin-only changes, such as deleting projects, and editing billing information.
|
||||
|
||||
### Adding Members
|
||||
|
||||
To add a new member to your team, visit your Team’s Settings page, and click “Invite Teammate”. You can then add their email address, and assign their role. Press “Save” to send the invitations, which will send an email to the invited team member where they can create a new account.
|
||||
|
||||
### Billing
|
||||
|
||||
Users can update billing settings and subscriptions for any teams where they are designated as an `owner`. To make updates to the team’s payment methods, visit the Billing page under the Team Settings tab. You can add new cards, delete cards, and set a payment method as a default. The default payment method will be used in the event that another payment method fails.
|
||||
|
||||
### Subscriptions
|
||||
|
||||
From the Subscriptions page, a team owner can see all current plans for their team. From here, you can see the price of each plan, if there is an active trial, and when you will be billed next.
|
||||
|
||||
### Invoices
|
||||
|
||||
The Invoices page will you show you the invoices for your account, as well as the status on their payment.
|
||||
@@ -12,21 +12,25 @@ It's often best practice to write your Collections in separate files and then im
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
|------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
|
||||
| **`hooks`** | Entry points to "tie in" to Collection actions at specific points. [More](/docs/hooks/overview#collection-hooks) |
|
||||
| **`access`** | Provide access control functions to define exactly who should be able to do what with Documents in this Collection. [More](/docs/access-control/overview/#collections) |
|
||||
| **`auth`** | Specify options if you would like this Collection to feature authentication. For more, consult the [Authentication](/docs/authentication/config) documentation. |
|
||||
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](/docs/upload/overview) documentation. |
|
||||
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
|
||||
| **`versions`** | Set to true to enable default options, or configure with object properties. [More](/docs/versions/overview#collection-config) |
|
||||
| **`endpoints`** | Add custom routes to the REST API. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| Option | Description |
|
||||
|--------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Collection. |
|
||||
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| **`indexes`** * | Array of database indexes to create, including compound indexes that have multiple fields. |
|
||||
| **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-options). |
|
||||
| **`hooks`** | Entry points to "tie in" to Collection actions at specific points. [More](/docs/hooks/overview#collection-hooks) |
|
||||
| **`access`** | Provide access control functions to define exactly who should be able to do what with Documents in this Collection. [More](/docs/access-control/overview/#collections) |
|
||||
| **`auth`** | Specify options if you would like this Collection to feature authentication. For more, consult the [Authentication](/docs/authentication/config) documentation. |
|
||||
| **`upload`** | Specify options if you would like this Collection to support file uploads. For more, consult the [Uploads](/docs/upload/overview) documentation. |
|
||||
| **`timestamps`** | Set to false to disable documents' automatically generated `createdAt` and `updatedAt` timestamps. |
|
||||
| **`versions`** | Set to true to enable default options, or configure with object properties. [More](/docs/versions/overview#collection-config) |
|
||||
| **`endpoints`** | Add custom routes to the REST API. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| **`graphQL`** | An object with `singularName` and `pluralName` strings used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`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.*
|
||||
|
||||
@@ -35,7 +39,7 @@ It's often best practice to write your Collections in separate files and then im
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Orders: CollectionConfig = {
|
||||
export const Orders: CollectionConfig = {
|
||||
slug: 'orders',
|
||||
fields: [
|
||||
{
|
||||
@@ -49,7 +53,7 @@ const Orders: CollectionConfig = {
|
||||
relationTo: 'customers',
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -61,18 +65,21 @@ You can find an assortment of [example collection configs](https://github.com/pa
|
||||
|
||||
You can customize the way that the Admin panel behaves on a collection-by-collection basis by defining the `admin` property on a collection's config.
|
||||
|
||||
| Option | Description |
|
||||
| --------------------------- | -------------|
|
||||
| `group` | Text used as a label for grouping collection links together in the navigation. |
|
||||
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
|
||||
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin panel. If no field is defined, the ID of the document is used as the title. |
|
||||
| `description` | Text or React component to display below the Collection label in the List view to give editors more information. |
|
||||
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this collection's List view. |
|
||||
| `disableDuplicate ` | Disables the "Duplicate" button while editing documents within this collection. |
|
||||
| Option | Description |
|
||||
|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. |
|
||||
| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) |
|
||||
| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin panel. If no field is defined, the ID of the document is used as the title. |
|
||||
| `description` | Text or React component to display below the Collection label in the List view to give editors more information. |
|
||||
| `defaultColumns` | Array of field names that correspond to which columns to show by default in this collection's List view. |
|
||||
| `disableDuplicate ` | Disables the "Duplicate" button while editing documents within this collection. |
|
||||
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. |
|
||||
| `enableRichTextLink` | The [Rich Text](/docs/fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `enableRichTextRelationship` | The [Rich Text](/docs/fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. |
|
||||
| `preview` | Function to generate preview URLS within the Admin panel that can point to your app. [More](#preview). |
|
||||
| `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) |
|
||||
| `preview` | Function to generate preview URLS within the Admin panel that can point to your app. [More](#preview). |
|
||||
| `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) |
|
||||
|
||||
### Preview
|
||||
|
||||
@@ -90,7 +97,7 @@ If the function is specified, a Preview button will automatically appear in the
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Posts: CollectionConfig = {
|
||||
export const Posts: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
fields: [
|
||||
{
|
||||
@@ -111,6 +118,15 @@ const Posts: CollectionConfig = {
|
||||
};
|
||||
```
|
||||
|
||||
### Pagination
|
||||
|
||||
Here are a few options that you can specify options for pagination on a collection-by-collection basis:
|
||||
|
||||
| Option | Description |
|
||||
| --------------------------- | -------------|
|
||||
| `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. |
|
||||
| `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. |
|
||||
|
||||
### Access control
|
||||
|
||||
You can specify extremely granular access control (what users can do with documents in a collection) on a collection by collection basis. To learn more, go to the [Access Control](/docs/access-control/overview) docs.
|
||||
|
||||
@@ -8,6 +8,40 @@ keywords: config, configuration, documentation, Content Management System, cms,
|
||||
|
||||
Payload utilizes a few Express-specific middleware packages within its own routers. You can customize how they work by passing in configuration options to the main Payload config's `express` property.
|
||||
|
||||
### Custom Middleware
|
||||
|
||||
Payload allows you to pass in custom Express middleware to be used on all of the routes it opens. This is useful for adding logging or any other custom functionality to your endpoints.
|
||||
|
||||
There are 2 exposed properties. Each property is an array of middleware functions.
|
||||
|
||||
- `preMiddleware` - runs before any of the Payload middleware
|
||||
- `postMiddleware` - runs after all of the Payload middleware
|
||||
|
||||
```ts
|
||||
{
|
||||
express: {
|
||||
preMiddleware: [
|
||||
(req, res, next) => {
|
||||
// do something
|
||||
next()
|
||||
}
|
||||
],
|
||||
postMiddleware: [
|
||||
(req, res, next) => {
|
||||
// do something
|
||||
next()
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
// Example logging middleware function
|
||||
const requestLoggerMiddleware = (req, res, next) => {
|
||||
req.payload.logger.info(`request: ${req.method} ${req.url}`)
|
||||
next()
|
||||
}
|
||||
```
|
||||
|
||||
### JSON
|
||||
|
||||
`express.json()` is used to parse JSON body content into JavaScript objects accessible on the Express `req`. Payload allows you to customize all of the `json` method's options. Common examples of customization use-cases are increasing the max allowed JSON body size which defaults to `2MB`.
|
||||
|
||||
@@ -6,16 +6,16 @@ desc: Set up your Global config for your needs by defining fields, adding slugs
|
||||
keywords: globals, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
Global configs are in many ways similar to [Collections](/docs/configuration/collections). The big difference is that Collections will potentially contain *many* documents, while a Global is a "one-off". Globals are perfect for things like header nav, site-wide banner alerts, app-wide localized strings, and other "global" data that your site or app might rely on.
|
||||
Global configs are in many ways similar to [Collections](/docs/configuration/collections). The big difference is that Collections will potentially contain _many_ documents, while a Global is a "one-off". Globals are perfect for things like header nav, site-wide banner alerts, app-wide localized strings, and other "global" data that your site or app might rely on.
|
||||
|
||||
As with Collection configs, it's often best practice to write your Globals in separate files and then import them into the main Payload config.
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`slug`** * | Unique, URL-friendly string that will act as an identifier for this Global. |
|
||||
| **`fields`** * | Array of field types that will determine the structure and functionality of the data stored within this Global. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Global. |
|
||||
| **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. |
|
||||
| **`label`** | Text for the name in the Admin panel or an object with keys for each language. Auto-generated from slug if not defined. |
|
||||
| **`description`** | Text or React component to display below the Global header to give editors more information. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](/docs/configuration/globals#admin-options). |
|
||||
@@ -24,33 +24,34 @@ As with Collection configs, it's often best practice to write your Globals in se
|
||||
| **`versions`** | Set to true to enable default options, or configure with object properties. [More](/docs/versions/overview#globals-config) |
|
||||
| **`endpoints`** | Add custom routes to the REST API. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
#### Simple Global example
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload/types';
|
||||
import { GlobalConfig } from "payload/types";
|
||||
|
||||
const Nav: GlobalConfig = {
|
||||
slug: 'nav',
|
||||
fields: [
|
||||
{
|
||||
name: 'items',
|
||||
type: 'array',
|
||||
required: true,
|
||||
maxRows: 8,
|
||||
fields: [
|
||||
{
|
||||
name: 'page',
|
||||
type: 'relationship',
|
||||
relationTo: 'pages', // "pages" is the slug of an existing collection
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
},
|
||||
]
|
||||
slug: "nav",
|
||||
fields: [
|
||||
{
|
||||
name: "items",
|
||||
type: "array",
|
||||
required: true,
|
||||
maxRows: 8,
|
||||
fields: [
|
||||
{
|
||||
name: "page",
|
||||
type: "relationship",
|
||||
relationTo: "pages", // "pages" is the slug of an existing collection
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default Nav;
|
||||
@@ -64,9 +65,50 @@ You can find an [example Global config](https://github.com/payloadcms/public-dem
|
||||
|
||||
You can customize the way that the Admin panel behaves on a Global-by-Global basis by defining the `admin` property on a Global's config.
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------- | -------------|
|
||||
| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) |
|
||||
| Option | Description |
|
||||
|--------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `group` | Text used as a label for grouping collection and global links together in the navigation. |
|
||||
| `hidden` | Set to true or a function, called with the current user, returning true to exclude this global from navigation and admin routing. |
|
||||
| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) |
|
||||
| `preview` | Function to generate a preview URL within the Admin panel for this global that can point to your app. [More](#preview). |
|
||||
| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. |
|
||||
|
||||
### Preview
|
||||
|
||||
Global `admin` options can accept a `preview` function that will be used to generate a link pointing to the frontend of your app to preview data.
|
||||
|
||||
If the function is specified, a Preview button will automatically appear in the corresponding global's Edit view. Clicking the Preview button will link to the URL that is generated by the function.
|
||||
|
||||
**The preview function accepts two arguments:**
|
||||
|
||||
1. The document being edited
|
||||
1. An `options` object, containing `locale` and `token` properties. The `token` is the currently logged-in user's JWT.
|
||||
|
||||
**Example global with preview function:**
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from "payload/types";
|
||||
|
||||
export const MyGlobal: GlobalConfig = {
|
||||
slug: "my-global",
|
||||
fields: [
|
||||
{
|
||||
name: "slug",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
preview: (doc, { locale }) => {
|
||||
if (doc?.slug) {
|
||||
return `https://bigbird.com/preview/${doc.slug}?locale=${locale}`;
|
||||
}
|
||||
|
||||
return null;
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### Access control
|
||||
|
||||
@@ -85,14 +127,14 @@ Globals support all field types that Payload has to offer—including simple fie
|
||||
You can import global types as follows:
|
||||
|
||||
```ts
|
||||
import { GlobalConfig } from 'payload/types';
|
||||
import { GlobalConfig } from "payload/types";
|
||||
|
||||
// This is the type used for incoming global configs.
|
||||
// Only the bare minimum properties are marked as required.
|
||||
```
|
||||
|
||||
```ts
|
||||
import { SanitizedGlobalConfig } from 'payload/types';
|
||||
import { SanitizedGlobalConfig } from "payload/types";
|
||||
|
||||
// This is the type used after an incoming global config is fully sanitized.
|
||||
// Generally, this is only used internally by Payload.
|
||||
|
||||
@@ -11,42 +11,49 @@ Not only does Payload support managing localized content, it also has internatio
|
||||
While Payload's built-in features come translated, you may want to also translate parts of your project's configuration too. This is possible in places like collections and globals labels and groups, field labels, descriptions and input placeholder text. The admin UI will display all the correct translations you provide based on the user's language.
|
||||
|
||||
Here is an example of a simple collection supporting both English and Spanish editors:
|
||||
|
||||
```ts
|
||||
const Articles: CollectionConfig = {
|
||||
slug: 'articles',
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const Articles: CollectionConfig = {
|
||||
slug: "articles",
|
||||
labels: {
|
||||
singular: {
|
||||
en: 'Article', es: 'Artículo',
|
||||
en: "Article",
|
||||
es: "Artículo",
|
||||
},
|
||||
plural: {
|
||||
en: 'Articles', es: 'Artículos',
|
||||
en: "Articles",
|
||||
es: "Artículos",
|
||||
},
|
||||
},
|
||||
admin: {
|
||||
group: { en: 'Content', es: 'Contenido' },
|
||||
group: { en: "Content", es: "Contenido" },
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
name: "title",
|
||||
type: "text",
|
||||
label: {
|
||||
en: 'Title', es: 'Título',
|
||||
en: "Title",
|
||||
es: "Título",
|
||||
},
|
||||
admin: {
|
||||
placeholder: { en: 'Enter title', es: 'Introduce el título' }
|
||||
}
|
||||
placeholder: { en: "Enter title", es: "Introduce el título" },
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'type',
|
||||
type: 'radio',
|
||||
options: [{
|
||||
value: 'news',
|
||||
label: { en: 'News', es: 'Noticias' },
|
||||
}, // etc...
|
||||
name: "type",
|
||||
type: "radio",
|
||||
options: [
|
||||
{
|
||||
value: "news",
|
||||
label: { en: "News", es: "Noticias" },
|
||||
}, // etc...
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Admin UI
|
||||
@@ -55,8 +62,8 @@ The Payload admin panel reads the language settings of a user's browser and disp
|
||||
After a user logs in, they can change their language selection in the `/account` view.
|
||||
|
||||
<Banner>
|
||||
<strong>Note:</strong><br/>
|
||||
If there is a language that Payload does not yet support, we accept code <a href="https://github.com/payloadcms/payload/blob/master/contributing.md">contributions</a>.
|
||||
<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/master/contributing.md).
|
||||
</Banner>
|
||||
|
||||
### Node Express
|
||||
@@ -74,21 +81,22 @@ In your Payload config, you can add translations and customize the settings in `
|
||||
**Example Payload config extending i18n:**
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config'
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
export default buildConfig({
|
||||
//...
|
||||
i18n: {
|
||||
fallbackLng: 'en', // default
|
||||
fallbackLng: "en", // default
|
||||
debug: false, // default
|
||||
resources: {
|
||||
en: {
|
||||
custom: { // namespace can be anything you want
|
||||
key1: 'Translation with {{variable}}', // translation
|
||||
custom: {
|
||||
// namespace can be anything you want
|
||||
key1: "Translation with {{variable}}", // translation
|
||||
},
|
||||
// override existing translation keys
|
||||
general: {
|
||||
dashboard: 'Home',
|
||||
dashboard: "Home",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -72,6 +72,15 @@ All field types with a `name` property support the `localized` property—even t
|
||||
Enabling localization for field types that support nested fields will automatically create localized "sets" of all fields contained within the field. For example, if you have a page layout using a blocks field type, you have the choice of either localizing the full layout, by enabling localization on the top-level blocks field, or only certain fields within the layout.
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong>
|
||||
<br />
|
||||
When converting an existing field to or from `localized: true` the data
|
||||
structure in the document will change for this field and so existing data for
|
||||
this field will be lost. Before changing the localization setting on fields
|
||||
with existing data, you may need to consider a field migration strategy.
|
||||
</Banner>
|
||||
|
||||
### Retrieving localized docs
|
||||
|
||||
When retrieving documents, you can specify which locale you'd like to receive as well as which fallback locale should be used.
|
||||
|
||||
@@ -6,82 +6,86 @@ desc: The Payload config is central to everything that Payload does, from adding
|
||||
keywords: overview, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
Payload is a *config-based*, code-first CMS and application framework. The Payload config is central to everything that Payload does. It scaffolds the data that Payload stores as well as maintains custom React components, hook logic, custom validations, and much more. The config itself and all of its dependencies are run through Babel, so you can take full advantage of newer JavaScript features and even directly import React components containing JSX.
|
||||
Payload is a _config-based_, code-first CMS and application framework. The Payload config is central to everything that Payload does. It scaffolds the data that Payload stores as well as maintains custom React components, hook logic, custom validations, and much more.
|
||||
|
||||
**Also, because the Payload source code is fully written in TypeScript, its configs are strongly typed—meaning that even if you aren't using TypeScript to build your project, your IDE (such as VSCode) may still provide helpful information like type-ahead suggestions while you write your config.**
|
||||
**Also, because the Payload source code is fully written in TypeScript, its configs are strongly typed—meaning that even if you aren't using TypeScript, your IDE (such as VSCode) may still provide helpful information like type-ahead suggestions while you write your config.**
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br />This file is included in the Payload admin bundle, so make sure you do not embed any sensitive information.
|
||||
<strong>Important:</strong>
|
||||
<br />
|
||||
This file is included in the Payload admin bundle, so make sure you do not
|
||||
embed any sensitive information.
|
||||
</Banner>
|
||||
|
||||
## 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). |
|
||||
| `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) |
|
||||
| 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). |
|
||||
| `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) |
|
||||
|
||||
#### Simple example
|
||||
|
||||
```ts
|
||||
import { buildConfig } from 'payload/config';
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
export default buildConfig({
|
||||
collections: [
|
||||
{
|
||||
slug: 'pages',
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'content',
|
||||
type: 'richText',
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: 'header',
|
||||
fields: [
|
||||
{
|
||||
name: 'nav',
|
||||
type: 'array',
|
||||
fields: [
|
||||
{
|
||||
name: 'page',
|
||||
type: 'relationship',
|
||||
relationTo: 'pages',
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
collections: [
|
||||
{
|
||||
slug: "pages",
|
||||
fields: [
|
||||
{
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: "content",
|
||||
type: "richText",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
globals: [
|
||||
{
|
||||
slug: "header",
|
||||
fields: [
|
||||
{
|
||||
name: "nav",
|
||||
type: "array",
|
||||
fields: [
|
||||
{
|
||||
name: "page",
|
||||
type: "relationship",
|
||||
relationTo: "pages",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
});
|
||||
```
|
||||
|
||||
@@ -94,12 +98,15 @@ You can see a full [example config](https://github.com/payloadcms/public-demo/bl
|
||||
We suggest using the `dotenv` package to handle environment variables alongside of Payload. All that's necessary to do is to require the package as high up in your application as possible (for example, at the top of your `server.js` file), and ensure that it can find an `.env` file that you create.
|
||||
|
||||
**Add this line to the top of your server:**
|
||||
|
||||
```
|
||||
require('dotenv').config()
|
||||
// ...
|
||||
// the rest of your `server.js` file goes here
|
||||
```
|
||||
|
||||
Note that if you rely on any environment variables in your config itself, you should also call `dotenv()` at the top of your config itself as well. There's no harm in calling it in both your server and your config itself!
|
||||
|
||||
**Here is an example project structure w/ `dotenv` and an `.env` file:**
|
||||
|
||||
```
|
||||
@@ -111,8 +118,12 @@ project-name
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br />
|
||||
If you use an environment variable to configure any properties that are required for the Admin panel to function (ex. serverURL or any routes), you need to make sure that your Admin panel code can access it. <a href="/docs/admin/webpack#admin-environment-vars">Click here</a> for more info.
|
||||
<strong>Important:</strong>
|
||||
<br />
|
||||
If you use an environment variable to configure any properties that are
|
||||
required for the Admin panel to function (ex. serverURL or any routes), you
|
||||
need to make sure that your Admin panel code can access it. [Click
|
||||
here](/docs/admin/webpack#admin-environment-vars) for more info.
|
||||
</Banner>
|
||||
|
||||
### Customizing & overriding the config location
|
||||
@@ -133,53 +144,21 @@ But, you can specify where your Payload config is located as well as what it's n
|
||||
|
||||
### Developing within the Config
|
||||
|
||||
The Payload config itself, as well as all files that it requires or imports, are run through Babel. TypeScript and all common ES6 features are fully supported. To see the Babel config that is used to parse Payload configs, check out the Payload source code [here](https://github.com/payloadcms/payload/blob/master/src/babel.config.js).
|
||||
|
||||
Payload comes with `isomorphic-fetch` installed which means that even in Node, you can use the `fetch` API just as you would within the browser. No need to import `axios` or similar, unless you want to!
|
||||
|
||||
#### Payload Config and Babel
|
||||
|
||||
The entire Payload config is transpiled automatically by Payload via `babel`.
|
||||
|
||||
If for any reason you need to re-use the built-in Payload `babel.config.js`, you can do so by importing it as follows:
|
||||
|
||||
```
|
||||
import { config } from 'payload/babel';
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong><br/>
|
||||
Because the Payload config is transpiled internally, if you want to import it to share or reuse any of its properties within your own Node server's code, you need to make sure that <em>you manually transpile it</em> using <strong>babel-register</strong> or similar. For example, if you try to import your config directly into your server, your Node process will likely crash because the Payload config supports React components, TypeScript, and new ES6+ features.
|
||||
</Banner>
|
||||
|
||||
However, you can share code, like for example your config's `serverURL` property by "hoisting" your shared properties above your config and writing any "shared" code in a module that is compatible with your Node environment.
|
||||
|
||||
For example, to share your `serverURL`, you could create a file like the following:
|
||||
|
||||
`serverURL.js`:
|
||||
|
||||
```js
|
||||
const serverURL = 'http://localhost:3000';
|
||||
|
||||
module.exports = serverURL;
|
||||
```
|
||||
|
||||
Then, you could import this file into both your Payload config and your server, in an effort to avoid importing your full Payload config directly into your server.
|
||||
|
||||
|
||||
### TypeScript
|
||||
|
||||
You can import config types as follows:
|
||||
|
||||
```ts
|
||||
import { Config } from 'payload/config';
|
||||
import { Config } from "payload/config";
|
||||
|
||||
// This is the type used for an incoming Payload config.
|
||||
// Only the bare minimum properties are marked as required.
|
||||
```
|
||||
|
||||
```ts
|
||||
import { SanitizedConfig } from 'payload/config';
|
||||
import { SanitizedConfig } from "payload/config";
|
||||
|
||||
// This is the type used after an incoming Payload config is fully sanitized.
|
||||
// Generally, this is only used internally by Payload.
|
||||
|
||||
@@ -25,21 +25,22 @@ in the `email` property object of your payload init call. Payload will make use
|
||||
|
||||
The following options are configurable in the `email` property object as part of the options object when calling payload.init().
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------- | -------------|
|
||||
| **`fromName`** * | The name part of the From field that will be seen on the delivered email |
|
||||
| **`fromAddress`** * | The email address part of the From field that will be used when delivering email |
|
||||
| **`transport`** | The NodeMailer transport object for when you want to do it yourself, not needed when transportOptions is set |
|
||||
| **`transportOptions`** | An object that configures the transporter that Payload will create. For all the available options see the [NodeMailer documentation](https://nodemailer.com/smtp/) or see the examples below |
|
||||
| **`logMockCredentials`** | If set to true and no transport/transportOptions, ethereal credentials will be logged to console on startup |
|
||||
| Option | Description |
|
||||
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`fromName`** \* | The name part of the From field that will be seen on the delivered email |
|
||||
| **`fromAddress`** \* | The email address part of the From field that will be used when delivering email |
|
||||
| **`transport`** | The NodeMailer transport object for when you want to do it yourself, not needed when transportOptions is set |
|
||||
| **`transportOptions`** | An object that configures the transporter that Payload will create. For all the available options see the [NodeMailer documentation](https://nodemailer.com/smtp/) or see the examples below |
|
||||
| **`logMockCredentials`** | If set to true and no transport/transportOptions, ethereal credentials will be logged to console on startup |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Use SMTP
|
||||
|
||||
Simple Mail Transfer Protocol, also known as SMTP can be passed in using the `transportOptions` object on the `email` options.
|
||||
|
||||
**Example email part using SMTP:**
|
||||
|
||||
```ts
|
||||
payload.init({
|
||||
email: {
|
||||
@@ -47,24 +48,24 @@ payload.init({
|
||||
host: process.env.SMTP_HOST,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS
|
||||
pass: process.env.SMTP_PASS,
|
||||
},
|
||||
port: 587,
|
||||
secure: true, // use TLS
|
||||
tls: {
|
||||
// do not fail on invalid certs
|
||||
rejectUnauthorized: false
|
||||
}
|
||||
rejectUnauthorized: false,
|
||||
},
|
||||
fromName: 'hello',
|
||||
fromAddress: 'hello@example.com'
|
||||
}
|
||||
},
|
||||
fromName: "hello",
|
||||
fromAddress: "hello@example.com",
|
||||
},
|
||||
// ...
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
It is best practice to avoid saving credentials or API keys directly in your code, use <a href="/docs/configuration/overview#using-environment-variables-in-your-config">environment variables</a>.
|
||||
It is best practice to avoid saving credentials or API keys directly in your code, use [environment variables](/docs/configuration/overview#using-environment-variables-in-your-config).
|
||||
</Banner>
|
||||
|
||||
### Use an email service
|
||||
@@ -72,57 +73,62 @@ payload.init({
|
||||
Many third party mail providers are available and offer benefits beyond basic SMTP. As an example your payload init could look this if you wanted to use SendGrid.com though the same approach would work for any other [NodeMailer transports](https://nodemailer.com/transports/) shown here or provided by another third party.
|
||||
|
||||
```ts
|
||||
import payload from 'payload'
|
||||
import nodemailerSendgrid from 'nodemailer-sendgrid'
|
||||
import payload from "payload";
|
||||
import nodemailerSendgrid from "nodemailer-sendgrid";
|
||||
|
||||
const sendGridAPIKey = process.env.SENDGRID_API_KEY;
|
||||
|
||||
payload.init({
|
||||
...sendGridAPIKey ? {
|
||||
email: {
|
||||
transportOptions: nodemailerSendgrid({
|
||||
apiKey: sendGridAPIKey,
|
||||
}),
|
||||
fromName: 'Admin',
|
||||
fromAddress: 'admin@example.com',
|
||||
},
|
||||
} : {},
|
||||
...(sendGridAPIKey
|
||||
? {
|
||||
email: {
|
||||
transportOptions: nodemailerSendgrid({
|
||||
apiKey: sendGridAPIKey,
|
||||
}),
|
||||
fromName: "Admin",
|
||||
fromAddress: "admin@example.com",
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
});
|
||||
```
|
||||
|
||||
### Use a custom NodeMailer transport
|
||||
|
||||
To take full control of the mail transport you may wish to use `nodemailer.createTransport()` on your server and provide it to Payload init.
|
||||
|
||||
```ts
|
||||
import payload from 'payload'
|
||||
import nodemailer from 'nodemailer'
|
||||
import payload from "payload";
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
const payload = require('payload');
|
||||
const nodemailer = require('nodemailer');
|
||||
const payload = require("payload");
|
||||
const nodemailer = require("nodemailer");
|
||||
|
||||
const transport = await nodemailer.createTransport({
|
||||
host: process.env.SMTP_HOST,
|
||||
port: 587,
|
||||
auth: {
|
||||
user: process.env.SMTP_USER,
|
||||
pass: process.env.SMTP_PASS
|
||||
pass: process.env.SMTP_PASS,
|
||||
},
|
||||
});
|
||||
|
||||
payload.init({
|
||||
email: {
|
||||
fromName: 'Admin',
|
||||
fromAddress: 'admin@example.com',
|
||||
transport
|
||||
fromName: "Admin",
|
||||
fromAddress: "admin@example.com",
|
||||
transport,
|
||||
},
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
### Sending Mail
|
||||
|
||||
With a working transport you can call it anywhere you have access to payload by calling `payload.sendEmail(message)`. The `message` will contain the `to`, `subject` and `email` or `text` for the email being sent. To see all available message configuration options see [NodeMailer](https://nodemailer.com/message).
|
||||
|
||||
### Mock transport
|
||||
|
||||
By default, Payload uses a mock implementation that only sends mail to the [ethereal](https://ethereal.email) capture service that will never reach a user's inbox. While in development you may wish to make use of the captured messages which is why the payload output during server output helpfully logs this out on the server console.
|
||||
|
||||
To see ethereal credentials, add `logMockCredentials: true` to the email options. This will cause them to be logged to console on startup.
|
||||
@@ -130,8 +136,8 @@ To see ethereal credentials, add `logMockCredentials: true` to the email options
|
||||
```ts
|
||||
payload.init({
|
||||
email: {
|
||||
fromName: 'Admin',
|
||||
fromAddress: 'admin@example.com',
|
||||
fromName: "Admin",
|
||||
fromAddress: "admin@example.com",
|
||||
logMockCredentials: true, // Optional
|
||||
},
|
||||
// ...
|
||||
@@ -139,11 +145,12 @@ payload.init({
|
||||
```
|
||||
|
||||
**Console output when starting payload with a mock email instance and logMockCredentials: true**
|
||||
|
||||
```
|
||||
[06:37:21] INFO (payload): Starting Payload...
|
||||
[06:37:22] INFO (payload): Payload Demo Initialized
|
||||
[06:37:22] INFO (payload): listening on 3000...
|
||||
[06:37:22] INFO (payload): Connected to Mongo server successfully!
|
||||
[06:37:22] INFO (payload): Connected to MongoDB server successfully!
|
||||
[06:37:23] INFO (payload): E-mail configured with mock configuration
|
||||
[06:37:23] INFO (payload): Log into mock email provider at https://ethereal.email
|
||||
[06:37:23] INFO (payload): Mock email account username: hhav5jw7doo4euev@ethereal.email
|
||||
|
||||
@@ -6,8 +6,10 @@ desc: Array fields are intended for sets of repeating fields, that you define. L
|
||||
keywords: array, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Array field type is used when you need to have a set of "repeating" fields. It stores an array of objects containing the fields that you define. Its uses can be simple or highly complex.
|
||||
<Banner>
|
||||
The Array field type is used when you need to have a set of "repeating"
|
||||
fields. It stores an array of objects containing the fields that you define.
|
||||
Its uses can be simple or highly complex.
|
||||
</Banner>
|
||||
|
||||
**Example uses:**
|
||||
@@ -17,81 +19,85 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
|
||||
- Event agenda "timeslots" where you need to specify start & end time ([date field](/docs/fields/date)), label ([text field](/docs/fields/text)), and Learn More page [relationship](/docs/fields/relationship)
|
||||
|
||||

|
||||
*Admin panel screenshot of an Array field with a Row containing two text fields, a read-only text field and a checkbox*
|
||||
_Admin panel screenshot of an Array field with a Row containing two text fields, a read-only text field and a checkbox_
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`fields`** * | Array of field types to correspond to each row of the Array. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide an array of row data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Array will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`labels`** | Customize the row labels appearing in the Admin dashboard. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| Option | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`fields`** \* | Array of field types to correspond to each row of the Array. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide an array of row data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Array will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`labels`** | Customize the row labels appearing in the Admin dashboard. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin Config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------- |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
| **`components.RowLabel`** | Function or React component to be rendered as the label on the array row. Recieves `({ data, index, path })` as args |
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------- | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
| **`components.RowLabel`** | Function or React component to be rendered as the label on the array row. Receives `({ data, index, path })` as args |
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
```ts
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
name: 'slider', // required
|
||||
type: 'array', // required
|
||||
label: 'Image Slider',
|
||||
name: "slider", // required
|
||||
type: "array", // required
|
||||
label: "Image Slider",
|
||||
minRows: 2,
|
||||
maxRows: 10,
|
||||
interfaceName: "CardSlider", // optional
|
||||
labels: {
|
||||
singular: 'Slide',
|
||||
plural: 'Slides',
|
||||
singular: "Slide",
|
||||
plural: "Slides",
|
||||
},
|
||||
fields: [ // required
|
||||
fields: [
|
||||
// required
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
name: "title",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
name: 'image',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
name: "image",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
required: true,
|
||||
},
|
||||
{
|
||||
name: 'caption',
|
||||
type: 'text',
|
||||
}
|
||||
name: "caption",
|
||||
type: "text",
|
||||
},
|
||||
],
|
||||
admin: {
|
||||
components: {
|
||||
RowLabel: ({ data, index }) => {
|
||||
return data?.title || `Slide ${String(index).padStart(2, '0')}`;
|
||||
return data?.title || `Slide ${String(index).padStart(2, "0")}`;
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -6,8 +6,11 @@ desc: The Blocks field type is a great layout build and can be used to construct
|
||||
keywords: blocks, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Blocks field type is <strong>incredibly powerful</strong> and can be used as a <em>layout builder</em> as well as to define any other flexible content model you can think of. It stores an array of objects, where each object must match the shape of one of your provided block configs.
|
||||
<Banner>
|
||||
The Blocks field type is <strong>incredibly powerful</strong> and can be used
|
||||
as a <em>layout builder</em> as well as to define any other flexible content
|
||||
model you can think of. It stores an array of objects, where each object must
|
||||
match the shape of one of your provided block configs.
|
||||
</Banner>
|
||||
|
||||
**Example uses:**
|
||||
@@ -17,15 +20,14 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
|
||||
- Virtual event agenda "timeslots" where a timeslot could either be a `Break`, a `Presentation`, or a `BreakoutSession`.
|
||||
|
||||

|
||||
*Admin panel screenshot of a Blocks field type with Call to Action and Number block examples*
|
||||
|
||||
_Admin panel screenshot of a Blocks field type with Call to Action and Number block examples_
|
||||
|
||||
### Field config
|
||||
|
||||
| Option | Description |
|
||||
|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as the heading in the Admin panel or an object with keys for each language. Auto-generated from name if not defined. |
|
||||
| **`blocks`** * | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
@@ -33,38 +35,46 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
|
||||
| **`access`** | Provide field-level access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API response or the Admin panel. |
|
||||
| **`defaultValue`** | Provide an array of block data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this field will be kept, so there is no need to specify each nested field as `localized`. || **`required`** | Require this field to have a value. |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this field will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`labels`** | Customize the block row labels appearing in the Admin dashboard. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin Config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ------------------------------- |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------- |
|
||||
| **`initCollapsed`** | Set the initial collapsed state |
|
||||
|
||||
### Block configs
|
||||
|
||||
Blocks are defined as separate configs of their own.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong><br />
|
||||
Best practice is to define each block config in its own file, and then import them into your Blocks field as necessary. This way each block config can be easily shared between fields. For instance, using the "layout builder" example, you might want to feature a few of the same blocks in a Post collection as well as a Page collection. Abstracting into their own files trivializes their reusability.
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
Best practice is to define each block config in its own file, and then import
|
||||
them into your Blocks field as necessary. This way each block config can be
|
||||
easily shared between fields. For instance, using the "layout builder"
|
||||
example, you might want to feature a few of the same blocks in a Post
|
||||
collection as well as a Page collection. Abstracting into their own files
|
||||
trivializes their reusability.
|
||||
</Banner>
|
||||
|
||||
| Option | Description |
|
||||
|----------------------------|---------------------------------------------------------------------------------------------------------|
|
||||
| **`slug`** * | Identifier for this block type. Will be saved on each block as the `blockType` property. |
|
||||
| **`fields`** * | Array of fields to be stored in this block. |
|
||||
| **`labels`** | Customize the block labels that appear in the Admin dashboard. Auto-generated from slug if not defined. |
|
||||
| **`imageURL`** | Provide a custom image thumbnail to help editors identify this block in the Admin UI. |
|
||||
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
||||
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined |
|
||||
| Option | Description |
|
||||
| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`slug`** \* | Identifier for this block type. Will be saved on each block as the `blockType` property. |
|
||||
| **`fields`** \* | Array of fields to be stored in this block. |
|
||||
| **`labels`** | Customize the block labels that appear in the Admin dashboard. Auto-generated from slug if not defined. |
|
||||
| **`imageURL`** | Provide a custom image thumbnail to help editors identify this block in the Admin UI. |
|
||||
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
|
||||
|
||||
#### Auto-generated data per block
|
||||
|
||||
@@ -81,6 +91,7 @@ The Admin panel provides each block with a `blockName` field which optionally al
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.js`
|
||||
|
||||
```ts
|
||||
import { Block, CollectionConfig } from 'payload/types';
|
||||
|
||||
@@ -88,7 +99,9 @@ const QuoteBlock: Block = {
|
||||
slug: 'Quote', // required
|
||||
imageURL: 'https://google.com/path/to/image.jpg',
|
||||
imageAltText: 'A nice thumbnail image to show what this block looks like',
|
||||
fields: [ // required
|
||||
interfaceName: 'QuoteBlock', // optional
|
||||
fields: [
|
||||
// required
|
||||
{
|
||||
name: 'quoteHeader',
|
||||
type: 'text',
|
||||
@@ -98,10 +111,10 @@ const QuoteBlock: Block = {
|
||||
name: 'quoteText',
|
||||
type: 'text',
|
||||
},
|
||||
]
|
||||
],
|
||||
};
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
@@ -109,13 +122,13 @@ const ExampleCollection: CollectionConfig = {
|
||||
type: 'blocks', // required
|
||||
minRows: 1,
|
||||
maxRows: 20,
|
||||
blocks: [ // required
|
||||
QuoteBlock
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
blocks: [
|
||||
// required
|
||||
QuoteBlock,
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
@@ -124,5 +137,4 @@ As you build your own Block configs, you might want to store them in separate fi
|
||||
|
||||
```ts
|
||||
import type { Block } from 'payload/types';
|
||||
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
@@ -26,6 +26,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -35,7 +36,7 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -11,13 +11,13 @@ keywords: code, fields, config, configuration, documentation, Content Management
|
||||
The Code field type saves a string in the database, but provides the Admin panel with a code editor styled interface.
|
||||
</Banner>
|
||||
|
||||
This field uses `prismjs` for syntax highlighting and `react-simple-code-editor` for the editor itself.
|
||||
This field uses the `monaco-react` editor syntax highlighting.
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
@@ -32,26 +32,18 @@ This field uses `prismjs` for syntax highlighting and `react-simple-code-editor`
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin config
|
||||
### Admin Config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Code field type also allows for the customization of a `language` property.
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||
|
||||
The following `prismjs` plugins are imported, enabling the `language` property to accept the following values:
|
||||
|
||||
| Plugin | Language |
|
||||
| ---------------------------- | ----------- |
|
||||
| **`prism-css`** | `css` |
|
||||
| **`prism-clike`** | `clike` |
|
||||
| **`prism-markup`** | `markup`, `html`, `xml`, `svg`, `mathml`, `ssml`, `atom`, `rss` |
|
||||
| **`prism-javascript`** | `javascript`, `js` |
|
||||
| **`prism-json`** | `json` |
|
||||
| **`prism-jsx`** | `jsx` |
|
||||
| **`prism-typescript`** | `typescript`, `ts` |
|
||||
| **`prism-tsx`** | `tsx` |
|
||||
| **`prism-yaml`** | `yaml`, `yml` |
|
||||
| Option | Description |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`language`** | This property can be set to any language listed [here](https://github.com/microsoft/monaco-editor/tree/main/src/basic-languages). |
|
||||
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/typedoc/interfaces/editor.IDiffEditorConstructionOptions.html). |
|
||||
|
||||
### Example
|
||||
|
||||
@@ -59,7 +51,7 @@ The following `prismjs` plugins are imported, enabling the `language` property t
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
@@ -67,7 +59,7 @@ const ExampleCollection: CollectionConfig = {
|
||||
type: 'code', // required
|
||||
required: true,
|
||||
admin: {
|
||||
language: 'js'
|
||||
language: 'javascript'
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -17,6 +17,7 @@ keywords: row, fields, config, configuration, documentation, Content Management
|
||||
| **`label`** * | A label to render within the header of the collapsible component. This can be a string, function or react component. Function/components receive `({ data, path })` as args. |
|
||||
| **`fields`** * | Array of field types to nest within this Collapsible. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -34,7 +35,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -17,8 +17,8 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
@@ -28,7 +28,8 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -36,45 +37,72 @@ _\* An asterisk denotes that a property is required._
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can customize the following fields that will adjust how the component displays in the admin panel via the `date` property.
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`pickerAppearance`** | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. Defaults to `dayAndTime`. |
|
||||
| **`displayFormat`** | Determines how the date is presented. dayAndTime default to `MMM d, yyy h:mm a` timeOnly defaults to `h:mm a` dayOnly defaults to `MMM d, yyy` and monthOnly defaults to `MM/yyyy`. |
|
||||
| **`placeholder`** | Placeholder text for the field. |
|
||||
| **`monthsToShow`** | Number of months to display max is 2. Defaults to 1. |
|
||||
| **`minDate`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). |
|
||||
| **`maxDate`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). |
|
||||
| **`minTime`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). |
|
||||
| **`maxTime`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). |
|
||||
| **`timeIntervals`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). Defaults to 30 minutes. |
|
||||
| **`timeFormat`** | Passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). Defaults to `'h:mm aa'`. |
|
||||
| Property | Description |
|
||||
| ------------------------------ | ------------------------------------------------------------------------------------------- |
|
||||
| **`placeholder`** | Placeholder text for the field. |
|
||||
| **`date`** | Pass options to customize date field appearance. |
|
||||
| **`date.displayFormat`** | Format date to be shown in field **cell**. |
|
||||
| **`date.pickerAppearance`** \* | Determines the appearance of the datepicker: `dayAndTime` `timeOnly` `dayOnly` `monthOnly`. |
|
||||
| **`date.monthsToShow`** \* | Number of months to display max is 2. Defaults to 1. |
|
||||
| **`date.minDate`** \* | Min date value to allow. |
|
||||
| **`date.maxDate`** \* | Max date value to allow. |
|
||||
| **`date.minTime`** \* | Min time value to allow. |
|
||||
| **`date.maxTime`** \* | Max date value to allow. |
|
||||
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
|
||||
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
_\* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). ._
|
||||
|
||||
Common use cases for customizing the `date` property are to restrict your field to only show time or day input—but lots more can be done.
|
||||
#### Display Format and Picker Appearance
|
||||
|
||||
These properties only affect how the date is displayed in the UI. The full date is always stored in the format `YYYY-MM-DDTHH:mm:ss.SSSZ` (e.g. `1999-01-01T8:00:00.000+05:00`).
|
||||
|
||||
`displayFormat` determines how the date is presented in the field **cell**, you can pass any valid (unicode date format)[https://date-fns.org/v2.29.3/docs/format].
|
||||
|
||||
`pickerAppearance` sets the appearance of the **react datepicker**, the options available are `dayAndTime`, `dayOnly`, `timeOnly`, and `monthOnly`. By default, the datepicker will display `dayOnly`.
|
||||
|
||||
When only `pickerAppearance` is set, an equivalent format will be rendered in the date field cell. To overwrite this format, set `displayFormat`.
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
name: 'time', // required
|
||||
type: 'date', // required
|
||||
label: 'Event Start Time',
|
||||
defaultValue: '1988-11-05T8:00:00.000+05:00',
|
||||
name: "dateOnly",
|
||||
type: "date",
|
||||
admin: {
|
||||
date: {
|
||||
// All config options above should be placed here
|
||||
pickerAppearance: 'timeOnly',
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
pickerAppearance: "dayOnly",
|
||||
displayFormat: "d MMM yyy",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "timeOnly",
|
||||
type: "date",
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: "timeOnly",
|
||||
displayFormat: "h:mm:ss a",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "monthOnly",
|
||||
type: "date",
|
||||
admin: {
|
||||
date: {
|
||||
pickerAppearance: "monthOnly",
|
||||
displayFormat: "MMMM yyyy",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
@@ -27,6 +27,7 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -48,7 +49,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -6,28 +6,30 @@ desc: The Group field allows other fields to be nested under a common property.
|
||||
keywords: group, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Group field allows fields to be nested under a common property name. It also groups fields together visually in the Admin panel.
|
||||
<Banner>
|
||||
The Group field allows fields to be nested under a common property name. It
|
||||
also groups fields together visually in the Admin panel.
|
||||
</Banner>
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`fields`** * | Array of field types to nest within this Group. |
|
||||
| **`label`** | Used as a heading in the Admin panel and to name the generated GraphQL type. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide an object of data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Group will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| Option | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`fields`** \* | Array of field types to nest within this Group. |
|
||||
| **`label`** | Used as a heading in the Admin panel and to name the generated GraphQL type. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide an object of data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. If enabled, a separate, localized set of all data within this Group will be kept, so there is no need to specify each nested field as `localized`. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin config
|
||||
|
||||
@@ -40,32 +42,35 @@ Set this property to `true` to hide this field's gutter within the admin panel.
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
```ts
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
name: 'pageMeta', // required
|
||||
type: 'group', // required
|
||||
fields: [ // required
|
||||
name: "pageMeta", // required
|
||||
type: "group", // required
|
||||
interfaceName: "Meta", // optional
|
||||
fields: [
|
||||
// required
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
name: "title",
|
||||
type: "text",
|
||||
required: true,
|
||||
minLength: 20,
|
||||
maxLength: 100,
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'textarea',
|
||||
name: "description",
|
||||
type: "textarea",
|
||||
required: true,
|
||||
minLength: 40,
|
||||
maxLength: 160,
|
||||
}
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
61
docs/fields/json.mdx
Normal file
61
docs/fields/json.mdx
Normal file
@@ -0,0 +1,61 @@
|
||||
---
|
||||
title: JSON Field
|
||||
label: JSON
|
||||
order: 50
|
||||
desc: The JSON field type will store any string in the Database. Learn how to use JSON fields, see examples and options.
|
||||
|
||||
keywords: json, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The JSON field type saves actual JSON in the database, which differs from the Code field that saves the value as a string in the database.
|
||||
</Banner>
|
||||
|
||||
This field uses the `monaco-react` editor syntax highlighting.
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Admin Config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/api/interfaces/monaco.editor.IDiffEditorConstructionOptions.html). |
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'customerJSON', // required
|
||||
type: 'json', // required
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
};
|
||||
```
|
||||
@@ -14,10 +14,13 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`min`** | Minimum value accepted. Used in the default `validation` function. |
|
||||
| **`max`** | Maximum value accepted. Used in the default `validation` function. |
|
||||
| **`hasMany`** | Makes this field an ordered array of numbers instead of just a single number. |
|
||||
| **`minRows`** | Minimum number of numbers in the numbers array, if `hasMany` is set to true. |
|
||||
| **`maxRows`** | Maximum number of numbers in the numbers array, if `hasMany` is set to true. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
@@ -29,6 +32,7 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -54,7 +58,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -19,7 +19,7 @@ The required `type` property on a field determines what values it can accept, ho
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Page: CollectionConfig = {
|
||||
export const Page: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
fields: [
|
||||
{
|
||||
@@ -64,6 +64,10 @@ One of the most powerful parts about Payload is its ability for you to define fi
|
||||
|
||||
In addition to being able to define access control on a document-level, you can define extremely granular permissions on a field by field level. For more information about field-level access control, [click here](/docs/access-control/overview#fields).
|
||||
|
||||
### Field names
|
||||
|
||||
Some fields use their `name` property as a unique identifier to store and retrieve from the database. `__v`, `salt`, and `hash` are all reserved field names which are sanitized from Payload's config and cannot be used.
|
||||
|
||||
### Validation
|
||||
|
||||
Field validation is enforced automatically based on the field type and other properties such as `required` or `min` and `max` value constraints on certain field types. This default behavior can be replaced by providing your own validate function for any field. It will be used on both the frontend and the backend, so it should not rely on any Node-specific packages. The validation function can be either synchronous or asynchronous and expects to return either `true` or a string error message to display in both API responses and within the Admin panel.
|
||||
@@ -86,7 +90,7 @@ Example:
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Orders: CollectionConfig = {
|
||||
export const Orders: CollectionConfig = {
|
||||
slug: 'orders',
|
||||
fields: [
|
||||
{
|
||||
@@ -151,18 +155,19 @@ Example:
|
||||
|
||||
In addition to each field's base configuration, you can define specific traits and properties for fields that only have effect on how they are rendered in the Admin panel. The following properties are available for all fields within the `admin` property:
|
||||
|
||||
| Option | Description |
|
||||
| ------------- | -------------|
|
||||
| `condition` | You can programmatically show / hide fields based on what other fields are doing. [Click here](#conditional-logic) for more info. |
|
||||
| `components` | All field components can be completely and easily swapped out for custom components that you define. [Click here](#custom-components) for more info. |
|
||||
| `description` | Helper text to display with the field to provide more information for the editor user. [Click here](#description) for more info. |
|
||||
| `position` | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
|
||||
| `width` | Restrict the width of a field. you can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
|
||||
| `style` | Attach raw CSS style properties to the root DOM element of a field. |
|
||||
| `className` | Attach a CSS class name to the root DOM element of a field. |
|
||||
| `readOnly` | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
|
||||
| `disabled` | If a field is `disabled`, it is completely omitted from the Admin panel. |
|
||||
| `hidden` | Setting a field's `hidden` property on its `admin` config will transform it into a `hidden` input type. Its value will still submit with the Admin panel's requests, but the field itself will not be visible to editors. |
|
||||
| Option | Description |
|
||||
|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `condition` | You can programmatically show / hide fields based on what other fields are doing. [Click here](#conditional-logic) for more info. |
|
||||
| `components` | All field components can be completely and easily swapped out for custom components that you define. [Click here](#custom-components) for more info. |
|
||||
| `description` | Helper text to display with the field to provide more information for the editor user. [Click here](#description) for more info. |
|
||||
| `position` | Specify if the field should be rendered in the sidebar by defining `position: 'sidebar'`. |
|
||||
| `width` | Restrict the width of a field. you can pass any string-based value here, be it pixels, percentages, etc. This property is especially useful when fields are nested within a `Row` type where they can be organized horizontally. |
|
||||
| `style` | Attach raw CSS style properties to the root DOM element of a field. |
|
||||
| `className` | Attach a CSS class name to the root DOM element of a field. |
|
||||
| `readOnly` | Setting a field to `readOnly` has no effect on the API whatsoever but disables the admin component's editability to prevent editors from modifying the field's value. |
|
||||
| `disabled` | If a field is `disabled`, it is completely omitted from the Admin panel. |
|
||||
| `disableBulkEdit` | Set `disableBulkEdit` to `true` to prevent fields from appearing in the select options when making edits for multiple documents. |
|
||||
| `hidden` | Setting a field's `hidden` property on its `admin` config will transform it into a `hidden` input type. Its value will still submit with the Admin panel's requests, but the field itself will not be visible to editors. |
|
||||
|
||||
### Custom components
|
||||
|
||||
@@ -170,10 +175,11 @@ All Payload fields support the ability to swap in your own React components with
|
||||
|
||||
### Conditional logic
|
||||
|
||||
You can show and hide fields based on what other fields are doing by utilizing conditional logic on a field by field basis. The `condition` property on a field's admin config accepts a function which takes two arguments:
|
||||
You can show and hide fields based on what other fields are doing by utilizing conditional logic on a field by field basis. The `condition` property on a field's admin config accepts a function which takes three arguments:
|
||||
|
||||
- `data` - the entire document's data that is currently being edited
|
||||
- `siblingData` - only the fields that are direct siblings to the field with the condition
|
||||
- `{ user }` - the final argument is an object containing the currently authenticated user
|
||||
|
||||
The `condition` function should return a boolean that will control if the field should be displayed or not.
|
||||
|
||||
@@ -192,7 +198,7 @@ The `condition` function should return a boolean that will control if the field
|
||||
type: 'text',
|
||||
admin: {
|
||||
// highlight-start
|
||||
condition: (data, siblingData) => {
|
||||
condition: (data, siblingData, { user }) => {
|
||||
if (data.enableGreeting) {
|
||||
return true;
|
||||
} else {
|
||||
|
||||
@@ -17,7 +17,7 @@ The data structure in the database matches the GeoJSON structure to represent po
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Used as a field label in the Admin panel and to name the generated GraphQL type. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
|
||||
@@ -30,6 +30,7 @@ The data structure in the database matches the GeoJSON structure to represent po
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -39,7 +40,7 @@ The data structure in the database matches the GeoJSON structure to represent po
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Radio Field
|
||||
title: Radio Group Field
|
||||
label: Radio Group
|
||||
order: 120
|
||||
desc: The Radio field type allows for the selection of one value from a predefined set of possible values. Learn how to use Radio fields, see examples and options.
|
||||
@@ -7,14 +7,14 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Radio field type allows for the selection of one value from a predefined set of possible values and presents a radio group-style set of inputs to the Admin panel.
|
||||
The Radio Group field type allows for the selection of one value from a predefined set of possible values and presents a radio group-style set of inputs to the Admin panel.
|
||||
</Banner>
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** * | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing an `label` string and a `value` string. |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
@@ -27,6 +27,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -37,7 +38,7 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
|
||||
### Admin config
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Radio field type allows for the specification of the following `admin` properties:
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), the Radio Group field type allows for the specification of the following `admin` properties:
|
||||
|
||||
**`layout`**
|
||||
|
||||
@@ -49,7 +50,7 @@ The `layout` property allows for the radio group to be styled as a horizonally o
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
@@ -72,5 +73,4 @@ const ExampleCollection: CollectionConfig = {
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
@@ -6,8 +6,9 @@ desc: The Relationship field provides the ability to relate documents together.
|
||||
keywords: relationship, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Relationship field is one of the most powerful fields Payload features. It provides for the ability to easily relate documents together.
|
||||
<Banner>
|
||||
The Relationship field is one of the most powerful fields Payload features. It
|
||||
provides for the ability to easily relate documents together.
|
||||
</Banner>
|
||||
|
||||
**Example uses:**
|
||||
@@ -18,31 +19,36 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`relationTo`** * | Provide one or many collection `slug`s to be able to assign relationships to. |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-relationship-options). |
|
||||
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many relations instead of only one. |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](/docs/getting-started/concepts#depth) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| Option | Description |
|
||||
| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`relationTo`** \* | Provide one or many collection `slug`s to be able to assign relationships to. |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-relationship-options). |
|
||||
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many relations instead of only one. |
|
||||
| **`minRows`** | A number for the fewest allowed items during validation when a value is present. Used with `hasMany`. |
|
||||
| **`maxRows`** | A number for the most allowed items during validation when a value is present. Used with `hasMany`. |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](/docs/getting-started/concepts#depth) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build a [MongoDB index](https://docs.mongodb.com/manual/indexes/) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong><br/>
|
||||
The <a href="/docs/getting-started/concepts#depth">Depth</a> parameter can be used to automatically populate related documents that are returned by the API.
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
The [Depth](/docs/getting-started/concepts#depth) parameter can be used to
|
||||
automatically populate related documents that are returned by the API.
|
||||
</Banner>
|
||||
|
||||
### Admin config
|
||||
@@ -51,7 +57,11 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
|
||||
**`isSortable`**
|
||||
|
||||
Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop. (Only works when `hasMany` is set to `true`)
|
||||
Set to `true` if you'd like this field to be sortable within the Admin UI using drag and drop (only works when `hasMany` is set to `true`).
|
||||
|
||||
**`allowCreate`**
|
||||
|
||||
Set to `false` if you'd like to disable the ability to create new documents from within the relationship field (hides the "Add new" button in the admin UI).
|
||||
|
||||
### Filtering relationship options
|
||||
|
||||
@@ -59,43 +69,55 @@ Options can be dynamically limited by supplying a [query constraint](/docs/queri
|
||||
|
||||
The `filterOptions` property can either be a `Where` query directly, or a function that returns one. When using a function, it will be called with an argument object with the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| ------------- | -------------|
|
||||
| `relationTo` | The `relationTo` to filter against (as defined on the field) |
|
||||
| `data` | An object of the full collection or global document currently being edited |
|
||||
| `siblingData` | An object of the document data limited to fields within the same parent to the field |
|
||||
| `id` | The value of the collection `id`, will be `undefined` on create request |
|
||||
| `user` | The currently authenticated user object |
|
||||
| Property | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------ |
|
||||
| `relationTo` | The `relationTo` to filter against (as defined on the field) |
|
||||
| `data` | An object of the full collection or global document currently being edited |
|
||||
| `siblingData` | An object of the document data limited to fields within the same parent to the field |
|
||||
| `id` | The value of the collection `id`, will be `undefined` on create request |
|
||||
| `user` | The currently authenticated user object |
|
||||
|
||||
**Example:**
|
||||
### Example
|
||||
|
||||
```ts
|
||||
const relationshipField = {
|
||||
name: 'purchase',
|
||||
type: 'relationship',
|
||||
relationTo: ['products', 'services'],
|
||||
filterOptions: ({ relationTo, siblingData }) => {
|
||||
// returns a Where query dynamically by the type of relationship
|
||||
if (relationTo === 'products') {
|
||||
return {
|
||||
'stock': { greater_than: siblingData.quantity }
|
||||
}
|
||||
}
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
if (relationTo === 'services') {
|
||||
return {
|
||||
'isAvailable': { equals: true }
|
||||
}
|
||||
}
|
||||
},
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
name: "purchase",
|
||||
type: "relationship",
|
||||
relationTo: ["products", "services"],
|
||||
filterOptions: ({ relationTo, siblingData }) => {
|
||||
// returns a Where query dynamically by the type of relationship
|
||||
if (relationTo === "products") {
|
||||
return {
|
||||
stock: { greater_than: siblingData.quantity },
|
||||
};
|
||||
}
|
||||
|
||||
if (relationTo === "services") {
|
||||
return {
|
||||
isAvailable: { equals: true },
|
||||
};
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
You can learn more about writing queries [here](/docs/queries/overview).
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong><br/>
|
||||
When a relationship field has both <strong>filterOptions</strong> and a custom <strong>validate</strong> function, the api will not validate <strong>filterOptions</strong> unless you call the default relationship field validation function imported from <strong>payload/fields/validations</strong> in your validate function.
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
When a relationship field has both <strong>filterOptions</strong> and a custom{" "}
|
||||
<strong>validate</strong> function, the api will not validate{" "}
|
||||
<strong>filterOptions</strong> unless you call the default relationship field
|
||||
validation function imported from <strong>payload/fields/validations</strong>{" "}
|
||||
in your validate function.
|
||||
</Banner>
|
||||
|
||||
### How the data is saved
|
||||
@@ -123,10 +145,10 @@ The most simple pattern of a relationship is to use `hasMany: false` with a `rel
|
||||
The shape of the data to save for a document with the field configured this way would be:
|
||||
|
||||
```json
|
||||
{
|
||||
// Mongo ObjectID of the related user
|
||||
"owner": "6031ac9e1289176380734024"
|
||||
}
|
||||
{
|
||||
// MongoDB ObjectID of the related user
|
||||
"owner": "6031ac9e1289176380734024"
|
||||
}
|
||||
```
|
||||
|
||||
When querying documents in this collection via REST API, you could query as follows:
|
||||
@@ -154,12 +176,12 @@ Also known as **dynamic references**, in this configuration, the `relationTo` fi
|
||||
The shape of the data to save for a document with more than one relationship type would be:
|
||||
|
||||
```json
|
||||
{
|
||||
"owner": {
|
||||
"relationTo": "organizations",
|
||||
"value": "6031ac9e1289176380734024"
|
||||
}
|
||||
{
|
||||
"owner": {
|
||||
"relationTo": "organizations",
|
||||
"value": "6031ac9e1289176380734024"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Here is an example for how to query documents by this data (note the difference in referencing the `owner.value`):
|
||||
@@ -193,9 +215,9 @@ The `hasMany` tells Payload that there may be more than one collection saved to
|
||||
To save the to `hasMany` relationship field we need to send an array of IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"owners": [ "6031ac9e1289176380734024", "602c3c327b811235943ee12b" ]
|
||||
}
|
||||
{
|
||||
"owners": ["6031ac9e1289176380734024", "602c3c327b811235943ee12b"]
|
||||
}
|
||||
```
|
||||
|
||||
When querying documents, the format does not change for arrays:
|
||||
@@ -227,7 +249,8 @@ Relationship fields with `hasMany` set to more than one kind of collections save
|
||||
{
|
||||
"relationTo": "users",
|
||||
"value": "6031ac9e1289176380734024"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"relationTo": "organizations",
|
||||
"value": "602c3c327b811235943ee12b"
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ The Admin component is built on the powerful [`slatejs`](https://docs.slatejs.or
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
@@ -31,6 +31,7 @@ The Admin component is built on the powerful [`slatejs`](https://docs.slatejs.or
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -54,6 +55,7 @@ The default `elements` available in Payload are:
|
||||
- `h4`
|
||||
- `h5`
|
||||
- `h6`
|
||||
- `blockquote`
|
||||
- `link`
|
||||
- `ol`
|
||||
- `ul`
|
||||
@@ -81,6 +83,8 @@ Set this property to `true` to hide this field's gutter within the admin panel.
|
||||
|
||||
This allows [fields](/docs/fields/overview) to be saved as extra fields on a link inside the Rich Text Editor. When this is present, the fields will render inside a modal that can be opened by clicking the "edit" button on the link element.
|
||||
|
||||
`link.fields` may either be an array of fields (in which case all fields defined in it will be appended below the default fields) or a function that accepts the default fields as only argument and returns an array defining the entirety of fields to be used (thus providing a mechanism of overriding the default fields).
|
||||
|
||||

|
||||
*RichText link with custom fields*
|
||||
|
||||
@@ -104,7 +108,7 @@ Similar to the `relationship` element, the `upload` element is a user-friendly w
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong><br/>
|
||||
Collections are automatically allowed to be selected within the Rich Text relationship and upload elements by default. If you want to disable a collection from being able to be referenced in Rich Text fields, set the collection admin option of <strong>enableRichTextRelationship</strong> to false.
|
||||
Collections are automatically allowed to be selected within the Rich Text relationship and upload elements by default. If you want to disable a collection from being able to be referenced in Rich Text fields, set the collection admin options of <strong>enableRichTextLink</strong> and <strong>enableRichTextRelationship</strong> to false.
|
||||
</Banner>
|
||||
|
||||
Relationship and Upload elements are populated dynamically into your Rich Text field' content. Within the REST and Local APIs, any present RichText `relationship` or `upload` elements will respect the `depth` option that you pass, and will be populated accordingly. In GraphQL, each `richText` field accepts an argument of `depth` for you to utilize.
|
||||
@@ -137,7 +141,7 @@ Custom `Leaf` objects follow a similar pattern but require you to define the `Le
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
@@ -153,6 +157,7 @@ const ExampleCollection: CollectionConfig = {
|
||||
'h3',
|
||||
'h4',
|
||||
'link',
|
||||
'blockquote',
|
||||
{
|
||||
name: 'cta',
|
||||
Button: CustomCallToActionButton,
|
||||
@@ -270,7 +275,7 @@ const serialize = (children) => children.map((node, i) => {
|
||||
{serialize(node.children)}
|
||||
</h6>
|
||||
);
|
||||
case 'quote':
|
||||
case 'blockquote':
|
||||
return (
|
||||
<blockquote key={i}>
|
||||
{serialize(node.children)}
|
||||
@@ -366,5 +371,4 @@ import type {
|
||||
RichTextCustomElement,
|
||||
RichTextCustomLeaf,
|
||||
} from 'payload/types';
|
||||
|
||||
```
|
||||
|
||||
@@ -16,6 +16,7 @@ keywords: row, fields, config, configuration, documentation, Content Management
|
||||
| ---------------- | ----------- |
|
||||
| **`fields`** * | Array of field types to nest within this Row. |
|
||||
| **`admin`** | Admin-specific configuration excluding `description`, `readOnly`, and `hidden`. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -25,7 +26,7 @@ keywords: row, fields, config, configuration, documentation, Content Management
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -15,7 +15,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing a `label` string and a `value` string. |
|
||||
| **`hasMany`** | Boolean when, if set to `true`, allows this field to have many selections instead of only one. |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
@@ -30,6 +30,7 @@ keywords: select, multi-select, fields, config, configuration, documentation, Co
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -61,7 +62,7 @@ Set to `true` if you'd like this field to be sortable within the Admin UI using
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -6,70 +6,78 @@ desc: The Tabs field is a great way to organize complex editing experiences into
|
||||
keywords: tabs, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The Tabs field is presentational-only and only affects the Admin panel (unless a tab is named). By using it, you can place fields within a nice layout component that separates certain sub-fields by a tabbed interface.
|
||||
<Banner>
|
||||
The Tabs field is presentational-only and only affects the Admin panel (unless
|
||||
a tab is named). By using it, you can place fields within a nice layout
|
||||
component that separates certain sub-fields by a tabbed interface.
|
||||
</Banner>
|
||||
|
||||

|
||||
*Tabs field type used to separate Hero fields from Page Layout*
|
||||
_Tabs field type used to separate Hero fields from Page Layout_
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`tabs`** * | Array of tabs to render within this Tabs field. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| Option | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`tabs`** \* | Array of tabs to render within this Tabs field. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
#### Tab-specific Config
|
||||
|
||||
Each tab has its own required `label` and `fields` array. You can also optionally pass a `description` to render within each individual tab.
|
||||
|
||||
| Option | Description |
|
||||
| ----------------- | ----------- |
|
||||
| **`name`** | An optional property name to be used when stored and retrieved from the database, similar to a [Group](/docs/fields/group). |
|
||||
| **`label`** * | The label to render on the tab itself. |
|
||||
| **`fields`** * | The fields to render within this tab. |
|
||||
| **`description`** | Optionally render a description within this tab to describe the contents of the tab itself. |
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| **`name`** | An optional property name to be used when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** \* | The label to render on the tab itself. |
|
||||
| **`fields`** \* | The fields to render within this tab. |
|
||||
| **`description`** | Optionally render a description within this tab to describe the contents of the tab itself. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). (`name` must be present) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
```ts
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
type: 'tabs', // required
|
||||
tabs: [ // required
|
||||
type: "tabs", // required
|
||||
tabs: [
|
||||
// required
|
||||
{
|
||||
label: 'Tab One Label', // required
|
||||
description: 'This will appear within the tab above the fields.',
|
||||
fields: [ // required
|
||||
label: "Tab One Label", // required
|
||||
description: "This will appear within the tab above the fields.",
|
||||
fields: [
|
||||
// required
|
||||
{
|
||||
name: 'someTextField',
|
||||
type: 'text',
|
||||
name: "someTextField",
|
||||
type: "text",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'tabTwo',
|
||||
label: 'Tab Two Label', // required
|
||||
fields: [ // required
|
||||
name: "tabTwo",
|
||||
label: "Tab Two Label", // required
|
||||
interfaceName: "TabTwo", // optional (`name` must be present)
|
||||
fields: [
|
||||
// required
|
||||
{
|
||||
name: 'numberField', // accessible via tabTwo.numberField
|
||||
type: 'number',
|
||||
name: "numberField", // accessible via tabTwo.numberField
|
||||
type: "number",
|
||||
required: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
]
|
||||
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
@@ -29,6 +29,7 @@ keywords: text, fields, config, configuration, documentation, Content Management
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -50,7 +51,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -14,7 +14,7 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- | ----------- |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`unique`** | Enforce that each entry in the Collection has a unique value for this field. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
@@ -25,10 +25,11 @@ keywords: textarea, fields, config, configuration, documentation, Content Manage
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) [More](/docs/fields/overview#default-values) |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values)|
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
|
||||
@@ -50,7 +51,7 @@ Set this property to a string that will be used for browser autocomplete.
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
|
||||
@@ -6,8 +6,11 @@ desc: UI fields are purely presentational and allow developers to customize the
|
||||
keywords: custom field, react component, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
The UI (user interface) field gives you a ton of power to add your own React components directly into the Admin panel, nested directly within your other fields. It has absolutely no effect on the data of your documents. It is presentational-only.
|
||||
<Banner>
|
||||
The UI (user interface) field gives you a ton of power to add your own React
|
||||
components directly into the Admin panel, nested directly within your other
|
||||
fields. It has absolutely no effect on the data of your documents. It is
|
||||
presentational-only.
|
||||
</Banner>
|
||||
|
||||
This field is helpful if you need to build in custom functionality via React components within the Admin panel. Think of it as a way for you to "plug in" your own React components directly within your other fields, so you can provide your editors with new controls exactly where you want them to go.
|
||||
@@ -23,34 +26,36 @@ With this field, you can also inject custom `Cell` components that appear as add
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------- |-------------------------------------------------------------------------------------------------------------------|
|
||||
| **`name`** * | A unique identifier for this field. |
|
||||
| **`label`** | Human-readable label for this UI field. |
|
||||
| **`admin.components.Field`** | React component to be rendered for this field within the Edit view. [More](/docs/admin/components/#field-component) |
|
||||
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](/docs/admin/components/#field-component) |
|
||||
| Option | Description |
|
||||
| ------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | A unique identifier for this field. |
|
||||
| **`label`** | Human-readable label for this UI field. |
|
||||
| **`admin.components.Field`** \* | React component to be rendered for this field within the Edit view. [More](/docs/admin/components/#field-component) |
|
||||
| **`admin.components.Cell`** | React component to be rendered as a Cell within collection List views. [More](/docs/admin/components/#field-component) |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
```ts
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
type: 'ui', // required
|
||||
name: "myCustomUIField", // required
|
||||
type: "ui", // required
|
||||
admin: {
|
||||
components: {
|
||||
Field: MyCustomUIField,
|
||||
Cell: MyCustomUICell,
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -6,13 +6,13 @@ desc: Upload fields will allow a file to be uploaded, only from a collection sup
|
||||
keywords: upload, images media, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner >
|
||||
<Banner>
|
||||
The Upload field allows for the selection of a Document from a collection supporting Uploads, and formats the selection as a thumbnail in the Admin panel.
|
||||
</Banner>
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br/>
|
||||
To use this field, you need to have a Collection configured to allow Uploads. For more information, <a href="/docs/upload/overview">click here</a> to read about how to enable Uploads on a collection by collection basis.
|
||||
<strong>Important:</strong><br />
|
||||
To use this field, you need to have a Collection configured to allow Uploads. For more information, [click here](/docs/upload/overview) to read about how to enable Uploads on a collection by collection basis.
|
||||
</Banner>
|
||||
|
||||
**Example uses:**
|
||||
@@ -23,10 +23,10 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ---------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`name`** * | To be used as the property name when stored and retrieved from the database. |
|
||||
| **`*relationTo`** * | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
|
||||
| Option | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`*relationTo`** \* | Provide a single collection `slug` to allow this field to accept a relation to. <strong>Note: the related collection must be configured to support Uploads.</strong> |
|
||||
| **`filterOptions`** | A query to filter which options appear in the UI and validate against. [More](#filtering-upload-options). |
|
||||
| **`maxDepth`** | Sets a number limit on iterations of related documents to populate when queried. [Depth](/docs/getting-started/concepts#depth) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
@@ -41,27 +41,28 @@ keywords: upload, images media, fields, config, configuration, documentation, Co
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
*\* An asterisk denotes that a property is required.*
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
```ts
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: "example-collection",
|
||||
fields: [
|
||||
{
|
||||
name: 'backgroundImage', // required
|
||||
type: 'upload', // required
|
||||
relationTo: 'media', // required
|
||||
name: "backgroundImage", // required
|
||||
type: "upload", // required
|
||||
relationTo: "media", // required
|
||||
required: true,
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
### Filtering upload options
|
||||
@@ -70,23 +71,23 @@ Options can be dynamically limited by supplying a [query constraint](/docs/queri
|
||||
|
||||
The `filterOptions` property can either be a `Where` query directly, or a function that returns one. When using a function, it will be called with an argument object with the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| ------------- | -------------|
|
||||
| `relationTo` | The `relationTo` to filter against (as defined on the field) |
|
||||
| `data` | An object of the full collection or global document currently being edited |
|
||||
| `siblingData` | An object of the document data limited to fields within the same parent to the field |
|
||||
| `id` | The value of the collection `id`, will be `undefined` on create request |
|
||||
| `user` | The currently authenticated user object |
|
||||
| Property | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------ |
|
||||
| `relationTo` | The `relationTo` to filter against (as defined on the field) |
|
||||
| `data` | An object of the full collection or global document currently being edited |
|
||||
| `siblingData` | An object of the document data limited to fields within the same parent to the field |
|
||||
| `id` | The value of the collection `id`, will be `undefined` on create request |
|
||||
| `user` | The currently authenticated user object |
|
||||
|
||||
**Example:**
|
||||
|
||||
```ts
|
||||
const uploadField = {
|
||||
name: 'image',
|
||||
type: 'upload',
|
||||
relationTo: 'media',
|
||||
name: "image",
|
||||
type: "upload",
|
||||
relationTo: "media",
|
||||
filterOptions: {
|
||||
mimeType: { contains: 'image' },
|
||||
mimeType: { contains: "image" },
|
||||
},
|
||||
};
|
||||
```
|
||||
@@ -94,6 +95,6 @@ const uploadField = {
|
||||
You can learn more about writing queries [here](/docs/queries/overview).
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong><br/>
|
||||
<strong>Note:</strong><br />
|
||||
When an upload field has both <strong>filterOptions</strong> and a custom <strong>validate</strong> function, the api will not validate <strong>filterOptions</strong> unless you call the default upload field validation function imported from <strong>payload/fields/validations</strong> in your validate function.
|
||||
</Banner>
|
||||
|
||||
@@ -117,7 +117,7 @@ It is also possible to limit the depth for specific `relation` and `upload` fiel
|
||||
}
|
||||
```
|
||||
|
||||
If you were to query the Posts endpoint at, say, `http://localhost:3000/api/posts?depth=1`, you will retrieve Posts with populations one level deep. A returned result may look like the following:
|
||||
If you were to query the Posts endpoint at, say, `http://localhost:3000/api/posts?depth=1`, you will retrieve Posts with populations one level deep. This depth parameter can be thought of as N, where N is the number of levels you want to populate. To populate one level further, you would simply specify N+1 as the depth. A returned result may look like the following:
|
||||
|
||||
```
|
||||
// ?depth=1
|
||||
|
||||
@@ -11,11 +11,12 @@ keywords: documentation, getting started, guide, Content Management System, cms,
|
||||
Payload requires the following software:
|
||||
|
||||
- Yarn or NPM
|
||||
- NodeJS version 10+
|
||||
- A Mongo Database
|
||||
- Node.js version 14+
|
||||
- A MongoDB Database
|
||||
|
||||
<Banner type="warning">
|
||||
Before proceeding any further, please ensure that you have the above requirements met.
|
||||
Before proceeding any further, please ensure that you have the above
|
||||
requirements met.
|
||||
</Banner>
|
||||
|
||||
## Quickstart with create-payload-app
|
||||
@@ -26,16 +27,16 @@ To quickly scaffold a new Payload app in the fastest way possible, you can use [
|
||||
npx create-payload-app
|
||||
```
|
||||
|
||||
Then just follow the prompts! You can choose between a TypeScript project, which is fully supported by Payload, or a JavaScript project. You'll get set up with a new folder and a functioning Payload app inside.
|
||||
Then just follow the prompts! You'll get set up with a new folder and a functioning Payload app inside.
|
||||
|
||||
## From scratch
|
||||
## Adding to an existing app
|
||||
|
||||
Adding Payload to either a new or existing app is super straightforward. To add to an existing Node + Express app, just run `npm install --save --legacy-peer-deps payload`. Or, to start a new project from scratch, run `npm init` and then `npm install --save --legacy-peer-deps payload express`.
|
||||
Adding Payload to either a new or existing TypeScript + Express app is super straightforward. To add to an existing app, just run `npm install --save --legacy-peer-deps payload`.
|
||||
|
||||
From there, the first step is writing a baseline config. Create a new `payload.config.js` in the root of your project. The simplest config contains the following:
|
||||
From there, the first step is writing a baseline config. Create a new `payload.config.ts` in your project's `/src` directory (or whatever your root TS dir is). The simplest config contains the following:
|
||||
|
||||
```js
|
||||
import { buildConfig } from 'payload/config';
|
||||
import { buildConfig } from "payload/config";
|
||||
|
||||
export default buildConfig({
|
||||
// By default, Payload will boot up normally
|
||||
@@ -46,46 +47,61 @@ export default buildConfig({
|
||||
|
||||
Write the above code into your newly created config file. This baseline config will automatically provide you with a default `User` collection. For more information about users and authentication, including how to provide your own user config, jump to the [Authentication](/docs/authentication/config) section.
|
||||
|
||||
Although this is just the bare minimum config, there are *many* more options that you can control here. To reference the full config and all of its options, [click here](/docs/configuration/overview).
|
||||
Although this is just the bare minimum config, there are _many_ more options that you can control here. To reference the full config and all of its options, [click here](/docs/configuration/overview).
|
||||
|
||||
### Server
|
||||
|
||||
Now that you've got a baseline Payload config, it's time to initialize Payload. It requires an Express server that you provide, so if you're not familiar with how to set up a baseline Express server, please read up on exactly what Express is and why to use it. Express' own [Documentation](https://expressjs.com/en/starter/hello-world.html) is a good place to start. Otherwise, follow along below for how to build your own Express server to use with Payload.
|
||||
|
||||
1. Run `npm install --save --legacy-peer-deps express` if you have not done so already
|
||||
1. Create a new `server.js` file in the root folder of your app
|
||||
1. Add the following code to `server.js`:
|
||||
1. Create a new `server.ts` file in the root directory of your app
|
||||
1. Add the following code to `server.ts`:
|
||||
|
||||
```js
|
||||
const express = require('express');
|
||||
```ts
|
||||
import express from "express";
|
||||
|
||||
const app = express();
|
||||
|
||||
app.listen(3000, async () => {
|
||||
console.log('Express is now listening for incoming connections on port 3000.')
|
||||
console.log(
|
||||
"Express is now listening for incoming connections on port 3000."
|
||||
);
|
||||
});
|
||||
```
|
||||
|
||||
This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its `init()` method, which accepts a small set of arguments to tell it how to operate. For a full list of `init` arguments, please consult the [main configuration](/docs/configuration/overview#init) docs.
|
||||
This server doesn't do anything just yet. But, after you have this in place, we can initialize Payload via its asynchronous `init()` method, which accepts a small set of arguments to tell it how to operate.
|
||||
|
||||
To initialize Payload, update your `server.js` file to reflect the following code:
|
||||
To initialize Payload, update your `server.ts` file to reflect the following code:
|
||||
|
||||
```js
|
||||
const express = require('express');
|
||||
const payload = require('payload');
|
||||
```ts
|
||||
import express from "express";
|
||||
import payload from "payload";
|
||||
|
||||
require("dotenv").config();
|
||||
const app = express();
|
||||
|
||||
payload.init({
|
||||
secret: 'SECRET_KEY',
|
||||
mongoURL: 'mongodb://localhost/payload',
|
||||
express: app,
|
||||
})
|
||||
const start = async () => {
|
||||
await payload.init({
|
||||
secret: process.env.PAYLOAD_SECRET,
|
||||
mongoURL: process.env.MONGODB_URI,
|
||||
express: app,
|
||||
});
|
||||
|
||||
app.listen(3000, async () => {
|
||||
console.log('Express is now listening for incoming connections on port 3000.')
|
||||
});
|
||||
app.listen(3000, async () => {
|
||||
console.log(
|
||||
"Express is now listening for incoming connections on port 3000."
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
start();
|
||||
```
|
||||
|
||||
A quick reminder: in this configuration, we're making use of two environmental variables, `process.env.PAYLOAD_SECRET` and `process.env.MONGODB_URI`. Often, it's smart to store these values in an `.env` file at the root of your directory and set different values for each of your environments (local, stage, prod, etc). The `dotenv` package is very handy and works well alongside of Payload. A typical `.env` file will look like this:
|
||||
|
||||
```
|
||||
MONGODB_URI=mongodb://127.0.0.1/your-payload-app
|
||||
PAYLOAD_SECRET=your-payload-secret
|
||||
```
|
||||
|
||||
Here is a list of all properties available to pass through `payload.init`:
|
||||
@@ -96,19 +112,21 @@ Here is a list of all properties available to pass through `payload.init`:
|
||||
|
||||
##### `secret`
|
||||
|
||||
**Required**. This is a secure string that will be used to authenticate with Payload. It can be random but should be at least 14 characters and be very difficult to guess. Often, it's smart to store this value in an `env` and set different values for each of your environments (local, stage, prod, etc). The `dotenv` package is very handy and works well alongside of Payload.
|
||||
**Required**. This is a secure string that will be used to authenticate with Payload. It can be random but should be at least 14 characters and be very difficult to guess.
|
||||
|
||||
Payload uses this secret key to generate secure user tokens (JWT). Behind the scenes, we do not use your secret key to encrypt directly - instead, we first take the secret key and create an encrypted string using the SHA-256 hash function. Then, we reduce the encrypted string to its first 32 characters. This final value is what Payload uses for encryption.
|
||||
|
||||
##### `mongoURL`
|
||||
|
||||
**Required**. This is a fully qualified MongoDB connection string that points to your Mongo database. If you don't have Mongo installed locally, you can [follow these steps for Mac OSX](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/) and [these steps](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/) for Windows 10. If you want to use a local database and you know you have MongoDB installed locally, a typical connection string will look like this:
|
||||
**Required**. This is a fully qualified MongoDB connection string that points to your MongoDB database. If you don't have MongoDB installed locally, you can [follow these steps for Mac OSX](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-os-x/) and [these steps](https://docs.mongodb.com/manual/tutorial/install-mongodb-on-windows/) for Windows 10. If you want to use a local database and you know you have MongoDB installed locally, a typical connection string will look like this:
|
||||
|
||||
`mongodb://localhost/payload`
|
||||
`mongodb://127.0.0.1/payload`
|
||||
|
||||
In contrast to running Mongo locally, a popular option is to sign up for a free [MongoDB Atlas account](https://www.mongodb.com/cloud/atlas), which is a fully hosted and cloud-based installation of Mongo that you don't need to ever worry about.
|
||||
In contrast to running MongoDB locally, a popular option is to sign up for a free [MongoDB Atlas account](https://www.mongodb.com/cloud/atlas), which is a fully hosted and cloud-based installation of MongoDB that you don't need to ever worry about.
|
||||
|
||||
##### `mongoOptions`
|
||||
|
||||
Customize Mongo connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose.
|
||||
Customize MongoDB connection options. Payload will connect to your MongoDB database using default options which you can override and extend to include all the [options](https://mongoosejs.com/docs/connections.html#options) available to mongoose.
|
||||
|
||||
##### `email`
|
||||
|
||||
@@ -128,6 +146,10 @@ A function that is called immediately following startup that receives the Payloa
|
||||
|
||||
### Test it out
|
||||
|
||||
After you've gotten this far, it's time to boot up Payload. At the command line, run `npm install` and then `node server.js` in your application's folder to start up your app and initialize Payload.
|
||||
After you've gotten this far, it's time to boot up Payload. Start your project in your application's folder to get going.
|
||||
|
||||
After it starts, you can go to `http://localhost:3000/admin` to create your first Payload user!
|
||||
|
||||
### Docker
|
||||
|
||||
Looking to deploy Payload with Docker? New projects with `create-payload-app` come with a Dockerfile and docker-compose.yml file ready to go. Examples of these files can be seen in our [Deployment docs](/docs/production/deployment#docker).
|
||||
|
||||
@@ -8,7 +8,7 @@ keywords: documentation, getting started, guide, Content Management System, cms,
|
||||
|
||||
<YouTube
|
||||
id="In_lFhzmbME"
|
||||
title="Payload CMS Introduction - Closing the Gap Between Headless CMS and Application Frameworks"
|
||||
title="Payload Introduction - Closing the Gap Between Headless CMS and Application Frameworks"
|
||||
/>
|
||||
|
||||
<Banner type="success">
|
||||
@@ -19,7 +19,7 @@ keywords: documentation, getting started, guide, Content Management System, cms,
|
||||
|
||||
Out of the box, Payload gives you a lot of the things that you often need when developing a new website, web app, or native app:
|
||||
|
||||
- A Mongo database to store your data
|
||||
- A MongoDB database to store your data
|
||||
- A way to store, retrieve, and manipulate data of any shape via full REST and GraphQL APIs
|
||||
- Authentication—complete with commonly required functionality like registration, email verification, login, & password reset
|
||||
- Deep access control to your data, based on document or field-level functions
|
||||
|
||||
@@ -53,13 +53,13 @@ export default buildConfig({
|
||||
type: GraphQL.GraphQLFloat,
|
||||
},
|
||||
},
|
||||
args: {
|
||||
argNameHere: {
|
||||
type: new GraphQL.GraphQLNonNull(GraphQLString),
|
||||
}
|
||||
},
|
||||
resolve: myCustomQueryResolver,
|
||||
})
|
||||
}),
|
||||
args: {
|
||||
argNameHere: {
|
||||
type: new GraphQL.GraphQLNonNull(GraphQLString),
|
||||
}
|
||||
},
|
||||
resolve: myCustomQueryResolver,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,3 +67,90 @@ export default buildConfig({
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
### Resolver function
|
||||
|
||||
In your resolver, make sure you set `depth: 0` if you're returning data directly from the local API so that GraphQL can correctly resolve queries to nested values such as relationship data.
|
||||
|
||||
Your function will receive four arguments you can make use of:
|
||||
|
||||
Example
|
||||
|
||||
```ts
|
||||
async (obj, args, context, info) => { }
|
||||
```
|
||||
|
||||
**`obj`**
|
||||
|
||||
The previous object. Not very often used and usually discarded.
|
||||
|
||||
**`args`**
|
||||
|
||||
The available arguments from your query or mutation will be available to you here, these must be configured via the custom operation first.
|
||||
|
||||
**`context`**
|
||||
|
||||
An object containing the `req` and `res` objects that will provide you with the `payload`, `user` instances and more, like any other Payload API handler.
|
||||
|
||||
**`info`**
|
||||
|
||||
Contextual information about the currently running GraphQL operation. You can get schema information from this as well as contextual information about where this resolver function is being run.
|
||||
|
||||
### Types
|
||||
|
||||
We've exposed a few types and utilities to help you extend the API further. Payload uses the GraphQL.js package for which you can view the full list of available types in the [official documentation](https://graphql.org/graphql-js/type/).
|
||||
|
||||
**`GraphQL`**
|
||||
|
||||
You can directly import the GraphQL package used by Payload, most useful for typing. For queries, mutations and handlers make sure you use the `GraphQL` and `payload` instances provided via arguments.
|
||||
|
||||
**`buildPaginatedListType`**
|
||||
|
||||
This is a utility function that allows you to build a new GraphQL type for a paginated result similar to the Payload's generated schema.
|
||||
It takes in two arguments, the first for the name of this new schema type and the second for the GraphQL type to be used in the docs parameter.
|
||||
|
||||
Example
|
||||
|
||||
```ts
|
||||
export const getMyPosts = (GraphQL, payload) => {
|
||||
return {
|
||||
args: {},
|
||||
resolve: Resolver,
|
||||
// The name of your new type has to be unique
|
||||
type: buildPaginatedListType('AuthorPosts', payload.collections['posts'].graphQL?.type),
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**`payload.collections.slug.graphQL`**
|
||||
|
||||
If you want to extend more of the provided API then the `graphQL` object on your collection slug will contain additional types to help you re-use code for types, mutations and queries.
|
||||
|
||||
```ts
|
||||
graphQL?: {
|
||||
type: GraphQLObjectType
|
||||
paginatedType: GraphQLObjectType
|
||||
JWT: GraphQLObjectType
|
||||
versionType: GraphQLObjectType
|
||||
whereInputType: GraphQLInputObjectType
|
||||
mutationInputType: GraphQLNonNull<any>
|
||||
updateMutationInputType: GraphQLNonNull<any>
|
||||
}
|
||||
```
|
||||
|
||||
### Best practices
|
||||
|
||||
There are a few ways to structure your code, we recommend using a dedicated `graphql` directory so you can keep all of your logic in one place. You have total freedom of how you want to structure this but a common pattern is to group functions by type and with their resolver.
|
||||
|
||||
Example
|
||||
|
||||
```
|
||||
src/graphql
|
||||
---- queries/
|
||||
index.ts
|
||||
-- myCustomQuery/
|
||||
index.ts
|
||||
resolver.ts
|
||||
|
||||
---- mutations/
|
||||
```
|
||||
|
||||
@@ -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.
|
||||
|
||||
### GraphQL Schema generate script
|
||||
### Schema generatation script
|
||||
|
||||
Run the following command in a Payload project to generate your project's GraphQL schema from Payload:
|
||||
|
||||
@@ -16,9 +16,9 @@ Run the following command in a Payload project to generate your project's GraphQ
|
||||
payload generate:graphQLSchema
|
||||
```
|
||||
|
||||
You can run this command whenever you need to regenerate your graphQL schema and output it to a file, and then you can use the schema for writing your own graphQL elsewhere in other projects.
|
||||
You can run this command whenever you need to regenerate your GraphQL schema and output it to a file, and then you can use the schema for writing your own GraphQL elsewhere in other projects.
|
||||
|
||||
### GraphQL schema output file
|
||||
### Custom output file path
|
||||
|
||||
```js
|
||||
{
|
||||
@@ -29,12 +29,51 @@ You can run this command whenever you need to regenerate your graphQL schema and
|
||||
}
|
||||
```
|
||||
|
||||
### Custom Field Schemas
|
||||
|
||||
For `array`, `block`, `group` and named `tab` fields, you can generate top level reusable interfaces. The following group field config:
|
||||
|
||||
```ts
|
||||
{
|
||||
type: 'group',
|
||||
name: 'meta',
|
||||
interfaceName: 'SharedMeta', <-- here!!
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
will generate:
|
||||
|
||||
```ts
|
||||
// a top level reusable type!!
|
||||
type SharedMeta {
|
||||
title: String
|
||||
description: String
|
||||
}
|
||||
|
||||
// example usage inside collection schema
|
||||
type Collection1 {
|
||||
// ...other fields
|
||||
meta: SharedMeta
|
||||
}
|
||||
```
|
||||
|
||||
The above example outputs all your definitions to a file relative from your payload config as `./graphql/schema.graphql`. By default, the file will be output to your current working directory as `schema.graphql`.
|
||||
|
||||
#### Adding an NPM script
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br/>
|
||||
<strong>Important</strong>
|
||||
<br />
|
||||
Payload needs to be able to find your config to generate your GraphQL schema.
|
||||
</Banner>
|
||||
|
||||
@@ -45,8 +84,8 @@ To add an NPM script to generate your types and show Payload where to find your
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"generate:graphQLSchema": "PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema",
|
||||
},
|
||||
"generate:graphQLSchema": "cross-env PAYLOAD_CONFIG_PATH=src/payload.config.ts payload generate:graphQLSchema"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -16,13 +16,13 @@ The labels you provide for your Collections and Globals are used to name the Gra
|
||||
|
||||
At the top of your Payload config you can define all the options to manage GraphQL.
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | -------------|
|
||||
| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) |
|
||||
| `disablePlaygroundInProduction` | A boolean that if false will enable the graphQL playground, defaults to true. [More](/docs/graphql/overview#graphql-playground) |
|
||||
| `disable` | A boolean that if true will disable the graphQL entirely, defaults to false. |
|
||||
| Option | Description |
|
||||
| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `mutations` | Any custom Mutations to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `queries` | Any custom Queries to be added in addition to what Payload provides. [More](/docs/graphql/extending) |
|
||||
| `maxComplexity` | A number used to set the maximum allowed complexity allowed by requests [More](/docs/graphql/overview#query-complexity-limits) |
|
||||
| `disablePlaygroundInProduction` | A boolean that if false will enable the GraphQL playground, defaults to true. [More](/docs/graphql/overview#graphql-playground) |
|
||||
| `disable` | A boolean that if true will disable the GraphQL entirely, defaults to false. |
|
||||
| `schemaOutputFile` | A string for the file path used by the generate schema command. Defaults to `graphql.schema` next to `payload.config.ts` [More](/docs/graphql/graphql-schema) |
|
||||
|
||||
## Collections
|
||||
@@ -32,7 +32,7 @@ Everything that can be done to a Collection via the REST or Local API can be don
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const PublicUser: CollectionConfig = {
|
||||
export const PublicUser: CollectionConfig = {
|
||||
slug: 'public-users',
|
||||
auth: true, // Auth is enabled
|
||||
fields: [
|
||||
@@ -43,26 +43,26 @@ const PublicUser: CollectionConfig = {
|
||||
|
||||
**Payload will automatically open up the following queries:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`PublicUser`** | `findByID` |
|
||||
| **`PublicUsers`** | `find` |
|
||||
| **`mePublicUser`** | `me` auth operation |
|
||||
| Query Name | Operation |
|
||||
| ------------------ | ------------------- |
|
||||
| **`PublicUser`** | `findByID` |
|
||||
| **`PublicUsers`** | `find` |
|
||||
| **`mePublicUser`** | `me` auth operation |
|
||||
|
||||
**And the following mutations:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ------------------------------ | -------------|
|
||||
| **`createPublicUser`** | `create` |
|
||||
| **`updatePublicUser`** | `update` |
|
||||
| **`deletePublicUser`** | `delete` |
|
||||
| Query Name | Operation |
|
||||
| ------------------------------ | ------------------------------- |
|
||||
| **`createPublicUser`** | `create` |
|
||||
| **`updatePublicUser`** | `update` |
|
||||
| **`deletePublicUser`** | `delete` |
|
||||
| **`forgotPasswordPublicUser`** | `forgotPassword` auth operation |
|
||||
| **`resetPasswordPublicUser`** | `resetPassword` auth operation |
|
||||
| **`unlockPublicUser`** | `unlock` auth operation |
|
||||
| **`verifyPublicUser`** | `verify` auth operation |
|
||||
| **`loginPublicUser`** | `login` auth operation |
|
||||
| **`logoutPublicUser`** | `logout` auth operation |
|
||||
| **`refreshTokenPublicUser`** | `refresh` auth operation |
|
||||
| **`resetPasswordPublicUser`** | `resetPassword` auth operation |
|
||||
| **`unlockPublicUser`** | `unlock` auth operation |
|
||||
| **`verifyPublicUser`** | `verify` auth operation |
|
||||
| **`loginPublicUser`** | `login` auth operation |
|
||||
| **`logoutPublicUser`** | `logout` auth operation |
|
||||
| **`refreshTokenPublicUser`** | `refresh` auth operation |
|
||||
|
||||
## Globals
|
||||
|
||||
@@ -81,32 +81,32 @@ const Header: GlobalConfig = {
|
||||
|
||||
**Payload will open the following query:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`Header`** | `findOne` |
|
||||
| Query Name | Operation |
|
||||
| ------------ | --------- |
|
||||
| **`Header`** | `findOne` |
|
||||
|
||||
**And the following mutation:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`updateHeader`** | `update` |
|
||||
| Query Name | Operation |
|
||||
| ------------------ | --------- |
|
||||
| **`updateHeader`** | `update` |
|
||||
|
||||
## Preferences
|
||||
|
||||
User [preferences](/docs/admin/overview#preferences) for the admin panel are also available to GraphQL. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible and of the `key` argument.
|
||||
User [preferences](/docs/admin/overview#preferences) for the admin panel are also available to GraphQL. To query preferences you must supply an authorization token in the header and only the preferences of that user will be accessible and of the `key` argument.
|
||||
|
||||
**Payload will open the following query:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`Preference`** | `findOne` |
|
||||
| Query Name | Operation |
|
||||
| ---------------- | --------- |
|
||||
| **`Preference`** | `findOne` |
|
||||
|
||||
**And the following mutations:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`updatePreference`** | `update` |
|
||||
| **`deletePreference`** | `delete` |
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | --------- |
|
||||
| **`updatePreference`** | `update` |
|
||||
| **`deletePreference`** | `delete` |
|
||||
|
||||
## GraphQL Playground
|
||||
|
||||
@@ -115,8 +115,8 @@ GraphQL Playground is enabled by default for development purposes, but disabled
|
||||
You can even log in using the `login[collection-singular-label-here]` mutation to use the Playground as an authenticated user.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong><br/>
|
||||
To see more regarding how the above queries and mutations are used, visit your GraphQL playground (by default at <a href="http://localhost:3000/api/graphql-playground">(http://localhost:3000/api/graphql-playground</a>) while your server is running. There, you can use the "Schema" and "Docs" buttons on the right to see a ton of detail about how GraphQL operates within Payload.
|
||||
<strong>Tip:</strong><br />
|
||||
To see more regarding how the above queries and mutations are used, visit your GraphQL playground (by default at [http://localhost:3000/api/graphql-playground](http://localhost:3000/api/graphql-playground)) while your server is running. There, you can use the "Schema" and "Docs" buttons on the right to see a ton of detail about how GraphQL operates within Payload.
|
||||
</Banner>
|
||||
|
||||
## Query complexity limits
|
||||
|
||||
@@ -34,7 +34,7 @@ All collection Hook properties accept arrays of synchronous or asynchronous func
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const ExampleHooks: CollectionConfig = {
|
||||
export const ExampleHooks: CollectionConfig = {
|
||||
slug: 'example-hooks',
|
||||
fields: [
|
||||
{ name: 'name', type: 'text'},
|
||||
@@ -79,7 +79,13 @@ const beforeOperationHook: CollectionBeforeOperationHook = async ({
|
||||
|
||||
### beforeValidate
|
||||
|
||||
Runs before the `create` and `update` operations. This hook allows you to add or format data before the incoming data is validated.
|
||||
Runs before the `create` and `update` operations. This hook allows you to add or format data before the incoming data is validated server-side.
|
||||
|
||||
Please do note that this does not run before the client-side validation. If you added a `validate` function, this would be the lifecycle:
|
||||
|
||||
1. `validate` runs on the client
|
||||
2. if successful, `beforeValidate` runs on the server
|
||||
3. `validate` runs on the server
|
||||
|
||||
```ts
|
||||
import { CollectionBeforeOperationHook } from 'payload/types';
|
||||
|
||||
@@ -67,6 +67,7 @@ Field Hooks receive one `args` argument that contains the following properties:
|
||||
| **`previousSiblingDoc`** | The sibling data from the previous document in `afterChange` hook. |
|
||||
| **`req`** | The Express `request` object. It is mocked for Local API operations. |
|
||||
| **`value`** | The value of the field. |
|
||||
| **`previousValue`** | The previous value of the field, before changes were applied, only in `afterChange` hooks. |
|
||||
|
||||
#### Return value
|
||||
|
||||
|
||||
@@ -8,11 +8,11 @@ keywords: hooks, globals, config, configuration, documentation, Content Manageme
|
||||
|
||||
Globals feature the ability to define the following hooks:
|
||||
|
||||
- [beforeValidate](#beforeValidate)
|
||||
- [beforeChange](#beforeChange)
|
||||
- [afterChange](#afterChange)
|
||||
- [beforeRead](#beforeRead)
|
||||
- [afterRead](#afterRead)
|
||||
- [beforeValidate](#beforevalidate)
|
||||
- [beforeChange](#beforechange)
|
||||
- [afterChange](#afterchange)
|
||||
- [beforeRead](#beforeread)
|
||||
- [afterRead](#afterread)
|
||||
|
||||
## Config
|
||||
|
||||
|
||||
104
docs/integrations/vercel-visual-editing.mdx
Normal file
104
docs/integrations/vercel-visual-editing.mdx
Normal file
@@ -0,0 +1,104 @@
|
||||
---
|
||||
title: Vercel Visual Editing
|
||||
label: Vercel Visual Editing
|
||||
order: 10
|
||||
desc: Payload + Vercel Visual Editing allows yours editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it.
|
||||
keywords: vercel, vercel visual editing, visual editing, content source maps, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
[Vercel Visual Editing](https://vercel.com/docs/workflow-collaboration/visual-editing) will allow your editors to navigate directly from the content rendered on your front-end to the fields in Payload that control it. This requires no changes to your front-end code and very few changes to your Payload config.
|
||||
|
||||

|
||||
|
||||
<Banner type="warning">
|
||||
Vercel Visual Editing is an enterprise-only feature and only available for
|
||||
deployments hosted on Vercel. If you are an existing enterprise customer,
|
||||
[contact our sales team](https://payloadcms.com/for-enterprise) for help with
|
||||
your integration.
|
||||
</Banner>
|
||||
|
||||
### How it works
|
||||
|
||||
To power Vercel Visual Editing, Payload embeds Content Source Maps into its API responses. Content Source Maps are invisible, encoded JSON values that include a link back to the field in the CMS that generated the content. When rendered on the page, Vercel detects and decodes these values to display the Visual Editing interface.
|
||||
|
||||
For full details on how the encoding and decoding algorithm works, check out [`@vercel/stega`](https://www.npmjs.com/package/@vercel/stega).
|
||||
|
||||
### Getting Started
|
||||
|
||||
Setting up Payload with Vercel Visual Editing is easy. First, install the `@payloadcms/plugin-csm` plugin into your project. This plugin requires an API key to install, [contact our sales team](https://payloadcms.com/for-enterprise) if you don't already have one.
|
||||
|
||||
```bash
|
||||
npm i @payloadcms/plugin-csm
|
||||
```
|
||||
|
||||
Then in the `plugins` array of your Payload config, call the plugin and enable any collections that require Content Source Maps.
|
||||
|
||||
```ts
|
||||
import { buildConfig } from "payload/config"
|
||||
import contentSourceMaps from "@payloadcms/plugin-csm"
|
||||
|
||||
const config = buildConfig({
|
||||
collections: [
|
||||
{
|
||||
slug: "pages",
|
||||
fields: [
|
||||
{
|
||||
name: 'slug',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'title,'
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
plugins: [
|
||||
contentSourceMaps({
|
||||
collections: ["pages"],
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
export default config
|
||||
```
|
||||
|
||||
Now in your Next.js app, include the `?encodeSourceMaps=true` parameter in any of your API requests. For performance reasons, this should only be done when in draft mode or on preview deployments.
|
||||
|
||||
```ts
|
||||
if (isDraftMode || process.env.VERCEL_ENV === "preview") {
|
||||
const res = await fetch(
|
||||
`${process.env.NEXT_PUBLIC_PAYLOAD_CMS_URL}/api/pages?where[slug][equals]=${slug}&encodeSourceMaps=true`
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
And that's it! You are now ready to enter Edit Mode and begin visually editing your content.
|
||||
|
||||
##### Edit Mode
|
||||
|
||||
To see Visual Editing on your site, you first need to visit any preview deployment on Vercel and login using the Vercel Toolbar. When Content Source Maps are detected on the page, a pencil icon will appear in the toolbar. Clicking this icon will enable Edit Mode, highlighting all editable fields on the page in blue.
|
||||
|
||||

|
||||
|
||||
### Troubleshooting
|
||||
|
||||
##### Dates
|
||||
|
||||
The plugin does not encode `date` fields by default, but for some cases like text that uses negative CSS letter-spacing, it may be necessary to split the encoded data out from the rendered text. This way you can safely use the cleaned data as expected.
|
||||
|
||||
```ts
|
||||
import { vercelStegaSplit } from "@vercel/stega";
|
||||
const { cleaned, encoded } = vercelStegaSplit(text);
|
||||
```
|
||||
|
||||
##### Blocks
|
||||
|
||||
All `blocks` fields by definition do not have plain text strings to encode. For this reason, blocks are given an additional `encodedSourceMap` key, which you can use to enable Visual Editing on entire sections of your site. You can then specify the editing container by adding the `data-vercel-edit-target` HTML attribute to any top-level element of your block.
|
||||
|
||||
```ts
|
||||
<div data-vercel-edit-target>
|
||||
<span style={{ display: "none" }}>{encodedSourceMap}</span>
|
||||
{children}
|
||||
</div>
|
||||
```
|
||||
@@ -9,8 +9,14 @@ keywords: local api, config, configuration, documentation, Content Management Sy
|
||||
The Payload Local API gives you the ability to execute the same operations that are available through REST and GraphQL within Node, directly on your server. Here, you don't need to deal with server latency or network speed whatsoever and can interact directly with your database.
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong><br/>
|
||||
The Local API is incredibly powerful when used with server-side rendering app frameworks like NextJS. With other headless CMS, you need to request your data from third-party servers which can add significant loading time to your server-rendered pages. With Payload, you don't have to leave your server to gather the data you need. It can be incredibly fast and is definitely a game changer.
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
The Local API is incredibly powerful when used with server-side rendering app
|
||||
frameworks like NextJS. With other headless CMS, you need to request your data
|
||||
from third-party servers which can add significant loading time to your
|
||||
server-rendered pages. With Payload, you don't have to leave your server to
|
||||
gather the data you need. It can be incredibly fast and is definitely a game
|
||||
changer.
|
||||
</Banner>
|
||||
|
||||
Here are some common examples of how you can use the Local API:
|
||||
@@ -28,15 +34,16 @@ You can gain access to the currently running `payload` object via two ways:
|
||||
You can import or require `payload` into your own files after it's been initialized, but you need to make sure that your `import` / `require` statements come **after** you call `payload.init()`—otherwise Payload won't have been initialized yet. That might be obvious. To us, it's usually not.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import payload from 'payload';
|
||||
import { CollectionAfterChangeHook } from 'payload/types';
|
||||
import payload from "payload";
|
||||
import { CollectionAfterChangeHook } from "payload/types";
|
||||
|
||||
const afterChangeHook: CollectionAfterChangeHook = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
collection: "posts",
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
##### Accessing from the `req`
|
||||
@@ -44,35 +51,41 @@ const afterChangeHook: CollectionAfterChangeHook = async () => {
|
||||
Payload is available anywhere you have access to the Express `req` - including within your access control and hook functions.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
const afterChangeHook: CollectionAfterChangeHook = async ({ req: { payload }}) => {
|
||||
const afterChangeHook: CollectionAfterChangeHook = async ({
|
||||
req: { payload },
|
||||
}) => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
collection: "posts",
|
||||
});
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Local options available
|
||||
|
||||
You can specify more options within the Local API vs. REST or GraphQL due to the server-only context that they are executed in.
|
||||
|
||||
| Local Option | Description |
|
||||
| -------------------- | ------------ |
|
||||
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
|
||||
| `data` | The data to use within the operation. Required for `create`, `update`. |
|
||||
| `depth` | [Control auto-population](/docs/getting-started/concepts#depth) of nested relationship and upload fields. |
|
||||
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
|
||||
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
|
||||
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
|
||||
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
|
||||
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
|
||||
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
|
||||
| Local Option | Description |
|
||||
| ------------------ | -------------------------------------------------------------------------------------------------------------------- |
|
||||
| `collection` | Required for Collection operations. Specifies the Collection slug to operate against. |
|
||||
| `data` | The data to use within the operation. Required for `create`, `update`. |
|
||||
| `depth` | [Control auto-population](/docs/getting-started/concepts#depth) of nested relationship and upload fields. |
|
||||
| `locale` | Specify [locale](/docs/configuration/localization) for any returned documents. |
|
||||
| `fallbackLocale` | Specify a [fallback locale](/docs/configuration/localization) to use for any returned documents. |
|
||||
| `overrideAccess` | Skip access control. By default, this property is set to true within all Local API operations. |
|
||||
| `user` | If you set `overrideAccess` to `false`, you can pass a user to use against the access control checks. |
|
||||
| `showHiddenFields` | Opt-in to receiving hidden fields. By default, they are hidden from returned documents in accordance to your config. |
|
||||
| `pagination` | Set to false to return all documents and avoid querying for document counts. |
|
||||
|
||||
*There are more options available on an operation by operation basis outlined below.*
|
||||
_There are more options available on an operation by operation basis outlined below._
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong><br/>
|
||||
By default, all access control checks are disabled in the Local API, but you can re-enable them if you'd like, as well as pass a specific user to run the operation with.
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
By default, all access control checks are disabled in the Local API, but you
|
||||
can re-enable them if you'd like, as well as pass a specific user to run the
|
||||
operation with.
|
||||
</Banner>
|
||||
|
||||
## Collections
|
||||
@@ -84,12 +97,13 @@ The following Collection operations are available through the Local API:
|
||||
```js
|
||||
// The created Post document is returned
|
||||
const post = await payload.create({
|
||||
collection: 'posts', // required
|
||||
data: { // required
|
||||
title: 'sure',
|
||||
description: 'maybe',
|
||||
collection: "posts", // required
|
||||
data: {
|
||||
// required
|
||||
title: "sure",
|
||||
description: "maybe",
|
||||
},
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUserDoc,
|
||||
overrideAccess: true,
|
||||
@@ -102,12 +116,12 @@ const post = await payload.create({
|
||||
// If your collection supports uploads, you can upload
|
||||
// a file directly through the Local API by providing
|
||||
// its full, absolute file path.
|
||||
filePath: path.resolve(__dirname, './path-to-image.jpg'),
|
||||
filePath: path.resolve(__dirname, "./path-to-image.jpg"),
|
||||
|
||||
// Alternatively, you can directly pass a File,
|
||||
// if file is provided, filePath will be omitted
|
||||
file: uploadedFile,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Find
|
||||
@@ -116,18 +130,18 @@ const post = await payload.create({
|
||||
// Result will be a paginated set of Posts.
|
||||
// See /docs/queries/pagination for more.
|
||||
const result = await payload.find({
|
||||
collection: 'posts', // required
|
||||
collection: "posts", // required
|
||||
depth: 2,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
where: {}, // pass a `where` query here
|
||||
sort: '-title',
|
||||
locale: 'en',
|
||||
sort: "-title",
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Find by ID
|
||||
@@ -135,30 +149,31 @@ const result = await payload.find({
|
||||
```js
|
||||
// Result will be a Post document.
|
||||
const result = await payload.findByID({
|
||||
collection: 'posts', // required
|
||||
id: '507f1f77bcf86cd799439011', // required
|
||||
collection: "posts", // required
|
||||
id: "507f1f77bcf86cd799439011", // required
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Update
|
||||
#### Update by ID
|
||||
|
||||
```js
|
||||
// Result will be the updated Post document.
|
||||
const result = await payload.update({
|
||||
collection: 'posts', // required
|
||||
id: '507f1f77bcf86cd799439011', // required
|
||||
data: { // required
|
||||
title: 'sure',
|
||||
description: 'maybe',
|
||||
collection: "posts", // required
|
||||
id: "507f1f77bcf86cd799439011", // required
|
||||
data: {
|
||||
// required
|
||||
title: "sure",
|
||||
description: "maybe",
|
||||
},
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
@@ -167,13 +182,51 @@ const result = await payload.update({
|
||||
// If your collection supports uploads, you can upload
|
||||
// a file directly through the Local API by providing
|
||||
// its full, absolute file path.
|
||||
filePath: path.resolve(__dirname, './path-to-image.jpg'),
|
||||
filePath: path.resolve(__dirname, "./path-to-image.jpg"),
|
||||
|
||||
// If you are uploading a file and would like to replace
|
||||
// the existing file instead of generating a new filename,
|
||||
// you can set the following property to `true`
|
||||
overwriteExistingFiles: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Update Many
|
||||
|
||||
```js
|
||||
// Result will be an object with:
|
||||
// {
|
||||
// docs: [], // each document that was updated
|
||||
// errors: [], // each error also includes the id of the document
|
||||
// }
|
||||
const result = await payload.update({
|
||||
collection: "posts", // required
|
||||
where: {
|
||||
// required
|
||||
fieldName: { equals: "value" },
|
||||
},
|
||||
data: {
|
||||
// required
|
||||
title: "sure",
|
||||
description: "maybe",
|
||||
},
|
||||
depth: 0,
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
|
||||
// If your collection supports uploads, you can upload
|
||||
// a file directly through the Local API by providing
|
||||
// its full, absolute file path.
|
||||
filePath: path.resolve(__dirname, "./path-to-image.jpg"),
|
||||
|
||||
// If you are uploading a file and would like to replace
|
||||
// the existing file instead of generating a new filename,
|
||||
// you can set the following property to `true`
|
||||
overwriteExistingFiles: true,
|
||||
});
|
||||
```
|
||||
|
||||
#### Delete
|
||||
@@ -181,15 +234,38 @@ const result = await payload.update({
|
||||
```js
|
||||
// Result will be the now-deleted Post document.
|
||||
const result = await payload.delete({
|
||||
collection: 'posts', // required
|
||||
id: '507f1f77bcf86cd799439011', // required
|
||||
collection: "posts", // required
|
||||
id: "507f1f77bcf86cd799439011", // required
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Delete Many
|
||||
|
||||
```js
|
||||
// Result will be an object with:
|
||||
// {
|
||||
// docs: [], // each document that is now deleted
|
||||
// errors: [], // any errors that occurred, including the id of the errored on document
|
||||
// }
|
||||
const result = await payload.delete({
|
||||
collection: "posts", // required
|
||||
where: {
|
||||
// required
|
||||
fieldName: { equals: "value" },
|
||||
},
|
||||
depth: 0,
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
});
|
||||
```
|
||||
|
||||
## Auth Operations
|
||||
@@ -207,19 +283,20 @@ If a collection has [`Authentication`](/docs/authentication/overview) enabled, a
|
||||
// }
|
||||
|
||||
const result = await payload.login({
|
||||
collection: 'users', // required
|
||||
data: { // required
|
||||
email: 'dev@payloadcms.com',
|
||||
password: 'rip',
|
||||
collection: "users", // required
|
||||
data: {
|
||||
// required
|
||||
email: "dev@payloadcms.com",
|
||||
password: "rip",
|
||||
},
|
||||
req: req, // pass an Express `req` which will be provided to all hooks
|
||||
res: res, // used to automatically set an HTTP-only auth cookie
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Forgot Password
|
||||
@@ -227,12 +304,13 @@ const result = await payload.login({
|
||||
```js
|
||||
// Returned token will allow for a password reset
|
||||
const token = await payload.forgotPassword({
|
||||
collection: 'users', // required
|
||||
data: { // required
|
||||
email: 'dev@payloadcms.com',
|
||||
collection: "users", // required
|
||||
data: {
|
||||
// required
|
||||
email: "dev@payloadcms.com",
|
||||
},
|
||||
req: req, // pass an Express `req` which will be provided to all hooks
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Reset Password
|
||||
@@ -244,13 +322,14 @@ const token = await payload.forgotPassword({
|
||||
// user: { ... } // the user document that just logged in
|
||||
// }
|
||||
const result = await payload.forgotPassword({
|
||||
collection: 'users', // required
|
||||
data: { // required
|
||||
token: 'afh3o2jf2p3f...', // the token generated from the forgotPassword operation
|
||||
collection: "users", // required
|
||||
data: {
|
||||
// required
|
||||
token: "afh3o2jf2p3f...", // the token generated from the forgotPassword operation
|
||||
},
|
||||
req: req, // pass an Express `req` which will be provided to all hooks
|
||||
res: res, // used to automatically set an HTTP-only auth cookie
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Unlock
|
||||
@@ -258,13 +337,14 @@ const result = await payload.forgotPassword({
|
||||
```js
|
||||
// Returned result will be a boolean representing success or failure
|
||||
const result = await payload.unlock({
|
||||
collection: 'users', // required
|
||||
data: { // required
|
||||
email: 'dev@payloadcms.com',
|
||||
collection: "users", // required
|
||||
data: {
|
||||
// required
|
||||
email: "dev@payloadcms.com",
|
||||
},
|
||||
req: req, // pass an Express `req` which will be provided to all hooks
|
||||
overrideAccess: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Verify
|
||||
@@ -272,9 +352,9 @@ const result = await payload.unlock({
|
||||
```js
|
||||
// Returned result will be a boolean representing success or failure
|
||||
const result = await payload.verify({
|
||||
collection: 'users', // required
|
||||
token: 'afh3o2jf2p3f...', // the token saved on the user as `_verificationToken`
|
||||
})
|
||||
collection: "users", // required
|
||||
token: "afh3o2jf2p3f...", // the token saved on the user as `_verificationToken`
|
||||
});
|
||||
```
|
||||
|
||||
## Globals
|
||||
@@ -286,14 +366,14 @@ The following Global operations are available through the Local API:
|
||||
```js
|
||||
// Result will be the Header Global.
|
||||
const result = await payload.findGlobal({
|
||||
slug: 'header', // required
|
||||
slug: "header", // required
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Update
|
||||
@@ -301,44 +381,79 @@ const result = await payload.findGlobal({
|
||||
```js
|
||||
// Result will be the updated Header Global.
|
||||
const result = await payload.updateGlobal({
|
||||
slug: 'header', // required
|
||||
data: { // required
|
||||
slug: "header", // required
|
||||
data: {
|
||||
// required
|
||||
nav: [
|
||||
{
|
||||
url: 'https://google.com',
|
||||
url: "https://google.com",
|
||||
},
|
||||
{
|
||||
url: 'https://payloadcms.com',
|
||||
url: "https://payloadcms.com",
|
||||
},
|
||||
],
|
||||
},
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
## Example Script using Local API
|
||||
|
||||
The Local API is especially useful for running scripts
|
||||
|
||||
```ts
|
||||
import payload from "payload";
|
||||
import path from "path";
|
||||
import dotenv from "dotenv";
|
||||
|
||||
dotenv.config({
|
||||
path: path.resolve(__dirname, "../.env"),
|
||||
});
|
||||
|
||||
const { PAYLOAD_SECRET, MONGODB_URI } = process.env;
|
||||
|
||||
const doAction = async (): Promise<void> => {
|
||||
await payload.init({
|
||||
secret: PAYLOAD_SECRET,
|
||||
mongoURL: MONGODB_URI,
|
||||
local: true, // Enables local mode, doesn't spin up a server or frontend
|
||||
});
|
||||
|
||||
// Perform any Local API operations here
|
||||
await payload.find({
|
||||
collection: "posts",
|
||||
// where: {} // optional
|
||||
});
|
||||
|
||||
await payload.create({
|
||||
collection: "posts",
|
||||
data: {},
|
||||
});
|
||||
};
|
||||
|
||||
doAction();
|
||||
```
|
||||
|
||||
## TypeScript
|
||||
|
||||
Local API calls also support passing in a generic. This is especially useful if you generate your TS types using a [generate types script](/docs/typescript/generating-types).
|
||||
Local API calls will automatically infer your [generated types](/docs/typescript/generating-types).
|
||||
|
||||
Here is an example of usage:
|
||||
|
||||
```ts
|
||||
// Our generated types
|
||||
import { Post } from './payload-types'
|
||||
|
||||
// Add Post types as generic to create function
|
||||
const post: Post = await payload.create<Post>({
|
||||
collection: 'posts',
|
||||
// Properly inferred as `Post` type
|
||||
const post = await payload.create({
|
||||
collection: "posts",
|
||||
|
||||
// Data will now be typed as Post and give you type hints
|
||||
data: {
|
||||
title: 'my title',
|
||||
description: 'my description',
|
||||
title: "my title",
|
||||
description: "my description",
|
||||
},
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
@@ -12,9 +12,15 @@ keywords: deployment, production, config, configuration, documentation, Content
|
||||
|
||||
There are many ways to deploy Payload to a production environment. When evaluating how you will deploy Payload, you need to consider these main aspects:
|
||||
|
||||
1. [Basics](#basics)
|
||||
1. [Security](#security)
|
||||
1. [Your MongoDB](#mongodb)
|
||||
1. [Permanent File Storage](#file-storage)
|
||||
1. [Docker](#docker)
|
||||
|
||||
## Basics
|
||||
|
||||
In order for Payload to run, it requires both the server code and the built admin panel. These will be the `dist` and `build` directories by default. If you've used `create-payload-app` to create your project, executing the `build` npm script will build both and output these directories.
|
||||
|
||||
## Security
|
||||
|
||||
@@ -37,15 +43,17 @@ Because _**you**_ are in complete control of who can do what with your data, you
|
||||
Before running in Production, you need to have built a production-ready copy of the Payload Admin panel. To do this, Payload provides the `build` NPM script. You can use it by adding a `script` to your `package.json` file like this:
|
||||
|
||||
`package.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "project-name-here",
|
||||
"scripts": {
|
||||
"build": "payload build",
|
||||
"build": "payload build"
|
||||
},
|
||||
"dependencies": {
|
||||
// your dependencies
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Then, to build Payload, you would run `npm run build` in your project folder. A production-ready Admin bundle will be created in the `build` directory.
|
||||
@@ -64,6 +72,8 @@ Payload comes with a robust set of built-in anti-abuse measures, such as locking
|
||||
|
||||
## MongoDB
|
||||
|
||||
Payload can be used with any MongoDB compatible database including AWS DocumentDB or Azure Cosmos DB.
|
||||
|
||||
##### Managing MongoDB yourself
|
||||
|
||||
If you are using a [persistent filesystem-based cloud host](#persistent-vs-ephemeral-filesystems) such as a [DigitalOcean Droplet](https://www.digitalocean.com/products/droplets/) or an [Amazon EC2](https://aws.amazon.com/ec2/?ec2-whats-new.sort-by=item.additionalFields.postDateTime&ec2-whats-new.sort-order=desc) server, you might opt to install MongoDB directly on that server itself so that Node can communicate with it locally. With this approach, you can benefit from faster response times, but scaling can become more involved as your app's user base grows.
|
||||
@@ -73,10 +83,18 @@ If you are using a [persistent filesystem-based cloud host](#persistent-vs-ephem
|
||||
Alternatively, you can rely on a third-party MongoDB host such as [MongoDB Atlas](https://www.mongodb.com/). With Atlas or a similar cloud provider, you can trust them to take care of your database's availability, security, redundancy, and backups.
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Note regarding Azure Cosmos:</strong><br/>
|
||||
When using Azure Cosmos, MongoDB requires an index on any field being sorted on. To make this easier, see the <a href="/docs/configuration/overview">indexSortableFields</a> configuration option.
|
||||
<strong>Note:</strong><br />
|
||||
If versions are enabled and a collection has many documents you may need a minimum of an m10 mongoDB atlas cluster if you reach a sorting `exceeded memory limit` error to view a collection list in the admin UI. The limitations of the m2 and m5 tier clusters are here: [Atlas M0 (Free Cluster), M2, and M5 Limitations](https://www.mongodb.com/docs/atlas/reference/free-shared-limitations/?_ga=2.176267877.1329169847.1677683154-860992573.1647438381#operational-limitations).
|
||||
</Banner>
|
||||
|
||||
##### DocumentDB
|
||||
|
||||
When using AWS DocumentDB, you will need to configure connection options for authentication in the `mongoOptions` passed to `payload.init`. You also need to set `mongoOptions.useFacet` to `false` to disable use of the unsupported `$facet` aggregation.
|
||||
|
||||
##### CosmosDB
|
||||
|
||||
When using Azure Cosmos DB, an index is needed for any field you may want to sort on. To add the sort index for all fields that may be sorted in the admin UI use the <a href="/docs/configuration/overview">indexSortableFields</a> configuration option.
|
||||
|
||||
## File storage
|
||||
|
||||
If you are using Payload to [manage file uploads](/docs/upload/overview), you need to consider where your uploaded files will be permanently stored. If you do not use Payload for file uploads, then this section does not impact your app whatsoever.
|
||||
@@ -100,7 +118,7 @@ Alternatively, persistent filesystems will never delete your files and can be tr
|
||||
- Many other more traditional web hosts
|
||||
|
||||
<Banner type="error">
|
||||
<strong>Warning:</strong><br/>
|
||||
<strong>Warning:</strong><br />
|
||||
If you rely on Payload's <strong>Upload</strong> functionality, make sure you either use a host with a persistent filesystem or have an integration with a third-party file host like Amazon S3.
|
||||
</Banner>
|
||||
|
||||
@@ -108,7 +126,7 @@ Alternatively, persistent filesystems will never delete your files and can be tr
|
||||
|
||||
If you don't use Payload's `upload` functionality, you can go ahead and use Heroku or similar platform easily. Everything will work exactly as you want it to.
|
||||
|
||||
But, if you do, and you still want to use an ephemeral filesystem provider, you can write a hook-based solution to *copy* the files your users upload to a more permanent storage solution like Amazon S3 or DigitalOcean Spaces.
|
||||
But, if you do, and you still want to use an ephemeral filesystem provider, you can write a hook-based solution to _copy_ the files your users upload to a more permanent storage solution like Amazon S3 or DigitalOcean Spaces.
|
||||
|
||||
**To automatically send uploaded files to S3 or similar, you could:**
|
||||
|
||||
@@ -128,3 +146,76 @@ DigitalOcean provides extremely helpful documentation that can walk you through
|
||||
1. [Install and secure MongoDB](https://www.digitalocean.com/community/tutorials/how-to-install-mongodb-on-ubuntu-20-04)
|
||||
1. [Create a new MongoDB and user](https://medium.com/@mhagemann/how-to-add-a-new-user-to-a-mongodb-database-d896776b5362)
|
||||
1. [Set up Node for production](https://www.digitalocean.com/community/tutorials/how-to-set-up-a-node-js-application-for-production-on-ubuntu-20-04)
|
||||
|
||||
## 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.
|
||||
|
||||
```dockerfile
|
||||
FROM node:18-alpine as base
|
||||
|
||||
FROM base as builder
|
||||
|
||||
WORKDIR /home/node
|
||||
COPY package*.json ./
|
||||
|
||||
COPY . .
|
||||
RUN yarn install
|
||||
RUN yarn build
|
||||
|
||||
FROM base as runtime
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /home/node
|
||||
COPY package*.json ./
|
||||
|
||||
RUN yarn install --production
|
||||
COPY --from=builder /home/node/dist ./dist
|
||||
COPY --from=builder /home/node/build ./build
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "dist/server.js"]
|
||||
```
|
||||
|
||||
## Docker Compose
|
||||
|
||||
Here is an example of a docker-compose.yml file that can be used for development
|
||||
|
||||
```yml
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
payload:
|
||||
image: node:18-alpine
|
||||
ports:
|
||||
- "3000:3000"
|
||||
volumes:
|
||||
- .:/home/node/app
|
||||
- node_modules:/home/node/app/node_modules
|
||||
working_dir: /home/node/app/
|
||||
command: sh -c "yarn install && yarn dev"
|
||||
depends_on:
|
||||
- mongo
|
||||
environment:
|
||||
MONGODB_URI: mongodb://mongo:27017/payload
|
||||
PORT: 3000
|
||||
NODE_ENV: development
|
||||
PAYLOAD_SECRET: TESTING
|
||||
|
||||
mongo:
|
||||
image: mongo:latest
|
||||
ports:
|
||||
- "27017:27017"
|
||||
command:
|
||||
- --storageEngine=wiredTiger
|
||||
volumes:
|
||||
- data:/data/db
|
||||
logging:
|
||||
driver: none
|
||||
|
||||
volumes:
|
||||
data:
|
||||
node_modules:
|
||||
```
|
||||
|
||||
@@ -9,7 +9,7 @@ keywords: query, documents, overview, documentation, Content Management System,
|
||||
Payload provides an extremely granular querying language through all APIs. Each API takes the same syntax and fully supports all options.
|
||||
|
||||
<Banner>
|
||||
<strong>Here, "querying" relates to filtering or searching through documents within a Collection.</strong> You can build queries to pass to Find operations as well as to <a href="/docs/access-control/overview">restrict which documents certain users can access</a> via access control functions.
|
||||
<strong>Here, "querying" relates to filtering or searching through documents within a Collection.</strong> You can build queries to pass to Find operations as well as to [restrict which documents certain users can access](/docs/access-control/overview) via access control functions.
|
||||
</Banner>
|
||||
|
||||
### Simple queries
|
||||
@@ -17,94 +17,107 @@ Payload provides an extremely granular querying language through all APIs. Each
|
||||
For example, say you have a collection as follows:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
const Post: CollectionConfig = {
|
||||
slug: 'posts',
|
||||
export const Post: CollectionConfig = {
|
||||
slug: "posts",
|
||||
fields: [
|
||||
{
|
||||
name: 'color',
|
||||
type: 'select',
|
||||
options: [
|
||||
'mint',
|
||||
'dark-gray',
|
||||
'white',
|
||||
],
|
||||
name: "color",
|
||||
type: "select",
|
||||
options: ["mint", "dark-gray", "white"],
|
||||
},
|
||||
{
|
||||
name: 'featured',
|
||||
type: 'checkbox',
|
||||
}
|
||||
]
|
||||
}
|
||||
name: "featured",
|
||||
type: "checkbox",
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
You may eventually have a lot of documents within this Collection. If you wanted to find only documents with `color` equal to `mint`, you could write a query as follows:
|
||||
|
||||
```js
|
||||
const query = {
|
||||
color: { // property name to filter on
|
||||
equals: 'mint', // operator to use and value to compare against
|
||||
color: {
|
||||
// property name to filter on
|
||||
equals: "mint", // operator to use and value to compare against
|
||||
},
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
The above example demonstrates a simple query but you can get much more complex.
|
||||
|
||||
### Operators
|
||||
|
||||
| Operator | Description |
|
||||
| -------------------- | ------------ |
|
||||
| `equals` | The value must be exactly equal. |
|
||||
| `not_equals` | The query will return all documents where the value is not equal. |
|
||||
| `greater_than` | For numeric or date-based fields. |
|
||||
| `greater_than_equal` | For numeric or date-based fields. |
|
||||
| `less_than` | For numeric or date-based fields. |
|
||||
| `less_than_equal` | For numeric or date-based fields. |
|
||||
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
|
||||
| `contains` | Must contain the value entered, case-insensitive. |
|
||||
| `in` | The value must be found within the provided comma-delimited list of values. |
|
||||
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
|
||||
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
|
||||
| Operator | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `equals` | The value must be exactly equal. |
|
||||
| `not_equals` | The query will return all documents where the value is not equal. |
|
||||
| `greater_than` | For numeric or date-based fields. |
|
||||
| `greater_than_equal` | For numeric or date-based fields. |
|
||||
| `less_than` | For numeric or date-based fields. |
|
||||
| `less_than_equal` | For numeric or date-based fields. |
|
||||
| `like` | Case-insensitive string must be present. If string of words, all words must be present, in any order. |
|
||||
| `contains` | Must contain the value entered, case-insensitive. |
|
||||
| `in` | The value must be found within the provided comma-delimited list of values. |
|
||||
| `not_in` | The value must NOT be within the provided comma-delimited list of values. |
|
||||
| `all` | The value must contain all values provided in the comma-delimited list. |
|
||||
| `exists` | Only return documents where the value either exists (`true`) or does not exist (`false`). |
|
||||
| `near` | For distance related to a [point field](/docs/fields/point) comma separated as `<longitude>, <latitude>, <maxDistance in meters (nullable)>, <minDistance in meters (nullable)>`. |
|
||||
|
||||
<Banner type="success">
|
||||
<strong>Tip</strong>:<br/>
|
||||
<strong>Tip</strong>:<br />
|
||||
If you know your users will be querying on certain fields a lot, you can add <strong>index: true</strong> to a field's config which will speed up searches using that field immensely.
|
||||
</Banner>
|
||||
|
||||
### And / Or Logic
|
||||
|
||||
In addition to defining simple queries, you can join multiple queries together using simple AND / OR logic. Let's take the above `Post` collection for example and write a more complex query usnig AND / OR:
|
||||
In addition to defining simple queries, you can join multiple queries together using simple AND / OR logic. Let's take the above `Post` collection for example and write a more complex query using AND / OR:
|
||||
|
||||
```js
|
||||
const query = {
|
||||
or: [ // array of OR conditions
|
||||
or: [
|
||||
// array of OR conditions
|
||||
{
|
||||
color: {
|
||||
equals: 'mint',
|
||||
equals: "mint",
|
||||
},
|
||||
},
|
||||
{
|
||||
and: [ // nested array of AND conditions
|
||||
and: [
|
||||
// nested array of AND conditions
|
||||
{
|
||||
color: {
|
||||
equals: 'white',
|
||||
}
|
||||
equals: "white",
|
||||
},
|
||||
},
|
||||
{
|
||||
featured: {
|
||||
equals: false,
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
Written in plain English, if the above query were passed to a `find` operation, it would translate to finding posts where either the `color` is `mint` OR the `color` is `white` AND `featured` is set to false.
|
||||
|
||||
### Nested properties
|
||||
|
||||
When working with nested properties, which can happen when using relational fields, it is possible to use the dot notation to access the nested property. For example, when working with a `Song` collection that has a `artists` field which is related to an `Artists` collection using the `name: 'artists'`. You can access a property within the collection `Artists` like so:
|
||||
|
||||
```js
|
||||
const query = {
|
||||
"artists.featured": {
|
||||
// nested property name to filter on
|
||||
exists: true, // operator to use and boolean value that needs to be true
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### GraphQL Find Queries
|
||||
|
||||
All GraphQL `find` queries support the `where` argument, which accepts queries exactly as detailed above.
|
||||
@@ -135,24 +148,29 @@ This one isn't too bad, but more complex queries get unavoidably more difficult
|
||||
**For example, using fetch:**
|
||||
|
||||
```js
|
||||
import qs from 'qs';
|
||||
import qs from "qs";
|
||||
|
||||
const query = {
|
||||
color: {
|
||||
equals: 'mint',
|
||||
equals: "mint",
|
||||
},
|
||||
// This query could be much more complex
|
||||
// and QS would handle it beautifully
|
||||
}
|
||||
};
|
||||
|
||||
const getPosts = async () => {
|
||||
const stringifiedQuery = qs.stringify({
|
||||
where: query // ensure that `qs` adds the `where` property, too!
|
||||
}, { addQueryPrefix: true });
|
||||
const stringifiedQuery = qs.stringify(
|
||||
{
|
||||
where: query, // ensure that `qs` adds the `where` property, too!
|
||||
},
|
||||
{ addQueryPrefix: true }
|
||||
);
|
||||
|
||||
const response = await fetch(`http://localhost:3000/api/posts${stringifiedQuery}`);
|
||||
const response = await fetch(
|
||||
`http://localhost:3000/api/posts${stringifiedQuery}`
|
||||
);
|
||||
// Continue to handle the response below...
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Local API Queries
|
||||
@@ -162,19 +180,18 @@ The Local API's `find` operation accepts an object exactly how you write it. For
|
||||
```js
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
collection: "posts",
|
||||
where: {
|
||||
color: {
|
||||
equals: 'mint',
|
||||
equals: "mint",
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
|
||||
## Sort
|
||||
|
||||
Payload `find` queries support a `sort` parameter through all APIs. Pass the `name` of a top-level field to sort by that field in ascending order. Prefix the name of the field with a minus symbol ("-") to sort in descending order.
|
||||
@@ -183,6 +200,7 @@ Payload `find` queries support a `sort` parameter through all APIs. Pass the `na
|
||||
**`https://localhost:3000/api/posts?sort=-createdAt`**
|
||||
|
||||
**GraphQL example:**
|
||||
|
||||
```
|
||||
query {
|
||||
Posts(sort: "-createdAt") {
|
||||
@@ -198,10 +216,10 @@ query {
|
||||
```js
|
||||
const getPosts = async () => {
|
||||
const posts = await payload.find({
|
||||
collection: 'posts',
|
||||
sort: '-createdAt',
|
||||
collection: "posts",
|
||||
sort: "-createdAt",
|
||||
});
|
||||
|
||||
return posts;
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
@@ -7,7 +7,8 @@ keywords: rest, api, documentation, Content Management System, cms, headless, ja
|
||||
---
|
||||
|
||||
<Banner>
|
||||
A fully functional REST API is automatically generated from your Collection and Global configs.
|
||||
A fully functional REST API is automatically generated from your Collection
|
||||
and Global configs.
|
||||
</Banner>
|
||||
|
||||
All Payload API routes are mounted prefixed to your config's `routes.api` URL segment (default: `/api`).
|
||||
@@ -26,56 +27,534 @@ Note: Collection slugs must be formatted in kebab-case
|
||||
|
||||
**All CRUD operations are exposed as follows:**
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | --------------------------- | -------------------------------------- |
|
||||
| `GET` | `/api/{collection-slug}` | Find paginated documents |
|
||||
| `GET` | `/api/{collection-slug}/:id` | Find a specific document by ID |
|
||||
| `POST` | `/api/{collection-slug}` | Create a new document |
|
||||
| `PATCH` | `/api/{collection-slug}/:id` | Update a document by ID |
|
||||
| `DELETE` | `/api/{collection-slug}/:id` | Delete an existing document by ID |
|
||||
<RestExamples
|
||||
data={[
|
||||
{
|
||||
operation: "Find",
|
||||
method: "GET",
|
||||
path: "/api/{collection-slug}",
|
||||
description: "Find paginated documents",
|
||||
example: {
|
||||
slug: "getCollection",
|
||||
req: true,
|
||||
res: {
|
||||
paginated: true,
|
||||
data: {
|
||||
id: "644a5c24cc1383022535fc7c",
|
||||
title: "Home",
|
||||
content: "REST API examples",
|
||||
slug: "home",
|
||||
createdAt: "2023-04-27T11:27:32.419Z",
|
||||
updatedAt: "2023-04-27T11:27:32.419Z",
|
||||
},
|
||||
},
|
||||
drawerContent: (
|
||||
<>
|
||||
<h6>Additional <code>find</code> query parameters</h6>
|
||||
The <code>find</code> endpoint supports the following additional query parameters:
|
||||
<ul>
|
||||
<li>
|
||||
<a href="/docs/queries/overview#sort">sort</a> - sort by field
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docs/queries/overview">where</a> - pass a where query to constrain returned
|
||||
documents
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docs/queries/pagination#pagination-controls">limit</a> - limit the returned
|
||||
documents to a certain number
|
||||
</li>
|
||||
<li>
|
||||
<a href="/docs/queries/pagination#pagination-controls">page</a> - get a specific page of
|
||||
documents
|
||||
</li>
|
||||
</ul>
|
||||
</>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Find By ID",
|
||||
method: "GET",
|
||||
path: "/api/{collection-slug}/{id}",
|
||||
description: "Find a specific document by ID",
|
||||
example: {
|
||||
slug: "findByID",
|
||||
req: true,
|
||||
res: {
|
||||
id: "644a5c24cc1383022535fc7c",
|
||||
title: "Home",
|
||||
content: "REST API examples",
|
||||
slug: "home",
|
||||
createdAt: "2023-04-27T11:27:32.419Z",
|
||||
updatedAt: "2023-04-27T11:27:32.419Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Create",
|
||||
method: "POST",
|
||||
path: "/api/{collection-slug}",
|
||||
description: "Create a new document",
|
||||
example: {
|
||||
slug: "createDocument",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
body: {
|
||||
title: "New page",
|
||||
content: "Here is some content",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Page successfully created.",
|
||||
doc: {
|
||||
id: "644ba34c86359864f9535932",
|
||||
title: "New page",
|
||||
content: "Here is some content",
|
||||
slug: "new-page",
|
||||
createdAt: "2023-04-28T10:43:24.466Z",
|
||||
updatedAt: "2023-04-28T10:43:24.466Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Update",
|
||||
method: "PATCH",
|
||||
path: "/api/{collection-slug}",
|
||||
description: "Update all documents matching the where query",
|
||||
example: {
|
||||
slug: "updateDocument",
|
||||
req: {
|
||||
credentials: true,
|
||||
query: true,
|
||||
headers: true,
|
||||
body: {
|
||||
title: "I have been updated!",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
docs: [
|
||||
{
|
||||
id: "644ba34c86359864f9535932",
|
||||
title: "I have been updated!",
|
||||
content: "Here is some content",
|
||||
slug: "new-page",
|
||||
createdAt: "2023-04-28T10:43:24.466Z",
|
||||
updatedAt: "2023-04-28T10:45:23.724Z",
|
||||
},
|
||||
],
|
||||
errors: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Update By ID",
|
||||
method: "PATCH",
|
||||
path: "/api/{collection-slug}/{id}",
|
||||
description: "Update a document by ID",
|
||||
example: {
|
||||
slug: "updateDocumentByID",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
body: {
|
||||
title: "I have been updated by ID!",
|
||||
categories: "example-uuid",
|
||||
tags: {
|
||||
relationTo: "location",
|
||||
value: "another-example-uuid",
|
||||
},
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Updated successfully.",
|
||||
doc: {
|
||||
id: "644a5c24cc1383022535fc7c",
|
||||
title: "I have been updated by ID!",
|
||||
content: "REST API examples",
|
||||
categories: {
|
||||
id: "example-uuid",
|
||||
name: "Test Category",
|
||||
},
|
||||
tags: [
|
||||
{
|
||||
relationTo: "location",
|
||||
value: {
|
||||
id: "another-example-uuid",
|
||||
name: "Test Location",
|
||||
},
|
||||
},
|
||||
],
|
||||
slug: "home",
|
||||
createdAt: "2023-04-27T11:27:32.419Z",
|
||||
updatedAt: "2023-04-28T10:47:59.259Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Delete",
|
||||
method: "DELETE",
|
||||
path: "/api/{collection-slug}",
|
||||
description: "Delete all documents matching the where query",
|
||||
example: {
|
||||
slug: "deleteDocuments",
|
||||
req: {
|
||||
credentials: true,
|
||||
query: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
docs: [
|
||||
{
|
||||
id: "644ba4cf86359864f953594b",
|
||||
title: "New page",
|
||||
content: "Here is some content",
|
||||
slug: "new-page",
|
||||
createdAt: "2023-04-28T10:49:51.359Z",
|
||||
updatedAt: "2023-04-28T10:49:51.359Z",
|
||||
},
|
||||
],
|
||||
errors: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Delete by ID",
|
||||
method: "DELETE",
|
||||
path: "/api/{collection-slug}/{id}",
|
||||
description: "Delete an existing document by ID",
|
||||
example: {
|
||||
slug: "deleteByID",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
id: "644ba51786359864f9535954",
|
||||
title: "New page",
|
||||
content: "Here is some content",
|
||||
slug: "new-page",
|
||||
createdAt: "2023-04-28T10:51:03.028Z",
|
||||
updatedAt: "2023-04-28T10:51:03.028Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
##### Additional `find` query parameters
|
||||
|
||||
The `find` endpoint supports the following additional query parameters:
|
||||
|
||||
- [sort](/docs/queries/overview#sort) - sort by field
|
||||
- [where](/docs/queries/overview) - pass a `where` query to constrain returned documents
|
||||
- [limit](/docs/queries/pagination#pagination-controls) - limit the returned documents to a certain number
|
||||
- [page](/docs/queries/pagination#pagination-controls) - get a specific page of documents
|
||||
]}
|
||||
/>
|
||||
|
||||
## Auth Operations
|
||||
|
||||
Auth enabled collections are also given the following endpoints:
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | --------------------------- | ----------- |
|
||||
| `POST` | `/api/{collection-slug}/verify/:token` | [Email verification](/docs/authentication/operations#verify-by-email), if enabled. |
|
||||
| `POST` | `/api/{collection-slug}/unlock` | [Unlock a user's account](/docs/authentication/operations#unlock), if enabled. |
|
||||
| `POST` | `/api/{collection-slug}/login` | [Logs in](/docs/authentication/operations#login) a user with email / password. |
|
||||
| `POST` | `/api/{collection-slug}/logout` | [Logs out](/docs/authentication/operations#logout) a user. |
|
||||
| `POST` | `/api/{collection-slug}/refresh-token` | [Refreshes a token](/docs/authentication/operations#refresh) that has not yet expired. |
|
||||
| `GET` | `/api/{collection-slug}/me` | [Returns the currently logged in user with token](/docs/authentication/operations#me). |
|
||||
| `POST` | `/api/{collection-slug}/forgot-password` | [Password reset workflow](/docs/authentication/operations#forgot-password) entry point. |
|
||||
| `POST` | `/api/{collection-slug}/reset-password` | [To reset the user's password](/docs/authentication/operations#reset-password). |
|
||||
<RestExamples
|
||||
data={[
|
||||
{
|
||||
operation: "Login",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/login",
|
||||
description: "Logs in a user with email / password",
|
||||
example: {
|
||||
slug: "login",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
body: {
|
||||
email: "dev@payloadcms.com",
|
||||
password: "password",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Auth Passed",
|
||||
user: {
|
||||
id: "644b8453cd20c7857da5a9b0",
|
||||
email: "dev@payloadcms.com",
|
||||
_verified: true,
|
||||
createdAt: "2023-04-28T08:31:15.788Z",
|
||||
updatedAt: "2023-04-28T11:11:03.716Z",
|
||||
},
|
||||
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
exp: 1682689147,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Logout",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/logout",
|
||||
description: "Logs out a user",
|
||||
example: {
|
||||
slug: "logout",
|
||||
req: {
|
||||
headers: true,
|
||||
credentials: true,
|
||||
},
|
||||
res: {
|
||||
message: "You have been logged out successfully.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Unlock",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/unlock",
|
||||
description: "Unlock a user account",
|
||||
example: {
|
||||
slug: "unlockCollection",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
body: {
|
||||
email: "dev@payloadcms.com",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Success",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Refresh",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/refresh-token",
|
||||
description: "Refreshes a token that has not yet expired",
|
||||
example: {
|
||||
slug: "refreshToken",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
message: "Token refresh successful",
|
||||
refreshedToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
exp: 1682689362,
|
||||
user: {
|
||||
email: "dev@payloadcms.com",
|
||||
id: "644b8453cd20c7857da5a9b0",
|
||||
collection: "users",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Verify User",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/verify/{token}",
|
||||
description: "User verification",
|
||||
example: {
|
||||
slug: "verifyUser",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
message: "Email verified successfully.",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Current User",
|
||||
method: "GET",
|
||||
path: "/api/{user-collection}/me",
|
||||
description: "Returns the currently logged in user with token",
|
||||
example: {
|
||||
slug: "currentUser",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
user: {
|
||||
id: "644b8453cd20c7857da5a9b0",
|
||||
email: "dev@payloadcms.com",
|
||||
_verified: true,
|
||||
createdAt: "2023-04-28T08:31:15.788Z",
|
||||
updatedAt: "2023-04-28T11:45:23.926Z",
|
||||
_strategy: "local-jwt",
|
||||
},
|
||||
collection: "users",
|
||||
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
exp: 1682689523,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Forgot Password",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/forgot-password",
|
||||
description: "Password reset workflow entry point",
|
||||
example: {
|
||||
slug: "forgotPassword",
|
||||
req: {
|
||||
headers: true,
|
||||
credentials: true,
|
||||
body: {
|
||||
email: "dev@payloadcms.com",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Success",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Reset Password",
|
||||
method: "POST",
|
||||
path: "/api/{user-collection}/reset-password",
|
||||
description: "Reset user password",
|
||||
example: {
|
||||
slug: "resetPassword",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
body: {
|
||||
token: "7eac3830ffcfc7f9f66c00315dabeb11575dba91",
|
||||
password: "newPassword",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Password reset successfully.",
|
||||
token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9",
|
||||
user: {
|
||||
id: "644baa473ea9538765cc30fc",
|
||||
email: "dev@payloadcms.com",
|
||||
_verified: true,
|
||||
createdAt: "2023-04-28T11:13:11.569Z",
|
||||
updatedAt: "2023-04-28T11:49:23.860Z",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
]}
|
||||
/>
|
||||
|
||||
## Globals
|
||||
|
||||
Globals cannot be created or deleted, so there are only two REST endpoints opened:
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | --------------------------- | ----------------------- |
|
||||
| `GET` | `/api/globals/{globalSlug}` | Get a global by slug |
|
||||
| `POST` | `/api/globals/{globalSlug}` | Update a global by slug |
|
||||
<RestExamples
|
||||
data={[
|
||||
{
|
||||
operation: "Get Global",
|
||||
method: "GET",
|
||||
path: "/api/globals/{global-slug}",
|
||||
description: "Get a global by slug",
|
||||
example: {
|
||||
slug: "getGlobal",
|
||||
req: {
|
||||
credentials: true,
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
announcement: "Here is an announcement!",
|
||||
globalType: "announcement",
|
||||
createdAt: "2023-04-28T08:53:56.066Z",
|
||||
updatedAt: "2023-04-28T08:53:56.066Z",
|
||||
id: "644b89a496c64a833fe579c9",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Update Global",
|
||||
method: "POST",
|
||||
path: "/api/globals/{global-slug}",
|
||||
description: "Update a global by slug",
|
||||
example: {
|
||||
slug: "updateGlobal",
|
||||
req: {
|
||||
headers: true,
|
||||
credentials: true,
|
||||
body: {
|
||||
announcement: "Paging Doctor Scrunt",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
announcement: "Paging Doctor Scrunt",
|
||||
globalType: "announcement",
|
||||
createdAt: "2023-04-28T08:53:56.066Z",
|
||||
updatedAt: "2023-04-28T08:53:56.066Z",
|
||||
id: "644b89a496c64a833fe579c9",
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
## Preferences
|
||||
|
||||
In addition to the dynamically generated endpoints above Payload also has REST endpoints to manage the admin user [preferences](/docs/admin/overview#preferences) for data specific to the authenticated user.
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | --------------------------- | ----------------------- |
|
||||
| `GET` | `/api/_preferences/{key}` | Get a preference by key |
|
||||
| `POST` | `/api/_preferences/{key}` | Create or update by key |
|
||||
| `DELETE` | `/api/_preferences/{key}` | Delete a user preference by key |
|
||||
<RestExamples
|
||||
data={[
|
||||
{
|
||||
operation: "Get Preference",
|
||||
method: "GET",
|
||||
path: "/api/_preferences/{key}",
|
||||
description: "Get a preference by key",
|
||||
example: {
|
||||
slug: "getPreference",
|
||||
req: {
|
||||
headers: true,
|
||||
credentials: true,
|
||||
},
|
||||
res: {
|
||||
_id: "644bb7a8307b3d363c6edf2c",
|
||||
key: "region",
|
||||
user: "644b8453cd20c7857da5a9b0",
|
||||
userCollection: "users",
|
||||
__v: 0,
|
||||
createdAt: "2023-04-28T12:10:16.689Z",
|
||||
updatedAt: "2023-04-28T12:10:16.689Z",
|
||||
value: "Europe/London",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Create Preference",
|
||||
method: "POST",
|
||||
path: "/api/_preferences/{key}",
|
||||
description: "Create or update a preference by key",
|
||||
example: {
|
||||
slug: "createPreference",
|
||||
req: {
|
||||
headers: true,
|
||||
credentials: true,
|
||||
body: {
|
||||
value: "Europe/London",
|
||||
},
|
||||
},
|
||||
res: {
|
||||
message: "Updated successfully.",
|
||||
doc: {
|
||||
user: "644b8453cd20c7857da5a9b0",
|
||||
key: "region",
|
||||
userCollection: "users",
|
||||
value: "Europe/London",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
operation: "Delete Preference",
|
||||
method: "DELETE",
|
||||
path: "/api/_preferences/{key}",
|
||||
description: "Delete a preference by key",
|
||||
example: {
|
||||
slug: "deletePreference",
|
||||
req: {
|
||||
headers: true,
|
||||
},
|
||||
res: {
|
||||
message: "deletedSuccessfully",
|
||||
},
|
||||
},
|
||||
},
|
||||
]}
|
||||
/>
|
||||
|
||||
## Custom Endpoints
|
||||
|
||||
@@ -83,42 +562,48 @@ Additional REST API endpoints can be added to your application by providing an a
|
||||
|
||||
Each endpoint object needs to have:
|
||||
|
||||
| Property | Description |
|
||||
| ---------- | ----------------------------------------- |
|
||||
| **`path`** | A string for the endpoint route after the collection or globals slug |
|
||||
| **`method`** | The lowercase HTTP verb to use: 'get', 'head', 'post', 'put', 'delete', 'connect' or 'options' |
|
||||
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Express](https://expressjs.com/en/guide/routing.html#route-handlers) |
|
||||
| **`root`** | When `true`, defines the endpoint on the root Express app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload config, endpoints defined on `collections` or `globals` cannot be root. |
|
||||
| Property | Description |
|
||||
| ------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`path`** | A string for the endpoint route after the collection or globals slug |
|
||||
| **`method`** | The lowercase HTTP verb to use: 'get', 'head', 'post', 'put', 'delete', 'connect' or 'options' |
|
||||
| **`handler`** | A function or array of functions to be called with **req**, **res** and **next** arguments. [Express](https://expressjs.com/en/guide/routing.html#route-handlers) |
|
||||
| **`root`** | When `true`, defines the endpoint on the root Express app, bypassing Payload handlers and the `routes.api` subpath. Note: this only applies to top-level endpoints of your Payload config, endpoints defined on `collections` or `globals` cannot be root. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
import { CollectionConfig } from "payload/types";
|
||||
|
||||
// a collection of 'orders' with an additional route for tracking details, reachable at /api/orders/:id/tracking
|
||||
const Orders: CollectionConfig = {
|
||||
slug: 'orders',
|
||||
fields: [ /* ... */ ],
|
||||
export const Orders: CollectionConfig = {
|
||||
slug: "orders",
|
||||
fields: [
|
||||
/* ... */
|
||||
],
|
||||
// highlight-start
|
||||
endpoints: [
|
||||
{
|
||||
path: '/:id/tracking',
|
||||
method: 'get',
|
||||
path: "/:id/tracking",
|
||||
method: "get",
|
||||
handler: async (req, res, next) => {
|
||||
const tracking = await getTrackingInfo(req.params.id);
|
||||
if (tracking) {
|
||||
res.status(200).send({ tracking });
|
||||
} else {
|
||||
res.status(404).send({ error: 'not found' });
|
||||
res.status(404).send({ error: "not found" });
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
],
|
||||
// highlight-end
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
<Banner>
|
||||
<strong>Note:</strong><br/>
|
||||
**req** will have the **payload** object and can be used inside your endpoint handlers for making calls like req.payload.find() that will make use of access control and hooks.
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
**req** will have the **payload** object and can be used inside your endpoint
|
||||
handlers for making calls like req.payload.find() that will make use of access
|
||||
control and hooks.
|
||||
</Banner>
|
||||
|
||||
25
docs/troubleshooting/troubleshooting.mdx
Normal file
25
docs/troubleshooting/troubleshooting.mdx
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: Troubleshooting
|
||||
label: Troubleshooting
|
||||
order: 10
|
||||
desc: Troubleshooting Common Issues in Payload
|
||||
keywords: admin, components, custom, customize, documentation, Content Management System, cms, headless, javascript, node, react, express, troubleshooting
|
||||
---
|
||||
|
||||
## Common Issues
|
||||
|
||||
### "Unauthorized, you must be logged in to make this request" when attempting to log in
|
||||
|
||||
This means that your auth cookie is not being set or accepted correctly upon logging in. To resolve heck the following settings in your Payload config:
|
||||
|
||||
- CORS - If you are using the '*', try to explicitly only allow certain domains instead including the one you have specified.
|
||||
- CSRF - Do you have this set? if so, make sure your domain is whitelisted within the csrf domains. If not, probably not the issue, but probably can't hurt to whitelist it anyway.
|
||||
- Cookie settings. If these are completely undefined, then that's fine. but if you have cookie domain set, or anything similar, make sure you don't have the domain misconfigured
|
||||
|
||||
This error likely means that the auth cookie that Payload sets after logging in successfully is being rejected because of misconfiguration.
|
||||
|
||||
To further investigate the issue:
|
||||
|
||||
- Go to the login screen. Open your inspector. Go to the Network tab.
|
||||
- Log in and then find the login request that should appear in your network panel. Click the login request.
|
||||
- The login request should have a Set-Cookie header on the response, and the cookie should be getting set successfully. If it is not, most browsers generally have a little yellow ⚠️ symbol that you can hover over to see why the cookie was rejected.
|
||||
@@ -8,7 +8,9 @@ keywords: headless cms, typescript, documentation, Content Management System, cm
|
||||
|
||||
While building your own custom functionality into Payload, like plugins, hooks, access control functions, custom routes, GraphQL queries / mutations, or anything else, you may benefit from generating your own TypeScript types dynamically from your Payload config itself.
|
||||
|
||||
Run the following command in a Payload project to generate types:
|
||||
### Types generatation script
|
||||
|
||||
Run the following command in a Payload project to generate types based on your Payload config:
|
||||
|
||||
```
|
||||
payload generate:types
|
||||
@@ -16,6 +18,46 @@ payload generate:types
|
||||
|
||||
You can run this command whenever you need to regenerate your types, and then you can use these types in your Payload code directly.
|
||||
|
||||
### Configuration
|
||||
|
||||
In order for Payload to properly infer these types when using local operations, you'll need to alias the following in your tsconfig.json file:
|
||||
|
||||
```json
|
||||
// tsconfig.json
|
||||
|
||||
{
|
||||
"compilerOptions": {
|
||||
// ...
|
||||
"paths": {
|
||||
"payload/generated-types": [
|
||||
"./src/payload-types.ts" // Ensure this matches the path to your typescript outputFile
|
||||
]
|
||||
}
|
||||
}
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Custom output file path
|
||||
|
||||
You can specify where you want your types to be generated by adding a property to your Payload config:
|
||||
|
||||
```ts
|
||||
// payload.config.ts
|
||||
|
||||
{
|
||||
// ...
|
||||
typescript: {
|
||||
// defaults to: path.resolve(__dirname, './payload-types.ts')
|
||||
outputFile: path.resolve(__dirname, './generated-types.ts'),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
The above example places your types next to your Payload config itself as the file `generated-types.ts`.
|
||||
|
||||
### Example Usage
|
||||
|
||||
For example, let's look at the following simple Payload config:
|
||||
|
||||
```ts
|
||||
@@ -74,28 +116,65 @@ export interface Post {
|
||||
title?: string;
|
||||
author?: string | User;
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### Customizing the output path of your generated types
|
||||
### Custom Field Interfaces
|
||||
|
||||
You can specify where you want your types to be generated by adding a property to your Payload config:
|
||||
For `array`, `block`, `group` and named `tab` fields, you can generate top level reusable interfaces. The following group field config:
|
||||
|
||||
```
|
||||
```ts
|
||||
{
|
||||
// the remainder of your config
|
||||
typescript: {
|
||||
outputFile: path.resolve(__dirname, './generated-types.ts'),
|
||||
},
|
||||
type: 'group',
|
||||
name: 'meta',
|
||||
interfaceName: 'SharedMeta', <-- here!!
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'description',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
The above example places your types next to your Payload config itself as the file `generated-types.ts`. By default, the file will be output to your current working directory as `payload-types.ts`.
|
||||
will generate:
|
||||
|
||||
```ts
|
||||
// a top level reusable interface!!
|
||||
export interface SharedMeta {
|
||||
title?: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
// example usage inside collection interface
|
||||
export interface Collection1 {
|
||||
// ...other fields
|
||||
meta?: SharedMeta;
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Naming Collisions</strong>
|
||||
<br />
|
||||
Since these types are hoisted to the top level, you need to be aware that
|
||||
naming collisions can occur. For example, if you have a collection with the
|
||||
name of `Meta` and you also create a interface with the name `Meta` they will
|
||||
collide. It is recommended to scope your interfaces by appending the field
|
||||
type to the end, i.e. `MetaGroup` or similar.
|
||||
</Banner>
|
||||
|
||||
### Using your types
|
||||
|
||||
Now that your types have been generated, payloads local API will now be typed. It is common for users to want to use this in their frontend code, we recommend generating them with payload and then copying the file over to your frontend codebase. This is the simplest way to get your types into your frontend codebase.
|
||||
|
||||
#### Adding an NPM script
|
||||
|
||||
<Banner type="warning">
|
||||
<strong>Important:</strong><br/>
|
||||
<strong>Important</strong>
|
||||
<br />
|
||||
Payload needs to be able to find your config to generate your types.
|
||||
</Banner>
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ Every Payload Collection can opt-in to supporting Uploads by specifying the `upl
|
||||
|
||||
| Option | Description |
|
||||
| ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`staticURL`** \* | The base URL path to use to access your uploads. Example: `/media` |
|
||||
| **`staticURL`** \* | The URL path to use to access your uploads. Relative path like `/media` will be served by payload. Full path like `https://example.com/media` needs to be served by another web server. |
|
||||
| **`staticDir`** \* | The folder directory to use to store media in. Can be either an absolute path or relative to the directory that contains your config. |
|
||||
| **`imageSizes`** | If specified, image uploads will be automatically resized in accordance to these image sizes. [More](#image-sizes) |
|
||||
| **`formatOptions`** | An object with `format` and `options` that are used with the Sharp image library to format the upload file. [More](https://sharp.pixelplumbing.com/api-output#toformat) |
|
||||
@@ -60,7 +60,7 @@ _An asterisk denotes that a property above is required._
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Media: CollectionConfig = {
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
upload: {
|
||||
staticURL: '/media',
|
||||
@@ -81,17 +81,23 @@ const Media: CollectionConfig = {
|
||||
{
|
||||
name: 'tablet',
|
||||
width: 1024,
|
||||
// By specifying `null` or leaving a height undefined,
|
||||
// By specifying `undefined` or leaving a height undefined,
|
||||
// the image will be sized to a certain width,
|
||||
// but it will retain its original aspect ratio
|
||||
// and calculate a height automatically.
|
||||
height: null,
|
||||
height: undefined,
|
||||
position: 'centre',
|
||||
},
|
||||
],
|
||||
adminThumbnail: 'thumbnail',
|
||||
mimeTypes: ['image/*'],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'alt',
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
};
|
||||
```
|
||||
|
||||
@@ -165,7 +171,7 @@ You can specify how Payload retrieves admin thumbnails for your upload-enabled C
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Media: CollectionConfig = {
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
upload: {
|
||||
staticURL: '/media',
|
||||
@@ -200,7 +206,7 @@ Some example values are: `image/*`, `audio/*`, `video/*`, `image/png`, `applicat
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Media: CollectionConfig = {
|
||||
export const Media: CollectionConfig = {
|
||||
slug: 'media',
|
||||
upload: {
|
||||
staticURL: '/media',
|
||||
|
||||
@@ -28,7 +28,7 @@ Collections and Globals both support the same options for configuring autosave.
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Pages: CollectionConfig = {
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
|
||||
@@ -84,7 +84,7 @@ Here is an example that utilizes the `_status` field to require a user to be log
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Pages: CollectionConfig = {
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
@@ -119,7 +119,7 @@ Here is an example for how to write an access control function that grants acces
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types';
|
||||
|
||||
const Pages: CollectionConfig = {
|
||||
export const Pages: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
access: {
|
||||
read: ({ req }) => {
|
||||
|
||||
@@ -7,13 +7,14 @@ keywords: version history, revisions, audit log, draft, publish, restore, autosa
|
||||
---
|
||||
|
||||
<Banner>
|
||||
Payload's powerful Versions functionality allows you to keep a running history of changes over time and extensible to fit any content publishing workflow.
|
||||
Payload's powerful Versions functionality allows you to keep a running history
|
||||
of changes over time and extensible to fit any content publishing workflow.
|
||||
</Banner>
|
||||
|
||||
When enabled, Payload will automatically scaffold a new Collection in your database to store versions of your document(s) over time, and the Admin UI will be extended with additional views that allow you to browse document versions, view diffs in order to see exactly what has changed in your documents (and when they changed), and restore documents back to prior versions easily.
|
||||
|
||||

|
||||
*Comparing an old version to a newer version of a document*
|
||||
_Comparing an old version to a newer version of a document_
|
||||
|
||||
**With Versions, you can:**
|
||||
|
||||
@@ -25,7 +26,9 @@ When enabled, Payload will automatically scaffold a new Collection in your datab
|
||||
- Build a powerful publishing schedule mechanism to create documents and have them become publicly readable automatically at a future date
|
||||
|
||||
<Banner type="success">
|
||||
Versions are extremely performant and totally opt-in. They don't change the shape of your data at all. All versions are stored in a separate Collection and can be turned on and off easily at your discretion.
|
||||
Versions are extremely performant and totally opt-in. They don't change the
|
||||
shape of your data at all. All versions are stored in a separate Collection
|
||||
and can be turned on and off easily at your discretion.
|
||||
</Banner>
|
||||
|
||||
### Options
|
||||
@@ -50,22 +53,19 @@ When you have versions, drafts, _and_ `autosave` enabled, the Admin UI will auto
|
||||
|
||||
Configuring Versions is done by adding the `versions` key to your Collection configs. Set it to `true` to enable default Versions settings, or customize versions options by setting the property equal to an object containing the following available options:
|
||||
|
||||
| Option | Description |
|
||||
| ---------------------------- | -------------|
|
||||
| `maxPerDoc` | Use this setting to control how many versions to keep on a document by document basis. Must be an integer. |
|
||||
| `retainDeleted` | Boolean to determine if, when a document is deleted, you'd like to retain versions of that document, or go through and automatically delete all versions that are associated with the deleted document. |
|
||||
| `drafts ` | Enable [Drafts](/docs/versions/drafts) mode for this collection. To enable, set to `true` or pass an object with `draft` [options](/docs/versions/drafts#options). |
|
||||
|
||||
| Option | Description |
|
||||
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `maxPerDoc` | Use this setting to control how many versions to keep on a document by document basis. Must be an integer. Defaults to 100, use 0 to save all versions. |
|
||||
| `drafts ` | Enable [Drafts](/docs/versions/drafts) mode for this collection. To enable, set to `true` or pass an object with `draft` [options](/docs/versions/drafts#options). |
|
||||
|
||||
### Global config
|
||||
|
||||
Global versions work similarly to Collection versions but have a slightly different set of config properties supported.
|
||||
|
||||
| Option | Description |
|
||||
| --------- | -------------|
|
||||
| `max` | Use this setting to control how many versions to keep on a global by global basis. Must be an integer. |
|
||||
| `drafts` | Enable [Drafts](/docs/versions/drafts) mode for this global. To enable, set to `true` or pass an object with `draft` [options](/docs/versions/drafts#options) |
|
||||
|
||||
| Option | Description |
|
||||
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `max` | Use this setting to control how many versions to keep on a global by global basis. Must be an integer. |
|
||||
| `drafts` | Enable [Drafts](/docs/versions/drafts) mode for this global. To enable, set to `true` or pass an object with `draft` [options](/docs/versions/drafts#options) |
|
||||
|
||||
#### Database impact
|
||||
|
||||
@@ -99,24 +99,24 @@ Versions expose new operations for both collections and globals. They allow you
|
||||
|
||||
**Collection REST endpoints:**
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | ------------------------------------ | -------------------------------------- |
|
||||
| `GET` | `/api/{collectionSlug}/versions` | Find and query paginated versions |
|
||||
| `GET` | `/api/{collectionSlug}/versions/:id` | Find a specific version by ID |
|
||||
| `POST` | `/api/{collectionSlug}/versions/:id` | Restore a version by ID |
|
||||
| Method | Path | Description |
|
||||
| ------ | ------------------------------------ | --------------------------------- |
|
||||
| `GET` | `/api/{collectionSlug}/versions` | Find and query paginated versions |
|
||||
| `GET` | `/api/{collectionSlug}/versions/:id` | Find a specific version by ID |
|
||||
| `POST` | `/api/{collectionSlug}/versions/:id` | Restore a version by ID |
|
||||
|
||||
**Collection GraphQL queries:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`version{collection.label.singular}`** | `findVersionByID` |
|
||||
| **`versions{collection.label.plural}`** | `findVersions` |
|
||||
| Query Name | Operation |
|
||||
| ---------------------------------------- | ----------------- |
|
||||
| **`version{collection.label.singular}`** | `findVersionByID` |
|
||||
| **`versions{collection.label.plural}`** | `findVersions` |
|
||||
|
||||
**And mutation:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`restoreVersion{collection.label.singular}`** | `restoreVersion` |
|
||||
| Query Name | Operation |
|
||||
| ----------------------------------------------- | ---------------- |
|
||||
| **`restoreVersion{collection.label.singular}`** | `restoreVersion` |
|
||||
|
||||
**Collection Local API methods:**
|
||||
|
||||
@@ -126,18 +126,18 @@ Versions expose new operations for both collections and globals. They allow you
|
||||
// Result will be a paginated set of Versions.
|
||||
// See /docs/queries/pagination for more.
|
||||
const result = await payload.findVersions({
|
||||
collection: 'posts', // required
|
||||
collection: "posts", // required
|
||||
depth: 2,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
where: {}, // pass a `where` query here
|
||||
sort: '-createdAt',
|
||||
locale: 'en',
|
||||
sort: "-createdAt",
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Find by ID
|
||||
@@ -145,15 +145,15 @@ const result = await payload.findVersions({
|
||||
```js
|
||||
// Result will be a Post document.
|
||||
const result = await payload.findVersionByID({
|
||||
collection: 'posts', // required
|
||||
id: '507f1f77bcf86cd799439013', // required
|
||||
collection: "posts", // required
|
||||
id: "507f1f77bcf86cd799439013", // required
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Restore
|
||||
@@ -161,35 +161,35 @@ const result = await payload.findVersionByID({
|
||||
```js
|
||||
// Result will be the restored global document.
|
||||
const result = await payload.restoreVersion({
|
||||
collection: 'posts', // required
|
||||
id: '507f1f77bcf86cd799439013', // required
|
||||
collection: "posts", // required
|
||||
id: "507f1f77bcf86cd799439013", // required
|
||||
depth: 2,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
**Global REST endpoints:**
|
||||
|
||||
| Method | Path | Description |
|
||||
| -------- | ---------------------------------------- | -------------------------------------- |
|
||||
| `GET` | `/api/globals/{globalSlug}/versions` | Find and query paginated versions |
|
||||
| `GET` | `/api/globals/{globalSlug}/versions/:id` | Find a specific version by ID |
|
||||
| `POST` | `/api/globals/{globalSlug}/versions/:id` | Restore a version by ID |
|
||||
| Method | Path | Description |
|
||||
| ------ | ---------------------------------------- | --------------------------------- |
|
||||
| `GET` | `/api/globals/{globalSlug}/versions` | Find and query paginated versions |
|
||||
| `GET` | `/api/globals/{globalSlug}/versions/:id` | Find a specific version by ID |
|
||||
| `POST` | `/api/globals/{globalSlug}/versions/:id` | Restore a version by ID |
|
||||
|
||||
**Global GraphQL queries:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`version{global.label}`** | `findVersionByID` |
|
||||
| **`versions{global.label}`** | `findVersions` |
|
||||
| Query Name | Operation |
|
||||
| ---------------------------- | ----------------- |
|
||||
| **`version{global.label}`** | `findVersionByID` |
|
||||
| **`versions{global.label}`** | `findVersions` |
|
||||
|
||||
**Global GraphQL mutation:**
|
||||
|
||||
| Query Name | Operation |
|
||||
| ---------------------- | -------------|
|
||||
| **`restoreVersion{global.label}`** | `restoreVersion` |
|
||||
| Query Name | Operation |
|
||||
| ---------------------------------- | ---------------- |
|
||||
| **`restoreVersion{global.label}`** | `restoreVersion` |
|
||||
|
||||
**Global Local API methods:**
|
||||
|
||||
@@ -199,18 +199,18 @@ const result = await payload.restoreVersion({
|
||||
// Result will be a paginated set of Versions.
|
||||
// See /docs/queries/pagination for more.
|
||||
const result = await payload.findGlobalVersions({
|
||||
slug: 'header', // required
|
||||
slug: "header", // required
|
||||
depth: 2,
|
||||
page: 1,
|
||||
limit: 10,
|
||||
where: {}, // pass a `where` query here
|
||||
sort: '-createdAt',
|
||||
locale: 'en',
|
||||
sort: "-createdAt",
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Find by ID
|
||||
@@ -218,15 +218,15 @@ const result = await payload.findGlobalVersions({
|
||||
```js
|
||||
// Result will be a Post document.
|
||||
const result = await payload.findGlobalVersionByID({
|
||||
slug: 'header', // required
|
||||
id: '507f1f77bcf86cd799439013', // required
|
||||
slug: "header", // required
|
||||
id: "507f1f77bcf86cd799439013", // required
|
||||
depth: 2,
|
||||
locale: 'en',
|
||||
locale: "en",
|
||||
fallbackLocale: false,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
#### Restore
|
||||
@@ -234,13 +234,13 @@ const result = await payload.findGlobalVersionByID({
|
||||
```js
|
||||
// Result will be the restored global document.
|
||||
const result = await payload.restoreGlobalVersion({
|
||||
slug: 'header', // required
|
||||
id: '507f1f77bcf86cd799439013', // required
|
||||
slug: "header", // required
|
||||
id: "507f1f77bcf86cd799439013", // required
|
||||
depth: 2,
|
||||
user: dummyUser,
|
||||
overrideAccess: false,
|
||||
showHiddenFields: true,
|
||||
})
|
||||
});
|
||||
```
|
||||
|
||||
### Access Control
|
||||
@@ -249,6 +249,6 @@ Versions expose a new access control function on both Collections and Globals th
|
||||
|
||||
**New version access control:**
|
||||
|
||||
| Function | Allows/Denies Access |
|
||||
| ------------------------ | -------------------- |
|
||||
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. |
|
||||
| Function | Allows/Denies Access |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`readVersions`** | Used to control who can read versions, and who can't. Will automatically restrict the Admin UI version viewing access. |
|
||||
|
||||
35
errors.js
35
errors.js
@@ -1,6 +1,39 @@
|
||||
const { APIError, Forbidden } = require('./dist/errors');
|
||||
const {
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
DuplicateCollection,
|
||||
DuplicateGlobal,
|
||||
ErrorDeletingFile,
|
||||
FileUploadError,
|
||||
Forbidden,
|
||||
InvalidConfiguration,
|
||||
InvalidFieldName,
|
||||
InvalidFieldRelationship,
|
||||
LockedAuth,
|
||||
MissingCollectionLabel,
|
||||
MissingFieldInputOptions,
|
||||
MissingFieldType,
|
||||
MissingFile,
|
||||
NotFound,
|
||||
ValidationError,
|
||||
} = require('./dist/errors');
|
||||
|
||||
module.exports = {
|
||||
APIError,
|
||||
AuthenticationError,
|
||||
DuplicateCollection,
|
||||
DuplicateGlobal,
|
||||
ErrorDeletingFile,
|
||||
FileUploadError,
|
||||
Forbidden,
|
||||
InvalidConfiguration,
|
||||
InvalidFieldName,
|
||||
InvalidFieldRelationship,
|
||||
LockedAuth,
|
||||
MissingCollectionLabel,
|
||||
MissingFieldInputOptions,
|
||||
MissingFieldType,
|
||||
MissingFile,
|
||||
NotFound,
|
||||
ValidationError,
|
||||
};
|
||||
|
||||
17
eslint-config/configs/base/index.js
Normal file
17
eslint-config/configs/base/index.js
Normal file
@@ -0,0 +1,17 @@
|
||||
module.exports = {
|
||||
plugins: [
|
||||
'node',
|
||||
],
|
||||
env: {
|
||||
node: true,
|
||||
},
|
||||
extends: [
|
||||
'./rules/best-practices',
|
||||
'./rules/errors',
|
||||
'./rules/es6',
|
||||
'./rules/imports',
|
||||
'./rules/style',
|
||||
'./rules/variables',
|
||||
].map(require.resolve),
|
||||
rules: {},
|
||||
};
|
||||
356
eslint-config/configs/base/rules/best-practices.js
Normal file
356
eslint-config/configs/base/rules/best-practices.js
Normal file
@@ -0,0 +1,356 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
// enforces getter/setter pairs in objects
|
||||
'accessor-pairs': 'off',
|
||||
|
||||
// enforces return statements in callbacks of array's methods
|
||||
// https://eslint.org/docs/rules/array-callback-return
|
||||
'array-callback-return': ['error', { allowImplicit: true }],
|
||||
|
||||
// treat var statements as if they were block scoped
|
||||
'block-scoped-var': 'error',
|
||||
|
||||
// specify the maximum cyclomatic complexity allowed in a program
|
||||
complexity: ['off', 11],
|
||||
|
||||
// enforce that class methods use "this"
|
||||
// https://eslint.org/docs/rules/class-methods-use-this
|
||||
'class-methods-use-this': ['error', {
|
||||
exceptMethods: [],
|
||||
}],
|
||||
|
||||
// require return statements to either always or never specify values
|
||||
'consistent-return': 'error',
|
||||
|
||||
// specify curly brace conventions for all control statements
|
||||
curly: ['error', 'multi-line'], // multiline
|
||||
|
||||
// require default case in switch statements
|
||||
'default-case': ['error', { commentPattern: '^no default$' }],
|
||||
|
||||
// https://eslint.org/docs/rules/default-param-last
|
||||
// TODO: enable, semver-minor, when eslint v6.4 is required (which is a major)
|
||||
'default-param-last': 'off',
|
||||
|
||||
// encourages use of dot notation whenever possible
|
||||
'dot-notation': ['error', { allowKeywords: true }],
|
||||
|
||||
// enforces consistent newlines before or after dots
|
||||
// https://eslint.org/docs/rules/dot-location
|
||||
'dot-location': ['error', 'property'],
|
||||
|
||||
// require the use of === and !==
|
||||
// https://eslint.org/docs/rules/eqeqeq
|
||||
eqeqeq: ['error', 'always', { null: 'ignore' }],
|
||||
|
||||
// Require grouped accessor pairs in object literals and classes
|
||||
// https://eslint.org/docs/rules/grouped-accessor-pairs
|
||||
// TODO: enable in next major, altho the guide forbids getters/setters anyways
|
||||
'grouped-accessor-pairs': 'off',
|
||||
|
||||
// make sure for-in loops have an if statement
|
||||
'guard-for-in': 'error',
|
||||
|
||||
// enforce a maximum number of classes per file
|
||||
// https://eslint.org/docs/rules/max-classes-per-file
|
||||
'max-classes-per-file': ['error', 1],
|
||||
|
||||
// disallow the use of alert, confirm, and prompt
|
||||
'no-alert': 'warn',
|
||||
|
||||
// disallow use of arguments.caller or arguments.callee
|
||||
'no-caller': 'error',
|
||||
|
||||
// disallow lexical declarations in case/default clauses
|
||||
// https://eslint.org/docs/rules/no-case-declarations.html
|
||||
'no-case-declarations': 'error',
|
||||
|
||||
// Disallow returning value in constructor
|
||||
// https://eslint.org/docs/rules/no-constructor-return
|
||||
// TODO: enable, semver-major
|
||||
'no-constructor-return': 'off',
|
||||
|
||||
// disallow division operators explicitly at beginning of regular expression
|
||||
// https://eslint.org/docs/rules/no-div-regex
|
||||
'no-div-regex': 'off',
|
||||
|
||||
// disallow else after a return in an if
|
||||
// https://eslint.org/docs/rules/no-else-return
|
||||
'no-else-return': ['error', { allowElseIf: false }],
|
||||
|
||||
// disallow empty functions, except for standalone funcs/arrows
|
||||
// https://eslint.org/docs/rules/no-empty-function
|
||||
'no-empty-function': ['error', {
|
||||
allow: [
|
||||
'arrowFunctions',
|
||||
'functions',
|
||||
'methods',
|
||||
],
|
||||
}],
|
||||
|
||||
// disallow empty destructuring patterns
|
||||
// https://eslint.org/docs/rules/no-empty-pattern
|
||||
'no-empty-pattern': 'error',
|
||||
|
||||
// disallow comparisons to null without a type-checking operator
|
||||
'no-eq-null': 'off',
|
||||
|
||||
// disallow use of eval()
|
||||
'no-eval': 'error',
|
||||
|
||||
// disallow adding to native types
|
||||
'no-extend-native': 'error',
|
||||
|
||||
// disallow unnecessary function binding
|
||||
'no-extra-bind': 'error',
|
||||
|
||||
// disallow Unnecessary Labels
|
||||
// https://eslint.org/docs/rules/no-extra-label
|
||||
'no-extra-label': 'error',
|
||||
|
||||
// disallow fallthrough of case statements
|
||||
'no-fallthrough': 'error',
|
||||
|
||||
// disallow the use of leading or trailing decimal points in numeric literals
|
||||
'no-floating-decimal': 'error',
|
||||
|
||||
// disallow reassignments of native objects or read-only globals
|
||||
// https://eslint.org/docs/rules/no-global-assign
|
||||
'no-global-assign': ['error', { exceptions: [] }],
|
||||
// deprecated in favor of no-global-assign
|
||||
'no-native-reassign': 'off',
|
||||
|
||||
// disallow implicit type conversions
|
||||
// https://eslint.org/docs/rules/no-implicit-coercion
|
||||
'no-implicit-coercion': ['off', {
|
||||
boolean: false,
|
||||
number: true,
|
||||
string: true,
|
||||
allow: [],
|
||||
}],
|
||||
|
||||
// disallow var and named functions in global scope
|
||||
// https://eslint.org/docs/rules/no-implicit-globals
|
||||
'no-implicit-globals': 'off',
|
||||
|
||||
// disallow use of eval()-like methods
|
||||
'no-implied-eval': 'error',
|
||||
|
||||
// disallow this keywords outside of classes or class-like objects
|
||||
'no-invalid-this': 'off',
|
||||
|
||||
// disallow usage of __iterator__ property
|
||||
'no-iterator': 'error',
|
||||
|
||||
// disallow use of labels for anything other then loops and switches
|
||||
'no-labels': ['error', { allowLoop: false, allowSwitch: false }],
|
||||
|
||||
// disallow unnecessary nested blocks
|
||||
'no-lone-blocks': 'error',
|
||||
|
||||
// disallow creation of functions within loops
|
||||
'no-loop-func': 'error',
|
||||
|
||||
// disallow magic numbers
|
||||
// https://eslint.org/docs/rules/no-magic-numbers
|
||||
'no-magic-numbers': ['off', {
|
||||
ignore: [],
|
||||
ignoreArrayIndexes: true,
|
||||
enforceConst: true,
|
||||
detectObjects: false,
|
||||
}],
|
||||
|
||||
// disallow use of multiple spaces
|
||||
'no-multi-spaces': ['error', {
|
||||
ignoreEOLComments: false,
|
||||
}],
|
||||
|
||||
// disallow use of multiline strings
|
||||
'no-multi-str': 'error',
|
||||
|
||||
// disallow use of new operator when not part of the assignment or comparison
|
||||
'no-new': 'error',
|
||||
|
||||
// disallow use of new operator for Function object
|
||||
'no-new-func': 'error',
|
||||
|
||||
// disallows creating new instances of String, Number, and Boolean
|
||||
'no-new-wrappers': 'error',
|
||||
|
||||
// disallow use of (old style) octal literals
|
||||
'no-octal': 'error',
|
||||
|
||||
// disallow use of octal escape sequences in string literals, such as
|
||||
// var foo = 'Copyright \251';
|
||||
'no-octal-escape': 'error',
|
||||
|
||||
// disallow reassignment of function parameters
|
||||
// disallow parameter object manipulation except for specific exclusions
|
||||
// rule: https://eslint.org/docs/rules/no-param-reassign.html
|
||||
'no-param-reassign': ['error', {
|
||||
props: true,
|
||||
ignorePropertyModificationsFor: [
|
||||
'acc', // for reduce accumulators
|
||||
'accumulator', // for reduce accumulators
|
||||
'e', // for e.returnvalue
|
||||
'ctx', // for Koa routing
|
||||
'req', // for Express requests
|
||||
'request', // for Express requests
|
||||
'res', // for Express responses
|
||||
'response', // for Express responses
|
||||
'$scope', // for Angular 1 scopes
|
||||
'staticContext', // for ReactRouter context
|
||||
],
|
||||
}],
|
||||
|
||||
// disallow usage of __proto__ property
|
||||
'no-proto': 'error',
|
||||
|
||||
// disallow declaring the same variable more then once
|
||||
'no-redeclare': 'error',
|
||||
|
||||
// disallow certain object properties
|
||||
// https://eslint.org/docs/rules/no-restricted-properties
|
||||
'no-restricted-properties': ['error',
|
||||
{
|
||||
object: 'arguments',
|
||||
property: 'callee',
|
||||
message: 'arguments.callee is deprecated',
|
||||
}, {
|
||||
object: 'global',
|
||||
property: 'isFinite',
|
||||
message: 'Please use Number.isFinite instead',
|
||||
}, {
|
||||
object: 'self',
|
||||
property: 'isFinite',
|
||||
message: 'Please use Number.isFinite instead',
|
||||
}, {
|
||||
object: 'window',
|
||||
property: 'isFinite',
|
||||
message: 'Please use Number.isFinite instead',
|
||||
}, {
|
||||
object: 'global',
|
||||
property: 'isNaN',
|
||||
message: 'Please use Number.isNaN instead',
|
||||
}, {
|
||||
object: 'self',
|
||||
property: 'isNaN',
|
||||
message: 'Please use Number.isNaN instead',
|
||||
}, {
|
||||
object: 'window',
|
||||
property: 'isNaN',
|
||||
message: 'Please use Number.isNaN instead',
|
||||
}, {
|
||||
property: '__defineGetter__',
|
||||
message: 'Please use Object.defineProperty instead.',
|
||||
}, {
|
||||
property: '__defineSetter__',
|
||||
message: 'Please use Object.defineProperty instead.',
|
||||
}, {
|
||||
object: 'Math',
|
||||
property: 'pow',
|
||||
message: 'Use the exponentiation operator (**) instead.',
|
||||
}],
|
||||
|
||||
// disallow use of assignment in return statement
|
||||
'no-return-assign': ['error', 'always'],
|
||||
|
||||
// disallow redundant `return await`
|
||||
'no-return-await': 'error',
|
||||
|
||||
// disallow use of `javascript:` urls.
|
||||
'no-script-url': 'error',
|
||||
|
||||
// disallow self assignment
|
||||
// https://eslint.org/docs/rules/no-self-assign
|
||||
'no-self-assign': ['error', {
|
||||
props: true,
|
||||
}],
|
||||
|
||||
// disallow comparisons where both sides are exactly the same
|
||||
'no-self-compare': 'error',
|
||||
|
||||
// disallow use of comma operator
|
||||
'no-sequences': 'error',
|
||||
|
||||
// restrict what can be thrown as an exception
|
||||
'no-throw-literal': 'error',
|
||||
|
||||
// disallow unmodified conditions of loops
|
||||
// https://eslint.org/docs/rules/no-unmodified-loop-condition
|
||||
'no-unmodified-loop-condition': 'off',
|
||||
|
||||
// disallow usage of expressions in statement position
|
||||
'no-unused-expressions': ['error', {
|
||||
allowShortCircuit: false,
|
||||
allowTernary: false,
|
||||
allowTaggedTemplates: false,
|
||||
}],
|
||||
|
||||
// disallow unused labels
|
||||
// https://eslint.org/docs/rules/no-unused-labels
|
||||
'no-unused-labels': 'error',
|
||||
|
||||
// disallow unnecessary .call() and .apply()
|
||||
'no-useless-call': 'off',
|
||||
|
||||
// Disallow unnecessary catch clauses
|
||||
// https://eslint.org/docs/rules/no-useless-catch
|
||||
'no-useless-catch': 'error',
|
||||
|
||||
// disallow useless string concatenation
|
||||
// https://eslint.org/docs/rules/no-useless-concat
|
||||
'no-useless-concat': 'error',
|
||||
|
||||
// disallow unnecessary string escaping
|
||||
// https://eslint.org/docs/rules/no-useless-escape
|
||||
'no-useless-escape': 'error',
|
||||
|
||||
// disallow redundant return; keywords
|
||||
// https://eslint.org/docs/rules/no-useless-return
|
||||
'no-useless-return': 'error',
|
||||
|
||||
// disallow use of void operator
|
||||
// https://eslint.org/docs/rules/no-void
|
||||
'no-void': 'error',
|
||||
|
||||
// disallow usage of configurable warning terms in comments: e.g. todo
|
||||
'no-warning-comments': ['off', { terms: ['todo', 'fixme', 'xxx'], location: 'start' }],
|
||||
|
||||
// disallow use of the with statement
|
||||
'no-with': 'error',
|
||||
|
||||
// require using Error objects as Promise rejection reasons
|
||||
// https://eslint.org/docs/rules/prefer-promise-reject-errors
|
||||
'prefer-promise-reject-errors': ['error', { allowEmptyReject: true }],
|
||||
|
||||
// Suggest using named capture group in regular expression
|
||||
// https://eslint.org/docs/rules/prefer-named-capture-group
|
||||
'prefer-named-capture-group': 'off',
|
||||
|
||||
// https://eslint.org/docs/rules/prefer-regex-literals
|
||||
// TODO; enable, semver-minor, once eslint v6.4 is required (which is a major)
|
||||
'prefer-regex-literals': 'off',
|
||||
|
||||
// require use of the second argument for parseInt()
|
||||
radix: 'error',
|
||||
|
||||
// require `await` in `async function` (note: this is a horrible rule that should never be used)
|
||||
// https://eslint.org/docs/rules/require-await
|
||||
'require-await': 'off',
|
||||
|
||||
// Enforce the use of u flag on RegExp
|
||||
// https://eslint.org/docs/rules/require-unicode-regexp
|
||||
'require-unicode-regexp': 'off',
|
||||
|
||||
// requires to declare all vars on top of their containing scope
|
||||
'vars-on-top': 'error',
|
||||
|
||||
// require immediate function invocation to be wrapped in parentheses
|
||||
// https://eslint.org/docs/rules/wrap-iife.html
|
||||
'wrap-iife': ['error', 'outside', { functionPrototypeMethods: false }],
|
||||
|
||||
// require or disallow Yoda conditions
|
||||
yoda: 'error',
|
||||
},
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user