Compare commits
506 Commits
alpha-post
...
db-postgre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
82bd5c656f | ||
|
|
afe8992ca6 | ||
|
|
48a410e294 | ||
|
|
82b88a315f | ||
|
|
cc94078607 | ||
|
|
1c30ad73b6 | ||
|
|
d9442dcce3 | ||
|
|
de92c50847 | ||
|
|
b7f5f932f6 | ||
|
|
bc9e591e37 | ||
|
|
ad38011348 | ||
|
|
d02b1fb084 | ||
|
|
51efe4f39b | ||
|
|
30e535b5b9 | ||
|
|
4bd3bb9400 | ||
|
|
69c93d3c62 | ||
|
|
78aa957043 | ||
|
|
cd06c022c0 | ||
|
|
8299e9fc33 | ||
|
|
9df5ab8a10 | ||
|
|
6979f5a1b1 | ||
|
|
723791b94f | ||
|
|
aa3833ec83 | ||
|
|
2972af2af1 | ||
|
|
857b9a4ac3 | ||
|
|
f829b084ba | ||
|
|
6ae682698d | ||
|
|
622cdb0440 | ||
|
|
cac52da638 | ||
|
|
3cb3c1aceb | ||
|
|
db4aacebb8 | ||
|
|
b735d6aa16 | ||
|
|
fbec3a33e0 | ||
|
|
034be89bdb | ||
|
|
1f2af0963b | ||
|
|
20f1ece2d7 | ||
|
|
2be5ad0eba | ||
|
|
5c58bd322d | ||
|
|
23f3eb1cf0 | ||
|
|
af67749e49 | ||
|
|
43dab5c705 | ||
|
|
9b7e62dc20 | ||
|
|
6e38cc2bcf | ||
|
|
83551bfcaa | ||
|
|
7b44d9d28a | ||
|
|
182d5db6de | ||
|
|
93109ec84a | ||
|
|
4d9e0f35f0 | ||
|
|
19327c8d6d | ||
|
|
831f1ff5be | ||
|
|
a8ac8b4633 | ||
|
|
36b1f5a763 | ||
|
|
24f697219b | ||
|
|
3fccd34abe | ||
|
|
a38f8e93a6 | ||
|
|
84570e6e3b | ||
|
|
5ad8e0edcb | ||
|
|
91bac9c0aa | ||
|
|
33f6edc9d5 | ||
|
|
e1f91f5170 | ||
|
|
0e75dfb5c1 | ||
|
|
1300e264be | ||
|
|
5600125de7 | ||
|
|
22e270f89c | ||
|
|
593f82bcba | ||
|
|
cbf3da1144 | ||
|
|
1a2aab4126 | ||
|
|
d0ba694c80 | ||
|
|
d78df36d9b | ||
|
|
02572d945a | ||
|
|
f05a433320 | ||
|
|
9ce3b3ab29 | ||
|
|
ade637befb | ||
|
|
c31b8dcaa0 | ||
|
|
0ffdcc685f | ||
|
|
881119ba3a | ||
|
|
60372faf36 | ||
|
|
8bca0b0b86 | ||
|
|
87a1d698b2 | ||
|
|
c11600aac3 | ||
|
|
ad01c6784d | ||
|
|
62601c54a7 | ||
|
|
4a144ddc44 | ||
|
|
9152a238d2 | ||
|
|
fc8b835264 | ||
|
|
28ee5e34c3 | ||
|
|
e25886649f | ||
|
|
985796be54 | ||
|
|
bd8b5123b0 | ||
|
|
c380deee4a | ||
|
|
0b12aac895 | ||
|
|
90d3f178ab | ||
|
|
a8c9625cde | ||
|
|
938d069523 | ||
|
|
1a337ec223 | ||
|
|
08f372e6c2 | ||
|
|
2994269f22 | ||
|
|
8d1a706928 | ||
|
|
fcb29bb1c6 | ||
|
|
2c402cc65c | ||
|
|
ad38f76011 | ||
|
|
b974a2c042 | ||
|
|
cb8d562132 | ||
|
|
1f0036054a | ||
|
|
aaa4397351 | ||
|
|
6185f8a5d8 | ||
|
|
e47e544364 | ||
|
|
2e80350a5a | ||
|
|
4c4f924e90 | ||
|
|
170957c380 | ||
|
|
9061ae05e7 | ||
|
|
fe0028c899 | ||
|
|
ec1ad0b662 | ||
|
|
e5f32562a3 | ||
|
|
ba6100cbe8 | ||
|
|
c08c8b5628 | ||
|
|
9e918831d1 | ||
|
|
25c9a145be | ||
|
|
3b1d331316 | ||
|
|
5aa68b5e5d | ||
|
|
d8e9084db2 | ||
|
|
65690a675c | ||
|
|
9530d28a67 | ||
|
|
509ec677c4 | ||
|
|
a00439ea89 | ||
|
|
0055a8eb36 | ||
|
|
de5d6cc4bd | ||
|
|
51f84a4fcf | ||
|
|
c0ba6cc19a | ||
|
|
5fa99fb060 | ||
|
|
e3c3ddac34 | ||
|
|
6186493246 | ||
|
|
9b44296092 | ||
|
|
cbd03ed2f8 | ||
|
|
cf135fd1e4 | ||
|
|
e7608f5507 | ||
|
|
608d6d0a87 | ||
|
|
9bbacc4fb1 | ||
|
|
7df7bf448b | ||
|
|
44599cbc7b | ||
|
|
373787de31 | ||
|
|
c1c86009a5 | ||
|
|
6cf6ca3ea8 | ||
|
|
6706bdb140 | ||
|
|
5caaa032bb | ||
|
|
4cf8c5bd78 | ||
|
|
d6afee662b | ||
|
|
0fc62446b8 | ||
|
|
823fde07c3 | ||
|
|
fe35b7d32c | ||
|
|
3b45b0d085 | ||
|
|
742a7af93d | ||
|
|
a7e7c92768 | ||
|
|
e10d5df0b2 | ||
|
|
3023118b71 | ||
|
|
80375d1798 | ||
|
|
589b492b2e | ||
|
|
bdeef377ea | ||
|
|
b76c5c8c11 | ||
|
|
58c9fecbae | ||
|
|
e88de5db60 | ||
|
|
ce75fab4fc | ||
|
|
5b57f1411a | ||
|
|
11ff2042f3 | ||
|
|
8f9481f8a7 | ||
|
|
5de32b2534 | ||
|
|
dbcffc688f | ||
|
|
17cf179d16 | ||
|
|
1dc86aa6e6 | ||
|
|
d8e0824547 | ||
|
|
1453547e35 | ||
|
|
4c6874449a | ||
|
|
332c9b3a98 | ||
|
|
73544b5b5e | ||
|
|
e03302160a | ||
|
|
edb530fc64 | ||
|
|
064b4baed8 | ||
|
|
4cb8259b8b | ||
|
|
34b2451b3b | ||
|
|
29ccd06553 | ||
|
|
a5971c12b3 | ||
|
|
0900baf8f9 | ||
|
|
d1a9a3e4d5 | ||
|
|
d27a33dc1d | ||
|
|
d01c586a90 | ||
|
|
caa0d7cf0d | ||
|
|
c40b5a1784 | ||
|
|
b0869ea0ed | ||
|
|
00faebed4b | ||
|
|
638a35a2e7 | ||
|
|
44bca2ed36 | ||
|
|
fa90cec758 | ||
|
|
2164dcc594 | ||
|
|
a3ae416085 | ||
|
|
02d2c51717 | ||
|
|
b3503e3dce | ||
|
|
2e5400fa7a | ||
|
|
48dc116f57 | ||
|
|
9b2ba7cc0e | ||
|
|
916923071a | ||
|
|
3ceb6efd32 | ||
|
|
8184e0005a | ||
|
|
1c0d43c61a | ||
|
|
0eb7b44735 | ||
|
|
c038acb3a4 | ||
|
|
f8c2ccf6b1 | ||
|
|
e6092fd36c | ||
|
|
e0eae77758 | ||
|
|
0780ff22bb | ||
|
|
e7f6bfbe9d | ||
|
|
23df60dba5 | ||
|
|
8919b86571 | ||
|
|
8104fac5ed | ||
|
|
59ef1263a5 | ||
|
|
813e3dbc98 | ||
|
|
12a23092e1 | ||
|
|
4a49beb552 | ||
|
|
80530c666e | ||
|
|
f53e2df951 | ||
|
|
db58e2bab2 | ||
|
|
d88e97e123 | ||
|
|
bb72e506e6 | ||
|
|
b1f727fd6a | ||
|
|
72af18229b | ||
|
|
af52b526c8 | ||
|
|
60525623bf | ||
|
|
0fba582926 | ||
|
|
5d1cad3adb | ||
|
|
e31f72da8e | ||
|
|
7aa058d604 | ||
|
|
64e80d242e | ||
|
|
e8f2ca484e | ||
|
|
ceca5c4e97 | ||
|
|
ee13736288 | ||
|
|
815bdfac0b | ||
|
|
7a7f0ed7e8 | ||
|
|
ad42d541b3 | ||
|
|
32ed95e1ee | ||
|
|
70e57fef18 | ||
|
|
0a07f607b9 | ||
|
|
3918fc7c21 | ||
|
|
13f71ac475 | ||
|
|
07720e777a | ||
|
|
efff47e400 | ||
|
|
453ac218ea | ||
|
|
d4b09bd9cd | ||
|
|
dd67e03fc1 | ||
|
|
548de80bee | ||
|
|
2c05fbbb5e | ||
|
|
9b54659818 | ||
|
|
e9f550406e | ||
|
|
98b87e2278 | ||
|
|
5f3d0169be | ||
|
|
35c2a085ef | ||
|
|
1ac943ed5e | ||
|
|
25cee8bb10 | ||
|
|
419aef452d | ||
|
|
ea52489126 | ||
|
|
e80c70acae | ||
|
|
70b0064d0b | ||
|
|
9636bf6efd | ||
|
|
8f4d0da4e0 | ||
|
|
f0f1dbdcb0 | ||
|
|
a895aee8b1 | ||
|
|
aa1dac08c1 | ||
|
|
b8cd1c6ba4 | ||
|
|
6344464bc6 | ||
|
|
5d4022f144 | ||
|
|
bf942fdfa6 | ||
|
|
d6c25783cf | ||
|
|
82e9d31127 | ||
|
|
399e606b34 | ||
|
|
0d18822062 | ||
|
|
00fc0343da | ||
|
|
6323965c65 | ||
|
|
6d6823c3e5 | ||
|
|
ca70298436 | ||
|
|
4f565759f6 | ||
|
|
df39602758 | ||
|
|
6ea6172afa | ||
|
|
486774796d | ||
|
|
1cd1c38764 | ||
|
|
f6d7da7510 | ||
|
|
cdc4cb971b | ||
|
|
e0191b54e1 | ||
|
|
2315781f18 | ||
|
|
a0a58e7fd2 | ||
|
|
e1813fb884 | ||
|
|
da184d40ec | ||
|
|
ca8675f89d | ||
|
|
e8c6c9338d | ||
|
|
558534aff8 | ||
|
|
29c901ba9b | ||
|
|
f3876c2a39 | ||
|
|
c3a3942969 | ||
|
|
23b135b963 | ||
|
|
e3c8105cc2 | ||
|
|
2c71aaef75 | ||
|
|
922fb9b7fa | ||
|
|
0740d5095e | ||
|
|
b392d656fe | ||
|
|
c0eef90cdc | ||
|
|
db22cbdf21 | ||
|
|
1e8a6b7899 | ||
|
|
5d934ba02d | ||
|
|
f651665f2f | ||
|
|
5d3659d48a | ||
|
|
47106d5a1a | ||
|
|
afa2b942e0 | ||
|
|
20ddd0de5b | ||
|
|
64f705c3c9 | ||
|
|
b30ea8aa6b | ||
|
|
471d2113a7 | ||
|
|
8725d41164 | ||
|
|
0bd81aa25a | ||
|
|
8c09ca9be5 | ||
|
|
90d7ee3e65 | ||
|
|
58bbd8c00f | ||
|
|
003ad065c3 | ||
|
|
70715926a8 | ||
|
|
b3a6bfacf2 | ||
|
|
e1d9accb27 | ||
|
|
f2f55a84cc | ||
|
|
eba53ba60a | ||
|
|
f73d503fec | ||
|
|
6930c4e9f2 | ||
|
|
3eb681e847 | ||
|
|
cb4638cfa1 | ||
|
|
b40e9f85a2 | ||
|
|
e5a7907a72 | ||
|
|
3f25d1ca84 | ||
|
|
d5720bea7b | ||
|
|
8ce15c8b07 | ||
|
|
9f5efef78f | ||
|
|
dfba5222f3 | ||
|
|
b99d24fcfa | ||
|
|
836ed77568 | ||
|
|
1c5d5b07c8 | ||
|
|
da5f1f2240 | ||
|
|
c84c58c7b4 | ||
|
|
1c1b8f3cec | ||
|
|
3f69f83180 | ||
|
|
371353f153 | ||
|
|
a92c6334b6 | ||
|
|
eb9e771a9c | ||
|
|
ee5390aaca | ||
|
|
a861311c5a | ||
|
|
74c3fe1bb2 | ||
|
|
a2be50279e | ||
|
|
403eb06acf | ||
|
|
f5c2cd74cc | ||
|
|
a6a1963ec6 | ||
|
|
0647c870f1 | ||
|
|
3b88adc7d0 | ||
|
|
82383a5b5f | ||
|
|
f9dda628b2 | ||
|
|
93eb0e4a31 | ||
|
|
2e362f44f4 | ||
|
|
775502b161 | ||
|
|
84d75ce6ca | ||
|
|
175cf229c0 | ||
|
|
bb40bd3efb | ||
|
|
3d74c133aa | ||
|
|
0f6b6ca970 | ||
|
|
8e1692ef10 | ||
|
|
1d1ee913fc | ||
|
|
beca43341f | ||
|
|
84818469ea | ||
|
|
0a259d27b5 | ||
|
|
e2e56a4d58 | ||
|
|
d0f7677d5f | ||
|
|
35956eb837 | ||
|
|
d92af295eb | ||
|
|
493fde5ccc | ||
|
|
c6bd20ef33 | ||
|
|
6d5ac1de1e | ||
|
|
fa3b3dd62d | ||
|
|
1115387744 | ||
|
|
53e8690feb | ||
|
|
4319fe1c6e | ||
|
|
2fee0c0d44 | ||
|
|
7923edd7bc | ||
|
|
5702b83e82 | ||
|
|
63e5c43fe6 | ||
|
|
04f2888135 | ||
|
|
0f69b9c2f8 | ||
|
|
f1bb2f8151 | ||
|
|
ea528b8c10 | ||
|
|
0053e40404 | ||
|
|
605c0be43c | ||
|
|
3152b4c4c5 | ||
|
|
a64b80babc | ||
|
|
5cfde542b1 | ||
|
|
772020963e | ||
|
|
5e083689d0 | ||
|
|
911764a490 | ||
|
|
e3b81d913d | ||
|
|
41b3b17911 | ||
|
|
e9860b36f3 | ||
|
|
14b39fbc85 | ||
|
|
d08e85d08c | ||
|
|
abcbf9974d | ||
|
|
d01437d212 | ||
|
|
06729a0a73 | ||
|
|
2bd7822a16 | ||
|
|
bc7daf6b49 | ||
|
|
feab679ef7 | ||
|
|
be39ed4317 | ||
|
|
570e192eb4 | ||
|
|
22f4967dd4 | ||
|
|
4873c36129 | ||
|
|
f0ec21cdda | ||
|
|
da737bdf8e | ||
|
|
40508880c1 | ||
|
|
8f420d841a | ||
|
|
9022e27308 | ||
|
|
acf2e41312 | ||
|
|
6acfae8ee7 | ||
|
|
20bdd91da4 | ||
|
|
50502834c9 | ||
|
|
2b731c1088 | ||
|
|
983733ad74 | ||
|
|
555d02769a | ||
|
|
682eca2186 | ||
|
|
6affa1c304 | ||
|
|
1d14d9f8b8 | ||
|
|
0abaddc2ef | ||
|
|
57dc93da5d | ||
|
|
21b9453cf4 | ||
|
|
136993ec2b | ||
|
|
63bc4cabe1 | ||
|
|
6a8a6e4ef4 | ||
|
|
9828772890 | ||
|
|
6116573164 | ||
|
|
cab6babd60 | ||
|
|
55399424a1 | ||
|
|
28d3f73c2a | ||
|
|
28a30120dd | ||
|
|
40a0921597 | ||
|
|
7eae86bcb3 | ||
|
|
0b80e4a403 | ||
|
|
b378532ddf | ||
|
|
d419275fb5 | ||
|
|
0fb3a9ca89 | ||
|
|
f43cf185d4 | ||
|
|
5d15955f83 | ||
|
|
2d35e06667 | ||
|
|
d2de6db449 | ||
|
|
a3e78161b5 | ||
|
|
d543665995 | ||
|
|
db7dddf1c5 | ||
|
|
3027a03ad1 | ||
|
|
85e38b7cfd | ||
|
|
9090540ece | ||
|
|
46ef284f6b | ||
|
|
0727dcd963 | ||
|
|
52f8d4f9f0 | ||
|
|
f1fa374ed1 | ||
|
|
6b691eee43 | ||
|
|
be3beabb9b | ||
|
|
1fa00cc25c | ||
|
|
f70943524b | ||
|
|
a67080a291 | ||
|
|
69a99445c9 | ||
|
|
00d8480062 | ||
|
|
7424ba9090 | ||
|
|
ec4d2f97cb | ||
|
|
9d9ac0ec28 | ||
|
|
635e7c26e8 | ||
|
|
c4a4678afb | ||
|
|
a5a91c08a9 | ||
|
|
7db58b482b | ||
|
|
1b914083c8 | ||
|
|
657d14c07b | ||
|
|
fbf8ab72a4 | ||
|
|
997f158149 | ||
|
|
c3be5d1d5e | ||
|
|
250bcd8189 | ||
|
|
a71d37b398 | ||
|
|
5c5523195c | ||
|
|
bff4cf518f | ||
|
|
8015e999cd | ||
|
|
0c905f0da7 | ||
|
|
e691a90a4c | ||
|
|
0b2da4fba7 | ||
|
|
1c6d6788a3 | ||
|
|
ecc7978184 | ||
|
|
1b9ee64a67 | ||
|
|
22b02226c3 | ||
|
|
e4102b88d8 | ||
|
|
a099f55a69 | ||
|
|
1f1445c798 | ||
|
|
741a5e3650 | ||
|
|
365047a3fb | ||
|
|
42c06acd18 | ||
|
|
f2c8ac4a9a | ||
|
|
05e8914db7 | ||
|
|
35191bdd66 | ||
|
|
98890eee1f | ||
|
|
ef43629502 | ||
|
|
c703497924 | ||
|
|
5caad706bb | ||
|
|
aa048d5409 | ||
|
|
aafd538cf8 | ||
|
|
1b42bd207d | ||
|
|
9fac2ef24e |
@@ -8,6 +8,3 @@
|
||||
**/dist/**
|
||||
**/node_modules
|
||||
**/temp
|
||||
playwright.config.ts
|
||||
jest.config.js
|
||||
test/live-preview/next-app
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
/** @type {import('eslint').Linter.Config} */
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
ignorePatterns: ['README.md', 'packages/**/*.spec.ts'],
|
||||
overrides: [
|
||||
{
|
||||
files: ['packages/**'],
|
||||
plugins: ['payload'],
|
||||
rules: {
|
||||
'payload/no-jsx-import-statements': 'warn',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['scripts/**'],
|
||||
rules: {
|
||||
'@typescript-eslint/no-unused-vars': 'off',
|
||||
'no-console': 'off',
|
||||
'perfectionist/sort-object-types': 'off',
|
||||
'perfectionist/sort-objects': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||
},
|
||||
{
|
||||
files: ['packages/eslint-config-payload/**'],
|
||||
rules: {
|
||||
'perfectionist/sort-objects': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['package.json', 'tsconfig.json'],
|
||||
rules: {
|
||||
'perfectionist/sort-array-includes': 'off',
|
||||
'perfectionist/sort-astro-attributes': 'off',
|
||||
'perfectionist/sort-classes': 'off',
|
||||
'perfectionist/sort-enums': 'off',
|
||||
'perfectionist/sort-exports': 'off',
|
||||
'perfectionist/sort-imports': 'off',
|
||||
'perfectionist/sort-interfaces': 'off',
|
||||
'perfectionist/sort-jsx-props': 'off',
|
||||
'perfectionist/sort-keys': 'off',
|
||||
'perfectionist/sort-maps': 'off',
|
||||
'perfectionist/sort-named-exports': 'off',
|
||||
'perfectionist/sort-named-imports': 'off',
|
||||
'perfectionist/sort-object-types': 'off',
|
||||
'perfectionist/sort-objects': 'off',
|
||||
'perfectionist/sort-svelte-attributes': 'off',
|
||||
'perfectionist/sort-union-types': 'off',
|
||||
'perfectionist/sort-vue-attributes': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
parserOptions: {
|
||||
project: ['./tsconfig.json'],
|
||||
tsconfigRootDir: __dirname,
|
||||
EXPERIMENTAL_useSourceOfProjectReferenceRedirect: true,
|
||||
EXPERIMENTAL_useProjectService: true,
|
||||
sourceType: 'module',
|
||||
ecmaVersion: 'latest',
|
||||
},
|
||||
root: true,
|
||||
}
|
||||
38
.eslintrc.js
Normal file
38
.eslintrc.js
Normal file
@@ -0,0 +1,38 @@
|
||||
module.exports = {
|
||||
extends: ['@payloadcms'],
|
||||
overrides: [
|
||||
{
|
||||
extends: ['plugin:@typescript-eslint/disable-type-checked'],
|
||||
files: ['*.js', '*.cjs', '*.json', '*.md', '*.yml', '*.yaml'],
|
||||
},
|
||||
{
|
||||
files: ['packages/eslint-config-payload/**'],
|
||||
rules: {
|
||||
'perfectionist/sort-objects': 'off',
|
||||
},
|
||||
},
|
||||
{
|
||||
files: ['package.json', 'tsconfig.json'],
|
||||
rules: {
|
||||
'perfectionist/sort-array-includes': 'off',
|
||||
'perfectionist/sort-astro-attributes': 'off',
|
||||
'perfectionist/sort-classes': 'off',
|
||||
'perfectionist/sort-enums': 'off',
|
||||
'perfectionist/sort-exports': 'off',
|
||||
'perfectionist/sort-imports': 'off',
|
||||
'perfectionist/sort-interfaces': 'off',
|
||||
'perfectionist/sort-jsx-props': 'off',
|
||||
'perfectionist/sort-keys': 'off',
|
||||
'perfectionist/sort-maps': 'off',
|
||||
'perfectionist/sort-named-exports': 'off',
|
||||
'perfectionist/sort-named-imports': 'off',
|
||||
'perfectionist/sort-object-types': 'off',
|
||||
'perfectionist/sort-objects': 'off',
|
||||
'perfectionist/sort-svelte-attributes': 'off',
|
||||
'perfectionist/sort-union-types': 'off',
|
||||
'perfectionist/sort-vue-attributes': 'off',
|
||||
},
|
||||
},
|
||||
],
|
||||
root: true,
|
||||
}
|
||||
@@ -16,6 +16,3 @@ fb7d1be2f3325d076b7c967b1730afcef37922c2
|
||||
|
||||
# lint and format create-payload-app
|
||||
5fd3d430001efe86515262ded5e26f00c1451181
|
||||
|
||||
# 3.0 prettier & lint everywhere
|
||||
6789e61488a1d3de56f472ac3214faf344030005
|
||||
|
||||
35
.github/CODEOWNERS
vendored
35
.github/CODEOWNERS
vendored
@@ -1,41 +1,32 @@
|
||||
# Order matters. The last matching pattern takes precedence.
|
||||
|
||||
### Core ###
|
||||
/packages/payload/src/uploads/ @denolfe
|
||||
/packages/payload/src/admin/ @jmikrut @jacobsfletch @JarrodMFlesch
|
||||
|
||||
### Adapters ###
|
||||
/packages/db-*/ @denolfe @jmikrut @DanRibbens
|
||||
/packages/richtext-*/ @denolfe @jmikrut @DanRibbens @AlessioGr
|
||||
/packages/richtext-*/ @AlessioGr
|
||||
|
||||
### Plugins ###
|
||||
/packages/plugin-*/ @denolfe @jmikrut @DanRibbens
|
||||
/packages/plugin-cloud*/ @denolfe
|
||||
/packages/plugin-form-builder/ @jacobsfletch
|
||||
/packages/plugin-live-preview*/ @jacobsfletch
|
||||
/packages/plugin-nested-docs/ @jacobsfletch
|
||||
/packages/plugin-redirects/ @jacobsfletch
|
||||
/packages/plugin-search/ @jacobsfletch
|
||||
/packages/plugin-sentry/ @JessChowdhury
|
||||
/packages/plugin-seo/ @jacobsfletch
|
||||
/packages/plugin-stripe/ @jacobsfletch
|
||||
|
||||
### Examples ###
|
||||
/examples/ @jacobsfletch
|
||||
/examples/testing/ @JarrodMFlesch
|
||||
/examples/email/ @JessChowdhury
|
||||
/examples/whitelabel/ @JessChowdhury
|
||||
|
||||
### Templates ###
|
||||
/templates/ @jacobsfletch @denolfe
|
||||
|
||||
### Misc ###
|
||||
/packages/create-payload-app/ @denolfe
|
||||
/packages/eslint-config-payload/ @denolfe
|
||||
/packages/payload-admin-bar/ @jacobsfletch
|
||||
/packages/eslint-*/ @denolfe
|
||||
|
||||
### Build Files ###
|
||||
/**/package.json @denolfe
|
||||
|
||||
/tsconfig.json @denolfe
|
||||
/**/tsconfig*.json @denolfe
|
||||
|
||||
/jest.config.js @denolfe
|
||||
/**/jest.config.js @denolfe
|
||||
|
||||
### Root ###
|
||||
/package.json @denolfe
|
||||
/scripts/ @denolfe
|
||||
/.husky/ @denolfe
|
||||
/.vscode/ @denolfe
|
||||
/.github/ @denolfe
|
||||
/.github/CODEOWNERS @denolfe
|
||||
|
||||
188
.github/workflows/main.yml
vendored
188
.github/workflows/main.yml
vendored
@@ -2,9 +2,9 @@ name: build
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, reopened, synchronize]
|
||||
types: [ opened, reopened, synchronize ]
|
||||
push:
|
||||
branches: ['main', 'alpha']
|
||||
branches: [ 'main' ]
|
||||
|
||||
jobs:
|
||||
changes:
|
||||
@@ -15,10 +15,14 @@ jobs:
|
||||
needs_build: ${{ steps.filter.outputs.needs_build }}
|
||||
templates: ${{ steps.filter.outputs.templates }}
|
||||
steps:
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 25
|
||||
- uses: dorny/paths-filter@v3
|
||||
- uses: dorny/paths-filter@v2
|
||||
id: filter
|
||||
with:
|
||||
filters: |
|
||||
@@ -45,10 +49,14 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 25
|
||||
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
@@ -71,7 +79,7 @@ jobs:
|
||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- run: pnpm install
|
||||
- run: pnpm run build:core
|
||||
- run: pnpm run build
|
||||
|
||||
- name: Cache build
|
||||
uses: actions/cache@v4
|
||||
@@ -79,56 +87,13 @@ jobs:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
plugins-build:
|
||||
needs: changes
|
||||
if: ${{ needs.changes.outputs.needs_build == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 25
|
||||
|
||||
- name: Use Node.js 18
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Get pnpm store directory
|
||||
shell: bash
|
||||
run: |
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/cache@v4
|
||||
name: Setup pnpm cache
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-pnpm-store-
|
||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
|
||||
- run: pnpm install
|
||||
- run: pnpm run build:plugins
|
||||
|
||||
tests:
|
||||
runs-on: ubuntu-latest
|
||||
needs: core-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
database:
|
||||
- mongodb
|
||||
- postgres
|
||||
- postgres-custom-schema
|
||||
- postgres-uuid
|
||||
- supabase
|
||||
database: [mongoose, postgres, postgres-custom-schema, postgres-uuid, supabase]
|
||||
env:
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
@@ -139,10 +104,14 @@ jobs:
|
||||
AWS_REGION: us-east-1
|
||||
|
||||
steps:
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
@@ -162,7 +131,7 @@ jobs:
|
||||
- name: Start PostgreSQL
|
||||
uses: CasperWA/postgresql-action@v1.2
|
||||
with:
|
||||
postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions
|
||||
postgresql version: '14' # See https://hub.docker.com/_/postgres for available versions
|
||||
postgresql db: ${{ env.POSTGRES_DB }}
|
||||
postgresql user: ${{ env.POSTGRES_USER }}
|
||||
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
||||
@@ -201,8 +170,11 @@ jobs:
|
||||
echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV
|
||||
if: matrix.database == 'supabase'
|
||||
|
||||
- name: Component Tests
|
||||
run: pnpm test:components
|
||||
|
||||
- name: Integration Tests
|
||||
run: pnpm test:int --testPathIgnorePatterns=test/fields # Ignore fields tests until reworked
|
||||
run: pnpm test:int
|
||||
env:
|
||||
NODE_OPTIONS: --max-old-space-size=8096
|
||||
PAYLOAD_DATABASE: ${{ matrix.database }}
|
||||
@@ -214,29 +186,17 @@ jobs:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# find test -type f -name 'e2e.spec.ts' | sort | xargs dirname | xargs -I {} basename {}
|
||||
suite:
|
||||
- _community
|
||||
- access-control
|
||||
# - admin
|
||||
- auth
|
||||
# - field-error-states
|
||||
# - fields-relationship
|
||||
# - fields
|
||||
- fields/lexical
|
||||
- live-preview
|
||||
# - localization
|
||||
# - plugin-nested-docs
|
||||
# - plugin-seo
|
||||
# - refresh-permissions
|
||||
# - uploads
|
||||
# - versions
|
||||
part: [ 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8 ]
|
||||
|
||||
steps:
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
@@ -250,34 +210,34 @@ jobs:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Install Playwright
|
||||
run: pnpm exec playwright install
|
||||
|
||||
- name: E2E Tests
|
||||
uses: nick-fields/retry@v3
|
||||
uses: nick-fields/retry@v2
|
||||
with:
|
||||
retry_on: error
|
||||
max_attempts: 2
|
||||
timeout_minutes: 15
|
||||
command: pnpm test:e2e ${{ matrix.suite }}
|
||||
command: pnpm test:e2e --part ${{ matrix.part }} --bail
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: always()
|
||||
with:
|
||||
name: test-results
|
||||
path: test/test-results/
|
||||
path: test-results/
|
||||
retention-days: 1
|
||||
|
||||
tests-type-generation:
|
||||
if: false # This should be replaced with gen on a real Payload project
|
||||
runs-on: ubuntu-latest
|
||||
needs: core-build
|
||||
|
||||
steps:
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
@@ -297,6 +257,47 @@ jobs:
|
||||
- name: Generate GraphQL schema file
|
||||
run: pnpm dev:generate-graphql-schema graphql-schema-gen
|
||||
|
||||
build-packages:
|
||||
runs-on: ubuntu-latest
|
||||
needs: core-build
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
pkg:
|
||||
- db-mongodb
|
||||
- db-postgres
|
||||
- bundler-webpack
|
||||
- bundler-vite
|
||||
- richtext-slate
|
||||
- richtext-lexical
|
||||
- live-preview
|
||||
- live-preview-react
|
||||
|
||||
steps:
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Restore build
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ./*
|
||||
key: ${{ github.sha }}-${{ github.run_number }}
|
||||
|
||||
- name: Build ${{ matrix.pkg }}
|
||||
run: pnpm turbo run build --filter=${{ matrix.pkg }}
|
||||
|
||||
plugins:
|
||||
runs-on: ubuntu-latest
|
||||
needs: core-build
|
||||
@@ -314,10 +315,14 @@ jobs:
|
||||
- plugin-seo
|
||||
|
||||
steps:
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v3
|
||||
@@ -336,25 +341,30 @@ jobs:
|
||||
|
||||
- name: Test ${{ matrix.pkg }}
|
||||
run: pnpm --filter ${{ matrix.pkg }} run test
|
||||
if: matrix.pkg != 'create-payload-app' # degit doesn't work within GitHub Actions
|
||||
|
||||
templates:
|
||||
needs: changes
|
||||
if: false # Disable until templates are updated for 3.0
|
||||
if: ${{ needs.changes.outputs.templates == 'true' }}
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
template: [blank, website, ecommerce]
|
||||
template: [ blank, website, ecommerce ]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 25
|
||||
|
||||
- name: Use Node.js 18
|
||||
# https://github.com/actions/virtual-environments/issues/1187
|
||||
- name: tune linux network
|
||||
run: sudo ethtool -K eth0 tx off rx off
|
||||
|
||||
- name: Use Node.js 20
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 20
|
||||
|
||||
- name: Start MongoDB
|
||||
uses: supercharge/mongodb-github-action@1.10.0
|
||||
|
||||
11
.github/workflows/release-canary.yml
vendored
Normal file
11
.github/workflows/release-canary.yml
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
name: release-canary
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Echo
|
||||
run: echo "Register release-canary workflow"
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -9,13 +9,6 @@ test-results
|
||||
.localstack
|
||||
/migrations
|
||||
.localstack
|
||||
.turbo
|
||||
|
||||
.turbo
|
||||
|
||||
# Ignore test directory media folder/files
|
||||
/media
|
||||
/versions
|
||||
|
||||
# Created by https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
@@ -288,4 +281,3 @@ $RECYCLE.BIN/
|
||||
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||
|
||||
/build
|
||||
.swc
|
||||
5
.idea/runConfigurations/Run_Dev_Fields.xml
generated
5
.idea/runConfigurations/Run_Dev_Fields.xml
generated
@@ -1,8 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="--no-deprecation fields" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
|
||||
<envs>
|
||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
||||
</envs>
|
||||
<configuration default="false" name="Run Dev Fields" type="NodeJSConfigurationType" application-parameters="fields" path-to-js-file="node_modules/.pnpm/nodemon@3.0.3/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
5
.idea/runConfigurations/Run_Dev__community.xml
generated
5
.idea/runConfigurations/Run_Dev__community.xml
generated
@@ -1,8 +1,5 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="--no-deprecation _community" path-to-js-file="test/dev.js" working-dir="$PROJECT_DIR$">
|
||||
<envs>
|
||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
||||
</envs>
|
||||
<configuration default="false" name="Run Dev _community" type="NodeJSConfigurationType" application-parameters="_community" path-to-js-file="node_modules/.pnpm/nodemon@3.0.3/node_modules/nodemon/bin/nodemon.js" working-dir="$PROJECT_DIR$">
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -1 +1 @@
|
||||
v18.19.1
|
||||
v18.17.1
|
||||
|
||||
@@ -9,4 +9,3 @@
|
||||
**/node_modules
|
||||
**/temp
|
||||
**/docs/**
|
||||
tsconfig.json
|
||||
|
||||
16
.release-it.pre.js
Normal file
16
.release-it.pre.js
Normal file
@@ -0,0 +1,16 @@
|
||||
module.exports = {
|
||||
verbose: true,
|
||||
git: {
|
||||
requireCleanWorkingDir: false,
|
||||
commit: false,
|
||||
push: false,
|
||||
tag: false,
|
||||
},
|
||||
npm: {
|
||||
skipChecks: true,
|
||||
tag: 'beta',
|
||||
},
|
||||
hooks: {
|
||||
'before:init': ['pnpm install', 'pnpm clean', 'pnpm build'],
|
||||
},
|
||||
}
|
||||
15
.swcrc
15
.swcrc
@@ -1,15 +0,0 @@
|
||||
{
|
||||
"$schema": "https://json.schemastore.org/swcrc",
|
||||
"sourceMaps": "inline",
|
||||
"jsc": {
|
||||
"target": "esnext",
|
||||
"parser": {
|
||||
"syntax": "typescript",
|
||||
"tsx": true,
|
||||
"dts": true
|
||||
}
|
||||
},
|
||||
"module": {
|
||||
"type": "es6"
|
||||
}
|
||||
}
|
||||
7
.vscode/extensions.json
vendored
7
.vscode/extensions.json
vendored
@@ -1,8 +1,3 @@
|
||||
{
|
||||
"recommendations": [
|
||||
"dbaeumer.vscode-eslint",
|
||||
"esbenp.prettier-vscode",
|
||||
"firsttris.vscode-jest-runner",
|
||||
"ms-playwright.playwright"
|
||||
]
|
||||
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
|
||||
}
|
||||
|
||||
36
.vscode/launch.json
vendored
36
.vscode/launch.json
vendored
@@ -3,26 +3,12 @@
|
||||
// Hover to view descriptions of existing attributes.
|
||||
"configurations": [
|
||||
{
|
||||
"command": "pnpm generate:types",
|
||||
"name": "Generate Types CLI",
|
||||
"request": "launch",
|
||||
"type": "node-terminal",
|
||||
"cwd": "${workspaceFolder}"
|
||||
},
|
||||
{
|
||||
"command": "node --no-deprecation test/dev.js fields",
|
||||
"command": "pnpm run dev _community",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Community",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev live-preview -- --no-turbo",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Live Preview",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev plugin-cloud-storage",
|
||||
"cwd": "${workspaceFolder}",
|
||||
@@ -33,6 +19,13 @@
|
||||
"PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER": "s3"
|
||||
}
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev collections-graphql",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev GraphQL",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev fields",
|
||||
"cwd": "${workspaceFolder}",
|
||||
@@ -41,7 +34,7 @@
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "pnpm run dev:postgres versions",
|
||||
"command": "pnpm run dev:postgres fields",
|
||||
"cwd": "${workspaceFolder}",
|
||||
"name": "Run Dev Postgres",
|
||||
"request": "launch",
|
||||
@@ -116,6 +109,17 @@
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "ts-node ./packages/payload/src/bin/index.ts generate:types",
|
||||
"env": {
|
||||
"PAYLOAD_CONFIG_PATH": "test/_community/config.ts",
|
||||
"DISABLE_SWC": "true" // SWC messes up debugging the bin scripts
|
||||
},
|
||||
"name": "Generate Types CLI",
|
||||
"outputCapture": "std",
|
||||
"request": "launch",
|
||||
"type": "node-terminal"
|
||||
},
|
||||
{
|
||||
"command": "ts-node ./packages/payload/src/bin/index.ts migrate:status",
|
||||
"env": {
|
||||
|
||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -35,10 +35,5 @@
|
||||
"eslint.rules.customizations": [{ "rule": "*", "severity": "warn" }],
|
||||
"typescript.tsdk": "node_modules/typescript/lib",
|
||||
// Load .git-blame-ignore-revs file
|
||||
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
|
||||
"[javascript][typescript][typescriptreact]": {
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.fixAll.eslint": "explicit"
|
||||
}
|
||||
}
|
||||
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"]
|
||||
}
|
||||
|
||||
194
CHANGELOG.md
194
CHANGELOG.md
@@ -1,3 +1,197 @@
|
||||
## [2.18.0](https://github.com/payloadcms/payload/compare/v2.17.0...v2.18.0) (2024-05-16)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* store focal point on uploads ([#6364](https://github.com/payloadcms/payload/issues/6364)) ([82b88a3](https://github.com/payloadcms/payload/commit/82b88a315ff1d52f0b19a70224d5c600a3a97eb5))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db-postgres:** filter with ID not_in AND queries - postgres ([#6358](https://github.com/payloadcms/payload/issues/6358)) ([cc94078](https://github.com/payloadcms/payload/commit/cc940786072c0065f10fdd2893050bddc4595a21)), closes [#5151](https://github.com/payloadcms/payload/issues/5151)
|
||||
* **richtext-lexical:** upload, relationship and block node insertion fails sometimes ([#6390](https://github.com/payloadcms/payload/issues/6390)) ([48a410e](https://github.com/payloadcms/payload/commit/48a410e294598af9c73577a04f86466248f93da0))
|
||||
|
||||
## [2.17.0](https://github.com/payloadcms/payload/compare/v2.16.1...v2.17.0) (2024-05-15)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds misc translations to API view and react select ([#6138](https://github.com/payloadcms/payload/issues/6138)) ([30e535b](https://github.com/payloadcms/payload/commit/30e535b5b929dddead007d8a9adca62808595e2c))
|
||||
|
||||
* **richtext-lexical:** remove LexicalBlock, RichTextFieldRequiredEditor and FieldWithRichTextRequiredEditor types ([#6279](https://github.com/payloadcms/payload/issues/6279)) ([9df5ab8](https://github.com/payloadcms/payload/commit/9df5ab8a10a35ad34615d7e4da024f59ff037e0e))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* appends `editDepth` value to `radio` & `checkbox` IDs when inside drawer ([#6181](https://github.com/payloadcms/payload/issues/6181)) ([69c93d3](https://github.com/payloadcms/payload/commit/69c93d3c62394a5cf995a2eaec9a3ab30e0f77af))
|
||||
* collection labels with locales not working when creating new doc ([#5995](https://github.com/payloadcms/payload/issues/5995)) ([51efe4f](https://github.com/payloadcms/payload/commit/51efe4f39bcaadccb109a2a02a690ca65041ee57))
|
||||
* safely access cookie header for uploads ([#6367](https://github.com/payloadcms/payload/issues/6367)) ([de92c50](https://github.com/payloadcms/payload/commit/de92c50847640661f915455f8db0029873ddc7ab))
|
||||
* step-nav breadcrumbs ellipsis ([#6345](https://github.com/payloadcms/payload/issues/6345)) ([d02b1fb](https://github.com/payloadcms/payload/commit/d02b1fb084e636e49122ad55b25b9c49eb761f1c))
|
||||
*
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **richtext-lexical:** remove LexicalBlock, RichTextFieldRequiredEditor and FieldWithRichTextRequiredEditor types (#6279)
|
||||
|
||||
## [2.16.1](https://github.com/payloadcms/payload/compare/v2.16.0...v2.16.1) (2024-05-07)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **richtext-lexical:** add maxDepth property to various lexical features ([#6250](https://github.com/payloadcms/payload/issues/6250)) ([857b9a4](https://github.com/payloadcms/payload/commit/857b9a4ac3236c740458750f156a3a4274eda210)), closes [#6242](https://github.com/payloadcms/payload/issues/6242)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **richtext-lexical:** export missing HorizontalRuleFeature ([#6236](https://github.com/payloadcms/payload/issues/6236)) ([f829b08](https://github.com/payloadcms/payload/commit/f829b084ba9649ef596cce4a7bf6ae8c7ccf57e3))
|
||||
|
||||
## [2.16.0](https://github.com/payloadcms/payload/compare/v2.15.0...v2.16.0) (2024-05-06)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* adds disableListColumn, disableListFilter to fields admin props ([#6188](https://github.com/payloadcms/payload/issues/6188)) ([db4aace](https://github.com/payloadcms/payload/commit/db4aacebb801f1cc11ef8732f9f3b78475256641))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* graphql upload relations returning null ([#6233](https://github.com/payloadcms/payload/issues/6233)) ([cac52da](https://github.com/payloadcms/payload/commit/cac52da638a0df4356120a2f61c6aaf25641a5ad))
|
||||
* hide drag handles when `admin.isSortable: false` ([#6225](https://github.com/payloadcms/payload/issues/6225)) ([622cdb0](https://github.com/payloadcms/payload/commit/622cdb044002b2c3182c3b0432b51befbfb9b979))
|
||||
* **plugin-form-builder:** hook overrides not working as intended ([#6203](https://github.com/payloadcms/payload/issues/6203)) ([b735d6a](https://github.com/payloadcms/payload/commit/b735d6aa169acca8cb638859d2c8ba43e315f02c))
|
||||
|
||||
## [2.15.0](https://github.com/payloadcms/payload/compare/v2.14.2...v2.15.0) (2024-05-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add isSortable to arrays and blocks ([#5962](https://github.com/payloadcms/payload/issues/5962)) ([5c58bd3](https://github.com/payloadcms/payload/commit/5c58bd322da966fe610959df13dfd49add35a2ef))
|
||||
* use filterOptions in list relationship filter ([#6156](https://github.com/payloadcms/payload/issues/6156)) ([23f3eb1](https://github.com/payloadcms/payload/commit/23f3eb1cf0b75a4044319d7cd3e5000d5b4e42c4))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bulk publish from collection list ([#6063](https://github.com/payloadcms/payload/issues/6063)) ([84570e6](https://github.com/payloadcms/payload/commit/84570e6e3bbb81fcae80da92b01bc56d09906072))
|
||||
* cascade draft arg in nested GraphQL relationship queries ([#6141](https://github.com/payloadcms/payload/issues/6141)) ([a8ac8b4](https://github.com/payloadcms/payload/commit/a8ac8b463349664f3188ae77217f037da72f796b))
|
||||
* GraphQL nested relationships not respecting req locale ([#6117](https://github.com/payloadcms/payload/issues/6117)) ([3fccd34](https://github.com/payloadcms/payload/commit/3fccd34abe5a332f88f5e950b755cd1d21441fb6))
|
||||
* hide unusable fields from collection filter select ([#6135](https://github.com/payloadcms/payload/issues/6135)) ([2be5ad0](https://github.com/payloadcms/payload/commit/2be5ad0ebafd1d3c1c0567e2085ccfd593f18271))
|
||||
* incorrect `localesNotSaved` translation ([#5996](https://github.com/payloadcms/payload/issues/5996)) ([af67749](https://github.com/payloadcms/payload/commit/af67749e49db92e675b63b52190e562468894706))
|
||||
* **plugin-cloud:** purge cache for all sizes ([#5301](https://github.com/payloadcms/payload/issues/5301)) ([831f1ff](https://github.com/payloadcms/payload/commit/831f1ff5bed7e083cc076e9eb5ff9a2b2f1ed710))
|
||||
* properly adds `readonly` styles to disabled `radio` fields ([#6176](https://github.com/payloadcms/payload/issues/6176)) ([9b7e62d](https://github.com/payloadcms/payload/commit/9b7e62dc20dca7402c6c68dfb8a5995c211993af))
|
||||
* resets filter state when param state change within route ([#6169](https://github.com/payloadcms/payload/issues/6169)) ([6e38cc2](https://github.com/payloadcms/payload/commit/6e38cc2bcfb08b608abcb6aac4b4c1f6eea63428))
|
||||
* **richtext-lexical:** drag and add block handles disappear too quickly for smaller screen sizes. ([#6145](https://github.com/payloadcms/payload/issues/6145)) ([24f6972](https://github.com/payloadcms/payload/commit/24f697219b5071d91a5c37aafb50e2d823b68d4c))
|
||||
* **richtext-lexical:** floating toolbar caret positioned incorrectly for some line heights ([#6151](https://github.com/payloadcms/payload/issues/6151)) ([36b1f5a](https://github.com/payloadcms/payload/commit/36b1f5a763f782c140e62aa062b4077d6efd0738))
|
||||
* sanitizes fields in default edit view for drawer content ([#6175](https://github.com/payloadcms/payload/issues/6175)) ([43dab5c](https://github.com/payloadcms/payload/commit/43dab5c7053831a0c71f3a6860113f653cab674f))
|
||||
* version restoration ([#6039](https://github.com/payloadcms/payload/issues/6039)) ([91bac9c](https://github.com/payloadcms/payload/commit/91bac9c0aa1ff3da052b9c2ad83fa5ac23a16d1d))
|
||||
|
||||
## [2.14.2](https://github.com/payloadcms/payload/compare/v2.14.1...v2.14.2) (2024-04-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **deps:** dedupes react ([#6058](https://github.com/payloadcms/payload/issues/6058)) ([d0ba694](https://github.com/payloadcms/payload/commit/d0ba694c80a1b699c4f2cad98b1f0bde1f0d43ca))
|
||||
|
||||
## [2.14.1](https://github.com/payloadcms/payload/compare/v2.14.0...v2.14.1) (2024-04-25)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db-postgres:** cumulative updates ([#6033](https://github.com/payloadcms/payload/issues/6033)) ([c31b8dc](https://github.com/payloadcms/payload/commit/c31b8dcaa0c43132d8a01e0cc43094f466cc9168))
|
||||
* disable api key checkbox does not remove api key ([#6017](https://github.com/payloadcms/payload/issues/6017)) ([0ffdcc6](https://github.com/payloadcms/payload/commit/0ffdcc685f4e917a02e62dbaccec7cc8ebbf695d))
|
||||
* **richtext-lexical:** minimize the amount of times sanitizeFields is called ([#6018](https://github.com/payloadcms/payload/issues/6018)) ([60372fa](https://github.com/payloadcms/payload/commit/60372faf36b7f6d92a61ccbaee0f528e50f5a51a))
|
||||
|
||||
## [2.14.0](https://github.com/payloadcms/payload/compare/v2.13.0...v2.14.0) (2024-04-24)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* add count operation to collections ([#5936](https://github.com/payloadcms/payload/issues/5936)) ([c380dee](https://github.com/payloadcms/payload/commit/c380deee4a1db82bce9fea264060000957a53eee))
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* bulk publish ([#6006](https://github.com/payloadcms/payload/issues/6006)) ([c11600a](https://github.com/payloadcms/payload/commit/c11600aac38cd67019765faf2a41e62df13e50cc))
|
||||
* **db-postgres:** extra version suffix added to table names ([#5939](https://github.com/payloadcms/payload/issues/5939)) ([bd8b512](https://github.com/payloadcms/payload/commit/bd8b5123b0991e53eb209315897dbca10d14d45e))
|
||||
* **db-postgres:** Fixes nested groups inside nested blocks ([#5882](https://github.com/payloadcms/payload/issues/5882)) ([e258866](https://github.com/payloadcms/payload/commit/e25886649fce414d5d47918f35ba2d4d2ba59174))
|
||||
* **db-postgres:** row table names were not being built properly - v2 ([#5961](https://github.com/payloadcms/payload/issues/5961)) ([9152a23](https://github.com/payloadcms/payload/commit/9152a238d2982503e7f509350651b0ba3f83b1ec))
|
||||
* header filters ([#5997](https://github.com/payloadcms/payload/issues/5997)) ([ad01c67](https://github.com/payloadcms/payload/commit/ad01c6784d283386dc819dfcd47455cad5accfaa))
|
||||
* min/max attributes missing from number input ([#5779](https://github.com/payloadcms/payload/issues/5779)) ([985796b](https://github.com/payloadcms/payload/commit/985796be54b593af0a4934685ab8621b9badda10))
|
||||
* removes `equals` & `not_equals` operators from fields with `hasMany` ([#5885](https://github.com/payloadcms/payload/issues/5885)) ([a8c9625](https://github.com/payloadcms/payload/commit/a8c9625cdec33476a5da87bcd9f010f9d7fb9a94))
|
||||
|
||||
## [2.13.0](https://github.com/payloadcms/payload/compare/v2.12.1...v2.13.0) (2024-04-19)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* allow configuration for setting headers on external file fetch ([ec1ad0b](https://github.com/payloadcms/payload/commit/ec1ad0b6628d400d7435821c8a72b6746bf87577))
|
||||
* **db-\*:** custom db table and enum names ([#5045](https://github.com/payloadcms/payload/issues/5045)) ([9bbacc4](https://github.com/payloadcms/payload/commit/9bbacc4fb1ad247634f394e95c42ee3adade8048))
|
||||
* json field schemas ([#5726](https://github.com/payloadcms/payload/issues/5726)) ([2c402cc](https://github.com/payloadcms/payload/commit/2c402cc65c9e8f7f33e2fb0ce5e1a8ceff52af1b))
|
||||
* **plugin-seo:** add Chinese translation ([#5429](https://github.com/payloadcms/payload/issues/5429)) ([fcb29bb](https://github.com/payloadcms/payload/commit/fcb29bb1c637867301bbc1070b4a84383bf0e90a))
|
||||
* **richtext-lexical:** add HorizontalRuleFeature ([d8e9084](https://github.com/payloadcms/payload/commit/d8e9084db21828968046ab59775633e409ce5c2a))
|
||||
* **richtext-lexical:** improve floating handle y-positioning by positioning it in the center for smaller elements. ([0055a8e](https://github.com/payloadcms/payload/commit/0055a8eb36b95722cccdc5eb3101a79d3e764f8b))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* adds type error validations for `email` and `password` in login operation ([#4852](https://github.com/payloadcms/payload/issues/4852)) ([1f00360](https://github.com/payloadcms/payload/commit/1f0036054a9461535b0992f2449e91e4eaf97d4e))
|
||||
* avoids getting and setting doc preferences when creating new ([#5757](https://github.com/payloadcms/payload/issues/5757)) ([e3c3dda](https://github.com/payloadcms/payload/commit/e3c3ddac34dff8fa085f5b702be2838d513be300))
|
||||
* block field type missing dbName ([#5695](https://github.com/payloadcms/payload/issues/5695)) ([e7608f5](https://github.com/payloadcms/payload/commit/e7608f5507d3b85ea3f44b5cb1f43edf67608b1b))
|
||||
* **db-mongodb:** failing `contains` query with special chars ([#5774](https://github.com/payloadcms/payload/issues/5774)) ([5fa99fb](https://github.com/payloadcms/payload/commit/5fa99fb060cabbb69b5d6688748260e562e6bea3))
|
||||
* **db-mongodb:** ignore end session errors ([#5904](https://github.com/payloadcms/payload/issues/5904)) ([cb8d562](https://github.com/payloadcms/payload/commit/cb8d562132bee437798880e1d7f64dbfdee36949))
|
||||
* **db-mongodb:** version fields indexSortableFields ([#5863](https://github.com/payloadcms/payload/issues/5863)) ([fe0028c](https://github.com/payloadcms/payload/commit/fe0028c89945303a431b48efdae7b6e22304c8a3))
|
||||
* **db-postgres:** hasMany relationship query contains operator ([#4212](https://github.com/payloadcms/payload/issues/4212)) ([608d6d0](https://github.com/payloadcms/payload/commit/608d6d0a872af224ea42c3e6c8a3b4f21678f550))
|
||||
* **db-postgres:** issue querying by localised relationship not respecting locale as constraint ([#5666](https://github.com/payloadcms/payload/issues/5666)) ([44599cb](https://github.com/payloadcms/payload/commit/44599cbc7b8f23d6d8c7a3e05466237406812a6d))
|
||||
* **db-postgres:** query hasMany fields with in ([#5881](https://github.com/payloadcms/payload/issues/5881)) ([6185f8a](https://github.com/payloadcms/payload/commit/6185f8a5d845d12651f5a3ee128eb43d3b9d2449))
|
||||
* **db-postgres:** relationship query pagination ([#5802](https://github.com/payloadcms/payload/issues/5802)) ([65690a6](https://github.com/payloadcms/payload/commit/65690a675c17cfacebe775a327a57741ac09416a))
|
||||
* **db-postgres:** validateExistingBlockIsIdentical localized ([#5839](https://github.com/payloadcms/payload/issues/5839)) ([4c4f924](https://github.com/payloadcms/payload/commit/4c4f924e90ee23a73c9a7cc7e69bbc2caf902b92))
|
||||
* duplicate document multiple times in quick succession ([#5642](https://github.com/payloadcms/payload/issues/5642)) ([373787d](https://github.com/payloadcms/payload/commit/373787de31cbbd33b587aa4be6344948f082f5bb))
|
||||
* missing date locales ([#5656](https://github.com/payloadcms/payload/issues/5656)) ([c1c8600](https://github.com/payloadcms/payload/commit/c1c86009a5e9aad401a05f7c63ad37bd3f88dc84))
|
||||
* number ids were not sanitized to number in rest api ([51f84a4](https://github.com/payloadcms/payload/commit/51f84a4fcfd437eb73c7d83205b66e3620085909))
|
||||
* passes parent id instead of incoming id to saveVersion ([#5831](https://github.com/payloadcms/payload/issues/5831)) ([25c9a14](https://github.com/payloadcms/payload/commit/25c9a145bec9e9566d2bbcba59d5b34394e10bbd))
|
||||
* **plugin-seo:** uses correct key for ukrainian translation ([#5873](https://github.com/payloadcms/payload/issues/5873)) ([e47e544](https://github.com/payloadcms/payload/commit/e47e544364031ac834565a4d86ef6ec9c04e63c0))
|
||||
* properly handle drafts in bulk update ([#5872](https://github.com/payloadcms/payload/issues/5872)) ([ad38f76](https://github.com/payloadcms/payload/commit/ad38f760111abf947c6b0ee4b983ee1224a9bf1b))
|
||||
* req.collection being lost when querying a global inside a collection ([#5727](https://github.com/payloadcms/payload/issues/5727)) ([cbd03ed](https://github.com/payloadcms/payload/commit/cbd03ed2f8819ee8ac20e8739cc03e88ff4caa25))
|
||||
* **richtext-lexical:** catch errors that may occur during HTML generation ([#5754](https://github.com/payloadcms/payload/issues/5754)) ([9b44296](https://github.com/payloadcms/payload/commit/9b442960929d00faa07f1383b1267f71e6f44efe))
|
||||
* **richtext-lexical:** do not allow omitting editor prop for sub-richtext fields within lexical defined in the payload config ([#5766](https://github.com/payloadcms/payload/issues/5766)) ([6186493](https://github.com/payloadcms/payload/commit/6186493246157b4d4b33c8c47378f08581315942))
|
||||
* **richtext-lexical:** incorrect floating handle y-position calculation next to certain kinds of HTML elements like HR ([de5d6cc](https://github.com/payloadcms/payload/commit/de5d6cc4bd591745156f0b8c56795b7bd2eaad7e))
|
||||
* **richtext-lexical:** limit unnecessary floating handle positioning updates ([a00439e](https://github.com/payloadcms/payload/commit/a00439ea893e074d64be83ee6af1e780178a7ee3))
|
||||
* **richtext-lexical:** pass through config for schema generation. Makes it more robust ([#5700](https://github.com/payloadcms/payload/issues/5700)) ([cf135fd](https://github.com/payloadcms/payload/commit/cf135fd1e4aeb30121281399e26be901393ada6d))
|
||||
* **richtext-lexical:** use correct nodeType on HorizontalRule feature HTML converter ([#5805](https://github.com/payloadcms/payload/issues/5805)) ([3b1d331](https://github.com/payloadcms/payload/commit/3b1d3313165499616673f6d363c90ef884994525))
|
||||
* updates type name of `CustomPublishButtonProps` to `CustomPublishButtonType` ([#5644](https://github.com/payloadcms/payload/issues/5644)) ([7df7bf4](https://github.com/payloadcms/payload/commit/7df7bf448bd26e870a1fde8aaa47430904d68366))
|
||||
* updates var ([9530d28](https://github.com/payloadcms/payload/commit/9530d28a6760a667b718027a49ea43ba1accd546))
|
||||
* use isolateObjectProperty function in createLocalReq ([#5748](https://github.com/payloadcms/payload/issues/5748)) ([c0ba6cc](https://github.com/payloadcms/payload/commit/c0ba6cc19a20c043a08ca77caacd47ef7cfb48f4))
|
||||
* uses find instead of fieldIndex for custom ID check ([509ec67](https://github.com/payloadcms/payload/commit/509ec677c42993d9c08facf6928a5ef1e9767508))
|
||||
|
||||
### ⚠ BREAKING CHANGES
|
||||
|
||||
* **richtext-lexical:** do not allow omitting editor prop for sub-richtext fields within lexical defined in the payload config ([#5766](https://github.com/payloadcms/payload/issues/5766))
|
||||
|
||||
## [2.12.1](https://github.com/payloadcms/payload/compare/v2.12.0...v2.12.1) (2024-04-03)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* Skip parsing if operator is 'exist' ([#5404](https://github.com/payloadcms/payload/issues/5404)) ([742a7af](https://github.com/payloadcms/payload/commit/742a7af93d2e9ef4d41ee093cef875322792ae72))
|
||||
* updates colors of tooltip in light mode ([#5632](https://github.com/payloadcms/payload/issues/5632)) ([a7e7c92](https://github.com/payloadcms/payload/commit/a7e7c9276835e0a35a18daccb218c901ca2fdd8c))
|
||||
|
||||
## [2.12.0](https://github.com/payloadcms/payload/compare/v2.11.2...v2.12.0) (2024-04-03)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **plugin-seo:** adds Norwegian translation ([#5621](https://github.com/payloadcms/payload/issues/5621)) ([589b492](https://github.com/payloadcms/payload/commit/589b492b2e6bc578e6f17649ff6d936ffd88b8b5))
|
||||
* **richtext-*:** add ability to provide custom Field and Error components ([#5574](https://github.com/payloadcms/payload/issues/5574)) ([02d2c51](https://github.com/payloadcms/payload/commit/02d2c517176a775c6eeb4b164d9e6b45d8f5e4c1))
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **db-postgres:** error on delete having joins ([#5459](https://github.com/payloadcms/payload/issues/5459)) ([9169230](https://github.com/payloadcms/payload/commit/916923071a2c28077326bfd2059d1665ef47e94f))
|
||||
* image resize tiff files ([#5415](https://github.com/payloadcms/payload/issues/5415)) ([8184e00](https://github.com/payloadcms/payload/commit/8184e0005af1b6da93d0921c31547515a4ce6343))
|
||||
* number field with hasMany accept defaultValue array ([#5618](https://github.com/payloadcms/payload/issues/5618)) ([a3ae416](https://github.com/payloadcms/payload/commit/a3ae4160850290c194bb228e1fbeb8c7533cead3))
|
||||
* regression of filterOptions using different transaction ([#5169](https://github.com/payloadcms/payload/issues/5169)) ([3ceb6ef](https://github.com/payloadcms/payload/commit/3ceb6efd32cfa9556c6656469fa43d61d7679b1d))
|
||||
* **richtext-lexical:** Blocks: generated output schema is not fully correct ([#5259](https://github.com/payloadcms/payload/issues/5259)) ([e7f6bfb](https://github.com/payloadcms/payload/commit/e7f6bfbe9da4cab42c7ec7019371d5e79af17ec9))
|
||||
* **richtext-lexical:** checklist html converter incorrectly outputting children ([#5570](https://github.com/payloadcms/payload/issues/5570)) ([2e5400f](https://github.com/payloadcms/payload/commit/2e5400fa7a5ac7441e00134a7f4299022228f64f))
|
||||
* **richtext-lexical:** disable instanceof HTMLImageElement check as it causes issues when used on the server ([2164dcc](https://github.com/payloadcms/payload/commit/2164dcc594b5c16d7111b71cdb01f5f7aaa7e127))
|
||||
* **richtext-lexical:** Link: add open-in-new-tab to html converter ([23df60d](https://github.com/payloadcms/payload/commit/23df60dba5682255ce6f60e3ee8e6901f6a70c7b))
|
||||
* **richtext-lexical:** properly center add- and drag-block handles ([#5568](https://github.com/payloadcms/payload/issues/5568)) ([48dc116](https://github.com/payloadcms/payload/commit/48dc116f57113c3124ff93a50fa1189053e21d76))
|
||||
* sets beforeValidateHook req type to required ([#5608](https://github.com/payloadcms/payload/issues/5608)) ([e10d5df](https://github.com/payloadcms/payload/commit/e10d5df0b2dd21b86cce44d0e36b31e9d3411b39))
|
||||
|
||||
## [2.11.2](https://github.com/payloadcms/payload/compare/v2.11.1...v2.11.2) (2024-02-23)
|
||||
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
<hr/>
|
||||
|
||||
> [!IMPORTANT]
|
||||
> 🎉 <strong>Payload 2.0 is now available!</strong> Read more in the <a target="_blank" href="https://payloadcms.com/blog/payload-2-0" rel="dofollow"><strong>announcement post</strong></a>.
|
||||
> 🎉 <strong>Payload 3.0 beta released!</strong> You can now deploy Payload fully in any Next.js app folder. Read more in the <a target="_blank" href="https://payloadcms.com/blog/30-beta-install-payload-into-any-nextjs-app-with-one-line" rel="dofollow"><strong>announcement post</strong></a>.
|
||||
|
||||
<h3>Benefits over a regular CMS</h3>
|
||||
<ul>
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { NotFoundView } from '@payloadcms/next/views/NotFound/index.js'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
segments: string[]
|
||||
}
|
||||
searchParams: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
}
|
||||
|
||||
const NotFound = ({ params, searchParams }: Args) => NotFoundView({ config, params, searchParams })
|
||||
|
||||
export default NotFound
|
||||
@@ -1,22 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import config from '@payload-config'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import { RootPage, generatePageMetadata } from '@payloadcms/next/views/Root/index.js'
|
||||
|
||||
type Args = {
|
||||
params: {
|
||||
segments: string[]
|
||||
}
|
||||
searchParams: {
|
||||
[key: string]: string | string[]
|
||||
}
|
||||
}
|
||||
|
||||
export const generateMetadata = ({ params, searchParams }: Args): Promise<Metadata> =>
|
||||
generatePageMetadata({ config, params, searchParams })
|
||||
|
||||
const Page = ({ params, searchParams }: Args) => RootPage({ config, params, searchParams })
|
||||
|
||||
export default Page
|
||||
@@ -1,9 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { REST_DELETE, REST_GET, REST_PATCH, REST_POST } from '@payloadcms/next/routes/index.js'
|
||||
|
||||
export const GET = REST_GET(config)
|
||||
export const POST = REST_POST(config)
|
||||
export const DELETE = REST_DELETE(config)
|
||||
export const PATCH = REST_PATCH(config)
|
||||
@@ -1,6 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { GRAPHQL_PLAYGROUND_GET } from '@payloadcms/next/routes/index.js'
|
||||
|
||||
export const GET = GRAPHQL_PLAYGROUND_GET(config)
|
||||
@@ -1,6 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
/* DO NOT MODIFY it because it could be re-written at any time. */
|
||||
import config from '@payload-config'
|
||||
import { GRAPHQL_POST } from '@payloadcms/next/routes/index.js'
|
||||
|
||||
export const POST = GRAPHQL_POST(config)
|
||||
@@ -1,15 +0,0 @@
|
||||
/* THIS FILE WAS GENERATED AUTOMATICALLY BY PAYLOAD. */
|
||||
import configPromise from '@payload-config'
|
||||
import { RootLayout } from '@payloadcms/next/layouts/Root/index.js'
|
||||
/* DO NOT MODIFY IT BECAUSE IT COULD BE REWRITTEN AT ANY TIME. */
|
||||
import React from 'react'
|
||||
|
||||
import './custom.scss'
|
||||
|
||||
type Args = {
|
||||
children: React.ReactNode
|
||||
}
|
||||
|
||||
const Layout = ({ children }: Args) => <RootLayout config={configPromise}>{children}</RootLayout>
|
||||
|
||||
export default Layout
|
||||
@@ -1,43 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
||||
import React from 'react'
|
||||
|
||||
import type { Page as PageType } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../_api/serverURL.js'
|
||||
import { Blocks } from '../../_components/Blocks/index.js'
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { Hero } from '../../_components/Hero/index.js'
|
||||
|
||||
export const PageClient: React.FC<{
|
||||
page: PageType
|
||||
}> = ({ page: initialPage }) => {
|
||||
const { data } = useLivePreview<PageType>({
|
||||
depth: 2,
|
||||
initialData: initialPage,
|
||||
serverURL: PAYLOAD_SERVER_URL,
|
||||
})
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<Gutter>
|
||||
<h1 id="page-title">{data.title}</h1>
|
||||
</Gutter>
|
||||
<Hero {...data?.hero} />
|
||||
<Blocks
|
||||
blocks={[
|
||||
...(data?.layout ?? []),
|
||||
{
|
||||
blockName: 'Relationships',
|
||||
blockType: 'relationships',
|
||||
data,
|
||||
},
|
||||
]}
|
||||
disableTopPadding={
|
||||
!data?.hero || data?.hero?.type === 'none' || data?.hero?.type === 'lowImpact'
|
||||
}
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
import { notFound } from 'next/navigation.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { fetchDoc } from '../../_api/fetchDoc.js'
|
||||
import { fetchDocs } from '../../_api/fetchDocs.js'
|
||||
import { PageClient } from './page.client.js'
|
||||
|
||||
// eslint-disable-next-line no-restricted-exports
|
||||
export default async function Page({ params: { slug = 'home' } }) {
|
||||
let page: Page | null = null
|
||||
|
||||
try {
|
||||
page = await fetchDoc<Page>({
|
||||
slug,
|
||||
collection: 'pages',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
if (!page) {
|
||||
return notFound()
|
||||
}
|
||||
|
||||
return <PageClient page={page} />
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const pages = await fetchDocs<Page>('pages')
|
||||
return pages?.map(({ slug }) => slug)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import { useLivePreview } from '@payloadcms/live-preview-react'
|
||||
import React from 'react'
|
||||
|
||||
import type { Post as PostType } from '../../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
||||
import { Blocks } from '../../../_components/Blocks/index.js'
|
||||
import { PostHero } from '../../../_heros/PostHero/index.js'
|
||||
|
||||
export const PostClient: React.FC<{
|
||||
post: PostType
|
||||
}> = ({ post: initialPost }) => {
|
||||
const { data } = useLivePreview<PostType>({
|
||||
depth: 2,
|
||||
initialData: initialPost,
|
||||
serverURL: PAYLOAD_SERVER_URL,
|
||||
})
|
||||
|
||||
return (
|
||||
<React.Fragment>
|
||||
<PostHero post={data} />
|
||||
<Blocks blocks={data?.layout} />
|
||||
<Blocks
|
||||
blocks={[
|
||||
{
|
||||
blockName: 'Related Posts',
|
||||
blockType: 'relatedPosts',
|
||||
docs: data?.relatedPosts,
|
||||
introContent: [
|
||||
{
|
||||
type: 'h4',
|
||||
children: [
|
||||
{
|
||||
text: 'Related posts',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
type: 'p',
|
||||
children: [
|
||||
{
|
||||
text: 'The posts displayed here are individually selected for this page. Admins can select any number of related posts to display here and the layout will adjust accordingly. Alternatively, you could swap this out for the "Archive" block to automatically populate posts by category complete with pagination. To manage related posts, ',
|
||||
},
|
||||
{
|
||||
type: 'link',
|
||||
children: [
|
||||
{
|
||||
text: 'navigate to the admin dashboard',
|
||||
},
|
||||
],
|
||||
url: `/admin/collections/posts/${data?.id}`,
|
||||
},
|
||||
{
|
||||
text: '.',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
relationTo: 'posts',
|
||||
},
|
||||
]}
|
||||
disableTopPadding
|
||||
/>
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
import { notFound } from 'next/navigation.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { Post } from '../../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { fetchDoc } from '../../../_api/fetchDoc.js'
|
||||
import { fetchDocs } from '../../../_api/fetchDocs.js'
|
||||
import { PostClient } from './page.client.js'
|
||||
|
||||
export default async function Post({ params: { slug = '' } }) {
|
||||
let post: Post | null = null
|
||||
|
||||
try {
|
||||
post = await fetchDoc<Post>({
|
||||
slug,
|
||||
collection: 'posts',
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(error) // eslint-disable-line no-console
|
||||
}
|
||||
|
||||
if (!post) {
|
||||
notFound()
|
||||
}
|
||||
|
||||
return <PostClient post={post} />
|
||||
}
|
||||
|
||||
export async function generateStaticParams() {
|
||||
try {
|
||||
const posts = await fetchDocs<Post>('posts')
|
||||
return posts?.map(({ slug }) => slug)
|
||||
} catch (error) {
|
||||
return []
|
||||
}
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
import { PAYLOAD_SERVER_URL } from './serverURL.js'
|
||||
|
||||
export const fetchDocs = async <T>(collection: string): Promise<T[]> => {
|
||||
const docs: T[] = await fetch(`${PAYLOAD_SERVER_URL}/api/${collection}?depth=0&limit=100`, {
|
||||
cache: 'no-store',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
method: 'GET',
|
||||
})
|
||||
?.then((res) => res.json())
|
||||
?.then((res) => {
|
||||
if (res.errors) throw new Error(res?.errors?.[0]?.message ?? 'Error fetching docs')
|
||||
|
||||
return res?.docs
|
||||
})
|
||||
|
||||
return docs
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { ArchiveBlockProps } from './types.js'
|
||||
|
||||
import { CollectionArchive } from '../../_components/CollectionArchive/index.js'
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const ArchiveBlock: React.FC<
|
||||
ArchiveBlockProps & {
|
||||
id?: string
|
||||
}
|
||||
> = (props) => {
|
||||
const {
|
||||
id,
|
||||
categories,
|
||||
introContent,
|
||||
limit,
|
||||
populateBy,
|
||||
populatedDocs,
|
||||
populatedDocsTotal,
|
||||
relationTo,
|
||||
selectedDocs,
|
||||
} = props
|
||||
|
||||
return (
|
||||
<div className={classes.archiveBlock} id={`block-${id}`}>
|
||||
{introContent && (
|
||||
<Gutter className={classes.introContent}>
|
||||
<RichText content={introContent} />
|
||||
</Gutter>
|
||||
)}
|
||||
<CollectionArchive
|
||||
categories={categories}
|
||||
limit={limit}
|
||||
populateBy={populateBy}
|
||||
populatedDocs={populatedDocs}
|
||||
populatedDocsTotal={populatedDocsTotal}
|
||||
relationTo={relationTo}
|
||||
selectedDocs={selectedDocs}
|
||||
sort="-publishedDate"
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
export type ArchiveBlockProps = Extract<
|
||||
Exclude<Page['layout'], undefined>[0],
|
||||
{ blockType: 'archive' }
|
||||
>
|
||||
@@ -1,38 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { CMSLink } from '../../_components/Link/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import { VerticalPadding } from '../../_components/VerticalPadding/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'cta' }>
|
||||
|
||||
export const CallToActionBlock: React.FC<
|
||||
Props & {
|
||||
id?: string
|
||||
}
|
||||
> = ({ invertBackground, links, richText }) => {
|
||||
return (
|
||||
<Gutter>
|
||||
<VerticalPadding
|
||||
className={[classes.callToAction, invertBackground && classes.invert]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
<div className={classes.wrap}>
|
||||
<div className={classes.content}>
|
||||
<RichText className={classes.richText} content={richText} />
|
||||
</div>
|
||||
<div className={classes.linkGroup}>
|
||||
{(links || []).map(({ link }, i) => {
|
||||
return <CMSLink key={i} {...link} invert={invertBackground} />
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</VerticalPadding>
|
||||
</Gutter>
|
||||
)
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { CMSLink } from '../../_components/Link/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'content' }>
|
||||
|
||||
export const ContentBlock: React.FC<
|
||||
Props & {
|
||||
id?: string
|
||||
}
|
||||
> = (props) => {
|
||||
const { columns } = props
|
||||
|
||||
return (
|
||||
<Gutter className={classes.content}>
|
||||
<div className={classes.grid}>
|
||||
{columns && columns.length > 0 ? (
|
||||
<Fragment>
|
||||
{columns.map((col, index) => {
|
||||
const { enableLink, link, richText, size } = col
|
||||
|
||||
return (
|
||||
<div className={[classes.column, classes[`column--${size}`]].join(' ')} key={index}>
|
||||
<RichText content={richText} />
|
||||
{enableLink && <CMSLink className={classes.link} {...link} />}
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</Fragment>
|
||||
) : null}
|
||||
</div>
|
||||
</Gutter>
|
||||
)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
import type { StaticImageData } from 'next/image.js'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { Media } from '../../_components/Media/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Props = Extract<Exclude<Page['layout'], undefined>[0], { blockType: 'mediaBlock' }> & {
|
||||
id?: string
|
||||
staticImage?: StaticImageData
|
||||
}
|
||||
|
||||
export const MediaBlock: React.FC<Props> = (props) => {
|
||||
const { media, position = 'default', staticImage } = props
|
||||
|
||||
let caption
|
||||
if (media && typeof media === 'object') caption = media.caption
|
||||
|
||||
return (
|
||||
<div className={classes.mediaBlock}>
|
||||
{position === 'fullscreen' && (
|
||||
<div className={classes.fullscreen}>
|
||||
<Media resource={media} src={staticImage} />
|
||||
</div>
|
||||
)}
|
||||
{position === 'default' && (
|
||||
<Gutter>
|
||||
<Media resource={media} src={staticImage} />
|
||||
</Gutter>
|
||||
)}
|
||||
{caption && (
|
||||
<Gutter className={classes.caption}>
|
||||
<RichText content={caption} />
|
||||
</Gutter>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Card } from '../../_components/Card/index.js'
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export type RelatedPostsProps = {
|
||||
blockName: string
|
||||
blockType: 'relatedPosts'
|
||||
docs?: (Post | string)[] | null
|
||||
introContent?: any
|
||||
relationTo: 'posts'
|
||||
}
|
||||
|
||||
export const RelatedPosts: React.FC<RelatedPostsProps> = (props) => {
|
||||
const { docs, introContent, relationTo } = props
|
||||
|
||||
return (
|
||||
<div className={classes.relatedPosts}>
|
||||
{introContent && (
|
||||
<Gutter className={classes.introContent}>
|
||||
<RichText content={introContent} />
|
||||
</Gutter>
|
||||
)}
|
||||
<Gutter>
|
||||
<div className={classes.grid}>
|
||||
{docs?.map((doc, index) => {
|
||||
if (typeof doc === 'string') return null
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
classes.column,
|
||||
docs.length === 2 && classes['cols-half'],
|
||||
docs.length >= 3 && classes['cols-thirds'],
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
key={index}
|
||||
>
|
||||
<Card doc={doc} relationTo={relationTo} showCategories />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Gutter>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export type RelationshipsBlockProps = {
|
||||
blockName: string
|
||||
blockType: 'relationships'
|
||||
data: Page
|
||||
}
|
||||
|
||||
export const RelationshipsBlock: React.FC<RelationshipsBlockProps> = (props) => {
|
||||
const { data } = props
|
||||
|
||||
return (
|
||||
<div className={classes.relationshipsBlock}>
|
||||
<Gutter>
|
||||
<p>
|
||||
This block is for testing purposes only. It renders every possible type of relationship.
|
||||
</p>
|
||||
<p>
|
||||
<b>Rich Text — Slate:</b>
|
||||
</p>
|
||||
{data?.richTextSlate && <RichText content={data.richTextSlate} renderUploadFilenameOnly />}
|
||||
<p>
|
||||
<b>Rich Text — Lexical:</b>
|
||||
</p>
|
||||
{data?.richTextLexical && (
|
||||
<RichText content={data.richTextLexical} renderUploadFilenameOnly serializer="lexical" />
|
||||
)}
|
||||
<p>
|
||||
<b>Upload:</b>
|
||||
</p>
|
||||
{data?.relationshipAsUpload ? (
|
||||
<div>
|
||||
{typeof data?.relationshipAsUpload === 'string'
|
||||
? data?.relationshipAsUpload
|
||||
: data?.relationshipAsUpload.filename}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Monomorphic Has One:</b>
|
||||
</p>
|
||||
{data?.relationshipMonoHasOne ? (
|
||||
<div>
|
||||
{typeof data?.relationshipMonoHasOne === 'string'
|
||||
? data?.relationshipMonoHasOne
|
||||
: data?.relationshipMonoHasOne.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Monomorphic Has Many:</b>
|
||||
</p>
|
||||
{data?.relationshipMonoHasMany ? (
|
||||
<Fragment>
|
||||
{data?.relationshipMonoHasMany.length
|
||||
? data?.relationshipMonoHasMany?.map((item, index) =>
|
||||
item ? (
|
||||
<div key={index}>{typeof item === 'string' ? item : item.title}</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)
|
||||
: 'None'}
|
||||
</Fragment>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Polymorphic Has One:</b>
|
||||
</p>
|
||||
{data?.relationshipPolyHasOne ? (
|
||||
<div>
|
||||
{typeof data?.relationshipPolyHasOne.value === 'string'
|
||||
? data?.relationshipPolyHasOne.value
|
||||
: data?.relationshipPolyHasOne.value.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Polymorphic Has Many:</b>
|
||||
</p>
|
||||
{data?.relationshipPolyHasMany ? (
|
||||
<Fragment>
|
||||
{data?.relationshipPolyHasMany.length
|
||||
? data?.relationshipPolyHasMany?.map((item, index) =>
|
||||
item.value ? (
|
||||
<div key={index}>
|
||||
{typeof item.value === 'string' ? item.value : item.value.title}
|
||||
</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)
|
||||
: 'None'}
|
||||
</Fragment>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Array of Relationships:</b>
|
||||
</p>
|
||||
{data?.arrayOfRelationships?.map((item, index) => (
|
||||
<div className={classes.array} key={index}>
|
||||
<p>
|
||||
<b>Rich Text:</b>
|
||||
</p>
|
||||
{item?.richTextInArray && <RichText content={item.richTextInArray} />}
|
||||
<p>
|
||||
<b>Upload:</b>
|
||||
</p>
|
||||
{item?.uploadInArray ? (
|
||||
<div>
|
||||
{typeof item?.uploadInArray === 'string'
|
||||
? item?.uploadInArray
|
||||
: item?.uploadInArray.filename}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Monomorphic Has One:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayMonoHasOne ? (
|
||||
<div>
|
||||
{typeof item?.relationshipInArrayMonoHasOne === 'string'
|
||||
? item?.relationshipInArrayMonoHasOne
|
||||
: item?.relationshipInArrayMonoHasOne.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Monomorphic Has Many:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayMonoHasMany ? (
|
||||
<Fragment>
|
||||
{item?.relationshipInArrayMonoHasMany.length
|
||||
? item?.relationshipInArrayMonoHasMany?.map((rel, relIndex) =>
|
||||
rel ? (
|
||||
<div key={relIndex}>{typeof rel === 'string' ? rel : rel.title}</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)
|
||||
: 'None'}
|
||||
</Fragment>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Polymorphic Has One:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayPolyHasOne ? (
|
||||
<div>
|
||||
{typeof item?.relationshipInArrayPolyHasOne.value === 'string'
|
||||
? item?.relationshipInArrayPolyHasOne.value
|
||||
: item?.relationshipInArrayPolyHasOne.value.title}
|
||||
</div>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
<p>
|
||||
<b>Polymorphic Has Many:</b>
|
||||
</p>
|
||||
{item?.relationshipInArrayPolyHasMany ? (
|
||||
<Fragment>
|
||||
{item?.relationshipInArrayPolyHasMany.length
|
||||
? item?.relationshipInArrayPolyHasMany?.map((rel, relIndex) =>
|
||||
rel.value ? (
|
||||
<div key={relIndex}>
|
||||
{typeof rel.value === 'string' ? rel.value : rel.value.title}
|
||||
</div>
|
||||
) : (
|
||||
'null'
|
||||
),
|
||||
)
|
||||
: 'None'}
|
||||
</Fragment>
|
||||
) : (
|
||||
<div>None</div>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</Gutter>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Props = {
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
id?: string
|
||||
invert?: boolean | null
|
||||
}
|
||||
|
||||
export const BackgroundColor: React.FC<Props> = (props) => {
|
||||
const { id, children, className, invert } = props
|
||||
|
||||
return (
|
||||
<div className={[invert && classes.invert, className].filter(Boolean).join(' ')} id={id}>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
import type { RelationshipsBlockProps } from '../../_blocks/Relationships/index.js'
|
||||
import type { VerticalPaddingOptions } from '../VerticalPadding/index.js'
|
||||
|
||||
import { ArchiveBlock } from '../../_blocks/ArchiveBlock/index.js'
|
||||
import { CallToActionBlock } from '../../_blocks/CallToAction/index.js'
|
||||
import { ContentBlock } from '../../_blocks/Content/index.js'
|
||||
import { MediaBlock } from '../../_blocks/MediaBlock/index.js'
|
||||
import { RelatedPosts, type RelatedPostsProps } from '../../_blocks/RelatedPosts/index.js'
|
||||
import { RelationshipsBlock } from '../../_blocks/Relationships/index.js'
|
||||
import { toKebabCase } from '../../_utilities/toKebabCase.js'
|
||||
import { BackgroundColor } from '../BackgroundColor/index.js'
|
||||
import { VerticalPadding } from '../VerticalPadding/index.js'
|
||||
|
||||
const blockComponents = {
|
||||
archive: ArchiveBlock,
|
||||
content: ContentBlock,
|
||||
cta: CallToActionBlock,
|
||||
mediaBlock: MediaBlock,
|
||||
relatedPosts: RelatedPosts,
|
||||
relationships: RelationshipsBlock,
|
||||
}
|
||||
|
||||
type Block = NonNullable<Page['layout']>[number]
|
||||
|
||||
export const Blocks: React.FC<{
|
||||
blocks?: (Block | RelatedPostsProps | RelationshipsBlockProps)[] | null
|
||||
disableTopPadding?: boolean
|
||||
}> = (props) => {
|
||||
const { blocks, disableTopPadding } = props
|
||||
|
||||
const hasBlocks = blocks && Array.isArray(blocks) && blocks.length > 0
|
||||
|
||||
if (hasBlocks) {
|
||||
return (
|
||||
<Fragment>
|
||||
{blocks.map((block, index) => {
|
||||
const { blockName, blockType } = block
|
||||
|
||||
if (blockType && blockType in blockComponents) {
|
||||
const Block = blockComponents[blockType]
|
||||
|
||||
// the cta block is containerized, so we don't consider it to be inverted at the block-level
|
||||
const blockIsInverted =
|
||||
'invertBackground' in block && blockType !== 'cta' ? block.invertBackground : false
|
||||
const prevBlock = blocks[index - 1]
|
||||
|
||||
const prevBlockInverted =
|
||||
prevBlock && 'invertBackground' in prevBlock && prevBlock?.invertBackground
|
||||
|
||||
const isPrevSame = Boolean(blockIsInverted) === Boolean(prevBlockInverted)
|
||||
|
||||
let paddingTop: VerticalPaddingOptions = 'large'
|
||||
let paddingBottom: VerticalPaddingOptions = 'large'
|
||||
|
||||
if (prevBlock && isPrevSame) {
|
||||
paddingTop = 'none'
|
||||
}
|
||||
|
||||
if (index === blocks.length - 1) {
|
||||
paddingBottom = 'large'
|
||||
}
|
||||
|
||||
if (disableTopPadding && index === 0) {
|
||||
paddingTop = 'none'
|
||||
}
|
||||
|
||||
if (Block) {
|
||||
return (
|
||||
<BackgroundColor invert={blockIsInverted} key={index}>
|
||||
<VerticalPadding bottom={paddingBottom} top={paddingTop}>
|
||||
{/* @ts-expect-error */}
|
||||
<Block id={toKebabCase(blockName)} {...block} />
|
||||
</VerticalPadding>
|
||||
</BackgroundColor>
|
||||
)
|
||||
}
|
||||
}
|
||||
return null
|
||||
})}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import type { ElementType } from 'react'
|
||||
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
export type Props = {
|
||||
appearance?: 'default' | 'none' | 'primary' | 'secondary'
|
||||
className?: string
|
||||
disabled?: boolean
|
||||
el?: 'a' | 'button' | 'link'
|
||||
href?: string
|
||||
invert?: boolean
|
||||
label?: string
|
||||
newTab?: boolean
|
||||
onClick?: () => void
|
||||
type?: 'button' | 'submit'
|
||||
}
|
||||
|
||||
export const Button: React.FC<Props> = ({
|
||||
type = 'button',
|
||||
appearance,
|
||||
className: classNameFromProps,
|
||||
disabled,
|
||||
el: elFromProps = 'link',
|
||||
href,
|
||||
invert,
|
||||
label,
|
||||
newTab,
|
||||
onClick,
|
||||
}) => {
|
||||
let el = elFromProps
|
||||
|
||||
const newTabProps = newTab ? { rel: 'noopener noreferrer', target: '_blank' } : {}
|
||||
|
||||
const className = [
|
||||
classes.button,
|
||||
classNameFromProps,
|
||||
classes[`appearance--${appearance}`],
|
||||
invert && classes[`${appearance}--invert`],
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')
|
||||
|
||||
const content = (
|
||||
<div className={classes.content}>
|
||||
<span className={classes.label}>{label}</span>
|
||||
</div>
|
||||
)
|
||||
|
||||
if (onClick || type === 'submit') el = 'button'
|
||||
|
||||
if (el === 'link') {
|
||||
return (
|
||||
<Link className={className} href={href || ''} {...newTabProps} onClick={onClick}>
|
||||
{content}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
const Element: ElementType = el
|
||||
|
||||
return (
|
||||
<Element
|
||||
className={className}
|
||||
href={href}
|
||||
type={type}
|
||||
{...newTabProps}
|
||||
disabled={disabled}
|
||||
onClick={onClick}
|
||||
>
|
||||
{content}
|
||||
</Element>
|
||||
)
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Media } from '../Media/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
export const Card: React.FC<{
|
||||
alignItems?: 'center'
|
||||
className?: string
|
||||
doc?: Post
|
||||
hideImagesOnMobile?: boolean
|
||||
orientation?: 'horizontal' | 'vertical'
|
||||
relationTo?: 'posts'
|
||||
showCategories?: boolean
|
||||
title?: string
|
||||
}> = (props) => {
|
||||
const {
|
||||
className,
|
||||
doc,
|
||||
orientation = 'vertical',
|
||||
relationTo,
|
||||
showCategories,
|
||||
title: titleFromProps,
|
||||
} = props
|
||||
|
||||
const { slug, categories, meta, title } = doc || {}
|
||||
const { description, image: metaImage } = meta || {}
|
||||
|
||||
const hasCategories = categories && Array.isArray(categories) && categories.length > 0
|
||||
const titleToUse = titleFromProps || title
|
||||
const sanitizedDescription = description?.replace(/\s/g, ' ') // replace non-breaking space with white space
|
||||
const href = `/live-preview/${relationTo}/${slug}`
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[classes.card, className, orientation && classes[orientation]]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
<Link className={classes.mediaWrapper} href={href}>
|
||||
{!metaImage && <div className={classes.placeholder}>No image</div>}
|
||||
{metaImage && typeof metaImage !== 'string' && (
|
||||
<Media fill imgClassName={classes.image} resource={metaImage} />
|
||||
)}
|
||||
</Link>
|
||||
<div className={classes.content}>
|
||||
{showCategories && hasCategories && (
|
||||
<div className={classes.leader}>
|
||||
{showCategories && hasCategories && (
|
||||
<div>
|
||||
{categories?.map((category, index) => {
|
||||
const titleFromCategory = typeof category === 'string' ? category : category.title
|
||||
|
||||
const categoryTitle = titleFromCategory || 'Untitled category'
|
||||
|
||||
const isLast = index === categories.length - 1
|
||||
|
||||
return (
|
||||
<Fragment key={index}>
|
||||
{categoryTitle}
|
||||
{!isLast && <Fragment>, </Fragment>}
|
||||
</Fragment>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
{titleToUse && (
|
||||
<h4 className={classes.title}>
|
||||
<Link className={classes.titleLink} href={href}>
|
||||
{titleToUse}
|
||||
</Link>
|
||||
</h4>
|
||||
)}
|
||||
{description && (
|
||||
<div className={classes.body}>
|
||||
{description && <p className={classes.description}>{sanitizedDescription}</p>}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
export const Chevron: React.FC<{
|
||||
className?: string
|
||||
rotate?: number
|
||||
}> = ({ className, rotate }) => {
|
||||
return (
|
||||
<svg
|
||||
className={className}
|
||||
height="100%"
|
||||
style={{
|
||||
transform: typeof rotate === 'number' ? `rotate(${rotate || 0}deg)` : undefined,
|
||||
}}
|
||||
viewBox="0 0 24 24"
|
||||
width="100%"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M23.245 4l-11.245 14.374-11.219-14.374-.781.619 12 15.381 12-15.391-.755-.609z"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
vectorEffect="non-scaling-stroke"
|
||||
/>
|
||||
</svg>
|
||||
)
|
||||
}
|
||||
@@ -1,186 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import qs from 'qs'
|
||||
import React, { Fragment, useCallback, useEffect, useRef, useState } from 'react'
|
||||
|
||||
import type { Post } from '../../../../../test/live-preview/payload-types.js'
|
||||
import type { ArchiveBlockProps } from '../../../_blocks/ArchiveBlock/types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
||||
import { Card } from '../../Card/index.js'
|
||||
import { Gutter } from '../../Gutter/index.js'
|
||||
import { PageRange } from '../../PageRange/index.js'
|
||||
import { Pagination } from '../../Pagination/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Result = {
|
||||
docs: (Post | string)[]
|
||||
hasNextPage: boolean
|
||||
hasPrevPage: boolean
|
||||
nextPage: number
|
||||
page: number
|
||||
prevPage: number
|
||||
totalDocs: number
|
||||
totalPages: number
|
||||
}
|
||||
|
||||
export type Props = Omit<ArchiveBlockProps, 'blockType'> & {
|
||||
className?: string
|
||||
onResultChange?: (result: Result) => void // eslint-disable-line no-unused-vars
|
||||
showPageRange?: boolean
|
||||
sort?: string
|
||||
}
|
||||
|
||||
export const CollectionArchiveByCollection: React.FC<Props> = (props) => {
|
||||
const {
|
||||
categories: catsFromProps,
|
||||
className,
|
||||
limit = 10,
|
||||
onResultChange,
|
||||
populatedDocs,
|
||||
populatedDocsTotal,
|
||||
relationTo,
|
||||
showPageRange,
|
||||
sort = '-createdAt',
|
||||
} = props
|
||||
|
||||
const [results, setResults] = useState<Result>({
|
||||
docs: populatedDocs?.map((doc) => doc.value) || [],
|
||||
hasNextPage: false,
|
||||
hasPrevPage: false,
|
||||
nextPage: 1,
|
||||
page: 1,
|
||||
prevPage: 1,
|
||||
totalDocs: typeof populatedDocsTotal === 'number' ? populatedDocsTotal : 0,
|
||||
totalPages: 1,
|
||||
})
|
||||
|
||||
const [isLoading, setIsLoading] = useState(false)
|
||||
const [error, setError] = useState<string | undefined>(undefined)
|
||||
const scrollRef = useRef<HTMLDivElement>(null)
|
||||
const hasHydrated = useRef(false)
|
||||
const [page, setPage] = useState(1)
|
||||
|
||||
const scrollToRef = useCallback(() => {
|
||||
const { current } = scrollRef
|
||||
if (current) {
|
||||
// current.scrollIntoView({
|
||||
// behavior: 'smooth',
|
||||
// })
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (!isLoading && typeof results.page !== 'undefined') {
|
||||
// scrollToRef()
|
||||
}
|
||||
}, [isLoading, scrollToRef, results])
|
||||
|
||||
useEffect(() => {
|
||||
// hydrate the block with fresh content after first render
|
||||
// don't show loader unless the request takes longer than x ms
|
||||
// and don't show it during initial hydration
|
||||
const timer = setTimeout(() => {
|
||||
if (hasHydrated) {
|
||||
setIsLoading(true)
|
||||
}
|
||||
}, 500)
|
||||
|
||||
const searchQuery = qs.stringify(
|
||||
{
|
||||
depth: 1,
|
||||
limit,
|
||||
page,
|
||||
sort,
|
||||
where: {
|
||||
...(catsFromProps && catsFromProps?.length > 0
|
||||
? {
|
||||
categories: {
|
||||
in:
|
||||
typeof catsFromProps === 'string'
|
||||
? [catsFromProps]
|
||||
: catsFromProps
|
||||
.map((cat) => (typeof cat === 'object' && cat !== null ? cat.id : cat))
|
||||
.join(','),
|
||||
},
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
},
|
||||
{ encode: false },
|
||||
)
|
||||
|
||||
const makeRequest = async () => {
|
||||
try {
|
||||
const req = await fetch(`${PAYLOAD_SERVER_URL}/api/${relationTo}?${searchQuery}`)
|
||||
const json = await req.json()
|
||||
clearTimeout(timer)
|
||||
hasHydrated.current = true
|
||||
|
||||
const { docs } = json as { docs: Post[] }
|
||||
|
||||
if (docs && Array.isArray(docs)) {
|
||||
setResults(json)
|
||||
setIsLoading(false)
|
||||
if (typeof onResultChange === 'function') {
|
||||
onResultChange(json)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn(err) // eslint-disable-line no-console
|
||||
setIsLoading(false)
|
||||
setError(`Unable to load "${relationTo} archive" data at this time.`)
|
||||
}
|
||||
}
|
||||
|
||||
void makeRequest()
|
||||
|
||||
return () => {
|
||||
if (timer) clearTimeout(timer)
|
||||
}
|
||||
}, [page, catsFromProps, relationTo, onResultChange, sort, limit])
|
||||
|
||||
return (
|
||||
<div className={[classes.collectionArchive, className].filter(Boolean).join(' ')}>
|
||||
<div className={classes.scrollRef} ref={scrollRef} />
|
||||
{!isLoading && error && <Gutter>{error}</Gutter>}
|
||||
<Fragment>
|
||||
{showPageRange !== false && (
|
||||
<Gutter>
|
||||
<div className={classes.pageRange}>
|
||||
<PageRange
|
||||
collection={relationTo}
|
||||
currentPage={results.page}
|
||||
limit={limit}
|
||||
totalDocs={results.totalDocs}
|
||||
/>
|
||||
</div>
|
||||
</Gutter>
|
||||
)}
|
||||
<Gutter>
|
||||
<div className={classes.grid}>
|
||||
{results.docs?.map((result, index) => {
|
||||
if (typeof result === 'string') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.column} key={index}>
|
||||
<Card doc={result} relationTo="posts" showCategories />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
{results.totalPages > 1 && (
|
||||
<Pagination
|
||||
className={classes.pagination}
|
||||
onClick={setPage}
|
||||
page={results.page}
|
||||
totalPages={results.totalPages}
|
||||
/>
|
||||
)}
|
||||
</Gutter>
|
||||
</Fragment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,42 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { ArchiveBlockProps } from '../../../_blocks/ArchiveBlock/types.js'
|
||||
|
||||
import { Card } from '../../Card/index.js'
|
||||
import { Gutter } from '../../Gutter/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export type Props = {
|
||||
className?: string
|
||||
selectedDocs?: ArchiveBlockProps['selectedDocs']
|
||||
}
|
||||
|
||||
export const CollectionArchiveBySelection: React.FC<Props> = (props) => {
|
||||
const { className, selectedDocs } = props
|
||||
|
||||
const result = selectedDocs?.map((doc) => doc.value)
|
||||
|
||||
return (
|
||||
<div className={[classes.collectionArchive, className].filter(Boolean).join(' ')}>
|
||||
<Fragment>
|
||||
<Gutter>
|
||||
<div className={classes.grid}>
|
||||
{result?.map((result, index) => {
|
||||
if (typeof result === 'string') {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classes.column} key={index}>
|
||||
<Card doc={result} relationTo="posts" showCategories />
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</Gutter>
|
||||
</Fragment>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { ArchiveBlockProps } from '../../_blocks/ArchiveBlock/types.js'
|
||||
|
||||
import { CollectionArchiveByCollection } from './PopulateByCollection/index.js'
|
||||
import { CollectionArchiveBySelection } from './PopulateBySelection/index.js'
|
||||
|
||||
export type Props = Omit<ArchiveBlockProps, 'blockType'> & {
|
||||
className?: string
|
||||
sort?: string
|
||||
}
|
||||
|
||||
export const CollectionArchive: React.FC<Props> = (props) => {
|
||||
const { className, populateBy, selectedDocs } = props
|
||||
|
||||
if (populateBy === 'selection') {
|
||||
return <CollectionArchiveBySelection className={className} selectedDocs={selectedDocs} />
|
||||
}
|
||||
|
||||
if (populateBy === 'collection') {
|
||||
return <CollectionArchiveByCollection {...props} className={className} />
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React from 'react'
|
||||
|
||||
import { fetchFooter } from '../../_api/fetchFooter.js'
|
||||
import { Gutter } from '../Gutter/index.js'
|
||||
import { CMSLink } from '../Link/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
export async function Footer() {
|
||||
const footer = await fetchFooter()
|
||||
|
||||
const navItems = footer?.navItems || []
|
||||
|
||||
return (
|
||||
<footer className={classes.footer}>
|
||||
<Gutter className={classes.wrap}>
|
||||
<Link href="/">
|
||||
<picture>
|
||||
<img
|
||||
alt="Payload Logo"
|
||||
className={classes.logo}
|
||||
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/admin/assets/images/payload-logo-light.svg"
|
||||
/>
|
||||
</picture>
|
||||
</Link>
|
||||
<nav className={classes.nav}>
|
||||
{navItems.map(({ link }, i) => {
|
||||
return <CMSLink key={i} {...link} />
|
||||
})}
|
||||
<Link href="/admin">Admin</Link>
|
||||
<Link href="https://github.com/payloadcms/payload/tree/main/templates/ecommerce">
|
||||
Source Code
|
||||
</Link>
|
||||
<Link href="https://github.com/payloadcms/payload">Payload</Link>
|
||||
</nav>
|
||||
</Gutter>
|
||||
</footer>
|
||||
)
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
import type { Ref } from 'react'
|
||||
|
||||
import React, { forwardRef } from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
left?: boolean
|
||||
ref?: Ref<HTMLDivElement>
|
||||
right?: boolean
|
||||
}
|
||||
|
||||
export const Gutter: React.FC<Props> = forwardRef<HTMLDivElement, Props>((props, ref) => {
|
||||
const { children, className, left = true, right = true } = props
|
||||
|
||||
return (
|
||||
<div
|
||||
className={[
|
||||
classes.gutter,
|
||||
left && classes.gutterLeft,
|
||||
right && classes.gutterRight,
|
||||
className,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
ref={ref}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
Gutter.displayName = 'Gutter'
|
||||
@@ -1,20 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import type { Header as HeaderType } from '../../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { CMSLink } from '../../Link/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const HeaderNav: React.FC<{ header: HeaderType }> = ({ header }) => {
|
||||
const navItems = header?.navItems || []
|
||||
|
||||
return (
|
||||
<nav className={classes.nav}>
|
||||
{navItems.map(({ link }, i) => {
|
||||
return <CMSLink key={i} {...link} />
|
||||
})}
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React from 'react'
|
||||
|
||||
import { fetchHeader } from '../../_api/fetchHeader.js'
|
||||
import { Gutter } from '../Gutter/index.js'
|
||||
import { HeaderNav } from './Nav/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
export async function Header() {
|
||||
const header = await fetchHeader()
|
||||
|
||||
return (
|
||||
<header className={classes.header}>
|
||||
<Gutter className={classes.wrap}>
|
||||
<Link href="/live-preview">
|
||||
<img
|
||||
alt="Payload Logo"
|
||||
className={classes.logo}
|
||||
src="https://raw.githubusercontent.com/payloadcms/payload/main/packages/payload/src/admin/assets/images/payload-logo-dark.svg"
|
||||
/>
|
||||
</Link>
|
||||
<HeaderNav header={header} />
|
||||
</Gutter>
|
||||
</header>
|
||||
)
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { HighImpactHero } from '../../_heros/HighImpact/index.js'
|
||||
import { LowImpactHero } from '../../_heros/LowImpact/index.js'
|
||||
|
||||
const heroes = {
|
||||
highImpact: HighImpactHero,
|
||||
lowImpact: LowImpactHero,
|
||||
}
|
||||
|
||||
export const Hero: React.FC<Page['hero']> = (props) => {
|
||||
const { type } = props || {}
|
||||
|
||||
if (!type || type === 'none') return null
|
||||
|
||||
const HeroToRender = heroes[type]
|
||||
|
||||
if (!HeroToRender) return null
|
||||
|
||||
return <HeroToRender {...props} />
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { Page, Post } from '../../../../test/live-preview/payload-types.js'
|
||||
import type { Props as ButtonProps } from '../Button/index.js'
|
||||
|
||||
import { Button } from '../Button/index.js'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
type CMSLinkType = {
|
||||
appearance?: ButtonProps['appearance']
|
||||
children?: React.ReactNode
|
||||
className?: string
|
||||
invert?: ButtonProps['invert']
|
||||
label?: string
|
||||
newTab?: boolean
|
||||
reference?: {
|
||||
relationTo: 'pages' | 'posts'
|
||||
value: Page | Post | string
|
||||
}
|
||||
type?: 'custom' | 'reference'
|
||||
url?: string
|
||||
}
|
||||
|
||||
export const CMSLink: React.FC<CMSLinkType> = ({
|
||||
type,
|
||||
appearance,
|
||||
children,
|
||||
className,
|
||||
invert,
|
||||
label,
|
||||
newTab,
|
||||
reference,
|
||||
url,
|
||||
}) => {
|
||||
const href =
|
||||
type === 'reference' && typeof reference?.value === 'object' && reference.value.slug
|
||||
? `/${reference.value.slug}`
|
||||
: url
|
||||
|
||||
if (!href) return null
|
||||
|
||||
if (!appearance) {
|
||||
const newTabProps = newTab ? { rel: 'noopener noreferrer', target: '_blank' } : {}
|
||||
|
||||
if (href || url) {
|
||||
return (
|
||||
<Link {...newTabProps} className={className} href={href || url || ''}>
|
||||
{label && label}
|
||||
{children && children}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
appearance={appearance}
|
||||
className={className}
|
||||
href={href}
|
||||
invert={invert}
|
||||
label={label}
|
||||
newTab={newTab}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,81 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import type { StaticImageData } from 'next/image.js'
|
||||
|
||||
import NextImageWithDefault from 'next/image.js'
|
||||
import React from 'react'
|
||||
|
||||
import type { Props as MediaProps } from '../types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
||||
import cssVariables from '../../../cssVariables.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const { breakpoints } = cssVariables
|
||||
|
||||
const NextImage = (NextImageWithDefault.default ||
|
||||
NextImageWithDefault) as typeof NextImageWithDefault.default
|
||||
|
||||
export const Image: React.FC<MediaProps> = (props) => {
|
||||
const {
|
||||
alt: altFromProps,
|
||||
fill,
|
||||
imgClassName,
|
||||
onClick,
|
||||
onLoad: onLoadFromProps,
|
||||
priority,
|
||||
resource,
|
||||
src: srcFromProps,
|
||||
} = props
|
||||
|
||||
const [isLoading, setIsLoading] = React.useState(true)
|
||||
|
||||
let width: number | undefined
|
||||
let height: number | undefined
|
||||
let alt = altFromProps
|
||||
let src: StaticImageData | string = srcFromProps || ''
|
||||
|
||||
if (!src && resource && typeof resource !== 'string') {
|
||||
const {
|
||||
alt: altFromResource,
|
||||
filename: fullFilename,
|
||||
height: fullHeight,
|
||||
width: fullWidth,
|
||||
} = resource
|
||||
|
||||
width = fullWidth || undefined
|
||||
height = fullHeight || undefined
|
||||
alt = altFromResource
|
||||
|
||||
const filename = fullFilename
|
||||
|
||||
src = `${PAYLOAD_SERVER_URL}/api/media/file/${filename}`
|
||||
}
|
||||
|
||||
// NOTE: this is used by the browser to determine which image to download at different screen sizes
|
||||
const sizes = Object.entries(breakpoints)
|
||||
.map(([, value]) => `(max-width: ${value}px) ${value}px`)
|
||||
.join(', ')
|
||||
|
||||
return (
|
||||
<NextImage
|
||||
alt={alt || ''}
|
||||
className={[isLoading && classes.placeholder, classes.image, imgClassName]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
fill={fill}
|
||||
height={!fill ? height : undefined}
|
||||
onClick={onClick}
|
||||
onLoad={() => {
|
||||
setIsLoading(false)
|
||||
if (typeof onLoadFromProps === 'function') {
|
||||
onLoadFromProps()
|
||||
}
|
||||
}}
|
||||
priority={priority}
|
||||
sizes={sizes}
|
||||
src={src}
|
||||
width={!fill ? width : undefined}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import React, { useEffect, useRef } from 'react'
|
||||
|
||||
import type { Props as MediaProps } from '../types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../../_api/serverURL.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const Video: React.FC<MediaProps> = (props) => {
|
||||
const { onClick, resource, videoClassName } = props
|
||||
|
||||
const videoRef = useRef<HTMLVideoElement>(null)
|
||||
// const [showFallback] = useState<boolean>()
|
||||
|
||||
useEffect(() => {
|
||||
const { current: video } = videoRef
|
||||
if (video) {
|
||||
video.addEventListener('suspend', () => {
|
||||
// setShowFallback(true);
|
||||
// console.warn('Video was suspended, rendering fallback image.')
|
||||
})
|
||||
}
|
||||
}, [])
|
||||
|
||||
if (resource && typeof resource !== 'string') {
|
||||
const { filename } = resource
|
||||
|
||||
return (
|
||||
<video
|
||||
autoPlay
|
||||
className={[classes.video, videoClassName].filter(Boolean).join(' ')}
|
||||
controls={false}
|
||||
loop
|
||||
muted
|
||||
onClick={onClick}
|
||||
playsInline
|
||||
ref={videoRef}
|
||||
>
|
||||
<source src={`${PAYLOAD_SERVER_URL}/media/${filename}`} />
|
||||
</video>
|
||||
)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import type { ElementType } from 'react'
|
||||
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Props } from './types.js'
|
||||
|
||||
import { Image } from './Image/index.js'
|
||||
import { Video } from './Video/index.js'
|
||||
|
||||
export const Media: React.FC<Props> = (props) => {
|
||||
const { className, htmlElement = 'div', resource } = props
|
||||
|
||||
const isVideo = typeof resource !== 'string' && resource?.mimeType?.includes('video')
|
||||
const Tag = (htmlElement as ElementType) || Fragment
|
||||
|
||||
return (
|
||||
<Tag
|
||||
{...(htmlElement !== null
|
||||
? {
|
||||
className,
|
||||
}
|
||||
: {})}
|
||||
>
|
||||
{isVideo ? (
|
||||
<Video {...props} />
|
||||
) : (
|
||||
<Image {...props} /> // eslint-disable-line
|
||||
)}
|
||||
</Tag>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import type { StaticImageData } from 'next/image'
|
||||
import type { ElementType, Ref } from 'react'
|
||||
|
||||
import type { Media as MediaType } from '../../../payload-types'
|
||||
|
||||
export interface Props {
|
||||
alt?: string
|
||||
className?: string
|
||||
fill?: boolean // for NextImage only
|
||||
htmlElement?: ElementType | null
|
||||
imgClassName?: string
|
||||
onClick?: () => void
|
||||
onLoad?: () => void
|
||||
priority?: boolean // for NextImage only
|
||||
ref?: Ref<HTMLImageElement | HTMLVideoElement | null>
|
||||
resource?: MediaType | string // for Payload media
|
||||
size?: string // for NextImage only
|
||||
src?: StaticImageData // for static media
|
||||
videoClassName?: string
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const defaultLabels = {
|
||||
plural: 'Docs',
|
||||
singular: 'Doc',
|
||||
}
|
||||
|
||||
const defaultCollectionLabels = {
|
||||
products: {
|
||||
plural: 'Products',
|
||||
singular: 'Product',
|
||||
},
|
||||
}
|
||||
|
||||
export const PageRange: React.FC<{
|
||||
className?: string
|
||||
collection?: string
|
||||
collectionLabels?: {
|
||||
plural?: string
|
||||
singular?: string
|
||||
}
|
||||
currentPage?: number
|
||||
limit?: number
|
||||
totalDocs?: number
|
||||
}> = (props) => {
|
||||
const {
|
||||
className,
|
||||
collection,
|
||||
collectionLabels: collectionLabelsFromProps,
|
||||
currentPage,
|
||||
limit,
|
||||
totalDocs,
|
||||
} = props
|
||||
|
||||
const indexStart = (currentPage ? currentPage - 1 : 1) * (limit || 1) + 1
|
||||
let indexEnd = (currentPage || 1) * (limit || 1)
|
||||
if (totalDocs && indexEnd > totalDocs) indexEnd = totalDocs
|
||||
|
||||
const { plural, singular } =
|
||||
collectionLabelsFromProps || defaultCollectionLabels[collection || ''] || defaultLabels || {}
|
||||
|
||||
return (
|
||||
<div className={[className, classes.pageRange].filter(Boolean).join(' ')}>
|
||||
{(typeof totalDocs === 'undefined' || totalDocs === 0) && 'Search produced no results.'}
|
||||
{typeof totalDocs !== 'undefined' &&
|
||||
totalDocs > 0 &&
|
||||
`Showing ${indexStart} - ${indexEnd} of ${totalDocs} ${totalDocs > 1 ? plural : singular}`}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,45 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import { Chevron } from '../Chevron/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const Pagination: React.FC<{
|
||||
className?: string
|
||||
onClick: (page: number) => void
|
||||
page: number
|
||||
totalPages: number
|
||||
}> = (props) => {
|
||||
const { className, onClick, page, totalPages } = props
|
||||
const hasNextPage = page < totalPages
|
||||
const hasPrevPage = page > 1
|
||||
|
||||
return (
|
||||
<div className={[classes.pagination, className].filter(Boolean).join(' ')}>
|
||||
<button
|
||||
className={classes.button}
|
||||
disabled={!hasPrevPage}
|
||||
onClick={() => {
|
||||
onClick(page - 1)
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Chevron className={classes.icon} rotate={90} />
|
||||
</button>
|
||||
<div className={classes.pageRange}>
|
||||
<span className={classes.pageRangeLabel}>
|
||||
Page {page} of {totalPages}
|
||||
</span>
|
||||
</div>
|
||||
<button
|
||||
className={classes.button}
|
||||
disabled={!hasNextPage}
|
||||
onClick={() => {
|
||||
onClick(page + 1)
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
<Chevron className={classes.icon} rotate={-90} />
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
import serializeLexical from './serializeLexical.js'
|
||||
import serializeSlate from './serializeSlate.js'
|
||||
|
||||
const RichText: React.FC<{
|
||||
className?: string
|
||||
content: any
|
||||
renderUploadFilenameOnly?: boolean
|
||||
serializer?: 'lexical' | 'slate'
|
||||
}> = ({ className, content, renderUploadFilenameOnly, serializer = 'slate' }) => {
|
||||
if (!content) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={[classes.richText, className].filter(Boolean).join(' ')}>
|
||||
{serializer === 'slate'
|
||||
? serializeSlate(content, renderUploadFilenameOnly)
|
||||
: serializeLexical(content, renderUploadFilenameOnly)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default RichText
|
||||
@@ -1,29 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export type VerticalPaddingOptions = 'large' | 'medium' | 'none'
|
||||
|
||||
type Props = {
|
||||
bottom?: VerticalPaddingOptions
|
||||
children: React.ReactNode
|
||||
className?: string
|
||||
top?: VerticalPaddingOptions
|
||||
}
|
||||
|
||||
export const VerticalPadding: React.FC<Props> = ({
|
||||
bottom = 'medium',
|
||||
children,
|
||||
className,
|
||||
top = 'medium',
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={[className, classes[`top-${top}`], classes[`bottom-${bottom}`]]
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -1,121 +0,0 @@
|
||||
@use './queries.scss' as *;
|
||||
@use './colors.scss' as *;
|
||||
@use './type.scss' as *;
|
||||
|
||||
:root {
|
||||
--base: 24px;
|
||||
--font-body: system-ui;
|
||||
--font-mono: 'Roboto Mono', monospace;
|
||||
|
||||
--gutter-h: 180px;
|
||||
--block-padding: 120px;
|
||||
|
||||
--theme-text: var(--color-base-750);
|
||||
|
||||
@include large-break {
|
||||
--gutter-h: 144px;
|
||||
--block-padding: 96px;
|
||||
}
|
||||
|
||||
@include mid-break {
|
||||
--gutter-h: 24px;
|
||||
--block-padding: 60px;
|
||||
}
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
html {
|
||||
@extend %body;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
html,
|
||||
body,
|
||||
#app {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: var(--font-body);
|
||||
margin: 0;
|
||||
color: var(--theme-text);
|
||||
}
|
||||
|
||||
::selection {
|
||||
background: var(--color-success-500);
|
||||
color: var(--color-base-800);
|
||||
}
|
||||
|
||||
::-moz-selection {
|
||||
background: var(--color-success-500);
|
||||
color: var(--color-base-800);
|
||||
}
|
||||
|
||||
img {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
display: block;
|
||||
}
|
||||
|
||||
h1 {
|
||||
@extend %h1;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@extend %h2;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@extend %h3;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@extend %h4;
|
||||
}
|
||||
|
||||
h5 {
|
||||
@extend %h5;
|
||||
}
|
||||
|
||||
h6 {
|
||||
@extend %h6;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: var(--base) 0;
|
||||
|
||||
@include mid-break {
|
||||
margin: calc(var(--base) * 0.75) 0;
|
||||
}
|
||||
}
|
||||
|
||||
#page-title {
|
||||
@extend %h6;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
padding-left: var(--base);
|
||||
margin: 0 0 var(--base);
|
||||
}
|
||||
|
||||
a {
|
||||
color: currentColor;
|
||||
|
||||
&:focus {
|
||||
opacity: 0.8;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
&:active {
|
||||
opacity: 0.7;
|
||||
outline: none;
|
||||
}
|
||||
}
|
||||
|
||||
svg {
|
||||
vertical-align: middle;
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { Media } from '../../_components/Media/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const HighImpactHero: React.FC<Page['hero']> = ({ media, richText }) => {
|
||||
return (
|
||||
<Gutter className={classes.hero}>
|
||||
<div className={classes.content}>
|
||||
<RichText content={richText} />
|
||||
</div>
|
||||
<div className={classes.media}>
|
||||
{typeof media === 'object' && media !== null && (
|
||||
<Fragment>
|
||||
<Media
|
||||
// fill
|
||||
imgClassName={classes.image}
|
||||
priority
|
||||
resource={media}
|
||||
/>
|
||||
{media?.caption && <RichText className={classes.caption} content={media.caption} />}
|
||||
</Fragment>
|
||||
)}
|
||||
</div>
|
||||
</Gutter>
|
||||
)
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
import React from 'react'
|
||||
|
||||
import type { Page } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import { VerticalPadding } from '../../_components/VerticalPadding/index.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
export const LowImpactHero: React.FC<Page['hero']> = ({ richText }) => {
|
||||
return (
|
||||
<Gutter className={classes.lowImpactHero}>
|
||||
<div className={classes.content}>
|
||||
<VerticalPadding>
|
||||
<RichText className={classes.richText} content={richText} />
|
||||
</VerticalPadding>
|
||||
</div>
|
||||
</Gutter>
|
||||
)
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import LinkWithDefault from 'next/link.js'
|
||||
import React, { Fragment } from 'react'
|
||||
|
||||
import type { Post } from '../../../../test/live-preview/payload-types.js'
|
||||
|
||||
import { PAYLOAD_SERVER_URL } from '../../_api/serverURL.js'
|
||||
import { Gutter } from '../../_components/Gutter/index.js'
|
||||
import { Media } from '../../_components/Media/index.js'
|
||||
import RichText from '../../_components/RichText/index.js'
|
||||
import { formatDateTime } from '../../_utilities/formatDateTime.js'
|
||||
import classes from './index.module.scss'
|
||||
|
||||
const Link = (LinkWithDefault.default || LinkWithDefault) as typeof LinkWithDefault.default
|
||||
|
||||
export const PostHero: React.FC<{
|
||||
post: Post
|
||||
}> = ({ post }) => {
|
||||
const { id, createdAt, meta: { description, image: metaImage } = {} } = post
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Gutter className={classes.postHero}>
|
||||
<div className={classes.content}>
|
||||
<RichText className={classes.richText} content={post?.hero?.richText} />
|
||||
<p className={classes.meta}>
|
||||
{createdAt && (
|
||||
<Fragment>
|
||||
{'Created on '}
|
||||
{formatDateTime(createdAt)}
|
||||
</Fragment>
|
||||
)}
|
||||
</p>
|
||||
<div>
|
||||
<p className={classes.description}>
|
||||
{`${description ? `${description} ` : ''}To edit this post, `}
|
||||
<Link href={`${PAYLOAD_SERVER_URL}/admin/collections/posts/${id}`}>
|
||||
navigate to the admin dashboard
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classes.media}>
|
||||
<div className={classes.mediaWrapper}>
|
||||
{!metaImage && <div className={classes.placeholder}>No image</div>}
|
||||
{metaImage && typeof metaImage !== 'string' && (
|
||||
<Media fill imgClassName={classes.image} resource={metaImage} />
|
||||
)}
|
||||
</div>
|
||||
{metaImage && typeof metaImage !== 'string' && metaImage?.caption && (
|
||||
<RichText className={classes.caption} content={metaImage.caption} />
|
||||
)}
|
||||
</div>
|
||||
</Gutter>
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
import type { Metadata } from 'next'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { Footer } from './_components/Footer/index.js'
|
||||
import { Header } from './_components/Header/index.js'
|
||||
import './_css/app.scss'
|
||||
|
||||
export const metadata: Metadata = {
|
||||
description: 'Payload Live Preview',
|
||||
title: 'Payload Live Preview',
|
||||
}
|
||||
|
||||
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||
return (
|
||||
<html lang="en">
|
||||
<body>
|
||||
<Header />
|
||||
{children}
|
||||
<Footer />
|
||||
</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
'use client'
|
||||
|
||||
import React from 'react'
|
||||
|
||||
import { Gutter } from './_components/Gutter/index.js'
|
||||
import { VerticalPadding } from './_components/VerticalPadding/index.js'
|
||||
|
||||
export default function NotFound() {
|
||||
return (
|
||||
<main>
|
||||
<VerticalPadding bottom="medium" top="none">
|
||||
<Gutter>
|
||||
<h1>404</h1>
|
||||
<p>This page could not be found.</p>
|
||||
</Gutter>
|
||||
</VerticalPadding>
|
||||
</main>
|
||||
)
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
import PageTemplate from './(pages)/[slug]/page.js'
|
||||
|
||||
export default PageTemplate
|
||||
@@ -1,5 +0,0 @@
|
||||
export const GET = () => {
|
||||
return Response.json({
|
||||
hello: 'elliot',
|
||||
})
|
||||
}
|
||||
@@ -33,7 +33,7 @@ import { webpackBundler } from '@payloadcms/bundler-webpack'
|
||||
export default buildConfig({
|
||||
// highlight-start
|
||||
admin: {
|
||||
bundler: webpackBundler(), // or viteBundler()
|
||||
bundler: webpackBundler() // or viteBundler()
|
||||
},
|
||||
// highlight-end
|
||||
})
|
||||
@@ -48,7 +48,7 @@ Since the bundled file is sent to the browser, it can't include any server-only
|
||||
<Banner type="warning">
|
||||
<strong>Using environment variables in the admin UI</strong>
|
||||
<br />
|
||||
Bundles should not contain sensitive information. By default, Payload excludes env variables from
|
||||
the bundle. If you need to use env variables in your payload config, you need to prefix them with
|
||||
`PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
||||
Bundles should not contain sensitive information. By default, Payload
|
||||
excludes env variables from the bundle. If you need to use env variables in your payload config,
|
||||
you need to prefix them with `PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
||||
</Banner>
|
||||
|
||||
@@ -13,29 +13,29 @@ To swap in your own React component, first, consult the list of available compon
|
||||
<Banner type="success">
|
||||
<strong>Tip:</strong>
|
||||
<br />
|
||||
Custom components will automatically be provided with all props that the default component
|
||||
normally accepts.
|
||||
Custom components will automatically be provided with all props that the default component normally
|
||||
accepts.
|
||||
</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 / mobile menu in its entirety. |
|
||||
| **`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. |
|
||||
| **`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/main/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. |
|
||||
| **`logout.Button`** | A custom React component. |
|
||||
| **`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. |
|
||||
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
||||
| **`actions`** | Array of custom components to be rendered in the Payload Admin UI header, providing additional interactivity and functionality. |
|
||||
| **`views`** | Override or create new views within the Payload Admin UI. [More](#views) |
|
||||
| Path | Description |
|
||||
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
||||
| **`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. |
|
||||
| **`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/main/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. |
|
||||
| **`logout.Button`** | A custom React component. |
|
||||
| **`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. |
|
||||
| **`providers`** | Define your own provider components that will wrap the Payload Admin UI. [More](#custom-providers) |
|
||||
| **`actions`** | Array of custom components to be rendered in the Payload Admin UI header, providing additional interactivity and functionality. |
|
||||
| **`views`** | Override or create new views within the Payload Admin UI. [More](#views) |
|
||||
|
||||
Here is a full example showing how to swap some of these components for your own.
|
||||
|
||||
@@ -77,10 +77,10 @@ export default buildConfig({
|
||||
|
||||
You can easily swap entire views with your own by using the `admin.components.views` property. At the root level, Payload renders the following views by default, all of which can be overridden:
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | ----------------------------------------------------------------------------- |
|
||||
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
|
||||
| **`Dashboard`** | The main landing page of the Admin panel. |
|
||||
| Property | Description |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
|
||||
| **`Dashboard`** | The main landing page of the Admin panel. |
|
||||
|
||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. For example:
|
||||
|
||||
@@ -135,10 +135,7 @@ To add a _new_ view to the Admin Panel, simply add another key to the `views` ob
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
Routes are cascading. This means that unless explicitly given the `exact` property, they will
|
||||
match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all
|
||||
routes in your application. Alternatively, you could define your nested route _before_ your parent
|
||||
route.
|
||||
Routes are cascading. This means that unless explicitly given the `exact` property, they will match on URLs that simply _start_ with the route's path. This is helpful when creating catch-all routes in your application. Alternatively, you could define your nested route _before_ your parent route.
|
||||
</Banner>
|
||||
|
||||
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
|
||||
@@ -171,7 +168,7 @@ import * as React from 'react'
|
||||
import {
|
||||
CustomSaveButtonProps,
|
||||
CustomSaveDraftButtonProps,
|
||||
CustomPublishButtonProps,
|
||||
CustomPublishButtonType,
|
||||
CustomPreviewButtonProps,
|
||||
} from 'payload/types'
|
||||
|
||||
@@ -188,7 +185,7 @@ export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
|
||||
return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
|
||||
}
|
||||
|
||||
export const CustomPublishButton: CustomPublishButtonProps = ({
|
||||
export const CustomPublishButton: CustomPublishButtonType = ({
|
||||
DefaultButton,
|
||||
disabled,
|
||||
label,
|
||||
@@ -217,7 +214,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
||||
PreviewButton: CustomPreviewButton,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
@@ -225,10 +222,10 @@ export const MyCollection: SanitizedCollectionConfig = {
|
||||
|
||||
To swap out entire views on collections, you can use the `admin.components.views` property on the collection's config. Payload renders the following views by default, all of which can be overridden:
|
||||
|
||||
| Property | Description |
|
||||
| ---------- | ------------------------------------------------------------------------- |
|
||||
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
||||
| **`List`** | The List view is used to show a list of documents for a given collection. |
|
||||
| Property | Description |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
||||
| **`List`** | The List view is used to show a list of documents for a given collection. |
|
||||
|
||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, tabs, etc, _as well as all nested routes_.
|
||||
|
||||
@@ -313,9 +310,9 @@ As with Collections, you can override components on a global-by-global basis via
|
||||
|
||||
To swap out views for globals, you can use the `admin.components.views` property on the global's config. Payload renders the following views by default, all of which can be overridden:
|
||||
|
||||
| Property | Description |
|
||||
| ---------- | ------------------------------------------------------------------- |
|
||||
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
|
||||
| Property | Description |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
|
||||
|
||||
To swap out any of these views, simply pass in your custom component to the `admin.components.views` property of your Payload config. This will replace the entire view, including the page breadcrumbs, title, and tabs, _as well as all nested views_.
|
||||
|
||||
@@ -382,13 +379,13 @@ You can also add _new_ tabs to the `Edit` view by adding another key to the `com
|
||||
|
||||
You can easily swap individual collection or global edit views. To do this, pass an _object_ to the `admin.components.views.Edit` property of the config. Payload renders the following views by default, all of which can be overridden:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Default`** | The Default view is the primary view in which your document is edited. |
|
||||
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
|
||||
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
||||
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
|
||||
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
|
||||
| Property | Description |
|
||||
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`Default`** | The Default view is the primary view in which your document is edited. |
|
||||
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
|
||||
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
||||
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
|
||||
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
|
||||
|
||||
Here is an example:
|
||||
|
||||
@@ -399,8 +396,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
||||
admin: {
|
||||
components: {
|
||||
views: {
|
||||
Edit: {
|
||||
// You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
||||
Edit: { // You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
||||
Default: MyCustomDefaultTab,
|
||||
Versions: MyCustomVersionsTab,
|
||||
Version: MyCustomVersionTab,
|
||||
@@ -427,7 +423,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
||||
Component: MyCustomTab,
|
||||
path: '/my-custom-tab',
|
||||
// You an swap the entire tab component out for your own
|
||||
Tab: MyCustomTab,
|
||||
Tab: MyCustomTab
|
||||
},
|
||||
AnotherCustomView: {
|
||||
Component: AnotherCustomView,
|
||||
@@ -436,7 +432,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
||||
Tab: {
|
||||
label: 'Another Custom View',
|
||||
href: '/another-custom-view',
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -543,6 +539,7 @@ const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
|
||||
const { value, setValue } = useField<string>({ path })
|
||||
// highlight-end
|
||||
|
||||
|
||||
return <input onChange={(e) => setValue(e.target.value)} value={value} />
|
||||
}
|
||||
```
|
||||
@@ -556,11 +553,11 @@ const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
|
||||
|
||||
These are the props that will be passed to your custom Label.
|
||||
|
||||
| Property | Description |
|
||||
| -------------- | ---------------------------------------------------------------- |
|
||||
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
||||
| **`label`** | Label value provided in field, it can be used with i18n. |
|
||||
| **`required`** | A boolean value that represents if the field is required or not. |
|
||||
| Property | Description |
|
||||
| ---------------- | ---------------------------------------------------------------- |
|
||||
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
||||
| **`label`** | Label value provided in field, it can be used with i18n. |
|
||||
| **`required`** | A boolean value that represents if the field is required or not. |
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -582,12 +579,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
||||
const { i18n } = useTranslation()
|
||||
|
||||
if (label) {
|
||||
return (
|
||||
<span>
|
||||
{getTranslation(label, i18n)}
|
||||
{required && <span className="required">*</span>}
|
||||
</span>
|
||||
)
|
||||
return (<span>
|
||||
{getTranslation(label, i18n)}
|
||||
{required && <span className="required">*</span>}
|
||||
</span>);
|
||||
}
|
||||
|
||||
return null
|
||||
@@ -598,10 +593,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
||||
|
||||
These are the props that will be passed to your custom Error.
|
||||
|
||||
| Property | Description |
|
||||
| --------------- | ------------------------------------------------------------- |
|
||||
| **`message`** | The error message. |
|
||||
| **`showError`** | A boolean value that represents if the error should be shown. |
|
||||
| Property | Description |
|
||||
| ---------------- | ------------------------------------------------------------- |
|
||||
| **`message`** | The error message. |
|
||||
| **`showError`** | A boolean value that represents if the error should be shown. |
|
||||
|
||||
#### Example
|
||||
|
||||
@@ -617,8 +612,8 @@ const CustomError: React.FC<Props> = (props) => {
|
||||
const { message, showError } = props
|
||||
|
||||
if (showError) {
|
||||
return <p style={{ color: 'red' }}>{message}</p>
|
||||
} else return null
|
||||
return <p style={{color: 'red'}}>{message}</p>
|
||||
} else return null;
|
||||
}
|
||||
```
|
||||
|
||||
@@ -635,15 +630,7 @@ import { Field } from 'payload/types'
|
||||
import './style.scss'
|
||||
|
||||
const ClearButton: React.FC = () => {
|
||||
return (
|
||||
<button
|
||||
onClick={() => {
|
||||
/* ... */
|
||||
}}
|
||||
>
|
||||
X
|
||||
</button>
|
||||
)
|
||||
return <button onClick={() => {/* ... */}}>X</button>
|
||||
}
|
||||
|
||||
const titleField: Field = {
|
||||
@@ -651,12 +638,12 @@ const titleField: Field = {
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
afterInput: [ClearButton],
|
||||
},
|
||||
},
|
||||
afterInput: [ClearButton]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default titleField
|
||||
export default titleField;
|
||||
```
|
||||
|
||||
## Custom providers
|
||||
@@ -670,7 +657,7 @@ As your admin customizations gets more complex you may want to share state betwe
|
||||
|
||||
### Styling Custom Components
|
||||
|
||||
Payload exports its SCSS variables and mixins for reuse in your own custom components. This is helpful in cases where you might want to style a custom input similarly to Payload's built-ini styling, so it blends more thoroughly into the existing admin UI.
|
||||
Payload exports its SCSS variables and mixins for reuse in your own custom components. This is helpful in cases where you might want to style a custom input similarly to Payload's built-in styling, so it blends more thoroughly into the existing admin UI.
|
||||
|
||||
To make use of Payload SCSS variables / mixins to use directly in your own components, you can import them as follows:
|
||||
|
||||
|
||||
@@ -104,7 +104,6 @@ By default the browser bundle will now include all the code from that file and a
|
||||
To fix this, we need to alias the `createStripeSubscription` file to a different file that can safely be included in the browser bundle.
|
||||
|
||||
First, we will create a mock file to replace the server-only file when bundling:
|
||||
|
||||
```js
|
||||
// mocks/modules.js
|
||||
|
||||
@@ -132,7 +131,7 @@ import { Subscriptions } from './collections/Subscriptions'
|
||||
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
|
||||
const fullFilePath = path.resolve(
|
||||
__dirname,
|
||||
'collections/Subscriptions/hooks/createStripeSubscription',
|
||||
'collections/Subscriptions/hooks/createStripeSubscription'
|
||||
)
|
||||
|
||||
export default buildConfig({
|
||||
@@ -174,23 +173,24 @@ export default buildConfig({
|
||||
admin: {
|
||||
bundler: viteBundler(),
|
||||
vite: (incomingViteConfig) => {
|
||||
const existingAliases = incomingViteConfig?.resolve?.alias || {}
|
||||
let aliasArray: { find: string | RegExp; replacement: string }[] = []
|
||||
const existingAliases = incomingViteConfig?.resolve?.alias || {};
|
||||
let aliasArray: { find: string | RegExp; replacement: string; }[] = [];
|
||||
|
||||
// Pass the existing Vite aliases
|
||||
if (Array.isArray(existingAliases)) {
|
||||
aliasArray = existingAliases
|
||||
aliasArray = existingAliases;
|
||||
} else {
|
||||
aliasArray = Object.values(existingAliases)
|
||||
aliasArray = Object.values(existingAliases);
|
||||
}
|
||||
|
||||
|
||||
// highlight-start
|
||||
// Add your own aliases using the find and replacement keys
|
||||
// remember, vite aliases are exact-match only
|
||||
aliasArray.push({
|
||||
find: '../server-only-module',
|
||||
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js'),
|
||||
})
|
||||
replacement: path.resolve(__dirname, './path/to/browser-safe-module.js')
|
||||
});
|
||||
// highlight-end
|
||||
|
||||
return {
|
||||
@@ -198,8 +198,8 @@ export default buildConfig({
|
||||
resolve: {
|
||||
...(incomingViteConfig?.resolve || {}),
|
||||
alias: aliasArray,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
@@ -639,12 +639,12 @@ export const CustomArrayManager = () => {
|
||||
|
||||
The `useCollapsible` hook allows you to control parent collapsibles:
|
||||
|
||||
| Property | Description |
|
||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------ | --- |
|
||||
| **`collapsed`** | State of the collapsible. `true` if open, `false` if collapsed |
|
||||
| **`isVisible`** | If nested, determine if the nearest collapsible is visible. `true` if no parent is closed, `false` otherwise |
|
||||
| **`toggle`** | Toggles the state of the nearest collapsible |
|
||||
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
||||
| Property | Description |
|
||||
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||
| **`collapsed`** | State of the collapsible. `true` if open, `false` if collapsed |
|
||||
| **`isVisible`** | If nested, determine if the nearest collapsible is visible. `true` if no parent is closed, `false` otherwise |
|
||||
| **`toggle`** | Toggles the state of the nearest collapsible |
|
||||
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -671,7 +671,7 @@ const CustomComponent: React.FC = () => {
|
||||
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
||||
|
||||
| Property | Description |
|
||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
||||
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||
| **`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 |
|
||||
| **`id`** | If the doc is a collection, its ID will be returned |
|
||||
@@ -804,17 +804,15 @@ const MyComponent: React.FC = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<span>
|
||||
The current theme is {theme} and autoMode is {autoMode}
|
||||
</span>
|
||||
<span>The current theme is {theme} and autoMode is {autoMode}</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setTheme((prev) => (prev === 'light' ? 'dark' : 'light'))}
|
||||
onClick={() => setTheme(prev => prev === "light" ? "dark" : "light")}
|
||||
>
|
||||
Toggle theme
|
||||
</button>
|
||||
</>
|
||||
)
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
@@ -835,7 +833,10 @@ const MyComponent: React.FC = () => {
|
||||
// highlight-end
|
||||
|
||||
return (
|
||||
<button type="button" onClick={resetColumns}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={resetColumns}
|
||||
>
|
||||
Reset columns
|
||||
</button>
|
||||
)
|
||||
@@ -846,10 +847,10 @@ const MyComponent: React.FC = () => {
|
||||
|
||||
The `useDocumentEvents` hook provides a way of subscribing to cross-document events, such as updates made to nested documents within a drawer. This hook will report document events that are outside the scope of the document currently being edited. This hook provides the following:
|
||||
|
||||
| Property | Description |
|
||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
|
||||
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
|
||||
| Property | Description |
|
||||
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
|
||||
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
|
||||
|
||||
**Example:**
|
||||
|
||||
@@ -859,11 +860,14 @@ import { useDocumentEvents } from 'payload/components/hooks'
|
||||
const ListenForUpdates: React.FC = () => {
|
||||
const { mostRecentUpdate } = useDocumentEvents()
|
||||
|
||||
return <span>{JSON.stringify(mostRecentUpdate)}</span>
|
||||
return (
|
||||
<span>
|
||||
{JSON.stringify(mostRecentUpdate)}
|
||||
</span>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
<Banner type="info">
|
||||
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future
|
||||
it will track more document-related events as needed, such as document creation, deletion, etc.
|
||||
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future it will track more document-related events as needed, such as document creation, deletion, etc.
|
||||
</Banner>
|
||||
|
||||
@@ -6,8 +6,7 @@ desc: NEEDS TO BE WRITTEN
|
||||
---
|
||||
|
||||
<Banner type="info">
|
||||
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love
|
||||
to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
|
||||
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
|
||||
</Banner>
|
||||
|
||||
Payload has a Vite bundler that you can install and bundle the Admin Panel with. This is an alternative to the [Webpack](/docs/admin/webpack) bundler and might give some performance boosts to your development workflow.
|
||||
@@ -28,7 +27,7 @@ export default buildConfig({
|
||||
collections: [],
|
||||
admin: {
|
||||
bundler: viteBundler(),
|
||||
},
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
@@ -37,8 +36,7 @@ Vite works fundamentally differently than Webpack. In development mode, it will
|
||||
It then uses Rollup to create production builds of your admin UI. With Vite, you should see a decent performance boost—especially after your first cold start. However, that first cold start might take a few more seconds.
|
||||
|
||||
<Banner type="warning">
|
||||
In most cases, Vite should work out of the box. But existing Payload plugins may need to make
|
||||
compatibility changes to support Vite.
|
||||
In most cases, Vite should work out of the box. But existing Payload plugins may need to make compatibility changes to support Vite.
|
||||
</Banner>
|
||||
|
||||
This is because Vite aliases work fundamentally differently than Webpack aliases, and Payload relies on aliasing server-only code out of the Payload config to ensure that the bundled admin JS works within your browser.
|
||||
|
||||
@@ -27,7 +27,7 @@ import { webpackBundler } from '@payloadcms/bundler-webpack'
|
||||
export default buildConfig({
|
||||
// highlight-start
|
||||
admin: {
|
||||
bundler: webpackBundler(),
|
||||
bundler: webpackBundler()
|
||||
},
|
||||
// highlight-end
|
||||
})
|
||||
|
||||
@@ -49,8 +49,7 @@ To enable API keys on a collection, set the `useAPIKey` auth option to `true`. F
|
||||
<strong>Important:</strong>
|
||||
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
|
||||
<br />
|
||||
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will
|
||||
no longer be valid.
|
||||
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will no longer be valid.
|
||||
</Banner>
|
||||
|
||||
#### Authenticating via API Key
|
||||
@@ -217,7 +216,7 @@ Example:
|
||||
{
|
||||
slug: 'customers',
|
||||
auth: {
|
||||
forgotPassword: {
|
||||
verify: {
|
||||
// highlight-start
|
||||
generateEmailSubject: ({ req, user }) => {
|
||||
return `Hey ${user.email}, reset your password!`;
|
||||
|
||||
@@ -57,7 +57,12 @@ export const Admins: CollectionConfig = {
|
||||
name: 'role',
|
||||
type: 'select',
|
||||
required: true,
|
||||
options: ['user', 'admin', 'editor', 'developer'],
|
||||
options: [
|
||||
'user',
|
||||
'admin',
|
||||
'editor',
|
||||
'developer',
|
||||
],
|
||||
},
|
||||
],
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ 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. |
|
||||
@@ -30,6 +30,7 @@ It's often best practice to write your Collections in separate files and then im
|
||||
| **`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. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`dbName`** | Custom table or collection name depending on the database adapter. Auto-generated from slug if not defined.
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -59,7 +60,8 @@ export const Orders: CollectionConfig = {
|
||||
#### More collection config examples
|
||||
|
||||
You can find an assortment
|
||||
of [example collection configs](https://github.com/payloadcms/public-demo/tree/master/src/payload/collections) in the Public
|
||||
of [example collection configs](https://github.com/payloadcms/public-demo/tree/master/src/payload/collections) in the
|
||||
Public
|
||||
Demo source code on GitHub.
|
||||
|
||||
### Admin options
|
||||
@@ -68,7 +70,7 @@ You can customize the way that the Admin panel behaves on a collection-by-collec
|
||||
property on a collection's config.
|
||||
|
||||
| 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) |
|
||||
@@ -129,7 +131,7 @@ export const Posts: CollectionConfig = {
|
||||
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. |
|
||||
|
||||
@@ -167,6 +169,53 @@ those three fields plus the ID field.
|
||||
so your admin queries can remain performant.
|
||||
</Banner>
|
||||
|
||||
### Admin Hooks
|
||||
|
||||
In addition to collection hooks themselves, Payload provides for admin UI-specific hooks that you can leverage.
|
||||
|
||||
**`beforeDuplicate`**
|
||||
|
||||
The `beforeDuplicate` hook is an async function that accepts an object containing the data to duplicate, as well as the
|
||||
locale of the doc to duplicate. Within this hook, you can modify the data to be duplicated, which is useful in cases
|
||||
where you have unique fields that need to be incremented or similar, as well as if you want to automatically modify a
|
||||
document's `title`.
|
||||
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { BeforeDuplicate, CollectionConfig } from 'payload/types'
|
||||
// Your auto-generated Page type
|
||||
import { Page } from '../payload-types.ts'
|
||||
|
||||
const beforeDuplicate: BeforeDuplicate<Page> = ({ data }) => {
|
||||
return {
|
||||
...data,
|
||||
title: `${data.title} Copy`,
|
||||
uniqueField: data.uniqueField ? `${data.uniqueField}-copy` : '',
|
||||
}
|
||||
}
|
||||
|
||||
export const Page: CollectionConfig = {
|
||||
slug: 'pages',
|
||||
admin: {
|
||||
hooks: {
|
||||
beforeDuplicate,
|
||||
},
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: 'title',
|
||||
type: 'text',
|
||||
},
|
||||
{
|
||||
name: 'uniqueField',
|
||||
type: 'text',
|
||||
unique: true,
|
||||
},
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
### TypeScript
|
||||
|
||||
You can import collection types as follows:
|
||||
|
||||
@@ -6,14 +6,18 @@ 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.
|
||||
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. |
|
||||
| **`label`** | Text for the name in the Admin panel or an object with keys for each language. Auto-generated from slug if not defined. |
|
||||
@@ -26,6 +30,7 @@ As with Collection configs, it's often best practice to write your Globals in se
|
||||
| **`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. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`dbName`** | Custom table or collection name for this global depending on the database adapter. Auto-generated from slug if not defined.
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
@@ -59,14 +64,16 @@ export default Nav
|
||||
|
||||
#### Global config example
|
||||
|
||||
You can find a few [example Global configs](https://github.com/payloadcms/public-demo/tree/master/src/payload/globals) in the Public Demo source code on GitHub.
|
||||
You can find a few [example Global configs](https://github.com/payloadcms/public-demo/tree/master/src/payload/globals)
|
||||
in the Public Demo source code on GitHub.
|
||||
|
||||
### Admin options
|
||||
|
||||
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.
|
||||
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 |
|
||||
| ------------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||
|---------------|-----------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `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) |
|
||||
@@ -76,9 +83,11 @@ You can customize the way that the Admin panel behaves on a Global-by-Global bas
|
||||
|
||||
### 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.
|
||||
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.
|
||||
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:**
|
||||
|
||||
@@ -113,15 +122,20 @@ export const MyGlobal: GlobalConfig = {
|
||||
|
||||
### Access control
|
||||
|
||||
As with Collections, you can specify extremely granular access control (what users can do with this Global) on a Global-by-Global basis. However, Globals only have `update` and `read` access control due to their nature of only having one document. To learn more, go to the [Access Control](/docs/access-control/overview) docs.
|
||||
As with Collections, you can specify extremely granular access control (what users can do with this Global) on a
|
||||
Global-by-Global basis. However, Globals only have `update` and `read` access control due to their nature of only having
|
||||
one document. To learn more, go to the [Access Control](/docs/access-control/overview) docs.
|
||||
|
||||
### Hooks
|
||||
|
||||
Globals also fully support a smaller subset of Hooks. To learn more, go to the [Hooks](/docs/hooks/overview) documentation.
|
||||
Globals also fully support a smaller subset of Hooks. To learn more, go to the [Hooks](/docs/hooks/overview)
|
||||
documentation.
|
||||
|
||||
### Field types
|
||||
|
||||
Globals support all field types that Payload has to offer—including simple fields like text and checkboxes all the way to more complicated layout-building field groups like Blocks. [Click here](/docs/fields/overview) to learn more about field types.
|
||||
Globals support all field types that Payload has to offer—including simple fields like text and checkboxes all the way
|
||||
to more complicated layout-building field groups like Blocks. [Click here](/docs/fields/overview) to learn more about
|
||||
field types.
|
||||
|
||||
### TypeScript
|
||||
|
||||
|
||||
@@ -49,7 +49,8 @@ export default buildConfig({
|
||||
{
|
||||
label: 'Arabic',
|
||||
code: 'ar',
|
||||
// opt-in to setting default text-alignment on Input fields to rtl (right-to-left) when current locale is rtl
|
||||
// opt-in to setting default text-alignment on Input fields to rtl (right-to-left)
|
||||
// when current locale is rtl
|
||||
rtl: true,
|
||||
},
|
||||
],
|
||||
@@ -105,7 +106,7 @@ language and country codes (ISO 3166‑1) such as `en-US`, `en-UK`, `es-MX`, etc
|
||||
### Locale Properties:
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
|
||||
|----------------------|--------------------------------------------------------------------------------------------------------------------------------|
|
||||
| **`code`** \* | Unique code to identify the language throughout the APIs for `locale` and `fallbackLocale` |
|
||||
| **`label`** | A string to use for the selector when choosing a language, or an object keyed on the i18n keys for different languages in use. |
|
||||
| **`rtl`** | A boolean that when true will make the admin UI display in Right-To-Left. |
|
||||
@@ -134,13 +135,9 @@ to support localization, you need to specify each field that you would like to l
|
||||
```js
|
||||
{
|
||||
name: 'title',
|
||||
type
|
||||
:
|
||||
'text',
|
||||
// highlight-start
|
||||
localized
|
||||
:
|
||||
true,
|
||||
type: 'text',
|
||||
// highlight-start
|
||||
localized: true,
|
||||
// highlight-end
|
||||
}
|
||||
```
|
||||
@@ -207,11 +204,11 @@ The `fallbackLocale` arg will accept valid locales as well as `none` to disable
|
||||
|
||||
```graphql
|
||||
query {
|
||||
Posts(locale: de, fallbackLocale: none) {
|
||||
docs {
|
||||
title
|
||||
Posts(locale: de, fallbackLocale: none) {
|
||||
docs {
|
||||
title
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
@@ -19,33 +19,33 @@ Payload is a _config-based_, code-first CMS and application framework. The Paylo
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description |
|
||||
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `admin` \* | Base Payload admin configuration. Specify bundler\*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
|
||||
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
|
||||
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
|
||||
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
||||
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
||||
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
||||
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
||||
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
||||
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
||||
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
||||
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
||||
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
||||
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
||||
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
||||
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
||||
| `debug` | Enable to expose more detailed error information. |
|
||||
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
||||
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
||||
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
||||
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
||||
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
| Option | Description |
|
||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `admin` \* | Base Payload admin configuration. Specify bundler*, custom components, control metadata, set the Admin user collection, and [more](/docs/admin/overview#admin-options). Required. |
|
||||
| `editor` \* | Rich Text Editor which will be used by richText fields. Required. |
|
||||
| `db` \* | Database Adapter which will be used by Payload. Read more [here](/docs/database/overview). Required. |
|
||||
| `serverURL` | A string used to define the absolute URL of your app including the protocol, for example `https://example.com`. No paths allowed, only protocol, domain and (optionally) port |
|
||||
| `collections` | An array of all Collections that Payload will manage. To read more about how to define your collection configs, [click here](/docs/configuration/collections). |
|
||||
| `globals` | An array of all Globals that Payload will manage. For more on Globals and their configs, [click here](/docs/configuration/globals). |
|
||||
| `cors` | Either a whitelist array of URLS to allow CORS requests from, or a wildcard string (`'*'`) to accept incoming requests from any domain. |
|
||||
| `localization` | Opt-in and control how Payload handles the translation of your content into multiple locales. [More](/docs/configuration/localization) |
|
||||
| `graphQL` | Manage GraphQL-specific functionality here. Define your own queries and mutations, manage query complexity limits, and [more](/docs/graphql/overview#graphql-options). |
|
||||
| `cookiePrefix` | A string that will be prefixed to all cookies that Payload sets. |
|
||||
| `csrf` | A whitelist array of URLs to allow Payload cookies to be accepted from as a form of CSRF protection. [More](/docs/authentication/overview#csrf-protection) |
|
||||
| `defaultDepth` | If a user does not specify `depth` while requesting a resource, this depth will be used. [More](/docs/getting-started/concepts#depth) |
|
||||
| `maxDepth` | The maximum allowed depth to be permitted application-wide. This setting helps prevent against malicious queries. Defaults to `10`. |
|
||||
| `indexSortableFields` | Automatically index all sortable top-level fields in the database to improve sort performance and add database compatibility for Azure Cosmos and similar. |
|
||||
| `upload` | Base Payload upload configuration. [More](/docs/upload/overview#payload-wide-upload-options). |
|
||||
| `routes` | Control the routing structure that Payload binds itself to. Specify `admin`, `api`, `graphQL`, and `graphQLPlayground`. |
|
||||
| `email` | Base email settings to allow Payload to generate email such as Forgot Password requests and other requirements. [More](/docs/email/overview#configuration) |
|
||||
| `express` | Express-specific middleware options such as compression and JSON parsing. [More](/docs/configuration/express) |
|
||||
| `debug` | Enable to expose more detailed error information. |
|
||||
| `telemetry` | Disable Payload telemetry by passing `false`. [More](/docs/configuration/overview#telemetry) |
|
||||
| `rateLimit` | Control IP-based rate limiting for all Payload resources. Used to prevent DDoS attacks and [more](/docs/production/preventing-abuse#rate-limiting-requests). |
|
||||
| `hooks` | Tap into Payload-wide hooks. [More](/docs/hooks/overview) |
|
||||
| `plugins` | An array of Payload plugins. [More](/docs/plugins/overview) |
|
||||
| `endpoints` | An array of custom API endpoints added to the Payload router. [More](/docs/rest-api/overview#custom-endpoints) |
|
||||
| `custom` | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
|
||||
@@ -20,8 +20,7 @@ Ensure you have an npm script called "payload" in your `package.json` file.
|
||||
```
|
||||
|
||||
<Banner>
|
||||
Note that you need to run Payload migrations through the package manager that you are using,
|
||||
because Payload should not be globally installed on your system.
|
||||
Note that you need to run Payload migrations through the package manager that you are using, because Payload should not be globally installed on your system.
|
||||
</Banner>
|
||||
|
||||
### Migration file contents
|
||||
@@ -42,15 +41,15 @@ Here is an example migration file:
|
||||
```ts
|
||||
import { MigrateUpArgs, MigrateDownArgs } from '@payloadcms/your-db-adapter'
|
||||
|
||||
export async function up({ payload, req }: MigrateUpArgs): Promise<void> {
|
||||
export async function up ({ payload, req }: MigrateUpArgs): Promise<void> {
|
||||
// Perform changes to your database here.
|
||||
// You have access to `payload` as an argument, and
|
||||
// everything is done in TypeScript.
|
||||
}
|
||||
};
|
||||
|
||||
export async function down({ payload, req }: MigrateDownArgs): Promise<void> {
|
||||
export async function down ({ payload, req }: MigrateDownArgs): Promise<void> {
|
||||
// Do whatever you need to revert changes if the `up` function fails
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
### Migrations Directory
|
||||
|
||||
@@ -31,12 +31,12 @@ export default buildConfig({
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
|
||||
|----------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `autoPluralization` | Tell Mongoose to auto-pluralize any collection names if it encounters any singular words used as collection `slug`s. |
|
||||
| `connectOptions` | 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. |
|
||||
| `disableIndexHints` | Set to true to disable hinting to MongoDB to use 'id' as index. This is currently done when counting documents for pagination, as it increases the speed of the count function used in that query. Disabling this optimization might fix some problems with AWS DocumentDB. Defaults to false |
|
||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. | |
|
||||
| `transactionOptions` | An object with configuration properties used in [transactions](https://www.mongodb.com/docs/manual/core/transactions/) or `false` which will disable the use of transactions. | |
|
||||
|
||||
### Access to Mongoose models
|
||||
|
||||
|
||||
@@ -42,15 +42,15 @@ You should prefer a relational DB like Postgres if:
|
||||
|
||||
#### Differences in Payload features
|
||||
|
||||
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
|
||||
It's important to note that almost everything Payload does is available in all of our officially supported database adapters, including localization, arrays, blocks, etc.
|
||||
|
||||
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
|
||||
The only thing that is not supported in Postgres yet is the [Point field](/docs/fields/point), but that should be added soon.
|
||||
|
||||
It's up to you to choose which database you would like to use.
|
||||
|
||||
## Configuration
|
||||
|
||||
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
|
||||
To configure the database for your Payload application, an adapter can be assigned to `config.db`. This property is required within your Payload config.
|
||||
|
||||
Here's an example:
|
||||
|
||||
@@ -67,7 +67,7 @@ export default buildConfig({
|
||||
db: postgresAdapter({
|
||||
pool: {
|
||||
connectionString: process.env.DATABASE_URI,
|
||||
},
|
||||
}
|
||||
}),
|
||||
})
|
||||
```
|
||||
```
|
||||
@@ -9,8 +9,7 @@ keywords: Postgres, documentation, typescript, Content Management System, cms, h
|
||||
To use Payload with Postgres, install the package `@payloadcms/db-postgres`. It leverages Drizzle ORM and `node-postgres` to interact with a Postgres database that you provide.
|
||||
|
||||
<Banner>
|
||||
The Postgres database adapter is currently in beta. If you would like to help us test this
|
||||
package, we'd love to hear if you find any bugs or issues!
|
||||
The Postgres database adapter is currently in beta. If you would like to help us test this package, we'd love to hear if you find any bugs or issues!
|
||||
</Banner>
|
||||
|
||||
It automatically manages changes to your database for you in development mode, and exposes a full suite of migration controls for you to leverage in order to keep other database environments in sync with your schema. DDL transformations are automatically generated.
|
||||
@@ -31,19 +30,25 @@ export default buildConfig({
|
||||
// `pool` is required.
|
||||
pool: {
|
||||
connectionString: process.env.DATABASE_URI,
|
||||
},
|
||||
}
|
||||
}),
|
||||
})
|
||||
```
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Description |
|
||||
| -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `pool` | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
|
||||
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
|
||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||
| Option | Description |
|
||||
|-----------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||
| `pool` \* | [Pool connection options](https://orm.drizzle.team/docs/quick-postgresql/node-postgres) that will be passed to Drizzle and `node-postgres`. |
|
||||
| `push` | Disable Drizzle's [`db push`](https://orm.drizzle.team/kit-docs/overview#prototyping-with-db-push) in development mode. By default, `push` is enabled for development mode only. |
|
||||
| `migrationDir` | Customize the directory that migrations are stored. |
|
||||
| `logger` | The instance of the logger to be passed to drizzle. By default Payload's will be used. |
|
||||
| `schemaName` | A string for the postgres schema to use, defaults to 'public'. |
|
||||
| `localesSuffix` | A string appended to the end of table names for storing localized fields. Default is '_locales'. |
|
||||
| `relationshipsSuffix` | A string appended to the end of table names for storing relationships. Default is '_rels'. |
|
||||
| `versionsSuffix` | A string appended to the end of table names for storing versions. Defaults to '_v'. |
|
||||
|
||||
|
||||
|
||||
### Access to Drizzle
|
||||
|
||||
@@ -85,7 +90,5 @@ Migrations are extremely powerful thanks to the seamless way that Payload and Dr
|
||||
1. Now your production database is in sync with your Payload config!
|
||||
|
||||
<Banner type="warning">
|
||||
Warning: do not mix "push" and migrations with your local development database. If you use "push"
|
||||
locally, and then try to migrate, Payload will throw a warning, telling you that these two methods
|
||||
are not meant to be used interchangeably.
|
||||
Warning: do not mix "push" and migrations with your local development database. If you use "push" locally, and then try to migrate, Payload will throw a warning, telling you that these two methods are not meant to be used interchangeably.
|
||||
</Banner>
|
||||
|
||||
@@ -20,7 +20,8 @@ The initial request made to Payload will begin a new transaction and attach it t
|
||||
|
||||
```ts
|
||||
const afterChange: CollectionAfterChangeHook = async ({ req }) => {
|
||||
// because req.transactionID is assigned from Payload and passed through, my-slug will only persist if the entire request is successful
|
||||
// because req.transactionID is assigned from Payload and passed through,
|
||||
// my-slug will only persist if the entire request is successful
|
||||
await req.payload.create({
|
||||
req,
|
||||
collection: 'my-slug',
|
||||
@@ -60,10 +61,44 @@ const afterChange: CollectionAfterChangeHook = async ({ req }) => {
|
||||
|
||||
### Direct Transaction Access
|
||||
|
||||
When writing your own scripts or custom endpoints, you may wish to have direct control over transactions. This is useful for interacting with your database outside of Payload's local API.
|
||||
When writing your own scripts or custom endpoints, you may wish to have direct control over transactions. This is useful for interacting with your database in something like a background job, outside the normal request-response flow.
|
||||
|
||||
The following functions can be used for managing transactions:
|
||||
|
||||
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls.
|
||||
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.
|
||||
`payload.db.beginTransaction` - Starts a new session and returns a transaction ID for use in other Payload Local API calls. Note that if your database does not support transactions, this will return `null`.\
|
||||
`payload.db.commitTransaction` - Takes the identifier for the transaction, finalizes any changes.\
|
||||
`payload.db.rollbackTransaction` - Takes the identifier for the transaction, discards any changes.
|
||||
|
||||
You can then use the transaction ID with Payload's local API by passing it inside the `PayloadRequest` object.
|
||||
|
||||
Here is an example for a "background job" function, which utilizes the direct transaction API to make sure it either succeeds completely or gets rolled back in case of an error.
|
||||
|
||||
```ts
|
||||
async function allOrNothingJob() {
|
||||
const req = {} as PayloadRequest;
|
||||
req.transactionID = await payload.db.beginTransaction();
|
||||
try {
|
||||
await payload.create({
|
||||
req, // use our manual transaction
|
||||
collection: 'my-slug',
|
||||
data: {
|
||||
some: 'data'
|
||||
}
|
||||
});
|
||||
|
||||
await payload.create({
|
||||
req, // use our manual transaction
|
||||
collection: 'something-else',
|
||||
data: {
|
||||
some: 'data'
|
||||
}
|
||||
});
|
||||
console.log('Everything done.');
|
||||
if (req.transactionID) await payload.db.commitTransaction(req.transactionID);
|
||||
} catch (e) {
|
||||
console.error('Oh no, something went wrong!');
|
||||
if (req.transactionID) await payload.db.rollbackTransaction(req.transactionID);
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
@@ -25,13 +25,13 @@ 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 |
|
||||
| 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) or see the examples below |
|
||||
| **`logMockCredentials`** | If set to true and no transport/transportOptions, ethereal credentials will be logged to console on startup |
|
||||
| **`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._
|
||||
|
||||
|
||||
39
docs/examples/overview.mdx
Normal file
39
docs/examples/overview.mdx
Normal file
@@ -0,0 +1,39 @@
|
||||
---
|
||||
title: Examples
|
||||
label: Overview
|
||||
order: 10
|
||||
desc:
|
||||
keywords: example, examples, starter, boilerplate, template, templates
|
||||
---
|
||||
|
||||
Payload provides a vast array of examples to help you get started with your project no matter what you are working on. These examples are designed to be easy to get up and running, and to be easy to understand. They showcase nothing more than the specific features being demonstrated, so you can easily decipher what is going on.
|
||||
|
||||
Examples are changing every day, so be sure to check back often to see what new examples have been added. If you have a specific example you would like to see, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.
|
||||
|
||||
- [Auth](https://github.com/payloadcms/payload/tree/main/examples/auth)
|
||||
- [Custom Server](https://github.com/payloadcms/payload/tree/main/examples/custom-server)
|
||||
- [Draft Preview](https://github.com/payloadcms/payload/tree/main/examples/draft-preview)
|
||||
- [Email](https://github.com/payloadcms/payload/tree/main/examples/email)
|
||||
- [Form Builder](https://github.com/payloadcms/payload/tree/main/examples/form-builder)
|
||||
- [Hierarchy](https://github.com/payloadcms/payload/tree/main/examples/hierarchy)
|
||||
- [Live Preview](https://github.com/payloadcms/payload/tree/main/examples/live-preview)
|
||||
- [Multi-tenant](https://github.com/payloadcms/payload/tree/main/examples/multi-tenant)
|
||||
- [Nested Docs](https://github.com/payloadcms/payload/tree/main/examples/nested-docs)
|
||||
- [Redirects](https://github.com/payloadcms/payload/tree/main/examples/redirects)
|
||||
- [Tests](https://github.com/payloadcms/payload/tree/main/examples/testing)
|
||||
- [Virtual Fields](https://github.com/payloadcms/payload/tree/main/examples/virtual-fields)
|
||||
- [White-label Admin UI](https://github.com/payloadcms/payload/tree/main/examples/whitelabel)
|
||||
|
||||
Where necessary, some examples include a front-end. Examples that require a front-end share this folder structure:
|
||||
|
||||
```plaintext
|
||||
example/
|
||||
├── payload/
|
||||
├── next-app/
|
||||
├── next-pages/
|
||||
├── react-router/
|
||||
├── vue/
|
||||
├── svelte/
|
||||
```
|
||||
|
||||
Where `payload` is your Payload project, and the other directories are dedicated to their respective front-end framework. We are adding new examples every day, so if your framework of choice is not yet supported in any particular example, please feel free to start a new [Discussion](https://github.com/payloadcms/payload/discussions) or open a new [PR](https://github.com/payloadcms/payload/pulls) to add it yourself.
|
||||
@@ -12,22 +12,24 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
|
||||
</Banner>
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/array.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/array-dark.png"
|
||||
alt="Array field with two Rows in Payload admin panel"
|
||||
caption="Admin panel screenshot of an Array field with two Rows"
|
||||
srcLight="https://payloadcms.com/images/docs/fields/array.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/array-dark.png"
|
||||
alt="Array field with two Rows in Payload admin panel"
|
||||
caption="Admin panel screenshot of an Array field with two Rows"
|
||||
/>
|
||||
|
||||
**Example uses:**
|
||||
|
||||
- A "slider" with an image ([upload field](/docs/fields/upload)) and a caption ([text field](/docs/fields/text))
|
||||
- Navigational structures where editors can specify nav items containing pages ([relationship field](/docs/fields/relationship)), an "open in new tab" [checkbox field](/docs/fields/checkbox)
|
||||
- Event agenda "timeslots" where you need to specify start & end time ([date field](/docs/fields/date)), label ([text field](/docs/fields/text)), and Learn More page [relationship](/docs/fields/relationship)
|
||||
- Navigational structures where editors can specify nav items containing
|
||||
pages ([relationship field](/docs/fields/relationship)), an "open in new tab" [checkbox field](/docs/fields/checkbox)
|
||||
- Event agenda "timeslots" where you need to specify start & end time ([date field](/docs/fields/date)),
|
||||
label ([text field](/docs/fields/text)), and Learn More page [relationship](/docs/fields/relationship)
|
||||
|
||||
### Config
|
||||
|
||||
| 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. |
|
||||
@@ -45,16 +47,19 @@ keywords: array, fields, config, configuration, documentation, Content Managemen
|
||||
| **`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). |
|
||||
| **`dbName`** | Custom table name for the field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined. |
|
||||
|
||||
_\* 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:
|
||||
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 |
|
||||
| **`isSortable`** | Disable array order sorting by setting this value to `false` |
|
||||
| **`components.RowLabel`** | Function or React component to be rendered as the label on the array row. Receives `({ data, index, path })` as args |
|
||||
|
||||
### Example
|
||||
@@ -63,6 +68,7 @@ In addition to the default [field admin config](/docs/fields/overview#admin-conf
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
import { RowLabelArgs } from 'payload/dist/admin/components/forms/RowLabel/types'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
@@ -97,7 +103,7 @@ export const ExampleCollection: CollectionConfig = {
|
||||
],
|
||||
admin: {
|
||||
components: {
|
||||
RowLabel: ({ data, index }) => {
|
||||
RowLabel: ({ data, index }: RowLabelArgs) => {
|
||||
return data?.title || `Slide ${String(index).padStart(2, '0')}`
|
||||
},
|
||||
},
|
||||
|
||||
@@ -14,22 +14,23 @@ keywords: blocks, fields, config, configuration, documentation, Content Manageme
|
||||
</Banner>
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/blocks.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/blocks-dark.png"
|
||||
alt="Admin panel screenshot of add Blocks drawer view"
|
||||
caption="Admin panel screenshot of add Blocks drawer view"
|
||||
srcLight="https://payloadcms.com/images/docs/fields/blocks.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/blocks-dark.png"
|
||||
alt="Admin panel screenshot of add Blocks drawer view"
|
||||
caption="Admin panel screenshot of add Blocks drawer view"
|
||||
/>
|
||||
|
||||
**Example uses:**
|
||||
|
||||
- A layout builder tool that grants editors to design highly customizable page or post layouts. Blocks could include configs such as `Quote`, `CallToAction`, `Slider`, `Content`, `Gallery`, or others.
|
||||
- A layout builder tool that grants editors to design highly customizable page or post layouts. Blocks could include
|
||||
configs such as `Quote`, `CallToAction`, `Slider`, `Content`, `Gallery`, or others.
|
||||
- A form builder tool where available block configs might be `Text`, `Select`, or `Checkbox`.
|
||||
- Virtual event agenda "timeslots" where a timeslot could either be a `Break`, a `Presentation`, or a `BreakoutSession`.
|
||||
|
||||
### Field 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. |
|
||||
| **`blocks`** \* | Array of [block configs](/docs/fields/blocks#block-configs) to be made available to this field. |
|
||||
@@ -51,11 +52,13 @@ _\* 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:
|
||||
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 |
|
||||
| **`isSortable`** | Disable block order sorting by setting this value to `false` |
|
||||
|
||||
### Block configs
|
||||
|
||||
@@ -72,7 +75,7 @@ Blocks are defined as separate configs of their own.
|
||||
</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. |
|
||||
@@ -80,6 +83,7 @@ Blocks are defined as separate configs of their own.
|
||||
| **`imageAltText`** | Customize this block's image thumbnail alt text. |
|
||||
| **`interfaceName`** | Create a top level, reusable [Typescript interface](/docs/typescript/generating-types#custom-field-interfaces) & [GraphQL type](/docs/graphql/graphql-schema#custom-field-schemas). |
|
||||
| **`graphQL.singularName`** | Text to use for the GraphQL schema name. Auto-generated from slug if not defined. NOTE: this is set for deprecation, prefer `interfaceName`. |
|
||||
| **`dbName`** | Custom table name for this block type when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from slug if not defined.
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
#### Auto-generated data per block
|
||||
@@ -92,7 +96,8 @@ The `blockType` is saved as the slug of the block that has been selected.
|
||||
|
||||
**`blockName`**
|
||||
|
||||
The Admin panel provides each block with a `blockName` field which optionally allows editors to label their blocks for better editability and readability.
|
||||
The Admin panel provides each block with a `blockName` field which optionally allows editors to label their blocks for
|
||||
better editability and readability.
|
||||
|
||||
### Example
|
||||
|
||||
@@ -139,7 +144,8 @@ export const ExampleCollection: CollectionConfig = {
|
||||
|
||||
### TypeScript
|
||||
|
||||
As you build your own Block configs, you might want to store them in separate files but retain typing accordingly. To do so, you can import and use Payload's `Block` type:
|
||||
As you build your own Block configs, you might want to store them in separate files but retain typing accordingly. To do
|
||||
so, you can import and use Payload's `Block` type:
|
||||
|
||||
```ts
|
||||
import type { Block } from 'payload/types'
|
||||
|
||||
@@ -17,21 +17,21 @@ keywords: checkbox, fields, config, configuration, documentation, Content Manage
|
||||
|
||||
### 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. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`label`** | Text used as a field label in the Admin panel or an object with keys for each language. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value, will default to false if field is also `required`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`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, will default to false if field is also `required`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
|
||||
@@ -23,24 +23,24 @@ 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. |
|
||||
| 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 an [index](/docs/database#overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`minLength`** | Used by the default validation function to ensure values are of a minimum character length. |
|
||||
| **`maxLength`** | Used by the default validation function to ensure values are of a maximum character length. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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._
|
||||
|
||||
|
||||
@@ -22,21 +22,21 @@ This field uses [`react-datepicker`](https://www.npmjs.com/package/react-datepic
|
||||
|
||||
### 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. |
|
||||
| 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. |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`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._
|
||||
|
||||
@@ -44,20 +44,20 @@ _\* 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.
|
||||
|
||||
| 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.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
|
||||
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
|
||||
| **`date.timeFormat`** \* | Determines time format. 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.overrides`** \* | Pass any valid props directly to the [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md) |
|
||||
| **`date.timeIntervals`** \* | Time intervals to display. Defaults to 30 minutes. |
|
||||
| **`date.timeFormat`** \* | Determines time format. Defaults to `'h:mm aa'`. |
|
||||
|
||||
_\* This property is passed directly to [react-datepicker](https://github.com/Hacker0x01/react-datepicker/blob/master/docs/datepicker.md). ._
|
||||
|
||||
|
||||
@@ -17,22 +17,22 @@ keywords: email, fields, config, configuration, documentation, Content Managemen
|
||||
|
||||
### 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. |
|
||||
| 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 an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`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._
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ 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
|
||||
keywords: json, jsonSchema, schema, validation, fields, config, configuration, documentation, Content Management System, cms, headless, javascript, node, react, express
|
||||
---
|
||||
|
||||
<Banner>
|
||||
@@ -23,22 +23,23 @@ 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. |
|
||||
| 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 an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`jsonSchema`** | Provide a JSON schema that will be used for validation. [JSON schemas](https://json-schema.org/learn/getting-started-step-by-step) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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._
|
||||
|
||||
@@ -46,13 +47,13 @@ _\* An asterisk denotes that a property is required._
|
||||
|
||||
In addition to the default [field admin config](/docs/fields/overview#admin-config), you can adjust the following properties:
|
||||
|
||||
| Option | Description |
|
||||
| ------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| Option | Description |
|
||||
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`editorOptions`** | Options that can be passed to the monaco editor, [view the full list](https://microsoft.github.io/monaco-editor/typedoc/variables/editor.EditorOptions.html). |
|
||||
|
||||
### Example
|
||||
|
||||
`collections/ExampleCollection.ts
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
@@ -68,3 +69,68 @@ export const ExampleCollection: CollectionConfig = {
|
||||
],
|
||||
}
|
||||
```
|
||||
|
||||
### JSON Schema Validation
|
||||
|
||||
Payload JSON fields fully support the [JSON schema](https://json-schema.org/) standard. By providing a schema in your field config, the editor will be guided in the admin UI, getting typeahead for properties and their formats automatically. When the document is saved, the default validation will prevent saving any invalid data in the field according to the schema in your config.
|
||||
|
||||
If you only provide a URL to a schema, Payload will fetch the desired schema if it is publicly available. If not, it is recommended to add the schema directly to your config or import it from another file so that it can be implemented consistently in your project.
|
||||
|
||||
|
||||
#### Local JSON Schema
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'customerJSON', // required
|
||||
type: 'json', // required
|
||||
jsonSchema: {
|
||||
uri: 'a://b/foo.json', // required
|
||||
fileMatch: ['a://b/foo.json'], // required
|
||||
schema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
foo: {
|
||||
enum: ['bar', 'foobar'],
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
},
|
||||
],
|
||||
}
|
||||
// {"foo": "bar"} or {"foo": "foobar"} - ok
|
||||
// Attempting to create {"foo": "not-bar"} will throw an error
|
||||
```
|
||||
|
||||
#### Remote JSON Schema
|
||||
|
||||
`collections/ExampleCollection.ts`
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
|
||||
export const ExampleCollection: CollectionConfig = {
|
||||
slug: 'example-collection',
|
||||
fields: [
|
||||
{
|
||||
name: 'customerJSON', // required
|
||||
type: 'json', // required
|
||||
jsonSchema: {
|
||||
uri: 'https://example.com/customer.schema.json', // required
|
||||
fileMatch: ['https://example.com/customer.schema.json'], // required
|
||||
},
|
||||
},
|
||||
],
|
||||
}
|
||||
// If 'https://example.com/customer.schema.json' has a JSON schema
|
||||
// {"foo": "bar"} or {"foo": "foobar"} - ok
|
||||
// Attempting to create {"foo": "not-bar"} will throw an error
|
||||
```
|
||||
|
||||
@@ -20,27 +20,27 @@ keywords: number, fields, config, configuration, documentation, Content Manageme
|
||||
|
||||
### 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. |
|
||||
| **`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. |
|
||||
| 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. |
|
||||
| **`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 an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`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._
|
||||
|
||||
|
||||
@@ -83,15 +83,15 @@ There are two arguments available to custom validation functions.
|
||||
|
||||
| Property | Description |
|
||||
| ------------- | ------------------------------------------------------------------------------------------------------------------------ |
|
||||
| `data` | An object containing the full collection or global document currently being edited |
|
||||
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
|
||||
| `operation` | Will be `create` or `update` depending on the UI action or API call |
|
||||
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
|
||||
| `t` | The function for translating text, [more](/docs/configuration/i18n) |
|
||||
| `user` | An object containing the currently authenticated user |
|
||||
| `data` | An object of the full collection or global document. |
|
||||
| `siblingData` | An object of the document data limited to fields within the same parent to the field. |
|
||||
| `operation` | Will be "create" or "update" depending on the UI action or API call. |
|
||||
| `id` | The value of the collection `id`, will be `undefined` on create request. |
|
||||
| `t` | The function for translating text, [more](/docs/configuration/i18n). |
|
||||
| `user` | The currently authenticated user object. |
|
||||
| `payload` | If the `validate` function is being executed on the server, Payload will be exposed for easily running local operations. |
|
||||
|
||||
### Example
|
||||
Example:
|
||||
|
||||
```ts
|
||||
import { CollectionConfig } from 'payload/types'
|
||||
@@ -163,19 +163,21 @@ 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. |
|
||||
| `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. |
|
||||
| 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. |
|
||||
| `disableListColumn` | Set `disableListColumn` to `true` to prevent fields from appearing in the list view column selector. |
|
||||
| `disableListFilter` | Set `disableListFilter` to `true` to prevent fields from appearing in the list view filter options. |
|
||||
| `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
|
||||
|
||||
|
||||
@@ -27,22 +27,22 @@ The data structure in the database matches the GeoJSON structure to represent po
|
||||
|
||||
### 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`** | 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. |
|
||||
| Option | Description |
|
||||
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`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 an [index](/docs/database/overview) for this field to produce faster queries. To support location queries, point index defaults to `2dsphere`, to disable the index set to `false`. |
|
||||
| **`validate`** | Provide a custom validation function that will be executed on both the Admin panel and the backend. [More](/docs/fields/overview#validation) |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`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) |
|
||||
| **`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._
|
||||
|
||||
|
||||
@@ -20,22 +20,23 @@ keywords: radio, fields, config, configuration, documentation, Content Managemen
|
||||
|
||||
### Config
|
||||
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing 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) |
|
||||
| Option | Description |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| **`name`** \* | To be used as the property name when stored and retrieved from the database. [More](/docs/fields/overview#field-names) |
|
||||
| **`options`** \* | Array of options to allow the field to store. Can either be an array of strings, or an array of objects containing 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) |
|
||||
| **`index`** | Build an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. The default value must exist within provided values in `options`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`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. The default value must exist within provided values in `options`. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See below for [more detail](#admin-config). |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`enumName`** | Custom enum name for this field when using SQL database adapter ([Postgres](/docs/database/postgres)). Auto-generated from name if not defined.
|
||||
|
||||
_\* An asterisk denotes that a property is required._
|
||||
|
||||
|
||||
@@ -12,10 +12,10 @@ keywords: relationship, fields, config, configuration, documentation, Content Ma
|
||||
</Banner>
|
||||
|
||||
<LightDarkImage
|
||||
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
|
||||
alt="Shows a relationship field in the Payload admin panel"
|
||||
caption="Admin panel screenshot of a Relationship field"
|
||||
srcLight="https://payloadcms.com/images/docs/fields/relationship.png"
|
||||
srcDark="https://payloadcms.com/images/docs/fields/relationship-dark.png"
|
||||
alt="Shows a relationship field in the Payload admin panel"
|
||||
caption="Admin panel screenshot of a Relationship field"
|
||||
/>
|
||||
|
||||
**Example uses:**
|
||||
@@ -26,28 +26,28 @@ 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. [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) |
|
||||
| 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 an [index](/docs/database/overview) for this field to produce faster queries. Set this field to `true` if your users will perform queries on this field's data often. |
|
||||
| **`saveToJWT`** | If this field is top-level and nested in a config supporting [Authentication](/docs/authentication/config), include its data in the user JWT. |
|
||||
| **`hooks`** | Provide field-based hooks to control logic for this field. [More](/docs/fields/overview#field-level-hooks) |
|
||||
| **`access`** | Provide field-based access control to denote what users can see and do with this field's data. [More](/docs/fields/overview#field-level-access-control) |
|
||||
| **`hidden`** | Restrict this field's visibility from all APIs entirely. Will still be saved to the database, but will not appear in any API or the Admin panel. |
|
||||
| **`defaultValue`** | Provide data to be used for this field's default value. [More](/docs/fields/overview#default-values) |
|
||||
| **`localized`** | Enable localization for this field. Requires [localization to be enabled](/docs/configuration/localization) in the Base config. |
|
||||
| **`required`** | Require this field to have a value. |
|
||||
| **`admin`** | Admin-specific configuration. See the [default field admin config](/docs/fields/overview#admin-config) for more details. |
|
||||
| **`custom`** | Extension point for adding custom data (e.g. for plugins) |
|
||||
| **`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._
|
||||
|
||||
@@ -131,13 +131,13 @@ The `filterOptions` property can either be a `Where` query, or a function return
|
||||
prevent all, or a `Where` query. When using a function, it will be
|
||||
called with an argument object with the following properties:
|
||||
|
||||
| Property | Description |
|
||||
| ------------- | ----------------------------------------------------------------------------------------------------- |
|
||||
| `relationTo` | The collection `slug` to filter against, limited to this field's `relationTo` property |
|
||||
| `data` | An object containing the full collection or global document currently being edited |
|
||||
| `siblingData` | An object containing document data that is scoped to only fields within the same parent of this field |
|
||||
| `id` | The `id` of the current document being edited. `id` is `undefined` during the `create` operation |
|
||||
| `user` | An object containing the currently authenticated user |
|
||||
| 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
|
||||
|
||||
@@ -287,7 +287,10 @@ To save the to `hasMany` relationship field we need to send an array of IDs:
|
||||
|
||||
```json
|
||||
{
|
||||
"owners": ["6031ac9e1289176380734024", "602c3c327b811235943ee12b"]
|
||||
"owners": [
|
||||
"6031ac9e1289176380734024",
|
||||
"602c3c327b811235943ee12b"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
@@ -359,6 +362,5 @@ Since we are referencing multiple collections, the field you are querying on may
|
||||
<Banner type="warning">
|
||||
<strong>Note:</strong>
|
||||
<br />
|
||||
You <strong>cannot</strong> query on a field within a polymorphic relationship as you would with a
|
||||
non-polymorphic relationship.
|
||||
You <strong>cannot</strong> query on a field within a polymorphic relationship as you would with a non-polymorphic relationship.
|
||||
</Banner>
|
||||
|
||||
@@ -18,7 +18,7 @@ keywords: rich text, fields, config, configuration, documentation, Content Manag
|
||||
caption="Admin panel screenshot of a Rich Text field"
|
||||
/>
|
||||
|
||||
Payload's rich text field is built on an "adapter pattern" which lets you specify which rich text editor you'd like to use.
|
||||
Payload's rich text field is built on an "adapter pattern" which lets you specify which rich text editor you'd like to use.
|
||||
|
||||
Right now, Payload is officially supporting two rich text editors:
|
||||
|
||||
@@ -26,13 +26,7 @@ Right now, Payload is officially supporting two rich text editors:
|
||||
2. [Lexical](/docs/rich-text/lexical) - beta, where things will be moving
|
||||
|
||||
<Banner type="success">
|
||||
<strong>
|
||||
Consistent with Payload's goal of making you learn as little of Payload as possible, customizing
|
||||
and using the Rich Text Editor does not involve learning how to develop for a <em>Payload</em>{' '}
|
||||
rich text editor.
|
||||
</strong>{' '}
|
||||
Instead, you can invest your time and effort into learning the underlying open-source tools that
|
||||
will allow you to apply your learnings elsewhere as well.
|
||||
<strong>Consistent with Payload's goal of making you learn as little of Payload as possible, customizing and using the Rich Text Editor does not involve learning how to develop for a <em>Payload</em> rich text editor.</strong> Instead, you can invest your time and effort into learning the underlying open-source tools that will allow you to apply your learnings elsewhere as well.
|
||||
</Banner>
|
||||
|
||||
### Config
|
||||
@@ -73,4 +67,4 @@ Override the default text direction of the Admin panel for this field. Set to `t
|
||||
|
||||
### Editor-specific options
|
||||
|
||||
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
|
||||
For a ton more editor-specific options, including how to build custom rich text elements directly into your editor, take a look at either the [Slate docs](/docs/rich-text/slate) or the [Lexical docs](/docs/rich-text/lexical) depending on which editor you're using.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user