Compare commits
743 Commits
alpha-post
...
feat/db-op
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f9677872b5 | ||
|
|
358e979c9e | ||
|
|
b691c6c9a7 | ||
|
|
0c4547b890 | ||
|
|
83a060b3f7 | ||
|
|
e20248489a | ||
|
|
9f788b192d | ||
|
|
ab7845d5bc | ||
|
|
9a9ff781bf | ||
|
|
118287097f | ||
|
|
6b48734375 | ||
|
|
087a30df86 | ||
|
|
7baf43aa0f | ||
|
|
d9cbd446ff | ||
|
|
7da131a93e | ||
|
|
f5575049f7 | ||
|
|
9b11a75ef8 | ||
|
|
f3b809193d | ||
|
|
25d83c3d06 | ||
|
|
b693de557b | ||
|
|
7beb4db796 | ||
|
|
e2d4a2a59f | ||
|
|
a5444d0e7c | ||
|
|
28a065072f | ||
|
|
efc0bc9ec9 | ||
|
|
ade1d27c95 | ||
|
|
1040731e32 | ||
|
|
30f28898b6 | ||
|
|
6cb0470906 | ||
|
|
170ea5badc | ||
|
|
cfb56589eb | ||
|
|
f312bac065 | ||
|
|
3dd3f5b135 | ||
|
|
59f4d125ab | ||
|
|
b2b2ee3338 | ||
|
|
7308abaabd | ||
|
|
9b1d0b2d0f | ||
|
|
9014f1fa63 | ||
|
|
ba75d876e3 | ||
|
|
f2b2e5cda9 | ||
|
|
f751f69239 | ||
|
|
f7ac9ff52a | ||
|
|
ba7a043a99 | ||
|
|
b149180db4 | ||
|
|
4efb9dd867 | ||
|
|
7002ca78b9 | ||
|
|
44ca3a4073 | ||
|
|
dc7c952ace | ||
|
|
c8a659cd39 | ||
|
|
6ba293c0f8 | ||
|
|
96a624ad5c | ||
|
|
545949dafc | ||
|
|
d9f61bbdc8 | ||
|
|
be06579b3e | ||
|
|
25e9bc62db | ||
|
|
aca567634b | ||
|
|
1f0934877c | ||
|
|
61da010991 | ||
|
|
ab9074220a | ||
|
|
afa90a4362 | ||
|
|
bc0516da90 | ||
|
|
46daf473c8 | ||
|
|
337b8ccbf3 | ||
|
|
ba2e4c278f | ||
|
|
3196036ae9 | ||
|
|
9bc3ad5159 | ||
|
|
94d18e8d74 | ||
|
|
c624eea0d8 | ||
|
|
f97627092c | ||
|
|
f00183029e | ||
|
|
b6c5aaa966 | ||
|
|
517aaa0665 | ||
|
|
2c2ffe406f | ||
|
|
7f39afa192 | ||
|
|
fc4d24aa88 | ||
|
|
efa56cefc1 | ||
|
|
907d7d1d3a | ||
|
|
eca1517237 | ||
|
|
9865ae998b | ||
|
|
1a0ef4824b | ||
|
|
39e110e633 | ||
|
|
3e780b9815 | ||
|
|
a308d6384f | ||
|
|
492ed30cb8 | ||
|
|
fca5a404db | ||
|
|
b13f7e8843 | ||
|
|
25dfdb66cd | ||
|
|
9c9e6896a5 | ||
|
|
a3085435ef | ||
|
|
1466657e8f | ||
|
|
1348483648 | ||
|
|
5321098d7e | ||
|
|
c57591bc4f | ||
|
|
9750bc217e | ||
|
|
468e5441f1 | ||
|
|
3c5cce4c6f | ||
|
|
9f0f94893d | ||
|
|
03b7892fc9 | ||
|
|
f96cf593ce | ||
|
|
8259611ce6 | ||
|
|
a3ed25a253 | ||
|
|
69e7b7a158 | ||
|
|
c6da99b4d1 | ||
|
|
ebd23caa56 | ||
|
|
faa9b21824 | ||
|
|
1690560f11 | ||
|
|
0058660b3f | ||
|
|
6d7ef919cb | ||
|
|
abffa37d85 | ||
|
|
1b208c7add | ||
|
|
2840632161 | ||
|
|
0841d5a35e | ||
|
|
bd19fcf259 | ||
|
|
18645771c8 | ||
|
|
20377bb22c | ||
|
|
7daaf3d780 | ||
|
|
667d3dc885 | ||
|
|
51474fa661 | ||
|
|
d475b16790 | ||
|
|
4d0befb67a | ||
|
|
84d214f992 | ||
|
|
51cd5942fa | ||
|
|
74105d8ee5 | ||
|
|
1cc61ddab6 | ||
|
|
99397a0bdb | ||
|
|
a5492afad6 | ||
|
|
6c1156e2e4 | ||
|
|
77e8ce980e | ||
|
|
39e34ce94e | ||
|
|
2aa2971fb9 | ||
|
|
c82d2caa29 | ||
|
|
cf52d64d98 | ||
|
|
320dcc0a08 | ||
|
|
ea18735d3b | ||
|
|
4baa0e3221 | ||
|
|
2d35d695ea | ||
|
|
bb911cc7ec | ||
|
|
874774375f | ||
|
|
d337c5b523 | ||
|
|
dab632388e | ||
|
|
6f63e724e3 | ||
|
|
b230da33ce | ||
|
|
58427ffae3 | ||
|
|
9ecc6c8899 | ||
|
|
336438506c | ||
|
|
025306f9e6 | ||
|
|
b1c9dee840 | ||
|
|
9a17d6614c | ||
|
|
28a6d14a9a | ||
|
|
074a3f0e14 | ||
|
|
0a51de7623 | ||
|
|
e2004e525d | ||
|
|
4014b124ca | ||
|
|
ca2ccc6614 | ||
|
|
7fd716188b | ||
|
|
02e0e6fff8 | ||
|
|
dfa0afe7b3 | ||
|
|
e1b8e6fe02 | ||
|
|
c2c5ac5a1c | ||
|
|
f597cdfcfd | ||
|
|
967bd941e5 | ||
|
|
5f1c47130d | ||
|
|
e8165b79c5 | ||
|
|
1c986a9832 | ||
|
|
fb4ef6fc0f | ||
|
|
015aafda75 | ||
|
|
dae56e60ee | ||
|
|
9f0aaf066e | ||
|
|
f6ba3befae | ||
|
|
68ea693a88 | ||
|
|
62fa22cb24 | ||
|
|
3b4bb3065a | ||
|
|
4e0725f7c6 | ||
|
|
ff70fd9813 | ||
|
|
e40570bd0d | ||
|
|
b7e852993b | ||
|
|
ab97590879 | ||
|
|
ed86b15242 | ||
|
|
d58631c12c | ||
|
|
37c8386a51 | ||
|
|
2f9ed34d13 | ||
|
|
921a5c065d | ||
|
|
e3003b443f | ||
|
|
8a622984e7 | ||
|
|
507e0954b2 | ||
|
|
63bc6ae52f | ||
|
|
d016fbd2a5 | ||
|
|
9525511e8b | ||
|
|
1e834e58a4 | ||
|
|
373cb00139 | ||
|
|
558b298bf0 | ||
|
|
cd24e2bb3c | ||
|
|
ac8c2096af | ||
|
|
626be15578 | ||
|
|
67c0b0e6e0 | ||
|
|
11239103a6 | ||
|
|
4998ef8c9b | ||
|
|
e44ce819ce | ||
|
|
b700208b98 | ||
|
|
4a54aa7776 | ||
|
|
4fddea86eb | ||
|
|
547acfe876 | ||
|
|
56c6700cf2 | ||
|
|
a352ebc552 | ||
|
|
312b4a94c3 | ||
|
|
cb3dbed127 | ||
|
|
3a73a9696f | ||
|
|
d587441e80 | ||
|
|
fcfc3c593f | ||
|
|
baf945b1ea | ||
|
|
4f9d78df5e | ||
|
|
f07783a279 | ||
|
|
eeddeceda9 | ||
|
|
4c832ad984 | ||
|
|
81bc777dfe | ||
|
|
a757635bc7 | ||
|
|
80bf0a3067 | ||
|
|
a06c06415c | ||
|
|
2dd7e82fdc | ||
|
|
63e04e2ae0 | ||
|
|
e71888a625 | ||
|
|
c5514f1441 | ||
|
|
23e2fe643e | ||
|
|
bdef2f1bc7 | ||
|
|
8f03cd7c78 | ||
|
|
c0092191a6 | ||
|
|
b9854ed60a | ||
|
|
576ee14976 | ||
|
|
bf77cec7e9 | ||
|
|
ab8b2f3fb8 | ||
|
|
db5f3f3ccd | ||
|
|
cece39957f | ||
|
|
157fff0417 | ||
|
|
88e113a545 | ||
|
|
d33afe48fe | ||
|
|
e76df32f09 | ||
|
|
b068f30f51 | ||
|
|
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/**
|
**/dist/**
|
||||||
**/node_modules
|
**/node_modules
|
||||||
**/temp
|
**/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
|
# lint and format create-payload-app
|
||||||
5fd3d430001efe86515262ded5e26f00c1451181
|
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.
|
# Order matters. The last matching pattern takes precedence.
|
||||||
|
|
||||||
### Core ###
|
### Core ###
|
||||||
/packages/payload/src/uploads/ @denolfe
|
|
||||||
/packages/payload/src/admin/ @jmikrut @jacobsfletch @JarrodMFlesch
|
|
||||||
|
|
||||||
### Adapters ###
|
### Adapters ###
|
||||||
/packages/db-*/ @denolfe @jmikrut @DanRibbens
|
/packages/richtext-*/ @AlessioGr
|
||||||
/packages/richtext-*/ @denolfe @jmikrut @DanRibbens @AlessioGr
|
|
||||||
|
|
||||||
### Plugins ###
|
### Plugins ###
|
||||||
/packages/plugin-*/ @denolfe @jmikrut @DanRibbens
|
|
||||||
/packages/plugin-cloud*/ @denolfe
|
/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 ###
|
||||||
/templates/ @jacobsfletch @denolfe
|
/templates/ @jacobsfletch @denolfe
|
||||||
|
|
||||||
### Misc ###
|
### Misc ###
|
||||||
/packages/create-payload-app/ @denolfe
|
/packages/create-payload-app/ @denolfe
|
||||||
/packages/eslint-config-payload/ @denolfe
|
/packages/eslint-*/ @denolfe
|
||||||
/packages/payload-admin-bar/ @jacobsfletch
|
|
||||||
|
### Build Files ###
|
||||||
|
/**/package.json @denolfe
|
||||||
|
|
||||||
|
/tsconfig.json @denolfe
|
||||||
|
/**/tsconfig*.json @denolfe
|
||||||
|
|
||||||
|
/jest.config.js @denolfe
|
||||||
|
/**/jest.config.js @denolfe
|
||||||
|
|
||||||
### Root ###
|
### Root ###
|
||||||
/package.json @denolfe
|
/package.json @denolfe
|
||||||
/scripts/ @denolfe
|
/scripts/ @denolfe
|
||||||
|
/.husky/ @denolfe
|
||||||
|
/.vscode/ @denolfe
|
||||||
/.github/ @denolfe
|
/.github/ @denolfe
|
||||||
/.github/CODEOWNERS @denolfe
|
|
||||||
|
|||||||
47
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
47
.github/ISSUE_TEMPLATE/1.bug_report.yml
vendored
@@ -1,47 +0,0 @@
|
|||||||
name: Bug Report
|
|
||||||
description: Create a bug report for Payload
|
|
||||||
labels: ['[possible-bug]']
|
|
||||||
body:
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: |
|
|
||||||
*Note:* Feature requests should be opened as [discussions](https://github.com/payloadcms/payload/discussions/new?category=feature-requests-ideas).
|
|
||||||
- type: input
|
|
||||||
id: reproduction-link
|
|
||||||
attributes:
|
|
||||||
label: Link to reproduction
|
|
||||||
description: Want us to look into your issue faster? Follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
|
|
||||||
validations:
|
|
||||||
required: false
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: Describe the Bug
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
|
||||||
attributes:
|
|
||||||
label: To Reproduce
|
|
||||||
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
id: version
|
|
||||||
attributes:
|
|
||||||
label: Payload Version
|
|
||||||
description: What version of Payload are you running?
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: input
|
|
||||||
id: adapters-plugins
|
|
||||||
attributes:
|
|
||||||
label: Adapters and Plugins
|
|
||||||
description: What adapters and plugins are you using? ie. db-mongodb, db-postgres, bundler-webpack, etc.
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
|
|
||||||
- type: markdown
|
|
||||||
attributes:
|
|
||||||
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
|
|
||||||
52
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/1.bug_report_v3.yml
vendored
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
name: Bug Report v3
|
||||||
|
description: Create a bug report for Payload v3 (beta)
|
||||||
|
labels: ['status: needs-triage', 'v3']
|
||||||
|
body:
|
||||||
|
- type: input
|
||||||
|
id: reproduction-link
|
||||||
|
attributes:
|
||||||
|
label: Link to reproduction
|
||||||
|
description: Want us to look into your issue faster? Follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Environment Info
|
||||||
|
description: Paste output from `pnpm payload info` (>= beta.92) _or_ Payload, Node.js, and Next.js versions.
|
||||||
|
render: text
|
||||||
|
placeholder: |
|
||||||
|
Payload:
|
||||||
|
Node.js:
|
||||||
|
Next.js:
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the Bug
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Reproduction Steps
|
||||||
|
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: adapters-plugins
|
||||||
|
attributes:
|
||||||
|
label: Adapters and Plugins
|
||||||
|
description: What adapters and plugins are you using if relevant? ie. db-mongodb, db-postgres, storage-vercel-blob, etc.
|
||||||
|
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
|
||||||
47
.github/ISSUE_TEMPLATE/2.bug_report.yml
vendored
Normal file
47
.github/ISSUE_TEMPLATE/2.bug_report.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Create a bug report for Payload
|
||||||
|
labels: ['status: needs-triage', 'v2']
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
*Note:* Feature requests should be opened as [discussions](https://github.com/payloadcms/payload/discussions/new?category=feature-requests-ideas).
|
||||||
|
- type: input
|
||||||
|
id: reproduction-link
|
||||||
|
attributes:
|
||||||
|
label: Link to reproduction
|
||||||
|
description: Want us to look into your issue faster? Follow the [reproduction-guide](https://github.com/payloadcms/payload/blob/main/.github/reproduction-guide.md) for more information.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Describe the Bug
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: To Reproduce
|
||||||
|
description: Steps to reproduce the behavior, please provide a clear description of how to reproduce the issue, based on the linked minimal reproduction. Screenshots can be provided in the issue body below. If using code blocks, make sure that [syntax highlighting is correct](https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#syntax-highlighting) and double check that the rendered preview is not broken.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: version
|
||||||
|
attributes:
|
||||||
|
label: Payload Version
|
||||||
|
description: What version of Payload are you running?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: adapters-plugins
|
||||||
|
attributes:
|
||||||
|
label: Adapters and Plugins
|
||||||
|
description: What adapters and plugins are you using? ie. db-mongodb, db-postgres, bundler-webpack, etc.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Before submitting the issue, go through the steps you've written down to make sure the steps provided are detailed and clear.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: Contributors should be able to follow the steps provided in order to reproduce the bug.
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: These steps are used to add integration tests to ensure the same issue does not happen again. Thanks in advance!
|
||||||
25
.github/PULL_REQUEST_TEMPLATE.md
vendored
25
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,23 +1,10 @@
|
|||||||
## Description
|
<!--
|
||||||
|
|
||||||
<!-- Please include a summary of the pull request and any related issues it fixes. Please also include relevant motivation and context. -->
|
For external contributors, please include:
|
||||||
|
|
||||||
- [ ] I have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
|
- A summary of the pull request and any related issues it fixes.
|
||||||
|
- Reasoning for the changes made or any additional context that may be useful.
|
||||||
|
|
||||||
## Type of change
|
Ensure you have read and understand the [CONTRIBUTING.md](https://github.com/payloadcms/payload/blob/main/CONTRIBUTING.md) document in this repository.
|
||||||
|
|
||||||
<!-- Please delete options that are not relevant. -->
|
-->
|
||||||
|
|
||||||
- [ ] Chore (non-breaking change which does not add functionality)
|
|
||||||
- [ ] Bug fix (non-breaking change which fixes an issue)
|
|
||||||
- [ ] New feature (non-breaking change which adds functionality)
|
|
||||||
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
|
|
||||||
- [ ] Change to the [templates](https://github.com/payloadcms/payload/tree/main/templates) directory (does not affect core functionality)
|
|
||||||
- [ ] Change to the [examples](https://github.com/payloadcms/payload/tree/main/examples) directory (does not affect core functionality)
|
|
||||||
- [ ] This change requires a documentation update
|
|
||||||
|
|
||||||
## Checklist:
|
|
||||||
|
|
||||||
- [ ] I have added tests that prove my fix is effective or that my feature works
|
|
||||||
- [ ] Existing test suite passes locally with my changes
|
|
||||||
- [ ] I have made corresponding changes to the documentation
|
|
||||||
|
|||||||
13
.github/actions/release-commenter/.eslintrc.js
vendored
Normal file
13
.github/actions/release-commenter/.eslintrc.js
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
es6: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: ['eslint:recommended', 'plugin:@typescript-eslint/eslint-recommended'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 2018,
|
||||||
|
sourceType: 'module',
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
}
|
||||||
8
.github/actions/release-commenter/.prettierrc.js
vendored
Normal file
8
.github/actions/release-commenter/.prettierrc.js
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
printWidth: 100,
|
||||||
|
parser: 'typescript',
|
||||||
|
semi: false,
|
||||||
|
singleQuote: true,
|
||||||
|
trailingComma: 'all',
|
||||||
|
arrowParens: 'avoid',
|
||||||
|
}
|
||||||
74
.github/actions/release-commenter/README.md
vendored
Normal file
74
.github/actions/release-commenter/README.md
vendored
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Release Commenter
|
||||||
|
|
||||||
|
This GitHub Action automatically comments on and/or labels Issues and PRs when a fix is released for them.
|
||||||
|
|
||||||
|
> [!IMPORTANT]
|
||||||
|
> 🔧 Heavily modified version of https://github.com/apexskier/github-release-commenter
|
||||||
|
|
||||||
|
## Fork Modifications
|
||||||
|
|
||||||
|
- Filters to closed PRs only
|
||||||
|
- Adds tag filter to support non-linear releases
|
||||||
|
- Better logging
|
||||||
|
- Moved to pnpm
|
||||||
|
- Uses @vercel/ncc for packaging
|
||||||
|
- Comments on locked issues by unlocking then re-locking
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
Use this action in a workflow [triggered by a release](https://docs.github.com/en/free-pro-team@latest/actions/reference/events-that-trigger-workflows#release). It will scan commits between that and the prior release, find associated Issues and PRs, and comment on them to let people know a release has been made. Associated Issues and PRs can be directly [linked](https://docs.github.com/en/free-pro-team@latest/github/managing-your-work-on-github/linking-a-pull-request-to-an-issue) to the commit or manually linked from a PR associated with the commit.
|
||||||
|
|
||||||
|
## Inputs
|
||||||
|
|
||||||
|
**GITHUB_TOKEN**
|
||||||
|
|
||||||
|
A GitHub personal access token with repo scope, such as [`secrets.GITHUB_TOKEN`](https://docs.github.com/en/free-pro-team@latest/actions/reference/authentication-in-a-workflow#about-the-github_token-secret).
|
||||||
|
|
||||||
|
**comment-template** (optional)
|
||||||
|
|
||||||
|
Override the comment posted on Issues and PRs. Set to the empty string to disable commenting. Several variables strings will be automatically replaced:
|
||||||
|
|
||||||
|
- `{release_link}` - a markdown link to the release
|
||||||
|
- `{release_name}` - the release's name
|
||||||
|
- `{release_tag}` - the release's tag
|
||||||
|
|
||||||
|
**label-template** (optional)
|
||||||
|
|
||||||
|
Add the given label. Multiple labels can be separated by commas. Several variable strings will be automatically replaced:
|
||||||
|
|
||||||
|
- `{release_name}` - the release's name
|
||||||
|
- `{release_tag}` - the release's tag
|
||||||
|
|
||||||
|
**skip-label** (optional)
|
||||||
|
|
||||||
|
Skip processing if any of the given labels are present. Same processing rules as **label-template**. Default is "dependencies".
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```yml
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
steps:
|
||||||
|
- uses: apexskier/github-release-commenter@v1
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
comment-template: |
|
||||||
|
Release {release_link} addresses this.
|
||||||
|
```
|
||||||
|
|
||||||
|
## Known limitations
|
||||||
|
|
||||||
|
These are some known limitations of this action. I'd like to try to address them in the future.
|
||||||
|
|
||||||
|
- Non-linear releases aren't supported. For example, releasing a patch to a prior major release after a new major release has been bumped.
|
||||||
|
- Non-sequential releases aren't supported. For example, if you release multiple prereleases between two official releases, this will only create a comment for the first prerelease in which a fix is released, not the final release.
|
||||||
|
- The first release for a project will be ignored. This is intentional, as the use case is unlikely. Most projects will either have several alphas that don't need release comments, or won't use issues/PRs for the first commit.
|
||||||
|
- If a large number of things are commented on, you may see the error `Error: You have triggered an abuse detection mechanism. Please wait a few minutes before you try again.`. Consider using the `skip-label` input to reduce your load on the GitHub API.
|
||||||
|
|
||||||
|
## Versions
|
||||||
|
|
||||||
|
Workflows will automatically update the tags `v1` and `latest`, allowing you to reference one of those instead of locking to a specific release.
|
||||||
32
.github/actions/release-commenter/action.yml
vendored
Normal file
32
.github/actions/release-commenter/action.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: Release Commenter
|
||||||
|
description: Comment on PRs and Issues when a fix is released
|
||||||
|
branding:
|
||||||
|
icon: message-square
|
||||||
|
color: blue
|
||||||
|
inputs:
|
||||||
|
GITHUB_TOKEN:
|
||||||
|
description: |
|
||||||
|
A GitHub personal access token with repo scope, such as
|
||||||
|
secrets.GITHUB_TOKEN.
|
||||||
|
required: true
|
||||||
|
comment-template:
|
||||||
|
description: |
|
||||||
|
Text template for the comment string.
|
||||||
|
required: false
|
||||||
|
default: |
|
||||||
|
Included in release {release_link}
|
||||||
|
label-template:
|
||||||
|
description: Add the given label. Multiple labels can be separated by commas.
|
||||||
|
required: false
|
||||||
|
skip-label:
|
||||||
|
description: Skip commenting if any of the given label are present. Multiple labels can be separated by commas.
|
||||||
|
required: false
|
||||||
|
default: "dependencies"
|
||||||
|
tag-filter:
|
||||||
|
description: |
|
||||||
|
Filter tags by a regular expression. Must be escaped. e.g. 'v\\d' to isolate tags between major versions.
|
||||||
|
required: false
|
||||||
|
default: null
|
||||||
|
runs:
|
||||||
|
using: node20
|
||||||
|
main: dist/index.js
|
||||||
34199
.github/actions/release-commenter/dist/index.js
vendored
Normal file
34199
.github/actions/release-commenter/dist/index.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
.github/actions/release-commenter/jest.config.js
vendored
Normal file
7
.github/actions/release-commenter/jest.config.js
vendored
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
module.exports = {
|
||||||
|
testEnvironment: 'node',
|
||||||
|
testPathIgnorePatterns: ['/node_modules/', '<rootDir>/dist/'],
|
||||||
|
transform: {
|
||||||
|
'^.+\\.(t|j)sx?$': ['@swc/jest'],
|
||||||
|
},
|
||||||
|
}
|
||||||
34
.github/actions/release-commenter/package.json
vendored
Normal file
34
.github/actions/release-commenter/package.json
vendored
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"name": "release-commenter",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"description": "GitHub Action to automatically comment on PRs and Issues when a fix is released.",
|
||||||
|
"main": "dist/index.js",
|
||||||
|
"license": "MIT",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"clean": "rimraf dist",
|
||||||
|
"build": "pnpm build:typecheck && pnpm build:ncc",
|
||||||
|
"build:ncc": "ncc build src/index.ts -t -o dist",
|
||||||
|
"build:typecheck": "tsc",
|
||||||
|
"test": "jest"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@actions/core": "^1.3.0",
|
||||||
|
"@actions/github": "^5.0.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@octokit/webhooks-types": "^7.5.1",
|
||||||
|
"@swc/jest": "^0.2.36",
|
||||||
|
"@types/jest": "^27.5.2",
|
||||||
|
"@types/node": "^20.16.5",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^4.33.0",
|
||||||
|
"@typescript-eslint/parser": "^4.33.0",
|
||||||
|
"@vercel/ncc": "0.38.1",
|
||||||
|
"concurrently": "^8.2.2",
|
||||||
|
"eslint": "^7.32.0",
|
||||||
|
"jest": "^29.7.0",
|
||||||
|
"prettier": "^3.3.3",
|
||||||
|
"ts-jest": "^26.5.6",
|
||||||
|
"typescript": "^4.9.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
5419
.github/actions/release-commenter/pnpm-lock.yaml
generated
vendored
Normal file
5419
.github/actions/release-commenter/pnpm-lock.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
266
.github/actions/release-commenter/src/__snapshots__/index.test.ts.snap
vendored
Normal file
266
.github/actions/release-commenter/src/__snapshots__/index.test.ts.snap
vendored
Normal file
@@ -0,0 +1,266 @@
|
|||||||
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
|
exports[`tests feature tests can apply labels 1`] = `
|
||||||
|
[
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"issue_number": 123,
|
||||||
|
"labels": [
|
||||||
|
":dart: landed",
|
||||||
|
"release-current_tag_name",
|
||||||
|
"Release Name",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"issue_number": 7,
|
||||||
|
"labels": [
|
||||||
|
":dart: landed",
|
||||||
|
"release-current_tag_name",
|
||||||
|
"Release Name",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`tests main test 1`] = `
|
||||||
|
{
|
||||||
|
"graphql": [MockFunction] {
|
||||||
|
"calls": [
|
||||||
|
[
|
||||||
|
"
|
||||||
|
{
|
||||||
|
resource(url: "http://repository/commit/SHA1") {
|
||||||
|
... on Commit {
|
||||||
|
messageHeadlineHTML
|
||||||
|
messageBodyHTML
|
||||||
|
associatedPullRequests(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
bodyHTML
|
||||||
|
number
|
||||||
|
state
|
||||||
|
labels(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
... on ConnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DisconnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"
|
||||||
|
{
|
||||||
|
resource(url: "http://repository/commit/SHA2") {
|
||||||
|
... on Commit {
|
||||||
|
messageHeadlineHTML
|
||||||
|
messageBodyHTML
|
||||||
|
associatedPullRequests(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
bodyHTML
|
||||||
|
number
|
||||||
|
state
|
||||||
|
labels(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
... on ConnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DisconnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
",
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"rest": {
|
||||||
|
"issues": {
|
||||||
|
"addLabels": [MockFunction],
|
||||||
|
"createComment": [MockFunction] {
|
||||||
|
"calls": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
|
||||||
|
"issue_number": 3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
|
||||||
|
"issue_number": 123,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"body": "Included in release [current_tag_name](http://current_release). Replacements: current_tag_name, current_tag_name.",
|
||||||
|
"issue_number": 7,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"get": [MockFunction] {
|
||||||
|
"calls": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"issue_number": 3,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"issue_number": 123,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"issue_number": 7,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"repos": {
|
||||||
|
"compareCommits": [MockFunction] {
|
||||||
|
"calls": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"base": "prior_tag_name",
|
||||||
|
"head": "current_tag_name",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"listReleases": [MockFunction] {
|
||||||
|
"calls": [
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"per_page": 100,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
"results": [
|
||||||
|
{
|
||||||
|
"type": "return",
|
||||||
|
"value": Promise {},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
`;
|
||||||
399
.github/actions/release-commenter/src/index.test.ts
vendored
Normal file
399
.github/actions/release-commenter/src/index.test.ts
vendored
Normal file
@@ -0,0 +1,399 @@
|
|||||||
|
import type * as githubModule from '@actions/github'
|
||||||
|
import type * as coreModule from '@actions/core'
|
||||||
|
import { mock } from 'node:test'
|
||||||
|
|
||||||
|
jest.mock('@actions/core')
|
||||||
|
jest.mock('@actions/github')
|
||||||
|
|
||||||
|
type Mocked<T> = {
|
||||||
|
-readonly [P in keyof T]: T[P] extends Function ? jest.Mock<T[P]> : jest.Mocked<Partial<T[P]>>
|
||||||
|
}
|
||||||
|
|
||||||
|
const github = require('@actions/github') as jest.Mocked<Mocked<typeof githubModule>>
|
||||||
|
const core = require('@actions/core') as jest.Mocked<Mocked<typeof coreModule>>
|
||||||
|
|
||||||
|
describe('tests', () => {
|
||||||
|
let mockOctokit: any = {}
|
||||||
|
let currentTag: string = 'current_tag_name'
|
||||||
|
|
||||||
|
;(core.warning as any) = jest.fn(console.warn.bind(console))
|
||||||
|
;(core.error as any) = jest.fn(console.error.bind(console))
|
||||||
|
|
||||||
|
let commentTempate: string = ''
|
||||||
|
let labelTemplate: string | null = null
|
||||||
|
const skipLabelTemplate: string | null = 'skip,test'
|
||||||
|
let tagFilter: string | RegExp | null = null
|
||||||
|
|
||||||
|
let simpleMockOctokit: any = {}
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
tagFilter = null
|
||||||
|
currentTag = 'current_tag_name'
|
||||||
|
;(github.context as any) = {
|
||||||
|
payload: {
|
||||||
|
repo: {
|
||||||
|
owner: 'owner',
|
||||||
|
repo: 'repo',
|
||||||
|
},
|
||||||
|
release: {
|
||||||
|
tag_name: currentTag,
|
||||||
|
},
|
||||||
|
repository: { html_url: 'http://repository' },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
github.getOctokit.mockReset().mockImplementationOnce(((token: string) => {
|
||||||
|
expect(token).toBe('GITHUB_TOKEN_VALUE')
|
||||||
|
return mockOctokit
|
||||||
|
}) as any)
|
||||||
|
;(core.getInput as any).mockImplementation((key: string) => {
|
||||||
|
if (key == 'GITHUB_TOKEN') {
|
||||||
|
return 'GITHUB_TOKEN_VALUE'
|
||||||
|
}
|
||||||
|
if (key == 'comment-template') {
|
||||||
|
return commentTempate
|
||||||
|
}
|
||||||
|
if (key == 'label-template') {
|
||||||
|
return labelTemplate
|
||||||
|
}
|
||||||
|
if (key == 'skip-label') {
|
||||||
|
return skipLabelTemplate
|
||||||
|
}
|
||||||
|
if (key == 'tag-filter') {
|
||||||
|
return tagFilter
|
||||||
|
}
|
||||||
|
fail(`Unexpected input key ${key}`)
|
||||||
|
})
|
||||||
|
|
||||||
|
commentTempate =
|
||||||
|
'Included in release {release_link}. Replacements: {release_name}, {release_tag}.'
|
||||||
|
labelTemplate = null
|
||||||
|
simpleMockOctokit = {
|
||||||
|
rest: {
|
||||||
|
issues: {
|
||||||
|
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
|
||||||
|
createComment: jest.fn(() => Promise.resolve()),
|
||||||
|
addLabels: jest.fn(() => Promise.resolve()),
|
||||||
|
},
|
||||||
|
repos: {
|
||||||
|
listReleases: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
name: 'Release Name',
|
||||||
|
tag_name: 'current_tag_name',
|
||||||
|
html_url: 'http://current_release',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag_name: 'prior_tag_name',
|
||||||
|
html_url: 'http://prior_release',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
compareCommits: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { commits: [{ sha: 'SHA1' }] },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
graphql: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
resource: {
|
||||||
|
messageHeadlineHTML: '',
|
||||||
|
messageBodyHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
|
||||||
|
associatedPullRequests: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
expect(core.error).not.toHaveBeenCalled()
|
||||||
|
expect(core.warning).not.toHaveBeenCalled()
|
||||||
|
expect(core.setFailed).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
test('main test', async () => {
|
||||||
|
mockOctokit = {
|
||||||
|
...simpleMockOctokit,
|
||||||
|
rest: {
|
||||||
|
issues: {
|
||||||
|
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
|
||||||
|
createComment: jest.fn(() => Promise.resolve()),
|
||||||
|
addLabels: jest.fn(() => Promise.resolve()),
|
||||||
|
},
|
||||||
|
repos: {
|
||||||
|
listReleases: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: [
|
||||||
|
{
|
||||||
|
tag_name: 'current_tag_name',
|
||||||
|
html_url: 'http://current_release',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
tag_name: 'prior_tag_name',
|
||||||
|
html_url: 'http://prior_release',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
compareCommits: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { commits: [{ sha: 'SHA1' }, { sha: 'SHA2' }] },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
graphql: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
resource: {
|
||||||
|
messageHeadlineHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #3.">Closes</span> <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="718013420" data-permission-text="Title is private" data-url="https://github.com/apexskier/github-release-commenter/issues/1" data-hovercard-type="issue" data-hovercard-url="/apexskier/github-release-commenter/issues/1/hovercard" href="https://github.com/apexskier/github-release-commenter/issues/1">#1</a>',
|
||||||
|
messageBodyHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
|
||||||
|
associatedPullRequests: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
edges: [
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
bodyHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #4.">Closes</span> <span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #5.">Closes</span>',
|
||||||
|
number: 9,
|
||||||
|
labels: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
nodes: [{ name: 'label1' }, { name: 'label2' }],
|
||||||
|
},
|
||||||
|
timelineItems: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
isCrossRepository: true,
|
||||||
|
__typename: 'ConnectedEvent',
|
||||||
|
subject: { number: 1 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isCrossRepository: false,
|
||||||
|
__typename: 'ConnectedEvent',
|
||||||
|
subject: { number: 2 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isCrossRepository: false,
|
||||||
|
__typename: 'DisconnectedEvent',
|
||||||
|
subject: { number: 2 },
|
||||||
|
},
|
||||||
|
{
|
||||||
|
isCrossRepository: false,
|
||||||
|
__typename: 'ConnectedEvent',
|
||||||
|
subject: { number: 2 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
node: {
|
||||||
|
bodyHTML: '',
|
||||||
|
number: 42,
|
||||||
|
labels: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
nodes: [{ name: 'label1' }, { name: 'skip' }],
|
||||||
|
},
|
||||||
|
timelineItems: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
nodes: [
|
||||||
|
{
|
||||||
|
isCrossRepository: true,
|
||||||
|
__typename: 'ConnectedEvent',
|
||||||
|
subject: { number: 82 },
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.isolateModules(() => {
|
||||||
|
require('./index')
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise<void>(setImmediate)
|
||||||
|
|
||||||
|
expect(mockOctokit).toMatchSnapshot()
|
||||||
|
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledTimes(3)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('can filter tags', () => {
|
||||||
|
const v3prev = 'v3.0.1'
|
||||||
|
const v3current = 'v3.0.2'
|
||||||
|
const v2prev = 'v2.0.1'
|
||||||
|
const v2current = 'v2.0.2'
|
||||||
|
|
||||||
|
const listReleasesData = [
|
||||||
|
{
|
||||||
|
name: 'Current Release Name',
|
||||||
|
tag_name: v3current,
|
||||||
|
html_url: 'http://v3.0.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Prev Release Name',
|
||||||
|
tag_name: v3prev,
|
||||||
|
html_url: 'http://v3.0.1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'v2 Current Release Name',
|
||||||
|
tag_name: v2current,
|
||||||
|
html_url: 'http://v2.0.2',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'v2 Prev Release Name',
|
||||||
|
tag_name: v2prev,
|
||||||
|
html_url: 'http://v2.0.1',
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
description | prevTag | currentTag | filter
|
||||||
|
${'no filter'} | ${v3prev} | ${v3current} | ${null}
|
||||||
|
${'v3'} | ${v3prev} | ${v3current} | ${'v\\d'}
|
||||||
|
${'v2'} | ${v2prev} | ${v2current} | ${'v\\d'}
|
||||||
|
`('should filter tags with $description', async ({ prevTag, currentTag, filter }) => {
|
||||||
|
// @ts-ignore
|
||||||
|
github.context.payload.release.tag_name = currentTag
|
||||||
|
|
||||||
|
tagFilter = filter
|
||||||
|
|
||||||
|
mockOctokit = {
|
||||||
|
...simpleMockOctokit,
|
||||||
|
rest: {
|
||||||
|
issues: {
|
||||||
|
get: jest.fn(() => Promise.resolve({ data: { locked: false } })),
|
||||||
|
createComment: jest.fn(() => Promise.resolve()),
|
||||||
|
addLabels: jest.fn(() => Promise.resolve()),
|
||||||
|
},
|
||||||
|
repos: {
|
||||||
|
listReleases: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: listReleasesData,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
compareCommits: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
data: { commits: [{ sha: 'SHA1' }] },
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
graphql: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
resource: {
|
||||||
|
messageHeadlineHTML: '',
|
||||||
|
messageBodyHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
|
||||||
|
associatedPullRequests: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.isolateModules(() => {
|
||||||
|
require('./index')
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise<void>(resolve => setImmediate(() => resolve()))
|
||||||
|
|
||||||
|
expect(github.getOctokit).toHaveBeenCalled()
|
||||||
|
expect(mockOctokit.rest.repos.compareCommits.mock.calls).toEqual([
|
||||||
|
[{ base: prevTag, head: currentTag }],
|
||||||
|
])
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('feature tests', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mockOctokit = simpleMockOctokit
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can disable comments', async () => {
|
||||||
|
commentTempate = ''
|
||||||
|
|
||||||
|
jest.isolateModules(() => {
|
||||||
|
require('./index')
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise<void>(resolve => setImmediate(() => resolve()))
|
||||||
|
|
||||||
|
expect(github.getOctokit).toHaveBeenCalled()
|
||||||
|
expect(mockOctokit.rest.issues.createComment).not.toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should unlock and comment', async () => {
|
||||||
|
mockOctokit = {
|
||||||
|
...simpleMockOctokit,
|
||||||
|
rest: {
|
||||||
|
...simpleMockOctokit.rest,
|
||||||
|
issues: {
|
||||||
|
// Return locked for both issues to be commented on
|
||||||
|
get: jest.fn(() => Promise.resolve({ data: { locked: true } })),
|
||||||
|
lock: jest.fn(() => Promise.resolve()),
|
||||||
|
unlock: jest.fn(() => Promise.resolve()),
|
||||||
|
createComment: jest.fn(() => Promise.resolve()),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
graphql: jest.fn(() =>
|
||||||
|
Promise.resolve({
|
||||||
|
resource: {
|
||||||
|
messageHeadlineHTML: '',
|
||||||
|
messageBodyHTML:
|
||||||
|
'<span class="issue-keyword tooltipped tooltipped-se" aria-label="This commit closes issue #123.">Closes</span> <p><span class="issue-keyword tooltipped tooltipped-se" aria-label="This pull request closes issue #7.">Closes</span>',
|
||||||
|
associatedPullRequests: {
|
||||||
|
pageInfo: { hasNextPage: false },
|
||||||
|
edges: [],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
jest.isolateModules(() => {
|
||||||
|
require('./index')
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise<void>(resolve => setImmediate(() => resolve()))
|
||||||
|
|
||||||
|
expect(github.getOctokit).toHaveBeenCalled()
|
||||||
|
|
||||||
|
// Should call once for both linked issues
|
||||||
|
expect(mockOctokit.rest.issues.unlock).toHaveBeenCalledTimes(2)
|
||||||
|
expect(mockOctokit.rest.issues.createComment).toHaveBeenCalledTimes(2)
|
||||||
|
expect(mockOctokit.rest.issues.lock).toHaveBeenCalledTimes(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it.skip('can apply labels', async () => {
|
||||||
|
labelTemplate = ':dart: landed,release-{release_tag},{release_name}'
|
||||||
|
|
||||||
|
jest.isolateModules(() => {
|
||||||
|
require('./index')
|
||||||
|
})
|
||||||
|
|
||||||
|
await new Promise<void>(resolve => setImmediate(() => resolve()))
|
||||||
|
|
||||||
|
expect(github.getOctokit).toHaveBeenCalled()
|
||||||
|
expect(mockOctokit.rest.issues.addLabels.mock.calls).toMatchSnapshot()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
349
.github/actions/release-commenter/src/index.ts
vendored
Normal file
349
.github/actions/release-commenter/src/index.ts
vendored
Normal file
@@ -0,0 +1,349 @@
|
|||||||
|
import * as core from '@actions/core'
|
||||||
|
import * as github from '@actions/github'
|
||||||
|
import type * as Webhooks from '@octokit/webhooks-types'
|
||||||
|
|
||||||
|
const closesMatcher = /aria-label="This (?:commit|pull request) closes issue #(\d+)\."/g
|
||||||
|
|
||||||
|
const releaseLinkTemplateRegex = /{release_link}/g
|
||||||
|
const releaseNameTemplateRegex = /{release_name}/g
|
||||||
|
const releaseTagTemplateRegex = /{release_tag}/g
|
||||||
|
|
||||||
|
;(async function main() {
|
||||||
|
try {
|
||||||
|
const payload = github.context.payload as Webhooks.EventPayloadMap['release']
|
||||||
|
|
||||||
|
const githubToken = core.getInput('GITHUB_TOKEN')
|
||||||
|
const tagFilter = core.getInput('tag-filter') || undefined // Accept tag filter as an input
|
||||||
|
const octokit = github.getOctokit(githubToken)
|
||||||
|
|
||||||
|
const commentTemplate = core.getInput('comment-template')
|
||||||
|
const labelTemplate = core.getInput('label-template') || null
|
||||||
|
const skipLabelTemplate = core.getInput('skip-label') || null
|
||||||
|
|
||||||
|
// Fetch the releases with the optional tag filter applied
|
||||||
|
const { data: rawReleases } = await octokit.rest.repos.listReleases({
|
||||||
|
...github.context.repo,
|
||||||
|
per_page: 100,
|
||||||
|
})
|
||||||
|
|
||||||
|
// Get the current release tag or latest tag
|
||||||
|
const currentTag = payload?.release?.tag_name || rawReleases?.[0]?.tag_name
|
||||||
|
|
||||||
|
let releases = rawReleases
|
||||||
|
|
||||||
|
// Filter releases by the tag filter if provided
|
||||||
|
if (tagFilter) {
|
||||||
|
core.info(`Filtering releases by tag filter: ${tagFilter}`)
|
||||||
|
// Get the matching part of the current release tag
|
||||||
|
const regexMatch = currentTag.match(tagFilter)?.[0]
|
||||||
|
if (!regexMatch) {
|
||||||
|
core.error(`Current release tag ${currentTag} does not match the tag filter ${tagFilter}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Matched string from filter: ${regexMatch}`)
|
||||||
|
|
||||||
|
releases = releases
|
||||||
|
.filter(release => {
|
||||||
|
const match = release.tag_name.match(regexMatch)?.[0]
|
||||||
|
return match
|
||||||
|
})
|
||||||
|
.slice(0, 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info(`Releases: ${JSON.stringify(releases, null, 2)}`)
|
||||||
|
|
||||||
|
if (releases.length < 2) {
|
||||||
|
if (!releases.length) {
|
||||||
|
core.error(`No releases found with the provided tag filter: '${tagFilter}'`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
core.info('first release')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const [currentRelease, priorRelease] = releases
|
||||||
|
|
||||||
|
core.info(`${priorRelease.tag_name}...${currentRelease.tag_name}`)
|
||||||
|
|
||||||
|
const {
|
||||||
|
data: { commits },
|
||||||
|
} = await octokit.rest.repos.compareCommits({
|
||||||
|
...github.context.repo,
|
||||||
|
base: priorRelease.tag_name,
|
||||||
|
head: currentRelease.tag_name,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!currentRelease.name) {
|
||||||
|
core.info('Current release has no name, will fall back to the tag name.')
|
||||||
|
}
|
||||||
|
const releaseLabel = currentRelease.name || currentRelease.tag_name
|
||||||
|
|
||||||
|
const comment = commentTemplate
|
||||||
|
.trim()
|
||||||
|
.split(releaseLinkTemplateRegex)
|
||||||
|
.join(`[${releaseLabel}](${currentRelease.html_url})`)
|
||||||
|
.split(releaseNameTemplateRegex)
|
||||||
|
.join(releaseLabel)
|
||||||
|
.split(releaseTagTemplateRegex)
|
||||||
|
.join(currentRelease.tag_name)
|
||||||
|
|
||||||
|
const parseLabels = (rawInput: string | null) =>
|
||||||
|
rawInput
|
||||||
|
?.split(releaseNameTemplateRegex)
|
||||||
|
.join(releaseLabel)
|
||||||
|
?.split(releaseTagTemplateRegex)
|
||||||
|
.join(currentRelease.tag_name)
|
||||||
|
?.split(',')
|
||||||
|
?.map(l => l.trim())
|
||||||
|
.filter(l => l)
|
||||||
|
|
||||||
|
const labels = parseLabels(labelTemplate)
|
||||||
|
const skipLabels = parseLabels(skipLabelTemplate)
|
||||||
|
|
||||||
|
const linkedIssuesPrs = new Set<number>()
|
||||||
|
|
||||||
|
await Promise.all(
|
||||||
|
commits.map(commit =>
|
||||||
|
(async () => {
|
||||||
|
const query = `
|
||||||
|
{
|
||||||
|
resource(url: "${payload.repository.html_url}/commit/${commit.sha}") {
|
||||||
|
... on Commit {
|
||||||
|
messageHeadlineHTML
|
||||||
|
messageBodyHTML
|
||||||
|
associatedPullRequests(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
bodyHTML
|
||||||
|
number
|
||||||
|
state
|
||||||
|
labels(first: 10) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
timelineItems(itemTypes: [CONNECTED_EVENT, DISCONNECTED_EVENT], first: 100) {
|
||||||
|
pageInfo {
|
||||||
|
hasNextPage
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
... on ConnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
... on DisconnectedEvent {
|
||||||
|
__typename
|
||||||
|
isCrossRepository
|
||||||
|
subject {
|
||||||
|
... on Issue {
|
||||||
|
number
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const response: {
|
||||||
|
resource: null | {
|
||||||
|
messageHeadlineHTML: string
|
||||||
|
messageBodyHTML: string
|
||||||
|
associatedPullRequests: {
|
||||||
|
pageInfo: { hasNextPage: boolean }
|
||||||
|
edges: ReadonlyArray<{
|
||||||
|
node: {
|
||||||
|
bodyHTML: string
|
||||||
|
number: number
|
||||||
|
state: 'OPEN' | 'CLOSED' | 'MERGED'
|
||||||
|
labels: {
|
||||||
|
pageInfo: { hasNextPage: boolean }
|
||||||
|
nodes: ReadonlyArray<{
|
||||||
|
name: string
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
timelineItems: {
|
||||||
|
pageInfo: { hasNextPage: boolean }
|
||||||
|
nodes: ReadonlyArray<{
|
||||||
|
__typename: 'ConnectedEvent' | 'DisconnectedEvent'
|
||||||
|
isCrossRepository: boolean
|
||||||
|
subject: {
|
||||||
|
number: number
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} = await octokit.graphql(query)
|
||||||
|
|
||||||
|
if (!response.resource) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// core.info(JSON.stringify(response.resource, null, 2))
|
||||||
|
|
||||||
|
core.info(`Checking commit: ${payload.repository.html_url}/commit/${commit.sha}`)
|
||||||
|
|
||||||
|
const associatedClosedPREdges = response.resource.associatedPullRequests.edges.filter(
|
||||||
|
e => e.node.state === 'MERGED',
|
||||||
|
)
|
||||||
|
|
||||||
|
if (associatedClosedPREdges.length) {
|
||||||
|
core.info(
|
||||||
|
` Associated Merged PRs:\n ${associatedClosedPREdges.map(pr => `${payload.repository.html_url}/pull/${pr.node.number}`).join('\n ')}`,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
core.info(' No associated merged PRs')
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = [
|
||||||
|
response.resource.messageHeadlineHTML,
|
||||||
|
response.resource.messageBodyHTML,
|
||||||
|
...associatedClosedPREdges.map(pr => pr.node.bodyHTML),
|
||||||
|
].join(' ')
|
||||||
|
|
||||||
|
for (const match of html.matchAll(closesMatcher)) {
|
||||||
|
const [, num] = match
|
||||||
|
linkedIssuesPrs.add(parseInt(num, 10))
|
||||||
|
core.info(
|
||||||
|
` Linked issue/PR from closesMatcher: ${payload.repository.html_url}/pull/${num}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response.resource.associatedPullRequests.pageInfo.hasNextPage) {
|
||||||
|
core.warning(`Too many PRs associated with ${commit.sha}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
const seen = new Set<number>()
|
||||||
|
for (const associatedPR of associatedClosedPREdges) {
|
||||||
|
if (associatedPR.node.timelineItems.pageInfo.hasNextPage) {
|
||||||
|
core.warning(`Too many links for #${associatedPR.node.number}`)
|
||||||
|
}
|
||||||
|
if (associatedPR.node.labels.pageInfo.hasNextPage) {
|
||||||
|
core.warning(`Too many labels for #${associatedPR.node.number}`)
|
||||||
|
}
|
||||||
|
// a skip labels is present on this PR
|
||||||
|
if (
|
||||||
|
skipLabels?.some(l => associatedPR.node.labels.nodes.some(({ name }) => name === l))
|
||||||
|
) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
linkedIssuesPrs.add(associatedPR.node.number)
|
||||||
|
core.info(
|
||||||
|
` Linked issue/PR from associated PR: ${payload.repository.html_url}/pull/${associatedPR.node.number}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
// These are sorted by creation date in ascending order. The latest event for a given issue/PR is all we need
|
||||||
|
// ignore links that aren't part of this repo
|
||||||
|
const links = associatedPR.node.timelineItems.nodes
|
||||||
|
.filter(node => !node.isCrossRepository)
|
||||||
|
.reverse()
|
||||||
|
for (const link of links) {
|
||||||
|
if (seen.has(link.subject.number)) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if (link.__typename == 'ConnectedEvent') {
|
||||||
|
linkedIssuesPrs.add(link.subject.number)
|
||||||
|
core.info(
|
||||||
|
`Linked issue/PR from connected event: ${payload.repository.html_url}/pull/${link.subject.number}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
seen.add(link.subject.number)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
core.info(
|
||||||
|
`Final issues/PRs to be commented on: \n${Array.from(linkedIssuesPrs)
|
||||||
|
.map(num => ` ${payload.repository.html_url}/pull/${num}`)
|
||||||
|
.join('\n')}`,
|
||||||
|
)
|
||||||
|
|
||||||
|
const requests: Array<Promise<unknown>> = []
|
||||||
|
for (const issueNumber of linkedIssuesPrs) {
|
||||||
|
const baseRequest = {
|
||||||
|
...github.context.repo,
|
||||||
|
issue_number: issueNumber,
|
||||||
|
}
|
||||||
|
if (comment) {
|
||||||
|
const commentRequest = {
|
||||||
|
...baseRequest,
|
||||||
|
body: comment,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if issue is locked or not
|
||||||
|
const { data: issue } = await octokit.rest.issues.get(baseRequest)
|
||||||
|
|
||||||
|
let createCommentPromise: () => Promise<void>
|
||||||
|
if (!issue.locked) {
|
||||||
|
createCommentPromise = async () => {
|
||||||
|
try {
|
||||||
|
await octokit.rest.issues.createComment(commentRequest)
|
||||||
|
} catch (error) {
|
||||||
|
core.error(error as Error)
|
||||||
|
core.error(
|
||||||
|
`Failed to comment on issue/PR: ${issueNumber}. ${payload.repository.html_url}/pull/${issueNumber}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
core.info(
|
||||||
|
`Issue/PR is locked: ${issueNumber}. Unlocking, commenting, and re-locking. ${payload.repository.html_url}/pull/${issueNumber}`,
|
||||||
|
)
|
||||||
|
createCommentPromise = async () => {
|
||||||
|
try {
|
||||||
|
core.debug(`Unlocking issue/PR: ${issueNumber}`)
|
||||||
|
await octokit.rest.issues.unlock(baseRequest)
|
||||||
|
core.debug(`Commenting on issue/PR: ${issueNumber}`)
|
||||||
|
await octokit.rest.issues.createComment(commentRequest)
|
||||||
|
core.debug(`Re-locking issue/PR: ${issueNumber}`)
|
||||||
|
await octokit.rest.issues.lock(baseRequest)
|
||||||
|
} catch (error) {
|
||||||
|
core.error(error as Error)
|
||||||
|
core.error(
|
||||||
|
`Failed to unlock, comment, and re-lock issue/PR: ${issueNumber}. ${payload.repository.html_url}/pull/${issueNumber}`,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
requests.push(createCommentPromise())
|
||||||
|
}
|
||||||
|
if (labels) {
|
||||||
|
const request = {
|
||||||
|
...baseRequest,
|
||||||
|
labels,
|
||||||
|
}
|
||||||
|
// core.info(JSON.stringify(request, null, 2))
|
||||||
|
requests.push(octokit.rest.issues.addLabels(request))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
await Promise.all(requests)
|
||||||
|
} catch (error) {
|
||||||
|
core.error(error as Error)
|
||||||
|
core.setFailed((error as Error).message)
|
||||||
|
}
|
||||||
|
})()
|
||||||
15
.github/actions/release-commenter/tsconfig.json
vendored
Normal file
15
.github/actions/release-commenter/tsconfig.json
vendored
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "es5",
|
||||||
|
"lib": ["es2020.string"],
|
||||||
|
"noEmit": true,
|
||||||
|
"strict": true,
|
||||||
|
"noUnusedLocals": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"downlevelIteration": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
},
|
||||||
|
"exclude": ["src/**/*.test.ts"]
|
||||||
|
}
|
||||||
47
.github/dependabot.yml
vendored
Normal file
47
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# docs: https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directories:
|
||||||
|
- /
|
||||||
|
- /.github/workflows
|
||||||
|
- /.github/actions/* # Not working until resolved: https://github.com/dependabot/dependabot-core/issues/6345
|
||||||
|
- /.github/actions/setup
|
||||||
|
target-branch: beta
|
||||||
|
schedule:
|
||||||
|
interval: monthly
|
||||||
|
timezone: America/Detroit
|
||||||
|
time: '06:00'
|
||||||
|
groups:
|
||||||
|
github_actions:
|
||||||
|
patterns:
|
||||||
|
- '*'
|
||||||
|
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: /
|
||||||
|
target-branch: beta
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
day: sunday
|
||||||
|
timezone: America/Detroit
|
||||||
|
time: '06:00'
|
||||||
|
commit-message:
|
||||||
|
prefix: 'chore(deps)'
|
||||||
|
labels:
|
||||||
|
- dependencies
|
||||||
|
groups:
|
||||||
|
production:
|
||||||
|
dependency-type: production
|
||||||
|
update-types:
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
patterns:
|
||||||
|
- '*'
|
||||||
|
dev:
|
||||||
|
dependency-type: development
|
||||||
|
update-types:
|
||||||
|
- minor
|
||||||
|
- patch
|
||||||
|
patterns:
|
||||||
|
- '*'
|
||||||
3977
.github/pnpm-lock.yaml
generated
vendored
Normal file
3977
.github/pnpm-lock.yaml
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
2
.github/pnpm-workspace.yaml
vendored
Normal file
2
.github/pnpm-workspace.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
packages:
|
||||||
|
- 'actions/*'
|
||||||
80
.github/workflows/label-author.yml
vendored
Normal file
80
.github/workflows/label-author.yml
vendored
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
name: label-author
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened]
|
||||||
|
issues:
|
||||||
|
types: [opened]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
debug-context:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: View context attributes
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: console.log(context)
|
||||||
|
|
||||||
|
label-created-by:
|
||||||
|
name: Label pr/issue on opening
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Tag with 'created-by'
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
if: github.event.action == 'opened'
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const payloadTeamUsernames = [
|
||||||
|
'denolfe',
|
||||||
|
'jmikrut',
|
||||||
|
'DanRibbens',
|
||||||
|
'jacobsfletch',
|
||||||
|
'JarrodMFlesch',
|
||||||
|
'AlessioGr',
|
||||||
|
'JessChowdhury',
|
||||||
|
'kendelljoseph',
|
||||||
|
'PatrikKozak',
|
||||||
|
'tylandavis',
|
||||||
|
'paulpopus',
|
||||||
|
];
|
||||||
|
|
||||||
|
const type = context.payload.pull_request ? 'pull_request' : 'issue';
|
||||||
|
|
||||||
|
const isTeamMember = payloadTeamUsernames
|
||||||
|
.map(n => n.toLowerCase())
|
||||||
|
.includes(context.payload[type].user.login.toLowerCase());
|
||||||
|
|
||||||
|
if (isTeamMember) {
|
||||||
|
github.rest.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: ['created-by: Payload team'],
|
||||||
|
});
|
||||||
|
console.log(`Added 'created-by: Payload team' label`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const association = context.payload[type].author_association;
|
||||||
|
let label = ''
|
||||||
|
if (association === 'MEMBER' || association === 'OWNER') {
|
||||||
|
label = 'created-by: Payload team';
|
||||||
|
} else if (association === 'CONTRIBUTOR') {
|
||||||
|
label = 'created-by: Contributor';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!label) return;
|
||||||
|
|
||||||
|
github.rest.issues.addLabels({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
labels: [label],
|
||||||
|
});
|
||||||
|
console.log(`Added '${label}' label.`);
|
||||||
116
.github/workflows/label-on-change.yml
vendored
Normal file
116
.github/workflows/label-on-change.yml
vendored
Normal file
@@ -0,0 +1,116 @@
|
|||||||
|
name: label-on-change
|
||||||
|
|
||||||
|
on:
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target
|
||||||
|
issues:
|
||||||
|
types:
|
||||||
|
- assigned
|
||||||
|
- closed
|
||||||
|
- labeled
|
||||||
|
- reopened
|
||||||
|
|
||||||
|
# TODO: Handle labeling on comment
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
on-labeled-ensure-one-status:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
# Only run on issue labeled and if label starts with 'status:'
|
||||||
|
if: github.event.action == 'labeled' && startsWith(github.event.label.name, 'status:')
|
||||||
|
steps:
|
||||||
|
- name: Ensure only one status label
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
// Get all labels that start with 'status:' and are not the incoming label
|
||||||
|
const incomingLabelName = context.payload.label.name;
|
||||||
|
const labelNamesToRemove = context.payload.issue.labels
|
||||||
|
.filter(label => label.name.startsWith('status:') && label.name !== incomingLabelName)
|
||||||
|
.map(label => label.name);
|
||||||
|
|
||||||
|
if (!labelNamesToRemove.length) {
|
||||||
|
console.log('No labels to remove');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Labels to remove: '${labelNamesToRemove}'`);
|
||||||
|
|
||||||
|
// If there is more than one status label, remove all but the incoming label
|
||||||
|
for (const labelName of labelNamesToRemove) {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
name: labelName,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
});
|
||||||
|
console.log(`Removed '${labelName}' label`);
|
||||||
|
}
|
||||||
|
|
||||||
|
on-issue-close:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
if: github.event.action == 'closed'
|
||||||
|
steps:
|
||||||
|
- name: Remove all labels on issue close
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
// Get all labels that start with 'status:' and 'stale'
|
||||||
|
const labelNamesToRemove = context.payload.issue.labels
|
||||||
|
.filter(label => label.name.startsWith('status:') || label.name === 'stale')
|
||||||
|
.map(label => label.name);
|
||||||
|
|
||||||
|
if (!labelNamesToRemove.length) {
|
||||||
|
console.log('No labels to remove');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Labels to remove: '${labelNamesToRemove}'`);
|
||||||
|
|
||||||
|
for (const labelName of labelNamesToRemove) {
|
||||||
|
await github.rest.issues.removeLabel({
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
name: labelName,
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
});
|
||||||
|
console.log(`Removed '${labelName}' label`);
|
||||||
|
}
|
||||||
|
|
||||||
|
on-issue-reopen:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
if: github.event.action == 'reopened'
|
||||||
|
steps:
|
||||||
|
- name: Add needs-triage label on issue reopen
|
||||||
|
uses: actions-ecosystem/action-add-labels@v1
|
||||||
|
with:
|
||||||
|
labels: 'status: needs-triage'
|
||||||
|
|
||||||
|
on-issue-assigned:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
if: >
|
||||||
|
github.event.action == 'assigned' &&
|
||||||
|
contains(github.event.issue.labels.*.name, 'status: needs-triage')
|
||||||
|
steps:
|
||||||
|
- name: Remove needs-triage label on issue assign
|
||||||
|
uses: actions-ecosystem/action-remove-labels@v1
|
||||||
|
with:
|
||||||
|
labels: 'status: needs-triage'
|
||||||
|
|
||||||
|
# on-pr-merge:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# if: github.event.pull_request.merged == true
|
||||||
|
# steps:
|
||||||
|
|
||||||
|
# on-pr-close:
|
||||||
|
# runs-on: ubuntu-latest
|
||||||
|
# if: github.event_name == 'pull_request_target' && github.event.pull_request.merged == false
|
||||||
|
# steps:
|
||||||
25
.github/workflows/lock-issues.yml
vendored
Normal file
25
.github/workflows/lock-issues.yml
vendored
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
name: lock-issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
# Run nightly at 12am EST
|
||||||
|
- cron: '0 4 * * *'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lock_issues:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Lock issues
|
||||||
|
uses: dessant/lock-threads@v5
|
||||||
|
with:
|
||||||
|
process-only: 'issues'
|
||||||
|
issue-inactive-days: '1'
|
||||||
|
log-output: true
|
||||||
|
issue-comment: >
|
||||||
|
This issue has been automatically locked.
|
||||||
|
|
||||||
|
Please open a new issue if this issue persists with any additional detail.
|
||||||
200
.github/workflows/main.yml
vendored
200
.github/workflows/main.yml
vendored
@@ -2,9 +2,9 @@ name: build
|
|||||||
|
|
||||||
on:
|
on:
|
||||||
pull_request:
|
pull_request:
|
||||||
types: [opened, reopened, synchronize]
|
types: [ opened, reopened, synchronize ]
|
||||||
push:
|
push:
|
||||||
branches: ['main', 'alpha']
|
branches: [ 'main' ]
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
changes:
|
changes:
|
||||||
@@ -15,15 +15,19 @@ jobs:
|
|||||||
needs_build: ${{ steps.filter.outputs.needs_build }}
|
needs_build: ${{ steps.filter.outputs.needs_build }}
|
||||||
templates: ${{ steps.filter.outputs.templates }}
|
templates: ${{ steps.filter.outputs.templates }}
|
||||||
steps:
|
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
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 25
|
fetch-depth: 25
|
||||||
- uses: dorny/paths-filter@v3
|
- uses: dorny/paths-filter@v2
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
filters: |
|
filters: |
|
||||||
needs_build:
|
needs_build:
|
||||||
- '.github/workflows/**'
|
- '.github/workflows/main.yml'
|
||||||
- 'packages/**'
|
- 'packages/**'
|
||||||
- 'test/**'
|
- 'test/**'
|
||||||
- 'pnpm-lock.yaml'
|
- 'pnpm-lock.yaml'
|
||||||
@@ -45,15 +49,19 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
fetch-depth: 25
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 9.7.0
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Get pnpm store directory
|
- name: Get pnpm store directory
|
||||||
@@ -71,7 +79,7 @@ jobs:
|
|||||||
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||||
|
|
||||||
- run: pnpm install
|
- run: pnpm install
|
||||||
- run: pnpm run build:core
|
- run: pnpm run build
|
||||||
|
|
||||||
- name: Cache build
|
- name: Cache build
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
@@ -79,56 +87,13 @@ jobs:
|
|||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
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:
|
tests:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: core-build
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
database:
|
database: [mongoose, postgres, postgres-custom-schema, postgres-uuid, supabase]
|
||||||
- mongodb
|
|
||||||
- postgres
|
|
||||||
- postgres-custom-schema
|
|
||||||
- postgres-uuid
|
|
||||||
- supabase
|
|
||||||
env:
|
env:
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: postgres
|
POSTGRES_PASSWORD: postgres
|
||||||
@@ -139,15 +104,19 @@ jobs:
|
|||||||
AWS_REGION: us-east-1
|
AWS_REGION: us-east-1
|
||||||
|
|
||||||
steps:
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 9.7.0
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
@@ -162,7 +131,7 @@ jobs:
|
|||||||
- name: Start PostgreSQL
|
- name: Start PostgreSQL
|
||||||
uses: CasperWA/postgresql-action@v1.2
|
uses: CasperWA/postgresql-action@v1.2
|
||||||
with:
|
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 db: ${{ env.POSTGRES_DB }}
|
||||||
postgresql user: ${{ env.POSTGRES_USER }}
|
postgresql user: ${{ env.POSTGRES_USER }}
|
||||||
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
postgresql password: ${{ env.POSTGRES_PASSWORD }}
|
||||||
@@ -201,8 +170,11 @@ jobs:
|
|||||||
echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV
|
echo "POSTGRES_URL=postgresql://postgres:postgres@127.0.0.1:54322/postgres" >> $GITHUB_ENV
|
||||||
if: matrix.database == 'supabase'
|
if: matrix.database == 'supabase'
|
||||||
|
|
||||||
|
- name: Component Tests
|
||||||
|
run: pnpm test:components
|
||||||
|
|
||||||
- name: Integration Tests
|
- name: Integration Tests
|
||||||
run: pnpm test:int --testPathIgnorePatterns=test/fields # Ignore fields tests until reworked
|
run: pnpm test:int
|
||||||
env:
|
env:
|
||||||
NODE_OPTIONS: --max-old-space-size=8096
|
NODE_OPTIONS: --max-old-space-size=8096
|
||||||
PAYLOAD_DATABASE: ${{ matrix.database }}
|
PAYLOAD_DATABASE: ${{ matrix.database }}
|
||||||
@@ -214,34 +186,22 @@ jobs:
|
|||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
# find test -type f -name 'e2e.spec.ts' | sort | xargs dirname | xargs -I {} basename {}
|
part: [ 1/8, 2/8, 3/8, 4/8, 5/8, 6/8, 7/8, 8/8 ]
|
||||||
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
|
|
||||||
|
|
||||||
steps:
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 9.7.0
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
@@ -250,39 +210,39 @@ jobs:
|
|||||||
path: ./*
|
path: ./*
|
||||||
key: ${{ github.sha }}-${{ github.run_number }}
|
key: ${{ github.sha }}-${{ github.run_number }}
|
||||||
|
|
||||||
- name: Install Playwright
|
|
||||||
run: pnpm exec playwright install
|
|
||||||
|
|
||||||
- name: E2E Tests
|
- name: E2E Tests
|
||||||
uses: nick-fields/retry@v3
|
uses: nick-fields/retry@v2
|
||||||
with:
|
with:
|
||||||
retry_on: error
|
retry_on: error
|
||||||
max_attempts: 2
|
max_attempts: 2
|
||||||
timeout_minutes: 15
|
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()
|
if: always()
|
||||||
with:
|
with:
|
||||||
name: test-results
|
name: test-results
|
||||||
path: test/test-results/
|
path: test-results/
|
||||||
retention-days: 1
|
retention-days: 1
|
||||||
|
|
||||||
tests-type-generation:
|
tests-type-generation:
|
||||||
if: false # This should be replaced with gen on a real Payload project
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: core-build
|
||||||
|
|
||||||
steps:
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 9.7.0
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
@@ -297,6 +257,47 @@ jobs:
|
|||||||
- name: Generate GraphQL schema file
|
- name: Generate GraphQL schema file
|
||||||
run: pnpm dev:generate-graphql-schema graphql-schema-gen
|
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: 9.7.0
|
||||||
|
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:
|
plugins:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
needs: core-build
|
needs: core-build
|
||||||
@@ -314,15 +315,19 @@ jobs:
|
|||||||
- plugin-seo
|
- plugin-seo
|
||||||
|
|
||||||
steps:
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Install pnpm
|
- name: Install pnpm
|
||||||
uses: pnpm/action-setup@v3
|
uses: pnpm/action-setup@v3
|
||||||
with:
|
with:
|
||||||
version: 8
|
version: 9.7.0
|
||||||
run_install: false
|
run_install: false
|
||||||
|
|
||||||
- name: Restore build
|
- name: Restore build
|
||||||
@@ -336,25 +341,30 @@ jobs:
|
|||||||
|
|
||||||
- name: Test ${{ matrix.pkg }}
|
- name: Test ${{ matrix.pkg }}
|
||||||
run: pnpm --filter ${{ matrix.pkg }} run test
|
run: pnpm --filter ${{ matrix.pkg }} run test
|
||||||
|
if: matrix.pkg != 'create-payload-app' # degit doesn't work within GitHub Actions
|
||||||
|
|
||||||
templates:
|
templates:
|
||||||
needs: changes
|
needs: changes
|
||||||
if: false # Disable until templates are updated for 3.0
|
if: ${{ needs.changes.outputs.templates == 'true' }}
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
template: [blank, website, ecommerce]
|
template: [ blank, website, ecommerce ]
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 25
|
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
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 18
|
node-version: 20
|
||||||
|
|
||||||
- name: Start MongoDB
|
- name: Start MongoDB
|
||||||
uses: supercharge/mongodb-github-action@1.10.0
|
uses: supercharge/mongodb-github-action@1.10.0
|
||||||
|
|||||||
32
.github/workflows/post-release.yml
vendored
Normal file
32
.github/workflows/post-release.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: post-release
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types:
|
||||||
|
- published
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
post_release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
# Only needed if debugging on a branch other than default
|
||||||
|
# ref: ${{ github.event.release.target_commitish || github.ref }}
|
||||||
|
- run: echo "npm_version=$(npm pkg get version | tr -d '"')" >> "$GITHUB_ENV"
|
||||||
|
- uses: ./.github/actions/release-commenter
|
||||||
|
continue-on-error: true
|
||||||
|
env:
|
||||||
|
ACTIONS_STEP_DEBUG: true
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag-filter: 'v\d'
|
||||||
|
|
||||||
|
|
||||||
|
# Change to blank to disable commenting
|
||||||
|
# comment-template: ''
|
||||||
|
|
||||||
|
comment-template: |
|
||||||
|
🚀 This is included in version {release_link}
|
||||||
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"
|
||||||
42
.github/workflows/stale.yml
vendored
Normal file
42
.github/workflows/stale.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
name: stale
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v9
|
||||||
|
id: stale
|
||||||
|
with:
|
||||||
|
debug-only: true
|
||||||
|
days-before-stale: 90
|
||||||
|
days-before-close: 7
|
||||||
|
ascending: true
|
||||||
|
operations-per-run: 300
|
||||||
|
|
||||||
|
# Ignore all assigned
|
||||||
|
exempt-all-assignees: false
|
||||||
|
|
||||||
|
# Issues
|
||||||
|
stale-issue-label: 'stale'
|
||||||
|
exempt-issue-labels: 'blocked,must,should,keep,created-by: Payload team,created-by: Contributor'
|
||||||
|
stale-issue-message: >
|
||||||
|
This issue has been marked as stale due to lack of activity. To keep the ticket open, please indicate that it is still relevant in a comment below.
|
||||||
|
close-issue-message: >
|
||||||
|
This issue was automatically closed due to lack of activity.
|
||||||
|
|
||||||
|
# Pull Requests
|
||||||
|
stale-pr-label: 'stale'
|
||||||
|
exempt-pr-labels: 'blocked,must,should,keep,created-by: Payload team,created-by: Contributor'
|
||||||
|
stale-pr-message: >
|
||||||
|
This PR is stale due to lack of activity. To keep the PR open, please indicate that it is still relevant in a comment below.
|
||||||
|
close-pr-message: >
|
||||||
|
This pull request was automatically closed due to lack of activity.
|
||||||
|
|
||||||
|
- name: Print outputs
|
||||||
|
run: echo ${{ format('{0},{1}', toJSON(steps.stale.outputs.staled-issues-prs), toJSON(steps.stale.outputs.closed-issues-prs)) }}
|
||||||
12
.gitignore
vendored
12
.gitignore
vendored
@@ -4,18 +4,14 @@ dist
|
|||||||
/.idea/*
|
/.idea/*
|
||||||
!/.idea/runConfigurations
|
!/.idea/runConfigurations
|
||||||
|
|
||||||
|
# Custom actions
|
||||||
|
!.github/actions/**/dist
|
||||||
|
|
||||||
test-results
|
test-results
|
||||||
.devcontainer
|
.devcontainer
|
||||||
.localstack
|
.localstack
|
||||||
/migrations
|
/migrations
|
||||||
.localstack
|
.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
|
# 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
|
# Edit at https://www.toptal.com/developers/gitignore?templates=node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
@@ -141,7 +137,6 @@ out
|
|||||||
|
|
||||||
# Nuxt.js build / generate output
|
# Nuxt.js build / generate output
|
||||||
.nuxt
|
.nuxt
|
||||||
dist
|
|
||||||
|
|
||||||
# Gatsby files
|
# Gatsby files
|
||||||
.cache/
|
.cache/
|
||||||
@@ -288,4 +283,3 @@ $RECYCLE.BIN/
|
|||||||
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
# End of https://www.toptal.com/developers/gitignore/api/node,macos,windows,webstorm,sublimetext,visualstudiocode
|
||||||
|
|
||||||
/build
|
/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">
|
<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$">
|
<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$">
|
||||||
<envs>
|
|
||||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
|
||||||
</envs>
|
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
5
.idea/runConfigurations/Run_Dev__community.xml
generated
5
.idea/runConfigurations/Run_Dev__community.xml
generated
@@ -1,8 +1,5 @@
|
|||||||
<component name="ProjectRunConfigurationManager">
|
<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$">
|
<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$">
|
||||||
<envs>
|
|
||||||
<env name="NODE_OPTIONS" value="--no-deprecation" />
|
|
||||||
</envs>
|
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
</component>
|
</component>
|
||||||
@@ -1 +1 @@
|
|||||||
v18.19.1
|
v18.17.1
|
||||||
|
|||||||
@@ -9,4 +9,3 @@
|
|||||||
**/node_modules
|
**/node_modules
|
||||||
**/temp
|
**/temp
|
||||||
**/docs/**
|
**/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": [
|
"recommendations": ["esbenp.prettier-vscode", "dbaeumer.vscode-eslint"]
|
||||||
"dbaeumer.vscode-eslint",
|
|
||||||
"esbenp.prettier-vscode",
|
|
||||||
"firsttris.vscode-jest-runner",
|
|
||||||
"ms-playwright.playwright"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|||||||
43
.vscode/launch.json
vendored
43
.vscode/launch.json
vendored
@@ -3,26 +3,12 @@
|
|||||||
// Hover to view descriptions of existing attributes.
|
// Hover to view descriptions of existing attributes.
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"command": "pnpm generate:types",
|
"command": "pnpm run dev _community",
|
||||||
"name": "Generate Types CLI",
|
|
||||||
"request": "launch",
|
|
||||||
"type": "node-terminal",
|
|
||||||
"cwd": "${workspaceFolder}"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"command": "node --no-deprecation test/dev.js fields",
|
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"name": "Run Dev Community",
|
"name": "Run Dev Community",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"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",
|
"command": "pnpm run dev plugin-cloud-storage",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@@ -33,6 +19,13 @@
|
|||||||
"PAYLOAD_PUBLIC_CLOUD_STORAGE_ADAPTER": "s3"
|
"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",
|
"command": "pnpm run dev fields",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@@ -41,7 +34,7 @@
|
|||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"command": "pnpm run dev:postgres versions",
|
"command": "pnpm run dev:postgres fields",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
"name": "Run Dev Postgres",
|
"name": "Run Dev Postgres",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
@@ -61,6 +54,13 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"type": "node-terminal"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"command": "pnpm run dev field-error-states",
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"name": "Run Dev Field Error States",
|
||||||
|
"request": "launch",
|
||||||
|
"type": "node-terminal"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"command": "pnpm run dev uploads",
|
"command": "pnpm run dev uploads",
|
||||||
"cwd": "${workspaceFolder}",
|
"cwd": "${workspaceFolder}",
|
||||||
@@ -116,6 +116,17 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"type": "node-terminal"
|
"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",
|
"command": "ts-node ./packages/payload/src/bin/index.ts migrate:status",
|
||||||
"env": {
|
"env": {
|
||||||
|
|||||||
7
.vscode/settings.json
vendored
7
.vscode/settings.json
vendored
@@ -36,9 +36,8 @@
|
|||||||
"typescript.tsdk": "node_modules/typescript/lib",
|
"typescript.tsdk": "node_modules/typescript/lib",
|
||||||
// Load .git-blame-ignore-revs file
|
// Load .git-blame-ignore-revs file
|
||||||
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
|
"gitlens.advanced.blame.customArguments": ["--ignore-revs-file", ".git-blame-ignore-revs"],
|
||||||
"[javascript][typescript][typescriptreact]": {
|
"jestrunner.jestCommand": "pnpm exec cross-env NODE_OPTIONS=\"--experimental-vm-modules --no-deprecation\" node 'node_modules/jest/bin/jest.js'",
|
||||||
"editor.codeActionsOnSave": {
|
"jestrunner.debugOptions": {
|
||||||
"source.fixAll.eslint": "explicit"
|
"runtimeArgs": ["--experimental-vm-modules", "--no-deprecation"]
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
450
CHANGELOG.md
450
CHANGELOG.md
@@ -1,3 +1,453 @@
|
|||||||
|
## [2.28.0](https://github.com/payloadcms/payload/compare/v2.27.0...v2.28.0) (2024-09-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* collections can use custom database operations ([#7675](https://github.com/payloadcms/payload/issues/7675)) ([6ba293c](https://github.com/payloadcms/payload/commit/6ba293c0f84f91bf89cf089a20e47de130013ebb))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **db-postgres:** migration exit codes ([#7873](https://github.com/payloadcms/payload/issues/7873)) ([25e9bc6](https://github.com/payloadcms/payload/commit/25e9bc62dbcbabcb3619cf83e3dc0110e0a4cabf)), closes [#7031](https://github.com/payloadcms/payload/issues/7031)
|
||||||
|
* **db-postgres:** query hasMany text/number in array/blocks ([#8033](https://github.com/payloadcms/payload/issues/8033)) ([96a624a](https://github.com/payloadcms/payload/commit/96a624ad5c5259b197b4ca793d8419d1e827de9c))
|
||||||
|
* **plugin-cloud:** better logging on static handler ([#7924](https://github.com/payloadcms/payload/issues/7924)) ([1f09348](https://github.com/payloadcms/payload/commit/1f0934877ce5aabb771c936c3677a26d2ef006ec))
|
||||||
|
|
||||||
|
## [2.27.0](https://github.com/payloadcms/payload/compare/v2.26.0...v2.27.0) (2024-08-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* add support for custom image size file names ([#7637](https://github.com/payloadcms/payload/issues/7637)) ([f976270](https://github.com/payloadcms/payload/commit/f97627092cabe4eabbebefa75afc53579188386b))
|
||||||
|
* upgrade react-toastify dependency, and upgrade to pnpm v9 in our monorepo ([#7667](https://github.com/payloadcms/payload/issues/7667)) ([94d18e8](https://github.com/payloadcms/payload/commit/94d18e8d747588efce225cde0b621db9b513e7c1))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* update state of field if either `valid` status or `errorMessage` changes ([#7632](https://github.com/payloadcms/payload/issues/7632)) ([c624eea](https://github.com/payloadcms/payload/commit/c624eea0d868938f4603860fa25be3df580ba7fe)), closes [#6413](https://github.com/payloadcms/payload/issues/6413)
|
||||||
|
|
||||||
|
## [2.26.0](https://github.com/payloadcms/payload/compare/v2.25.0...v2.26.0) (2024-08-09)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* adds classnames to edit, list views ([#7595](https://github.com/payloadcms/payload/issues/7595)) ([7f39afa](https://github.com/payloadcms/payload/commit/7f39afa1928b118451138e811ea71a04fce021d5))
|
||||||
|
* adds upload's relationship thumbnail ([#5015](https://github.com/payloadcms/payload/issues/5015)) ([39e110e](https://github.com/payloadcms/payload/commit/39e110e6331efff0ca8ca7174780076243a016de))
|
||||||
|
* **ui:** expose custom errors in delete many ([#7439](https://github.com/payloadcms/payload/issues/7439)) ([3e780b9](https://github.com/payloadcms/payload/commit/3e780b98155550f877021996dd094ba435dff81b))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **db-postgres:** localized array inside blocks field ([#7458](https://github.com/payloadcms/payload/issues/7458)) ([a308d63](https://github.com/payloadcms/payload/commit/a308d6384f9724c5ff330382070a5803fbcf167c)), closes [#5240](https://github.com/payloadcms/payload/issues/5240)
|
||||||
|
* deprecated `inflight` package ([#6558](https://github.com/payloadcms/payload/issues/6558)) ([eca1517](https://github.com/payloadcms/payload/commit/eca1517237c78983c192f4bafa92a86d94a0de9e)), closes [#6492](https://github.com/payloadcms/payload/issues/6492)
|
||||||
|
* enable `relationship` & `upload` field population in `versions` ([#7533](https://github.com/payloadcms/payload/issues/7533)) ([9865ae9](https://github.com/payloadcms/payload/commit/9865ae998b9aeb5d72724023976bb203133e19ff))
|
||||||
|
* filtering by non-poly `relationships` with `not_equals` operator ([#7573](https://github.com/payloadcms/payload/issues/7573)) ([efa56ce](https://github.com/payloadcms/payload/commit/efa56cefc15a48cd45b3aaba2eddacca79e1be30)), closes [#5212](https://github.com/payloadcms/payload/issues/5212) [#6278](https://github.com/payloadcms/payload/issues/6278)
|
||||||
|
* filtering by polymorphic `relationships` with `drafts` enabled ([#7565](https://github.com/payloadcms/payload/issues/7565)) ([907d7d1](https://github.com/payloadcms/payload/commit/907d7d1d3a89ed22bb991a1f238bb77d54e3e173)), closes [#6880](https://github.com/payloadcms/payload/issues/6880)
|
||||||
|
* retained date milliseconds ([#7393](https://github.com/payloadcms/payload/issues/7393)) ([9c9e689](https://github.com/payloadcms/payload/commit/9c9e6896a502de209c6cccf63cc5cfc0f0143bf3)), closes [#6108](https://github.com/payloadcms/payload/issues/6108)
|
||||||
|
* prevents `hasMany` text going outside of input boundaries ([#7454](https://github.com/payloadcms/payload/issues/7454)) ([1a0ef48](https://github.com/payloadcms/payload/commit/1a0ef4824b3d6548d36e7f28a2030640361c0655)), closes [#6034](https://github.com/payloadcms/payload/issues/6034)
|
||||||
|
* previousValue missing from ValidateOptions type ([#6931](https://github.com/payloadcms/payload/issues/6931)) ([fca5a40](https://github.com/payloadcms/payload/commit/fca5a404dbf3b440b428e55cf5e03db647f9a453))
|
||||||
|
* render singular label for `ArrayCell` when length is 1 ([#7585](https://github.com/payloadcms/payload/issues/7585)) ([fc4d24a](https://github.com/payloadcms/payload/commit/fc4d24aa8889ac9be76059a92478d5532b142b5c)), closes [#6099](https://github.com/payloadcms/payload/issues/6099)
|
||||||
|
|
||||||
|
## [2.25.0](https://github.com/payloadcms/payload/compare/v2.24.2...v2.25.0) (2024-07-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* allows metadata to be appended to the file of the output media ([#7295](https://github.com/payloadcms/payload/issues/7295)) ([3c5cce4](https://github.com/payloadcms/payload/commit/3c5cce4c6f108f87e87b091bbfec976423de73a2))
|
||||||
|
* **db-mongodb:** adds new optional `collation` feature flag behind mongodb collation option ([#7359](https://github.com/payloadcms/payload/issues/7359)) ([9750bc2](https://github.com/payloadcms/payload/commit/9750bc217ee7d63732a34908c84eb88b88dac0a8)), closes [#7349](https://github.com/payloadcms/payload/issues/7349)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* properly handles `0` value number fields in list view ([#7364](https://github.com/payloadcms/payload/issues/7364)) ([5321098](https://github.com/payloadcms/payload/commit/5321098d7eada43838f6d5c69f3233c150fe0afa)), closes [#5510](https://github.com/payloadcms/payload/issues/5510)
|
||||||
|
* preserves objectids in deepCopyObject ([#7385](https://github.com/payloadcms/payload/issues/7385)) ([1348483](https://github.com/payloadcms/payload/commit/134848364801c72cc773ef7b48854306d1b9bac3))
|
||||||
|
* relaxes equality check for relationship options in filter ([#7344](https://github.com/payloadcms/payload/issues/7344)) ([468e544](https://github.com/payloadcms/payload/commit/468e5441f16775134d915ec7caddb17b817d3408))
|
||||||
|
* supports null values in query strings ([#5241](https://github.com/payloadcms/payload/issues/5241)) ([c57591b](https://github.com/payloadcms/payload/commit/c57591bc4fb8d28b7de16a111faffea7d3e11f8d))
|
||||||
|
|
||||||
|
## [2.24.2](https://github.com/payloadcms/payload/compare/v2.24.1...v2.24.2) (2024-07-24)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **db-mongodb:** add jsonParse flag to mongooseAdapter that preserves existing, untracked MongoDB data types ([#7338](https://github.com/payloadcms/payload/issues/7338)) ([f96cf59](https://github.com/payloadcms/payload/commit/f96cf593cedcae0d8ed55f9a70e8e4e77917a876))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* allow autosave relationship drawers to function properly ([#7325](https://github.com/payloadcms/payload/issues/7325)) ([69e7b7a](https://github.com/payloadcms/payload/commit/69e7b7a158c38058ece54a97bfa79e65192774a6))
|
||||||
|
* **db-mongodb:** removes precedence of regular chars over international chars in sort ([#6923](https://github.com/payloadcms/payload/issues/6923)) ([0058660](https://github.com/payloadcms/payload/commit/0058660b3f8bd820abb4494ff53fa67f49f0f6b4)), closes [#6719](https://github.com/payloadcms/payload/issues/6719)
|
||||||
|
* fetches and sets permissions before setting user ([#7337](https://github.com/payloadcms/payload/issues/7337)) ([8259611](https://github.com/payloadcms/payload/commit/8259611ce60e23f6298a07564d5f6dd2966d61ff))
|
||||||
|
* **plugin-stripe:** properly types async webhooks ([#7316](https://github.com/payloadcms/payload/issues/7316)) ([c6da99b](https://github.com/payloadcms/payload/commit/c6da99b4d1b986089bb697486a7825db66323078))
|
||||||
|
|
||||||
|
## [2.24.1](https://github.com/payloadcms/payload/compare/v2.24.0...v2.24.1) (2024-07-22)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* aliases AfterMe, AfterLogout, and AfterRefresh hook types ([#7146](https://github.com/payloadcms/payload/issues/7146)) ([20377bb](https://github.com/payloadcms/payload/commit/20377bb22c867552e412c1cafd16869399aadd68))
|
||||||
|
* exports fallback hook types to ensure backwards compatibility ([#7217](https://github.com/payloadcms/payload/issues/7217)) ([1864577](https://github.com/payloadcms/payload/commit/18645771c86664f1246f0fb599c8265a4cd1d6c0))
|
||||||
|
* resizes images first before applying focal point ([#7278](https://github.com/payloadcms/payload/issues/7278)) ([1b208c7](https://github.com/payloadcms/payload/commit/1b208c7addf56ae8a1af5e408b001b3e5f080a38))
|
||||||
|
* uploads from drawer and focal point positioning ([#7244](https://github.com/payloadcms/payload/issues/7244)) ([0841d5a](https://github.com/payloadcms/payload/commit/0841d5a35ee00650c703231a08fc9a361861ba67))
|
||||||
|
|
||||||
|
## [2.24.0](https://github.com/payloadcms/payload/compare/v2.23.1...v2.24.0) (2024-07-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* adds ability to upload files from a remote url ([#7087](https://github.com/payloadcms/payload/issues/7087)) ([84d214f](https://github.com/payloadcms/payload/commit/84d214f99207ad78a466b8c16eb36e29f57cd0e3))
|
||||||
|
* **db-mongodb:** allows mongoose schemaOptions to be configured ([#7099](https://github.com/payloadcms/payload/issues/7099)) ([51474fa](https://github.com/payloadcms/payload/commit/51474fa661ae24ab8fc0d13001fafc0f35216c1e))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* ensures access query runs with locale when present ([#6981](https://github.com/payloadcms/payload/issues/6981)) ([a5492af](https://github.com/payloadcms/payload/commit/a5492afad672e19dd35b1f5370b51f22656f334c))
|
||||||
|
|
||||||
|
## [2.23.1](https://github.com/payloadcms/payload/compare/v2.23.0...v2.23.1) (2024-06-28)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* remove unused refresh arg, this affected me/refresh hooks ([#6976](https://github.com/payloadcms/payload/issues/6976)) ([c82d2ca](https://github.com/payloadcms/payload/commit/77e8ce980ef0bcb0380b499dd1ccdfd36199b707))
|
||||||
|
|
||||||
|
## [2.23.0](https://github.com/payloadcms/payload/compare/v2.22.2...v2.23.0) (2024-06-28)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* adds me and refresh hooks ([#6968](https://github.com/payloadcms/payload/issues/6968)) ([c82d2ca](https://github.com/payloadcms/payload/commit/c82d2caa29422083e97affc99a033296d78892d6))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **richtext-lexical:** html converters unnecessarily growing over time ([#6963](https://github.com/payloadcms/payload/issues/6963)) ([cf52d64](https://github.com/payloadcms/payload/commit/cf52d64d984d98ab782ca33f20b43c935ce60683))
|
||||||
|
|
||||||
|
## [2.22.2](https://github.com/payloadcms/payload/compare/v2.22.1...v2.22.2) (2024-06-26)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* return exp and strategy from auth ([#6943](https://github.com/payloadcms/payload/issues/6943)) ([ea18735](https://github.com/payloadcms/payload/commit/ea18735d3b2d2a96989009130e3724aab487e520))
|
||||||
|
|
||||||
|
## [2.22.1](https://github.com/payloadcms/payload/compare/v2.22.0...v2.22.1) (2024-06-25)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* graphql query concurrency issues ([#6857](https://github.com/payloadcms/payload/issues/6857)) ([bb911cc](https://github.com/payloadcms/payload/commit/bb911cc7eca1eeef15ade8eb043c0056c281e311))
|
||||||
|
* sends cropped image pixel values to server instead of percent values ([#6852](https://github.com/payloadcms/payload/issues/6852)) ([8747743](https://github.com/payloadcms/payload/commit/874774375f8beada9bac0a8ef3e77f63adc30834))
|
||||||
|
|
||||||
|
## [2.22.0](https://github.com/payloadcms/payload/compare/v2.21.0...v2.22.0) (2024-06-20)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* passes prev value through to validate functions ([#6805](https://github.com/payloadcms/payload/issues/6805)) ([0a51de7](https://github.com/payloadcms/payload/commit/0a51de7623d7c7790db52f0cc3e431b5ec3436f2))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* adjust json field schema for defaultValue ([#6872](https://github.com/payloadcms/payload/issues/6872)) ([58427ff](https://github.com/payloadcms/payload/commit/58427ffae3e0c1159fae817850b4c1770f43b9b9))
|
||||||
|
* array row validation messages ([#6780](https://github.com/payloadcms/payload/issues/6780)) ([68ea693](https://github.com/payloadcms/payload/commit/68ea693a88714951661464917d5df10a416a5ca0))
|
||||||
|
* cannot use empty string in defaultValue on text-like fields ([#6842](https://github.com/payloadcms/payload/issues/6842)) ([3364385](https://github.com/payloadcms/payload/commit/336438506ce5e54065f59a0352531e0255f5313d))
|
||||||
|
* corrects redirect with lonely slash on login ([#6784](https://github.com/payloadcms/payload/issues/6784)) ([dae56e6](https://github.com/payloadcms/payload/commit/dae56e60eef9e6456d9c51e7fc3b995a32e56f5e))
|
||||||
|
* **db-postgres:** cascade delete FKs on hasMany relationships ([#6735](https://github.com/payloadcms/payload/issues/6735)) ([9ecc6c8](https://github.com/payloadcms/payload/commit/9ecc6c889929a07d1163919eac14c9b33b90208a))
|
||||||
|
* **payload, db-mongodb:** querying relationships with `in` & `not_in` ([#6773](https://github.com/payloadcms/payload/issues/6773)) ([f6ba3be](https://github.com/payloadcms/payload/commit/f6ba3befaeb02edca66f04fbc2ea91d2d2549d08)), closes [#6741](https://github.com/payloadcms/payload/issues/6741)
|
||||||
|
* **plugin-cloud-storage:** missing error handling for invalid plugin config, leading to unexpected webpack errors ([#6786](https://github.com/payloadcms/payload/issues/6786)) ([015aafd](https://github.com/payloadcms/payload/commit/015aafda758938028c37a96e9b5fe62902757b09))
|
||||||
|
* **ui:** withinCollapsible always false from useCollapsible provider ([#6783](https://github.com/payloadcms/payload/issues/6783)) ([9f0aaf0](https://github.com/payloadcms/payload/commit/9f0aaf066e76210a85faf43b2b5dc5129ccf3879)), closes [#6760](https://github.com/payloadcms/payload/issues/6760)
|
||||||
|
* unflattening json objects containing keys with periods ([#6834](https://github.com/payloadcms/payload/issues/6834)) ([025306f](https://github.com/payloadcms/payload/commit/025306f9e685c030956dad3b0f0158c1dce49668)), closes [#5378](https://github.com/payloadcms/payload/issues/5378)
|
||||||
|
* upgrade swc, fixing swc issues on linux ([#6809](https://github.com/payloadcms/payload/issues/6809)) ([1c986a9](https://github.com/payloadcms/payload/commit/1c986a98321163c921cb071a160b6fa9fc8bd9ee))
|
||||||
|
|
||||||
|
|
||||||
|
## [2.21.0](https://github.com/payloadcms/payload/compare/v2.20.0...v2.21.0) (2024-06-14)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* draft validation ([#6746](https://github.com/payloadcms/payload/issues/6746)) ([ff70fd9](https://github.com/payloadcms/payload/commit/ff70fd9813ec7dc14bf54d3457c25e145fe01699))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* adjust version status pill when unpublished ([#6744](https://github.com/payloadcms/payload/issues/6744)) ([b7e8529](https://github.com/payloadcms/payload/commit/b7e852993beaaa465e38caa36e75e870819516b5))
|
||||||
|
* use correct time for isLocked check ([#6052](https://github.com/payloadcms/payload/issues/6052)) ([3b4bb30](https://github.com/payloadcms/payload/commit/3b4bb3065a6d2ac2f7d6aafd0fb4a35b580f3662))
|
||||||
|
* unable to save animated file types with undefined image sizes ([#6733](https://github.com/payloadcms/payload/issues/6733)) ([e40570b](https://github.com/payloadcms/payload/commit/e40570bd0d64660bb2ae5b5785b4c85c684ca9ab)), closes [#6727](https://github.com/payloadcms/payload/issues/6727)
|
||||||
|
|
||||||
|
## [2.20.0](https://github.com/payloadcms/payload/compare/v2.19.3...v2.20.0) (2024-06-11)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **ui:** updates draft/published version pills ([#6732](https://github.com/payloadcms/payload/issues/6732)) ([ed86b15](https://github.com/payloadcms/payload/commit/ed86b15242ccbd737f3fe80103afc7d8c4cc6915))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* adds multi select inputs for `number` & `text` fields in where builder ([#6662](https://github.com/payloadcms/payload/issues/6662)) ([e3003b4](https://github.com/payloadcms/payload/commit/e3003b443fd3b472670ade228c174c7f755b1732))
|
||||||
|
* create sharp file for `fileHasAdjustments` files or `fileIsAnimated` files ([#6710](https://github.com/payloadcms/payload/issues/6710)) ([921a5c0](https://github.com/payloadcms/payload/commit/921a5c065d6089f0118ad8be7adbf75614c8db9c))
|
||||||
|
* enable SaveDraft button when creating new documents ([#6672](https://github.com/payloadcms/payload/issues/6672)) ([63bc6ae](https://github.com/payloadcms/payload/commit/63bc6ae52f63adf98f442c2d7992461e7f5f86e4)), closes [#6671](https://github.com/payloadcms/payload/issues/6671) [/github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01#diff-b7c978f47b1f3beff95c78ad95078e600624cbcd7ac10f9378cc4ad6803db244L75-R79](https://github.com/payloadcms//github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01/issues/diff-b7c978f47b1f3beff95c78ad95078e600624cbcd7ac10f9378cc4ad6803db244L75-R79)
|
||||||
|
* handles localized nested relationship fields in versions ([#6679](https://github.com/payloadcms/payload/issues/6679)) ([8a62298](https://github.com/payloadcms/payload/commit/8a622984e7ce4a2439d5d63e2689404652f8c96b))
|
||||||
|
* live preview device position when using zoom ([#6667](https://github.com/payloadcms/payload/issues/6667)) ([9525511](https://github.com/payloadcms/payload/commit/9525511e8bc6bc3fbd7e21e36596404604f1c109))
|
||||||
|
* only use `metadata.pages` for height if animated ([#6729](https://github.com/payloadcms/payload/issues/6729)) ([2f9ed34](https://github.com/payloadcms/payload/commit/2f9ed34d13d94070db40b1eabd04655d2e13e094))
|
||||||
|
* removes `array` & `blocks` & `group` fields from sort ([#6574](https://github.com/payloadcms/payload/issues/6574)) ([507e095](https://github.com/payloadcms/payload/commit/507e0954b2743012f0b53c396d49461120a02b1a)), closes [#6469](https://github.com/payloadcms/payload/issues/6469)
|
||||||
|
* withinCollapsible should be undefined by default ([#6666](https://github.com/payloadcms/payload/issues/6666)) ([37c8386](https://github.com/payloadcms/payload/commit/37c8386a51172966057df3477517d160e1c4a9a7)), closes [#6658](https://github.com/payloadcms/payload/issues/6658)
|
||||||
|
|
||||||
|
## [2.19.3](https://github.com/payloadcms/payload/compare/v2.19.2...v2.19.3) (2024-06-07)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* scopes uploadEdits to documents, hoists action to doc provider ([#6664](https://github.com/payloadcms/payload/issues/6664)) ([373cb00](https://github.com/payloadcms/payload/commit/373cb0013902b52aba455542e10402316da4b2f4))
|
||||||
|
|
||||||
|
## [2.19.2](https://github.com/payloadcms/payload/compare/v2.19.1...v2.19.2) (2024-06-06)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* cascade draft arg when querying globals with graphql ([#6651](https://github.com/payloadcms/payload/issues/6651)) ([ac8c209](https://github.com/payloadcms/payload/commit/ac8c2096af641a6886e4543ee65c9790e45f080f))
|
||||||
|
* filtered out `disableListColumn` fields reappeared after toggling other fields ([#6636](https://github.com/payloadcms/payload/issues/6636)) ([626be15](https://github.com/payloadcms/payload/commit/626be155784dda181276bb87617433822a0accf3))
|
||||||
|
* resizing animated images ([#6621](https://github.com/payloadcms/payload/issues/6621)) ([67c0b0e](https://github.com/payloadcms/payload/commit/67c0b0e6e0b5b190f6a916b59ba02f8c18479e18)), closes [#2181](https://github.com/payloadcms/payload/issues/2181) [#6146](https://github.com/payloadcms/payload/issues/6146)
|
||||||
|
|
||||||
|
## [2.19.1](https://github.com/payloadcms/payload/compare/v2.19.0...v2.19.1) (2024-06-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* override ajv dependency version to 8.14.0 wherever possible ([#6618](https://github.com/payloadcms/payload/issues/6618)) ([e44ce81](https://github.com/payloadcms/payload/commit/e44ce819cefddeaaf20b2b7ce804e94a9272baf1))
|
||||||
|
|
||||||
|
## [2.19.0](https://github.com/payloadcms/payload/compare/v2.18.3...v2.19.0) (2024-06-04)
|
||||||
|
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* **translations:** update Turkish translations ([#5738](https://github.com/payloadcms/payload/issues/5738)) ([4fddea8](https://github.com/payloadcms/payload/commit/4fddea86ebd5f21705be2310f8b7053d31109189))
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* adds new `userEmailAlreadyRegistered` translations ([#6549](https://github.com/payloadcms/payload/issues/6549)) ([56c6700](https://github.com/payloadcms/payload/commit/56c6700cf25570cc217e28dc69459a3b81adbced)), closes [#6535](https://github.com/payloadcms/payload/issues/6535)
|
||||||
|
* adjusts sizing of remove/add buttons to be same size ([#6527](https://github.com/payloadcms/payload/issues/6527)) ([a352ebc](https://github.com/payloadcms/payload/commit/a352ebc5520bbd0f6a9caef068825976dba05ded)), closes [#6098](https://github.com/payloadcms/payload/issues/6098)
|
||||||
|
* focalPoint undefined handling ([#6552](https://github.com/payloadcms/payload/issues/6552)) ([fcfc3c5](https://github.com/payloadcms/payload/commit/fcfc3c593f69f63c51f8aa09973fcacbfbe04952))
|
||||||
|
* pagination on polymorphic relationship field requesting entries with page parameter set to NaN ([#5366](https://github.com/payloadcms/payload/issues/5366)) ([547acfe](https://github.com/payloadcms/payload/commit/547acfe876bdf0df2ce808941f72b690c9dbcae3))
|
||||||
|
* safely evaluates `field.admin` in WhereBuilder ([#6534](https://github.com/payloadcms/payload/issues/6534)) ([4f9d78d](https://github.com/payloadcms/payload/commit/4f9d78df5e38f3f70852bb6de47cff619f57c648))
|
||||||
|
* separate sort and search fields when looking up relationship. ([#5964](https://github.com/payloadcms/payload/issues/5964)) ([c009219](https://github.com/payloadcms/payload/commit/c0092191a6ded1098a94d9f48918ab79171e5e32)), closes [#4815](https://github.com/payloadcms/payload/issues/4815) [#5222](https://github.com/payloadcms/payload/issues/5222)
|
||||||
|
* ui field validation error with `admin.disableListColumn` property ([#6530](https://github.com/payloadcms/payload/issues/6530)) ([eeddece](https://github.com/payloadcms/payload/commit/eeddeceda988d7a4ce8ad31d3036a4ee84aceec3)), closes [#6521](https://github.com/payloadcms/payload/issues/6521)
|
||||||
|
* **ui:** blocks browser save dialog from opening when hotkey used with no changes ([#6365](https://github.com/payloadcms/payload/issues/6365)) ([8f03cd7](https://github.com/payloadcms/payload/commit/8f03cd7c789eda7613ddced0d45a32afe49b1e01)), closes [#214](https://github.com/payloadcms/payload/issues/214)
|
||||||
|
|
||||||
|
## [2.18.3](https://github.com/payloadcms/payload/compare/v2.18.2...v2.18.3) (2024-05-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **db-postgres:** query with like on id columns ([#6416](https://github.com/payloadcms/payload/issues/6416)) ([bf77cec](https://github.com/payloadcms/payload/commit/bf77cec7e9e7db4988e481d464178636203fca32))
|
||||||
|
* **db-postgres:** uuid custom db name ([#6409](https://github.com/payloadcms/payload/issues/6409)) ([db5f3f3](https://github.com/payloadcms/payload/commit/db5f3f3ccdaedd9e8036c3e39fc20650a309a151))
|
||||||
|
* nested `disableListColumn` in rows ([#6412](https://github.com/payloadcms/payload/issues/6412)) ([ab8b2f3](https://github.com/payloadcms/payload/commit/ab8b2f3fb87864484582b7d819ca307888a9449b)), closes [#6407](https://github.com/payloadcms/payload/issues/6407)
|
||||||
|
|
||||||
|
## [2.18.2](https://github.com/payloadcms/payload/compare/v2.18.1...v2.18.2) (2024-05-17)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* allow focal point when no sizes defined ([#6397](https://github.com/payloadcms/payload/issues/6397)) ([88e113a](https://github.com/payloadcms/payload/commit/88e113a5452300434f690186d10ea02ab159ffc3))
|
||||||
|
|
||||||
|
## [2.18.1](https://github.com/payloadcms/payload/compare/v2.18.0...v2.18.1) (2024-05-16)
|
||||||
|
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* add back explicit crop x and y values ([#6391](https://github.com/payloadcms/payload/issues/6391)) ([e76df32](https://github.com/payloadcms/payload/commit/e76df32f0987cc92dc8d9c693950e650c52576bf))
|
||||||
|
|
||||||
|
## [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)
|
## [2.11.2](https://github.com/payloadcms/payload/compare/v2.11.1...v2.11.2) (2024-02-23)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
<hr/>
|
<hr/>
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!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>
|
<h3>Benefits over a regular CMS</h3>
|
||||||
<ul>
|
<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',
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -37,9 +37,12 @@ const defaultPayloadAccess = ({ req: { user } }) => {
|
|||||||
<strong>Note:</strong>
|
<strong>Note:</strong>
|
||||||
<br />
|
<br />
|
||||||
In the Local API, all Access Control functions are skipped by default, allowing your server to do
|
In the Local API, all Access Control functions are skipped by default, allowing your server to do
|
||||||
whatever it needs. But, you can opt back in by setting the option <strong>
|
whatever it needs. But, you can opt back in by setting the option
|
||||||
|
{' '}
|
||||||
|
<strong>
|
||||||
overrideAccess
|
overrideAccess
|
||||||
</strong>{' '}
|
</strong>
|
||||||
|
{' '}
|
||||||
to <strong>false</strong>.
|
to <strong>false</strong>.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import { webpackBundler } from '@payloadcms/bundler-webpack'
|
|||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
// highlight-start
|
// highlight-start
|
||||||
admin: {
|
admin: {
|
||||||
bundler: webpackBundler(), // or viteBundler()
|
bundler: webpackBundler() // or viteBundler()
|
||||||
},
|
},
|
||||||
// highlight-end
|
// 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">
|
<Banner type="warning">
|
||||||
<strong>Using environment variables in the admin UI</strong>
|
<strong>Using environment variables in the admin UI</strong>
|
||||||
<br />
|
<br />
|
||||||
Bundles should not contain sensitive information. By default, Payload excludes env variables from
|
Bundles should not contain sensitive information. By default, Payload
|
||||||
the bundle. If you need to use env variables in your payload config, you need to prefix them with
|
excludes env variables from the bundle. If you need to use env variables in your payload config,
|
||||||
`PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
you need to prefix them with `PAYLOAD_PUBLIC_` to make them available to the client-side code.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|||||||
@@ -13,29 +13,29 @@ To swap in your own React component, first, consult the list of available compon
|
|||||||
<Banner type="success">
|
<Banner type="success">
|
||||||
<strong>Tip:</strong>
|
<strong>Tip:</strong>
|
||||||
<br />
|
<br />
|
||||||
Custom components will automatically be provided with all props that the default component
|
Custom components will automatically be provided with all props that the default component normally
|
||||||
normally accepts.
|
accepts.
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
### Base Component Overrides
|
### 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:
|
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 |
|
| Path | Description |
|
||||||
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
| **`Nav`** | Contains the sidebar / mobile menu in its entirety. |
|
||||||
| **`BeforeNavLinks`** | Array of components to inject into the built-in Nav, _before_ the links themselves. |
|
| **`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. |
|
| **`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. |
|
| **`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) |
|
| **`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. |
|
| **`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. |
|
| **`AfterLogin`** | Array of components to inject into the built-in Login, _after_ the default login form. |
|
||||||
| **`logout.Button`** | A custom React component. |
|
| **`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.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. |
|
| **`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) |
|
| **`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. |
|
| **`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) |
|
| **`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.
|
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:
|
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 |
|
| Property | Description |
|
||||||
| --------------- | ----------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Account`** | The Account view is used to show the currently logged in user's Account page. |
|
| **`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. |
|
| **`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:
|
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">
|
<Banner type="warning">
|
||||||
<strong>Note:</strong>
|
<strong>Note:</strong>
|
||||||
<br />
|
<br />
|
||||||
Routes are cascading. This means that unless explicitly given the `exact` property, they will
|
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.
|
||||||
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>
|
</Banner>
|
||||||
|
|
||||||
_For more examples regarding how to customize components, look at the following [examples](https://github.com/payloadcms/payload/tree/main/test/admin/components)._
|
_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 {
|
import {
|
||||||
CustomSaveButtonProps,
|
CustomSaveButtonProps,
|
||||||
CustomSaveDraftButtonProps,
|
CustomSaveDraftButtonProps,
|
||||||
CustomPublishButtonProps,
|
CustomPublishButtonType,
|
||||||
CustomPreviewButtonProps,
|
CustomPreviewButtonProps,
|
||||||
} from 'payload/types'
|
} from 'payload/types'
|
||||||
|
|
||||||
@@ -188,7 +185,7 @@ export const CustomSaveDraftButton: CustomSaveDraftButtonProps = ({
|
|||||||
return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
|
return <DefaultButton label={label} disabled={disabled} saveDraft={saveDraft} />
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CustomPublishButton: CustomPublishButtonProps = ({
|
export const CustomPublishButton: CustomPublishButtonType = ({
|
||||||
DefaultButton,
|
DefaultButton,
|
||||||
disabled,
|
disabled,
|
||||||
label,
|
label,
|
||||||
@@ -217,7 +214,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
PreviewButton: CustomPreviewButton,
|
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:
|
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 |
|
| Property | Description |
|
||||||
| ---------- | ------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
| **`Edit`** | The Edit view is used to edit a single document for a given collection. |
|
||||||
| **`List`** | The List view is used to show a list of documents for a given collection. |
|
| **`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_.
|
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:
|
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 |
|
| Property | Description |
|
||||||
| ---------- | ------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Edit`** | The Edit view is used to edit a single document for a given Global. |
|
| **`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_.
|
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:
|
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 |
|
| Property | Description |
|
||||||
| ----------------- | --------------------------------------------------------------------------------------------------------------------------- |
|
| ------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Default`** | The Default view is the primary view in which your document is edited. |
|
| **`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) |
|
| **`Versions`** | The Versions view is used to view the version history of a single document. [More details](../versions) |
|
||||||
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
| **`Version`** | The Version view is used to view a single version of a single document for a given collection. [More details](../versions). |
|
||||||
| **`API`** | The API view is used to display the REST API JSON response for a given document. |
|
| **`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) |
|
| **`LivePreview`** | The LivePreview view is used to display the Live Preview interface. [More details](../live-preview) |
|
||||||
|
|
||||||
Here is an example:
|
Here is an example:
|
||||||
|
|
||||||
@@ -399,8 +396,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
views: {
|
views: {
|
||||||
Edit: {
|
Edit: { // You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
||||||
// You can also define `components.views.Edit` as a component, this will override _all_ nested views
|
|
||||||
Default: MyCustomDefaultTab,
|
Default: MyCustomDefaultTab,
|
||||||
Versions: MyCustomVersionsTab,
|
Versions: MyCustomVersionsTab,
|
||||||
Version: MyCustomVersionTab,
|
Version: MyCustomVersionTab,
|
||||||
@@ -427,7 +423,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
Component: MyCustomTab,
|
Component: MyCustomTab,
|
||||||
path: '/my-custom-tab',
|
path: '/my-custom-tab',
|
||||||
// You an swap the entire tab component out for your own
|
// You an swap the entire tab component out for your own
|
||||||
Tab: MyCustomTab,
|
Tab: MyCustomTab
|
||||||
},
|
},
|
||||||
AnotherCustomView: {
|
AnotherCustomView: {
|
||||||
Component: AnotherCustomView,
|
Component: AnotherCustomView,
|
||||||
@@ -436,7 +432,7 @@ export const MyCollection: SanitizedCollectionConfig = {
|
|||||||
Tab: {
|
Tab: {
|
||||||
label: 'Another Custom View',
|
label: 'Another Custom View',
|
||||||
href: '/another-custom-view',
|
href: '/another-custom-view',
|
||||||
},
|
}
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -495,7 +491,7 @@ As an alternative to replacing the entire Field component, you may want to keep
|
|||||||
| Component | Description |
|
| Component | Description |
|
||||||
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
|
| ----------------- | --------------------------------------------------------------------------------------------------------------- |
|
||||||
| **`Label`** | Override the default Label in the Field Component. [More](#label-component) |
|
| **`Label`** | Override the default Label in the Field Component. [More](#label-component) |
|
||||||
| **`Error`** | Override the default Label in the Field Component. [More](#error-component) |
|
| **`Error`** | Override the default Error in the Field Component. [More](#error-component) |
|
||||||
| **`beforeInput`** | An array of elements that will be added before `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
|
| **`beforeInput`** | An array of elements that will be added before `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
|
||||||
| **`afterInput`** | An array of elements that will be added after `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
|
| **`afterInput`** | An array of elements that will be added after `input`/`textarea` elements. [More](#afterinput-and-beforeinput) |
|
||||||
|
|
||||||
@@ -543,6 +539,7 @@ const CustomTextField: React.FC<{ path: string }> = ({ path }) => {
|
|||||||
const { value, setValue } = useField<string>({ path })
|
const { value, setValue } = useField<string>({ path })
|
||||||
// highlight-end
|
// highlight-end
|
||||||
|
|
||||||
|
|
||||||
return <input onChange={(e) => setValue(e.target.value)} value={value} />
|
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.
|
These are the props that will be passed to your custom Label.
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| -------------- | ---------------------------------------------------------------- |
|
| ---------------- | ---------------------------------------------------------------- |
|
||||||
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
| **`htmlFor`** | Property used to set `for` attribute for label. |
|
||||||
| **`label`** | Label value provided in field, it can be used with i18n. |
|
| **`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. |
|
| **`required`** | A boolean value that represents if the field is required or not. |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@@ -582,12 +579,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
|||||||
const { i18n } = useTranslation()
|
const { i18n } = useTranslation()
|
||||||
|
|
||||||
if (label) {
|
if (label) {
|
||||||
return (
|
return (<span>
|
||||||
<span>
|
{getTranslation(label, i18n)}
|
||||||
{getTranslation(label, i18n)}
|
{required && <span className="required">*</span>}
|
||||||
{required && <span className="required">*</span>}
|
</span>);
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -598,10 +593,10 @@ const CustomLabel: React.FC<Props> = (props) => {
|
|||||||
|
|
||||||
These are the props that will be passed to your custom Error.
|
These are the props that will be passed to your custom Error.
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| --------------- | ------------------------------------------------------------- |
|
| ---------------- | ------------------------------------------------------------- |
|
||||||
| **`message`** | The error message. |
|
| **`message`** | The error message. |
|
||||||
| **`showError`** | A boolean value that represents if the error should be shown. |
|
| **`showError`** | A boolean value that represents if the error should be shown. |
|
||||||
|
|
||||||
#### Example
|
#### Example
|
||||||
|
|
||||||
@@ -617,8 +612,8 @@ const CustomError: React.FC<Props> = (props) => {
|
|||||||
const { message, showError } = props
|
const { message, showError } = props
|
||||||
|
|
||||||
if (showError) {
|
if (showError) {
|
||||||
return <p style={{ color: 'red' }}>{message}</p>
|
return <p style={{color: 'red'}}>{message}</p>
|
||||||
} else return null
|
} else return null;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -635,15 +630,7 @@ import { Field } from 'payload/types'
|
|||||||
import './style.scss'
|
import './style.scss'
|
||||||
|
|
||||||
const ClearButton: React.FC = () => {
|
const ClearButton: React.FC = () => {
|
||||||
return (
|
return <button onClick={() => {/* ... */}}>X</button>
|
||||||
<button
|
|
||||||
onClick={() => {
|
|
||||||
/* ... */
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
X
|
|
||||||
</button>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const titleField: Field = {
|
const titleField: Field = {
|
||||||
@@ -651,17 +638,17 @@ const titleField: Field = {
|
|||||||
type: 'text',
|
type: 'text',
|
||||||
admin: {
|
admin: {
|
||||||
components: {
|
components: {
|
||||||
afterInput: [ClearButton],
|
afterInput: [ClearButton]
|
||||||
},
|
}
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default titleField
|
export default titleField;
|
||||||
```
|
```
|
||||||
|
|
||||||
## Custom providers
|
## Custom providers
|
||||||
|
|
||||||
As your admin customizations gets more complex you may want to share state between fields or other components. You can add custom providers to do add your own context to any Payload app for use in other custom components within the admin panel. Within your config add `admin.components.providers`, these can be used to share context or provide other custom functionality. Read the [React context](https://reactjs.org/docs/context.html) docs to learn more.
|
As your admin customizations gets more complex you may want to share state between fields or other components. You can add custom providers to add your own context to any Payload app for use in other custom components within the admin panel. Within your config add `admin.components.providers`, these can be used to share context or provide other custom functionality. Read the [React context](https://reactjs.org/docs/context.html) docs to learn more.
|
||||||
|
|
||||||
<Banner type="warning">
|
<Banner type="warning">
|
||||||
<strong>Reminder:</strong> Don't forget to pass the **children** prop through the provider
|
<strong>Reminder:</strong> Don't forget to pass the **children** prop through the provider
|
||||||
@@ -670,7 +657,7 @@ As your admin customizations gets more complex you may want to share state betwe
|
|||||||
|
|
||||||
### Styling Custom Components
|
### 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:
|
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.
|
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:
|
First, we will create a mock file to replace the server-only file when bundling:
|
||||||
|
|
||||||
```js
|
```js
|
||||||
// mocks/modules.js
|
// mocks/modules.js
|
||||||
|
|
||||||
@@ -132,7 +131,7 @@ import { Subscriptions } from './collections/Subscriptions'
|
|||||||
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
|
const mockModulePath = path.resolve(__dirname, 'mocks/emptyObject.js')
|
||||||
const fullFilePath = path.resolve(
|
const fullFilePath = path.resolve(
|
||||||
__dirname,
|
__dirname,
|
||||||
'collections/Subscriptions/hooks/createStripeSubscription',
|
'collections/Subscriptions/hooks/createStripeSubscription'
|
||||||
)
|
)
|
||||||
|
|
||||||
export default buildConfig({
|
export default buildConfig({
|
||||||
@@ -174,23 +173,24 @@ export default buildConfig({
|
|||||||
admin: {
|
admin: {
|
||||||
bundler: viteBundler(),
|
bundler: viteBundler(),
|
||||||
vite: (incomingViteConfig) => {
|
vite: (incomingViteConfig) => {
|
||||||
const existingAliases = incomingViteConfig?.resolve?.alias || {}
|
const existingAliases = incomingViteConfig?.resolve?.alias || {};
|
||||||
let aliasArray: { find: string | RegExp; replacement: string }[] = []
|
let aliasArray: { find: string | RegExp; replacement: string; }[] = [];
|
||||||
|
|
||||||
// Pass the existing Vite aliases
|
// Pass the existing Vite aliases
|
||||||
if (Array.isArray(existingAliases)) {
|
if (Array.isArray(existingAliases)) {
|
||||||
aliasArray = existingAliases
|
aliasArray = existingAliases;
|
||||||
} else {
|
} else {
|
||||||
aliasArray = Object.values(existingAliases)
|
aliasArray = Object.values(existingAliases);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// highlight-start
|
// highlight-start
|
||||||
// Add your own aliases using the find and replacement keys
|
// Add your own aliases using the find and replacement keys
|
||||||
// remember, vite aliases are exact-match only
|
// remember, vite aliases are exact-match only
|
||||||
aliasArray.push({
|
aliasArray.push({
|
||||||
find: '../server-only-module',
|
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
|
// highlight-end
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -198,8 +198,8 @@ export default buildConfig({
|
|||||||
resolve: {
|
resolve: {
|
||||||
...(incomingViteConfig?.resolve || {}),
|
...(incomingViteConfig?.resolve || {}),
|
||||||
alias: aliasArray,
|
alias: aliasArray,
|
||||||
},
|
}
|
||||||
}
|
};
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -639,12 +639,12 @@ export const CustomArrayManager = () => {
|
|||||||
|
|
||||||
The `useCollapsible` hook allows you to control parent collapsibles:
|
The `useCollapsible` hook allows you to control parent collapsibles:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ----------------------- | ------------------------------------------------------------------------------------------------------------ | --- |
|
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`collapsed`** | State of the collapsible. `true` if open, `false` if collapsed |
|
| **`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 |
|
| **`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 |
|
| **`toggle`** | Toggles the state of the nearest collapsible |
|
||||||
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
| **`withinCollapsible`** | Determine when you are within another collaspible | |
|
||||||
|
|
||||||
**Example:**
|
**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:
|
The `useDocumentInfo` hook provides lots of information about the document currently being edited, including the following:
|
||||||
|
|
||||||
| Property | Description |
|
| Property | Description |
|
||||||
| ------------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|---------------------------|--------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`collection`** | If the doc is a collection, its collection config will be returned |
|
| **`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 |
|
| **`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 |
|
| **`id`** | If the doc is a collection, its ID will be returned |
|
||||||
@@ -804,17 +804,15 @@ const MyComponent: React.FC = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span>
|
<span>The current theme is {theme} and autoMode is {autoMode}</span>
|
||||||
The current theme is {theme} and autoMode is {autoMode}
|
|
||||||
</span>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setTheme((prev) => (prev === 'light' ? 'dark' : 'light'))}
|
onClick={() => setTheme(prev => prev === "light" ? "dark" : "light")}
|
||||||
>
|
>
|
||||||
Toggle theme
|
Toggle theme
|
||||||
</button>
|
</button>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -835,7 +833,10 @@ const MyComponent: React.FC = () => {
|
|||||||
// highlight-end
|
// highlight-end
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button type="button" onClick={resetColumns}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={resetColumns}
|
||||||
|
>
|
||||||
Reset columns
|
Reset columns
|
||||||
</button>
|
</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:
|
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 |
|
| Property | Description |
|
||||||
| ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
|
|---------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| **`mostRecentUpdate`** | An object containing the most recently updated document. It contains the `entitySlug`, `id` (if collection), and `updatedAt` properties |
|
| **`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. |
|
| **`reportUpdate`** | A method used to report updates to documents. It accepts the same arguments as the `mostRecentUpdate` property. |
|
||||||
|
|
||||||
**Example:**
|
**Example:**
|
||||||
|
|
||||||
@@ -859,11 +860,14 @@ import { useDocumentEvents } from 'payload/components/hooks'
|
|||||||
const ListenForUpdates: React.FC = () => {
|
const ListenForUpdates: React.FC = () => {
|
||||||
const { mostRecentUpdate } = useDocumentEvents()
|
const { mostRecentUpdate } = useDocumentEvents()
|
||||||
|
|
||||||
return <span>{JSON.stringify(mostRecentUpdate)}</span>
|
return (
|
||||||
|
<span>
|
||||||
|
{JSON.stringify(mostRecentUpdate)}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
<Banner type="info">
|
<Banner type="info">
|
||||||
Right now the `useDocumentEvents` hook only tracks recently updated documents, but in the future
|
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.
|
||||||
it will track more document-related events as needed, such as document creation, deletion, etc.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|||||||
@@ -6,8 +6,7 @@ desc: NEEDS TO BE WRITTEN
|
|||||||
---
|
---
|
||||||
|
|
||||||
<Banner type="info">
|
<Banner type="info">
|
||||||
The Vite bundler is currently in beta. If you would like to help us test this package, we'd love
|
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/)!
|
||||||
to hear from you if you find any [bugs or issues](https://github.com/payloadcms/payload/issues/)!
|
|
||||||
</Banner>
|
</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.
|
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: [],
|
collections: [],
|
||||||
admin: {
|
admin: {
|
||||||
bundler: viteBundler(),
|
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.
|
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">
|
<Banner type="warning">
|
||||||
In most cases, Vite should work out of the box. But existing Payload plugins may need to make
|
In most cases, Vite should work out of the box. But existing Payload plugins may need to make compatibility changes to support Vite.
|
||||||
compatibility changes to support Vite.
|
|
||||||
</Banner>
|
</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.
|
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({
|
export default buildConfig({
|
||||||
// highlight-start
|
// highlight-start
|
||||||
admin: {
|
admin: {
|
||||||
bundler: webpackBundler(),
|
bundler: webpackBundler()
|
||||||
},
|
},
|
||||||
// highlight-end
|
// highlight-end
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -49,8 +49,7 @@ To enable API keys on a collection, set the `useAPIKey` auth option to `true`. F
|
|||||||
<strong>Important:</strong>
|
<strong>Important:</strong>
|
||||||
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
|
If you change your `PAYLOAD_SECRET`, you will need to regenerate your API keys.
|
||||||
<br />
|
<br />
|
||||||
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will
|
The secret key is used to encrypt the API keys, so if you change the secret, existing API keys will no longer be valid.
|
||||||
no longer be valid.
|
|
||||||
</Banner>
|
</Banner>
|
||||||
|
|
||||||
#### Authenticating via API Key
|
#### Authenticating via API Key
|
||||||
@@ -217,7 +216,7 @@ Example:
|
|||||||
{
|
{
|
||||||
slug: 'customers',
|
slug: 'customers',
|
||||||
auth: {
|
auth: {
|
||||||
forgotPassword: {
|
verify: {
|
||||||
// highlight-start
|
// highlight-start
|
||||||
generateEmailSubject: ({ req, user }) => {
|
generateEmailSubject: ({ req, user }) => {
|
||||||
return `Hey ${user.email}, reset your password!`;
|
return `Hey ${user.email}, reset your password!`;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user