mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-22 15:29:44 +00:00
Compare commits
2132 Commits
subgraph/n
...
rizumu/fix
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
12d366d1d0 | ||
|
|
da042ae829 | ||
|
|
62096d46c1 | ||
|
|
2a5e0d231e | ||
|
|
08309595e0 | ||
|
|
3982f29fda | ||
|
|
57db10f408 | ||
|
|
1447b15f4c | ||
|
|
4a7c955a15 | ||
|
|
ba1fa1be25 | ||
|
|
5171decd8b | ||
|
|
5a74c019c7 | ||
|
|
934c650790 | ||
|
|
b2a828dda6 | ||
|
|
d1ed5ecc0d | ||
|
|
bfcbcf4873 | ||
|
|
0dd4ff2087 | ||
|
|
889d136154 | ||
|
|
c773230b21 | ||
|
|
8df41ab040 | ||
|
|
2b9a9e2371 | ||
|
|
4171219402 | ||
|
|
301355e018 | ||
|
|
ac17752c0b | ||
|
|
fc6943cdd3 | ||
|
|
9db96f2dcc | ||
|
|
19084e2799 | ||
|
|
6e04cb72b0 | ||
|
|
9c4d782b30 | ||
|
|
ac60d1ceb4 | ||
|
|
06d0a63a2f | ||
|
|
2dcfe84e99 | ||
|
|
f42a4dd6cc | ||
|
|
b5d3cfdd9a | ||
|
|
18d724c08d | ||
|
|
d0eee738b7 | ||
|
|
f3d9f4cffb | ||
|
|
d766cd6fe5 | ||
|
|
b9f232ebc6 | ||
|
|
6b1584ebce | ||
|
|
20181195e1 | ||
|
|
1bdc190154 | ||
|
|
e9919263ff | ||
|
|
810f027b5d | ||
|
|
e8f0ec5bb3 | ||
|
|
1b83d6b5a6 | ||
|
|
cd444b6e59 | ||
|
|
48b1ebf6cc | ||
|
|
9e8db6125c | ||
|
|
62e06f4358 | ||
|
|
74b61ecfdf | ||
|
|
8646ca4162 | ||
|
|
7d6e252814 | ||
|
|
50e0e29016 | ||
|
|
ced62caaa0 | ||
|
|
73f7e1108a | ||
|
|
f79a5dc6a8 | ||
|
|
a630caa9d5 | ||
|
|
6bf430b779 | ||
|
|
926d8fef85 | ||
|
|
1e0ba5ce9b | ||
|
|
95a1c86c23 | ||
|
|
5cc916bf9f | ||
|
|
c75255327a | ||
|
|
84e7102f70 | ||
|
|
3169628144 | ||
|
|
ca0937479d | ||
|
|
aebdda3063 | ||
|
|
882506dfb1 | ||
|
|
69a3239722 | ||
|
|
78c8dc3886 | ||
|
|
84379d9522 | ||
|
|
23b3914714 | ||
|
|
ea9cb3cb45 | ||
|
|
11f5439d29 | ||
|
|
4e8f665a19 | ||
|
|
20b0927783 | ||
|
|
e789227420 | ||
|
|
4db9e3d7fb | ||
|
|
1e9d4c7c37 | ||
|
|
180f95182d | ||
|
|
bcdb96a727 | ||
|
|
337fb2100a | ||
|
|
2407748425 | ||
|
|
5f349ed3cd | ||
|
|
8d0a523ffd | ||
|
|
97e5291b05 | ||
|
|
80097007c9 | ||
|
|
deba8df8ce | ||
|
|
694817297d | ||
|
|
28d74be363 | ||
|
|
2240645a7d | ||
|
|
cf9847a11e | ||
|
|
321fe71497 | ||
|
|
7d7c6a324a | ||
|
|
7d2d006c07 | ||
|
|
30d48f2356 | ||
|
|
451ef24ea6 | ||
|
|
727a3494e0 | ||
|
|
7a1a2dd654 | ||
|
|
75d7a3725b | ||
|
|
ba4c159ce5 | ||
|
|
29ae9b4483 | ||
|
|
a505aec037 | ||
|
|
9e78558849 | ||
|
|
efd9b04a6e | ||
|
|
194201e871 | ||
|
|
0daacfd914 | ||
|
|
5a35562d3d | ||
|
|
ceac8f3741 | ||
|
|
b1057f164b | ||
|
|
4a189bdc93 | ||
|
|
f0adb4c9d3 | ||
|
|
d5d0aa52c2 | ||
|
|
69c660b3b7 | ||
|
|
88579c2a40 | ||
|
|
7ab247aa1d | ||
|
|
c78d03dd2c | ||
|
|
65785af348 | ||
|
|
ec4ad5ea92 | ||
|
|
e9ddf29507 | ||
|
|
fdd8564c07 | ||
|
|
d18081a54e | ||
|
|
45cc6ca2b4 | ||
|
|
c303a3f037 | ||
|
|
c90fd18ade | ||
|
|
2ed1704749 | ||
|
|
7d5a4d423e | ||
|
|
7aaa0f022e | ||
|
|
a132dad216 | ||
|
|
9dbdc6a72b | ||
|
|
7b228d693d | ||
|
|
547af0e043 | ||
|
|
4ca6220adf | ||
|
|
1e41c6dc45 | ||
|
|
5224c63bce | ||
|
|
89c78b0ecb | ||
|
|
4a3bd39650 | ||
|
|
db1b81b7ff | ||
|
|
5e81343142 | ||
|
|
6566acb406 | ||
|
|
efc0431a5e | ||
|
|
1784e2b5a3 | ||
|
|
39df4ac9da | ||
|
|
eba0b42674 | ||
|
|
ef1852d551 | ||
|
|
983ebb2ba7 | ||
|
|
db71365768 | ||
|
|
17d7ba8bcb | ||
|
|
24a386c766 | ||
|
|
c42c9315f4 | ||
|
|
d068b8351e | ||
|
|
1cf8087be0 | ||
|
|
9c31d708a2 | ||
|
|
9a70e927aa | ||
|
|
dc444faa75 | ||
|
|
a055ec2dff | ||
|
|
2138ceea80 | ||
|
|
7972550f6b | ||
|
|
c7baf3c340 | ||
|
|
8403bd0e3e | ||
|
|
90f54414ab | ||
|
|
505c242ff4 | ||
|
|
fbc6edde25 | ||
|
|
2c215a6251 | ||
|
|
71a43193df | ||
|
|
d0d13bfe4c | ||
|
|
a1a8d48544 | ||
|
|
d22d62b670 | ||
|
|
8e357c41e3 | ||
|
|
c4912dcd54 | ||
|
|
109542dca3 | ||
|
|
ffc812a8f5 | ||
|
|
b745f533ba | ||
|
|
8f289c8e67 | ||
|
|
79b4c78116 | ||
|
|
48aea928e0 | ||
|
|
03ad06ea14 | ||
|
|
ff5943f770 | ||
|
|
b1117b9838 | ||
|
|
2d11fb1f90 | ||
|
|
e70b127f2a | ||
|
|
0d8e4fe719 | ||
|
|
5f5f44b310 | ||
|
|
b42878a9da | ||
|
|
5cc269eff1 | ||
|
|
16d7436883 | ||
|
|
db452c1e63 | ||
|
|
10d80165c4 | ||
|
|
c3997dfdb0 | ||
|
|
7bbbf59722 | ||
|
|
8bf60777e7 | ||
|
|
ba28fa4621 | ||
|
|
95ab88693c | ||
|
|
5d71d6f9cf | ||
|
|
8899b425a8 | ||
|
|
1fc4fd2ca8 | ||
|
|
1b9bacaeef | ||
|
|
65cc06771c | ||
|
|
3c154d8487 | ||
|
|
c6c20e53fb | ||
|
|
70c06d10bb | ||
|
|
f4482eb35a | ||
|
|
e77411d9da | ||
|
|
04f8ae416f | ||
|
|
e63337ccbe | ||
|
|
385c56d93d | ||
|
|
f3b82e377a | ||
|
|
85aa89da45 | ||
|
|
5e9b8785a5 | ||
|
|
386eb9391a | ||
|
|
b6f564dc30 | ||
|
|
3f290e2cbd | ||
|
|
37099c498b | ||
|
|
6b31596399 | ||
|
|
c6a9f43052 | ||
|
|
3e2d62efb4 | ||
|
|
aaaa0cdcb9 | ||
|
|
5ad9f86a58 | ||
|
|
b46f3853a5 | ||
|
|
86509bda43 | ||
|
|
b33f820b3b | ||
|
|
a7a4448878 | ||
|
|
85a5d1ed56 | ||
|
|
01e4260d4c | ||
|
|
fad8dae796 | ||
|
|
88aa6e894e | ||
|
|
0ce5aeb2bd | ||
|
|
a289f44263 | ||
|
|
500c9c6631 | ||
|
|
a8bd66b18f | ||
|
|
c53f197de2 | ||
|
|
50feb27339 | ||
|
|
bbf0a65abf | ||
|
|
9e3b845884 | ||
|
|
a041cc8e0e | ||
|
|
b64a46a386 | ||
|
|
1bf2470f8f | ||
|
|
681d4c6758 | ||
|
|
a199d11925 | ||
|
|
f13af07fed | ||
|
|
fd71c97dc4 | ||
|
|
b10d06166a | ||
|
|
47e6503681 | ||
|
|
797616c455 | ||
|
|
6048dc0c60 | ||
|
|
264663363a | ||
|
|
821f3765cc | ||
|
|
7f849e9a44 | ||
|
|
489b205bf5 | ||
|
|
5c7ac51d22 | ||
|
|
e7f698a08a | ||
|
|
ba3cc19e53 | ||
|
|
a91d8a1836 | ||
|
|
ba09d67e03 | ||
|
|
eb76222cd0 | ||
|
|
68f7ed14d9 | ||
|
|
dd0e8a6c6f | ||
|
|
9862b68799 | ||
|
|
ffa34c49a3 | ||
|
|
579201945e | ||
|
|
fc287a830c | ||
|
|
a674b99009 | ||
|
|
06b6832bea | ||
|
|
357ae8f0d8 | ||
|
|
5b245c9433 | ||
|
|
fef02e5f56 | ||
|
|
3f7e6fa53b | ||
|
|
6a1b184a63 | ||
|
|
669ee2633a | ||
|
|
09515cd13d | ||
|
|
1d815b3075 | ||
|
|
2d16105e8d | ||
|
|
e324c805ba | ||
|
|
1eadf80fec | ||
|
|
f1aba23ee1 | ||
|
|
934f2674e9 | ||
|
|
907662a42b | ||
|
|
378ac4880c | ||
|
|
4c6e7f106b | ||
|
|
1b58bf4966 | ||
|
|
3b4c0b5d2b | ||
|
|
a568c0651f | ||
|
|
46a486c694 | ||
|
|
dc395f5d6d | ||
|
|
61c9341450 | ||
|
|
d96d8cb9a9 | ||
|
|
d779df5f64 | ||
|
|
6fa2e8e3ca | ||
|
|
47e1808861 | ||
|
|
eae4b954d0 | ||
|
|
baea47c493 | ||
|
|
8673e0e6c4 | ||
|
|
b125e0aa3a | ||
|
|
aabea4b78d | ||
|
|
f85df302fb | ||
|
|
b2b50ac012 | ||
|
|
fe475403b0 | ||
|
|
efb08bf2ba | ||
|
|
2c84ecbf6e | ||
|
|
f987cf9dbd | ||
|
|
2b019935a7 | ||
|
|
f8ec532f1a | ||
|
|
b370b6387d | ||
|
|
516eb26d3e | ||
|
|
5c71854a96 | ||
|
|
04b03e22f8 | ||
|
|
b0d05c6ef6 | ||
|
|
f936ffcaf7 | ||
|
|
596c51d1ef | ||
|
|
381b5c7295 | ||
|
|
d70949dd47 | ||
|
|
abf93d2c11 | ||
|
|
f064fec3a8 | ||
|
|
abf591d122 | ||
|
|
e7a425eeae | ||
|
|
7d8c56c5e6 | ||
|
|
fe3b8be89f | ||
|
|
cf072b8420 | ||
|
|
fcebbbcba8 | ||
|
|
4b75528c39 | ||
|
|
dd14144f47 | ||
|
|
00cd9fadec | ||
|
|
98d694f7e3 | ||
|
|
b1fc8846a3 | ||
|
|
680c09a584 | ||
|
|
7fe4c07a9c | ||
|
|
577cd23c3e | ||
|
|
b1436a068b | ||
|
|
b6922cf386 | ||
|
|
6167861340 | ||
|
|
68f50670d3 | ||
|
|
67277d483d | ||
|
|
a4cf280887 | ||
|
|
344afa21a7 | ||
|
|
ab8bcc9522 | ||
|
|
4bab7bc609 | ||
|
|
bdcda7308b | ||
|
|
3039b4526d | ||
|
|
e3628ed156 | ||
|
|
271643aa93 | ||
|
|
7802213887 | ||
|
|
35fb141b07 | ||
|
|
475c9f7f89 | ||
|
|
e0aac8c9db | ||
|
|
83795d5db1 | ||
|
|
8ff5f07f9a | ||
|
|
49b936c50f | ||
|
|
4d7e9b70d1 | ||
|
|
4d0ba197a8 | ||
|
|
78fc86d153 | ||
|
|
906bc42f7f | ||
|
|
bb5aef9275 | ||
|
|
62f3ba0689 | ||
|
|
2338cbd4c9 | ||
|
|
83aa887456 | ||
|
|
37bfc53616 | ||
|
|
b240c090aa | ||
|
|
309a5b8c9a | ||
|
|
c06bc63c6f | ||
|
|
052d5320c0 | ||
|
|
e34d9bb411 | ||
|
|
f81b191fae | ||
|
|
4cd0c270bf | ||
|
|
5bed360a14 | ||
|
|
16b607c95c | ||
|
|
b0968509f9 | ||
|
|
7eb3eb2473 | ||
|
|
cccf51b652 | ||
|
|
ff68c42162 | ||
|
|
defaef8043 | ||
|
|
280131d33d | ||
|
|
6b3de73655 | ||
|
|
ae8293e2cd | ||
|
|
7b32a2fb6e | ||
|
|
27865278da | ||
|
|
61611fb0cb | ||
|
|
1cd6a7f667 | ||
|
|
a62362234c | ||
|
|
a39f6e6763 | ||
|
|
def6010d72 | ||
|
|
efdb8080ae | ||
|
|
995f482593 | ||
|
|
23b2302ce3 | ||
|
|
b745b58e6b | ||
|
|
6f3f1f9f24 | ||
|
|
c0feaa5f94 | ||
|
|
0a8f16fe19 | ||
|
|
d833ab65a6 | ||
|
|
dea4a76ceb | ||
|
|
2fd94319bc | ||
|
|
32062aa126 | ||
|
|
db70bd61d5 | ||
|
|
e10a9c112a | ||
|
|
7e41834094 | ||
|
|
ed1d944e0e | ||
|
|
10296d54e0 | ||
|
|
3f9fb421d0 | ||
|
|
282f9ce27a | ||
|
|
d2e49ac110 | ||
|
|
11eff4981f | ||
|
|
927773f553 | ||
|
|
1200c07fcd | ||
|
|
967f1e15e3 | ||
|
|
28f955ed6a | ||
|
|
3ac96979fe | ||
|
|
ca5774c0df | ||
|
|
4ab223d651 | ||
|
|
d60d9485f3 | ||
|
|
3c7d6968ed | ||
|
|
6134452891 | ||
|
|
f90e7f1f3c | ||
|
|
a70bcb048c | ||
|
|
3db44707fa | ||
|
|
2b831d5d87 | ||
|
|
e93da6bce4 | ||
|
|
914c3e4705 | ||
|
|
6ae6a05b14 | ||
|
|
fe57458a66 | ||
|
|
5eac669b41 | ||
|
|
9ef47e70cf | ||
|
|
8b8f38f4de | ||
|
|
6f9d5a7a5b | ||
|
|
a80312280d | ||
|
|
f9cf25ad82 | ||
|
|
7d029a4998 | ||
|
|
c846ab80ae | ||
|
|
eb93bb3c22 | ||
|
|
d7597acefe | ||
|
|
0c5e0d4b73 | ||
|
|
b5a9cbcc16 | ||
|
|
abcf8ba8e6 | ||
|
|
cab707a32c | ||
|
|
7378c858bd | ||
|
|
bcaaa00770 | ||
|
|
3e7f9627b4 | ||
|
|
c1fbb6a893 | ||
|
|
46b279b2b3 | ||
|
|
b17dc296ab | ||
|
|
0a22191c86 | ||
|
|
7ff7f780ca | ||
|
|
d225e77d30 | ||
|
|
ee2171b6ce | ||
|
|
3608ea6d18 | ||
|
|
273eae1e8d | ||
|
|
0d5fd0e90d | ||
|
|
b86f2b58e6 | ||
|
|
e971667264 | ||
|
|
0385fb4d75 | ||
|
|
71928af112 | ||
|
|
942758e3a5 | ||
|
|
456a96e875 | ||
|
|
d1ec780dbd | ||
|
|
06413df706 | ||
|
|
f5b3036b6c | ||
|
|
56109eccc0 | ||
|
|
de21f5ccd3 | ||
|
|
b035c95cc0 | ||
|
|
2b45828afc | ||
|
|
19b7d28d97 | ||
|
|
ad528461c9 | ||
|
|
c4b0372cd4 | ||
|
|
de32560816 | ||
|
|
10118d95e3 | ||
|
|
c2a88d3088 | ||
|
|
6ff80cfd36 | ||
|
|
d452240936 | ||
|
|
bc8b13b5a4 | ||
|
|
441f14c12e | ||
|
|
1adc0b6c00 | ||
|
|
2405be993c | ||
|
|
f55c01af65 | ||
|
|
3fec0e2d39 | ||
|
|
dbc5cdf600 | ||
|
|
4f9a40dcfd | ||
|
|
288f961688 | ||
|
|
1b37502d70 | ||
|
|
33a76714f7 | ||
|
|
44c98fbf62 | ||
|
|
8cf449c957 | ||
|
|
86d1c2a93a | ||
|
|
ccbdff0ad1 | ||
|
|
df6e4debb5 | ||
|
|
c7c7547454 | ||
|
|
c6df437662 | ||
|
|
a74df42cce | ||
|
|
28434e7165 | ||
|
|
c344a73739 | ||
|
|
f6101bccae | ||
|
|
75df19521b | ||
|
|
406abd7731 | ||
|
|
386f18a1e5 | ||
|
|
53f766af3d | ||
|
|
81eed7a1fa | ||
|
|
bfc87af9d1 | ||
|
|
f2eafae82d | ||
|
|
aa9f2f74b1 | ||
|
|
27fbc2ea7c | ||
|
|
9dcc3bf39a | ||
|
|
b838a70ed2 | ||
|
|
199eeae269 | ||
|
|
ee89fc575f | ||
|
|
cb6020dfc1 | ||
|
|
388a3d64cc | ||
|
|
2e0267105e | ||
|
|
7a9b23087e | ||
|
|
c4b4b84b41 | ||
|
|
537cdf7838 | ||
|
|
7d38f6bdc7 | ||
|
|
cfabeb0821 | ||
|
|
0cdee75460 | ||
|
|
c695b2e2bd | ||
|
|
2f0e3d35d3 | ||
|
|
64d1225037 | ||
|
|
be92f5bdbb | ||
|
|
ccc588b842 | ||
|
|
85f677f58c | ||
|
|
ee222c794b | ||
|
|
85b1534263 | ||
|
|
81a00b5e6c | ||
|
|
47732404cd | ||
|
|
b3d030e36b | ||
|
|
8e8818c24d | ||
|
|
8e414ab133 | ||
|
|
0b46288d32 | ||
|
|
5c41e4e09c | ||
|
|
de0f0ebac1 | ||
|
|
38dd58ae23 | ||
|
|
c10ce1caa1 | ||
|
|
63407abf3c | ||
|
|
0fd47a767d | ||
|
|
080a8da8f4 | ||
|
|
79ce3199d4 | ||
|
|
d70260615b | ||
|
|
cbbbb9c694 | ||
|
|
a28effc9f1 | ||
|
|
e06e8c0a3f | ||
|
|
58d8f10e40 | ||
|
|
ddfd89df60 | ||
|
|
78bd6704fe | ||
|
|
2ad1481f02 | ||
|
|
f7a0a92f3a | ||
|
|
7c236bcfc8 | ||
|
|
b6a04d245b | ||
|
|
cc5aece6b6 | ||
|
|
21a3f56187 | ||
|
|
a76c50252b | ||
|
|
c607c53543 | ||
|
|
b988238155 | ||
|
|
48bf415e52 | ||
|
|
13db014387 | ||
|
|
453257cd30 | ||
|
|
7c88bda647 | ||
|
|
deeed9853c | ||
|
|
5100bf6b00 | ||
|
|
6293b4bbe0 | ||
|
|
02d165bf2a | ||
|
|
5c76bec611 | ||
|
|
ce46f19de9 | ||
|
|
51ec57dc5c | ||
|
|
af3fa1cd8c | ||
|
|
0063bf618d | ||
|
|
15fbc8fb77 | ||
|
|
c90edcc201 | ||
|
|
bdffdc9f10 | ||
|
|
2acf16d3d0 | ||
|
|
2e72031344 | ||
|
|
3ba61c7265 | ||
|
|
547fb22398 | ||
|
|
f3fba4007b | ||
|
|
197a6cbae8 | ||
|
|
04b4485cc9 | ||
|
|
c60e9d8080 | ||
|
|
ae4a63c839 | ||
|
|
297b557b94 | ||
|
|
05e8e25b6b | ||
|
|
f6ef85e7c3 | ||
|
|
6a3f5271c8 | ||
|
|
bf5e3f3c77 | ||
|
|
d77100c401 | ||
|
|
24dfbe8b2b | ||
|
|
079a18a391 | ||
|
|
3815296ab5 | ||
|
|
0032675e00 | ||
|
|
ed34080e46 | ||
|
|
3b5cc8cd19 | ||
|
|
6cafeeff19 | ||
|
|
7360e09172 | ||
|
|
c77082fe2f | ||
|
|
ee625b4112 | ||
|
|
981979335e | ||
|
|
76d63948b2 | ||
|
|
1ef4921c0a | ||
|
|
c07176eb08 | ||
|
|
70661ec421 | ||
|
|
64c7113440 | ||
|
|
c4373deeea | ||
|
|
29c923e0e3 | ||
|
|
d17b86a6b8 | ||
|
|
f63cf8648e | ||
|
|
8a94232f61 | ||
|
|
05b0918915 | ||
|
|
a4e1b39823 | ||
|
|
184ba3915a | ||
|
|
125ca24d13 | ||
|
|
df279024c4 | ||
|
|
30a7f19a64 | ||
|
|
8a9b1c7071 | ||
|
|
0eeaf90647 | ||
|
|
854ac4350f | ||
|
|
27a2b785ac | ||
|
|
ba5809a9b4 | ||
|
|
7b3ea64714 | ||
|
|
59317bcda7 | ||
|
|
a20bae064f | ||
|
|
332b18bd91 | ||
|
|
a6aec4017b | ||
|
|
6fd6c60b9f | ||
|
|
808d78169b | ||
|
|
27895dac00 | ||
|
|
c5db2d8736 | ||
|
|
123c46d28b | ||
|
|
5662aa3790 | ||
|
|
f0bd360935 | ||
|
|
28543d7d9d | ||
|
|
b1462a6274 | ||
|
|
642317f6bd | ||
|
|
5a67044206 | ||
|
|
7fc8f8c897 | ||
|
|
c8bd5e43dd | ||
|
|
361ae2c589 | ||
|
|
fd4ffbc1f8 | ||
|
|
7b8f01f546 | ||
|
|
05587d8a19 | ||
|
|
ff6281c840 | ||
|
|
642e73773c | ||
|
|
a44b8d0581 | ||
|
|
ba7f870e0f | ||
|
|
d3685bc6df | ||
|
|
b254bae5c5 | ||
|
|
2e95ac9a71 | ||
|
|
16eddaac5f | ||
|
|
5f03d9a3cf | ||
|
|
37ab504bdc | ||
|
|
0dd060a369 | ||
|
|
6380037d1f | ||
|
|
cd9778bb6c | ||
|
|
b87a671a88 | ||
|
|
2dbd5f4cf0 | ||
|
|
7c6245ab1c | ||
|
|
850d1b9652 | ||
|
|
87aeab16a0 | ||
|
|
766e69bbf1 | ||
|
|
38bbf2fead | ||
|
|
a043e7a72e | ||
|
|
cdbc0fa5e5 | ||
|
|
4078e3ad8b | ||
|
|
9e64bf7278 | ||
|
|
e65898b9ec | ||
|
|
7845be9b15 | ||
|
|
0b4b420445 | ||
|
|
1579b5ea71 | ||
|
|
257d4fc7b9 | ||
|
|
39a9799db7 | ||
|
|
c1f9745e54 | ||
|
|
5821049493 | ||
|
|
b71150a939 | ||
|
|
94b9ecec71 | ||
|
|
dbc605e4da | ||
|
|
3447ea1981 | ||
|
|
9b16144390 | ||
|
|
20dc103aa9 | ||
|
|
cd65c4bfea | ||
|
|
680cf631e0 | ||
|
|
bd17247b4f | ||
|
|
48483670f5 | ||
|
|
690f7bdfb3 | ||
|
|
9dda7e937b | ||
|
|
b80e1744be | ||
|
|
bb822e999f | ||
|
|
9315a8810e | ||
|
|
034692120e | ||
|
|
36f197b34e | ||
|
|
d59cc61a21 | ||
|
|
e6a914117b | ||
|
|
d0e1998415 | ||
|
|
18811f50fc | ||
|
|
df36b23db8 | ||
|
|
835e22d754 | ||
|
|
2e9f877bbd | ||
|
|
bcaeccfc45 | ||
|
|
486c5ad6c0 | ||
|
|
cca2ac28e0 | ||
|
|
77465113cd | ||
|
|
9dd0ff3eb3 | ||
|
|
07d7c533da | ||
|
|
6805643204 | ||
|
|
a26a5c9a87 | ||
|
|
fbcf5315f4 | ||
|
|
27873d0351 | ||
|
|
b223c60cd0 | ||
|
|
a7f2ff16a9 | ||
|
|
f6c605434b | ||
|
|
9981d19b36 | ||
|
|
5ed264ce8e | ||
|
|
35dd90b6b0 | ||
|
|
314095a3c1 | ||
|
|
35ec2a3fa1 | ||
|
|
35827b8494 | ||
|
|
58011e77b6 | ||
|
|
8ba671a5eb | ||
|
|
5531a884a6 | ||
|
|
214defbdb4 | ||
|
|
db680c96ad | ||
|
|
1a482d750b | ||
|
|
84dad03f4d | ||
|
|
c5cb4cea43 | ||
|
|
e632f5c69b | ||
|
|
4589938ceb | ||
|
|
acdbbd547e | ||
|
|
9c60788948 | ||
|
|
c0bfe5489f | ||
|
|
8e59fbfaa2 | ||
|
|
5ab9d9d25c | ||
|
|
68945cb54d | ||
|
|
7119480f84 | ||
|
|
8153e65b3b | ||
|
|
a9ace409a4 | ||
|
|
c21510773e | ||
|
|
20bdc47550 | ||
|
|
3e44f6a0c1 | ||
|
|
84fad5b8a5 | ||
|
|
c1af1e29d2 | ||
|
|
7e2009188d | ||
|
|
1d31635072 | ||
|
|
54f96ca028 | ||
|
|
a5c2464c88 | ||
|
|
e62ef2e0aa | ||
|
|
7a2af7008b | ||
|
|
493e374b7d | ||
|
|
40137176f3 | ||
|
|
b63ef93bb7 | ||
|
|
68f6f2d2c8 | ||
|
|
3411ecbc15 | ||
|
|
8a3487a209 | ||
|
|
8bee428375 | ||
|
|
e4a41669f6 | ||
|
|
91afd9305e | ||
|
|
32b6b7eff9 | ||
|
|
10f2f2ca67 | ||
|
|
aca81a99c8 | ||
|
|
b227eefbdd | ||
|
|
cef6ab6ced | ||
|
|
37b9798602 | ||
|
|
1b10b0b0b6 | ||
|
|
c128551af5 | ||
|
|
83fb246119 | ||
|
|
2a12864a67 | ||
|
|
4cbf12849e | ||
|
|
9af4ee120c | ||
|
|
1200c0fd91 | ||
|
|
ff43f183d1 | ||
|
|
66a9214de6 | ||
|
|
1407f1d720 | ||
|
|
326670206d | ||
|
|
017a473f5b | ||
|
|
f6653ef45b | ||
|
|
af7db40fce | ||
|
|
165cf210d3 | ||
|
|
a815ce92a8 | ||
|
|
972527de70 | ||
|
|
77b274f27f | ||
|
|
b1885ebec8 | ||
|
|
6cb9131035 | ||
|
|
41e552b719 | ||
|
|
02d991d669 | ||
|
|
1aba15bbca | ||
|
|
78175e2c1b | ||
|
|
d597271954 | ||
|
|
9b6a78e7df | ||
|
|
193b09999f | ||
|
|
6a42484669 | ||
|
|
539fa91b0d | ||
|
|
ab25d1fc6e | ||
|
|
ecb69a4f1d | ||
|
|
7b4bea8e62 | ||
|
|
31d3168201 | ||
|
|
ec34498264 | ||
|
|
1e7897930c | ||
|
|
177a5a0d54 | ||
|
|
5721b1c27c | ||
|
|
c473130499 | ||
|
|
bad923a7f0 | ||
|
|
5f95dd1853 | ||
|
|
b36bf3d4a2 | ||
|
|
c4faaf4210 | ||
|
|
b877312336 | ||
|
|
4365873039 | ||
|
|
b4688e18f9 | ||
|
|
7b19abf83a | ||
|
|
955d20d8ea | ||
|
|
c66ca2ae66 | ||
|
|
0a09ecc7ac | ||
|
|
fab386275c | ||
|
|
38dd7b7089 | ||
|
|
be8dc6867e | ||
|
|
97bf9de83a | ||
|
|
6737828a2b | ||
|
|
984bd8696c | ||
|
|
2d9c811aa9 | ||
|
|
0d8e0fce17 | ||
|
|
2104f2a8a9 | ||
|
|
1e8938ceff | ||
|
|
6f51767451 | ||
|
|
9c8cc571e2 | ||
|
|
e8c238b70e | ||
|
|
fbcc396880 | ||
|
|
963e4b0904 | ||
|
|
d20aab757c | ||
|
|
c166a34fd8 | ||
|
|
7e6b64f216 | ||
|
|
939e9c0a2f | ||
|
|
0e9b8b03b7 | ||
|
|
a43109d58a | ||
|
|
3040924d76 | ||
|
|
0b59c00597 | ||
|
|
6224d2dc06 | ||
|
|
867b9ed316 | ||
|
|
5cdd0581fa | ||
|
|
9ded97d189 | ||
|
|
d849fcd00c | ||
|
|
7fab99b362 | ||
|
|
953ae434ea | ||
|
|
dbe016b934 | ||
|
|
cdbd0899e2 | ||
|
|
67d8c3177a | ||
|
|
67ee55ede1 | ||
|
|
f39e1d96e8 | ||
|
|
4636367de2 | ||
|
|
0b84ca83d8 | ||
|
|
477d498d6b | ||
|
|
fa13b3b240 | ||
|
|
4920e10f0c | ||
|
|
6bd151c91e | ||
|
|
2c3535c983 | ||
|
|
a4b9704a80 | ||
|
|
ad8dd7a9d8 | ||
|
|
a8b6f1e1ec | ||
|
|
cf8565eb13 | ||
|
|
fdc693204c | ||
|
|
fadece7fdf | ||
|
|
59dea644f2 | ||
|
|
170341db73 | ||
|
|
630fd00086 | ||
|
|
c8ffacf172 | ||
|
|
9d6c867607 | ||
|
|
bcd5a77837 | ||
|
|
f3b51a534e | ||
|
|
b0a1ce8290 | ||
|
|
1800d31a5a | ||
|
|
f300e37a89 | ||
|
|
4add6c3211 | ||
|
|
46535409c8 | ||
|
|
4163cb04b8 | ||
|
|
de5ea39c71 | ||
|
|
86f823b7d5 | ||
|
|
d17e7f567d | ||
|
|
e1ea72eb89 | ||
|
|
dc9a76200b | ||
|
|
4dc971383f | ||
|
|
c8385657db | ||
|
|
d0ab5e07c9 | ||
|
|
dcac6dba80 | ||
|
|
1dee497e40 | ||
|
|
b67f34e7f3 | ||
|
|
485bfd1628 | ||
|
|
31e16b6748 | ||
|
|
7bab620986 | ||
|
|
8b1b8d2a76 | ||
|
|
6b1e40a011 | ||
|
|
2592c18790 | ||
|
|
d27ced7cf3 | ||
|
|
026437e1a9 | ||
|
|
6703a1f1fa | ||
|
|
aafd7202c2 | ||
|
|
196645ce7e | ||
|
|
e800eeb202 | ||
|
|
f010180b79 | ||
|
|
9288709497 | ||
|
|
8c6979223d | ||
|
|
28e86820d6 | ||
|
|
7d97a6e505 | ||
|
|
1e71da9a38 | ||
|
|
52a96a14d6 | ||
|
|
7a25899ecc | ||
|
|
62254c1d4d | ||
|
|
d23a320f9f | ||
|
|
5bed4fbb70 | ||
|
|
a5c89c0152 | ||
|
|
de10bf0c3a | ||
|
|
75267957d5 | ||
|
|
ce44cea409 | ||
|
|
5d03f4477e | ||
|
|
361a1a76ef | ||
|
|
9abcf0fd32 | ||
|
|
aa25db1dfd | ||
|
|
550a65bf7a | ||
|
|
7813e5207a | ||
|
|
e87b17fb27 | ||
|
|
f0eca030c4 | ||
|
|
adff23bb84 | ||
|
|
38ef72cd90 | ||
|
|
d029bd8924 | ||
|
|
6dd93a54a6 | ||
|
|
c75157e86e | ||
|
|
997d673bd9 | ||
|
|
62adcf7184 | ||
|
|
048fa5bb88 | ||
|
|
a5ee5bfbad | ||
|
|
120c606f07 | ||
|
|
01b8ae5bb8 | ||
|
|
f26807f931 | ||
|
|
7472d1d9a1 | ||
|
|
64fddc078c | ||
|
|
7e76fd58a1 | ||
|
|
0d5f7d79bd | ||
|
|
de74d8a08c | ||
|
|
12f8d33b78 | ||
|
|
4d36369cd8 | ||
|
|
64365acf7d | ||
|
|
92b0783a9b | ||
|
|
51144e956c | ||
|
|
aa358403ac | ||
|
|
8ca184c0f8 | ||
|
|
cdaceebcaa | ||
|
|
2d688a896d | ||
|
|
ab14827f87 | ||
|
|
dd1dae7d2f | ||
|
|
63f9f30eec | ||
|
|
c781053bd2 | ||
|
|
fcc09c075d | ||
|
|
9b29860f47 | ||
|
|
790aac89f0 | ||
|
|
608b5f8342 | ||
|
|
75f067dbb3 | ||
|
|
024ede680d | ||
|
|
a0d275f223 | ||
|
|
c9f6b5ece8 | ||
|
|
47e9abd4ea | ||
|
|
82c88a003a | ||
|
|
be03fcc7d1 | ||
|
|
9d5e94859e | ||
|
|
316efd6666 | ||
|
|
d6a5e417c2 | ||
|
|
1728e4c6f0 | ||
|
|
a5a9ce223d | ||
|
|
c900df750e | ||
|
|
5acb656b15 | ||
|
|
530fa874b0 | ||
|
|
7ea9a8405d | ||
|
|
f69f8a4f38 | ||
|
|
9b5f67aadf | ||
|
|
a3fa551a17 | ||
|
|
3cd08e9e0c | ||
|
|
dc24c6617f | ||
|
|
f2fada0eab | ||
|
|
b3dbc41368 | ||
|
|
047bf68dc9 | ||
|
|
9a1c322490 | ||
|
|
6cf1f2d627 | ||
|
|
610ebd6ffe | ||
|
|
9d8e49b8f8 | ||
|
|
0500d77665 | ||
|
|
108af616d8 | ||
|
|
f7db430da8 | ||
|
|
1da2c8a914 | ||
|
|
4844311f3b | ||
|
|
0ee671843b | ||
|
|
682f4c624f | ||
|
|
5ba6472c70 | ||
|
|
3e133b71e6 | ||
|
|
00de6ae960 | ||
|
|
eb47a3aab2 | ||
|
|
655ddfd1df | ||
|
|
817214e6da | ||
|
|
a4791f6e6b | ||
|
|
33d41a452e | ||
|
|
9a8c3dff89 | ||
|
|
f48cbb6a82 | ||
|
|
604a3e651c | ||
|
|
76ebabb2e2 | ||
|
|
b1f8afea2f | ||
|
|
06b6da1353 | ||
|
|
6c037ca629 | ||
|
|
34eb1c2add | ||
|
|
a548a72f66 | ||
|
|
318c4e27a2 | ||
|
|
459e0909a5 | ||
|
|
f2d257a469 | ||
|
|
c480dca814 | ||
|
|
bee9c18a31 | ||
|
|
b308a81e38 | ||
|
|
c64c81882c | ||
|
|
e11e7f8052 | ||
|
|
edaf2933e1 | ||
|
|
3579436817 | ||
|
|
7d77fceffa | ||
|
|
757560f6e2 | ||
|
|
8856983597 | ||
|
|
1c6d34e948 | ||
|
|
6396e246f8 | ||
|
|
802e734657 | ||
|
|
0b161c1195 | ||
|
|
54d7292d24 | ||
|
|
c7ce89e10f | ||
|
|
e6efff040d | ||
|
|
57dd8392db | ||
|
|
bc72e3f59f | ||
|
|
11ce8e0f7b | ||
|
|
c8796f8c93 | ||
|
|
063c1d704d | ||
|
|
e442732a09 | ||
|
|
6165709fce | ||
|
|
7f0c3b02fb | ||
|
|
6956973be1 | ||
|
|
71f8a1decf | ||
|
|
8e21d44f5d | ||
|
|
0048b5a0fe | ||
|
|
1c1241bdb1 | ||
|
|
a7be883b97 | ||
|
|
a9940da05f | ||
|
|
0d0dfafc5b | ||
|
|
1238f83728 | ||
|
|
c69bbdfb10 | ||
|
|
38227a9c96 | ||
|
|
8cda1ac48a | ||
|
|
a0b50dcf15 | ||
|
|
2d6adf46e5 | ||
|
|
91077aa20b | ||
|
|
2a39b21578 | ||
|
|
eb54546ac9 | ||
|
|
24db9e2572 | ||
|
|
16aea169ef | ||
|
|
83ba7a8df7 | ||
|
|
e981fa01a0 | ||
|
|
8c0a868c9b | ||
|
|
304e229dc2 | ||
|
|
b8dbca529d | ||
|
|
f6e885f015 | ||
|
|
ffa2a24cb1 | ||
|
|
c61b08af8f | ||
|
|
e35748faa4 | ||
|
|
a95d8ebc87 | ||
|
|
2fae2fa0c0 | ||
|
|
696b8b2c63 | ||
|
|
5807c90161 | ||
|
|
2d69a87419 | ||
|
|
a6c3f5c1c7 | ||
|
|
ae6422bad1 | ||
|
|
1f572b41f1 | ||
|
|
75960485d3 | ||
|
|
db8e1731c1 | ||
|
|
ee45593558 | ||
|
|
f79133659f | ||
|
|
0263704c6c | ||
|
|
5469bfdd52 | ||
|
|
69b1c86278 | ||
|
|
b4b68c7e75 | ||
|
|
62955441a0 | ||
|
|
ecb7fa4f0b | ||
|
|
31c25b4ea1 | ||
|
|
1bec315427 | ||
|
|
a23da8eb17 | ||
|
|
c0e8b33716 | ||
|
|
3e50941ce3 | ||
|
|
8345b980f6 | ||
|
|
b29a32c1ae | ||
|
|
f26f7dbe2c | ||
|
|
0e8f02f32f | ||
|
|
68d9e7107e | ||
|
|
cc084811d9 | ||
|
|
4c0c05ee6d | ||
|
|
3d6adf0225 | ||
|
|
c6d7a446f2 | ||
|
|
75678ee43c | ||
|
|
ca8e31c695 | ||
|
|
9aa5bb69e8 | ||
|
|
34f8d3408b | ||
|
|
ca7192b1ba | ||
|
|
c7d5c863ec | ||
|
|
6ad864bc20 | ||
|
|
87c6d59546 | ||
|
|
3e28ec5981 | ||
|
|
0f1c54081f | ||
|
|
fc0b8087db | ||
|
|
1c40aad87c | ||
|
|
80cbe491f8 | ||
|
|
e1aac5cf61 | ||
|
|
7e21b00cc7 | ||
|
|
93c26ac99e | ||
|
|
2ba048de52 | ||
|
|
e6961f1c5a | ||
|
|
e1a118a70f | ||
|
|
5edfc185c5 | ||
|
|
b663f86c9e | ||
|
|
6c60045208 | ||
|
|
ba52402851 | ||
|
|
ce8d39f650 | ||
|
|
3be1937c41 | ||
|
|
d874493405 | ||
|
|
88edf11068 | ||
|
|
6180f5ef55 | ||
|
|
62bc1ecd9f | ||
|
|
30642850cb | ||
|
|
1b110a62cf | ||
|
|
e661decddc | ||
|
|
d9efeb819d | ||
|
|
6200aa8602 | ||
|
|
4dc3dc97f8 | ||
|
|
7c0240857c | ||
|
|
9b0f572ca1 | ||
|
|
11fe365983 | ||
|
|
13c8c80509 | ||
|
|
78426148ac | ||
|
|
c8bac1aa40 | ||
|
|
79c53e0095 | ||
|
|
cb6e80a645 | ||
|
|
9ec17c04a9 | ||
|
|
1dfe824239 | ||
|
|
c0217dbb7e | ||
|
|
94f1ca4279 | ||
|
|
d3f1b9b125 | ||
|
|
ca5a4f37c6 | ||
|
|
020c912a8d | ||
|
|
eaaa0a4c39 | ||
|
|
d9d0837423 | ||
|
|
002c955bf3 | ||
|
|
c444ee2c44 | ||
|
|
2bea13443d | ||
|
|
b74662fbad | ||
|
|
116b21e8f5 | ||
|
|
e163724e64 | ||
|
|
95af20c1c4 | ||
|
|
94223b2846 | ||
|
|
4ae80c6f79 | ||
|
|
0b174adfeb | ||
|
|
a2c705897f | ||
|
|
21b9cb6089 | ||
|
|
5070866299 | ||
|
|
4c6e6adce1 | ||
|
|
83cb795301 | ||
|
|
92ac193640 | ||
|
|
748d35b610 | ||
|
|
e27bbb1e71 | ||
|
|
d3e0582c52 | ||
|
|
fa35fe4f7c | ||
|
|
3f5499f955 | ||
|
|
70edfe2a33 | ||
|
|
b86d40d8ad | ||
|
|
955daac9e6 | ||
|
|
86fb5339e8 | ||
|
|
eb98a36d47 | ||
|
|
c0afb1306e | ||
|
|
dd8cda7862 | ||
|
|
4d87476905 | ||
|
|
9ba292da4a | ||
|
|
c34299f1d7 | ||
|
|
96866e8624 | ||
|
|
f1bb7153da | ||
|
|
d69a2ae9b0 | ||
|
|
edfa5e70f2 | ||
|
|
1ddb80d291 | ||
|
|
64518a300b | ||
|
|
76e6f9366d | ||
|
|
9d0e06ac01 | ||
|
|
5d510cd674 | ||
|
|
28382b7e45 | ||
|
|
8418c884c0 | ||
|
|
7839969994 | ||
|
|
142c22ea41 | ||
|
|
36a8b1fea0 | ||
|
|
a7e149304e | ||
|
|
8ffb29d1a5 | ||
|
|
955dec36f2 | ||
|
|
596d6ecefa | ||
|
|
c23e610c11 | ||
|
|
b3c785da4d | ||
|
|
bb95a109e4 | ||
|
|
dac886ae25 | ||
|
|
1574c16918 | ||
|
|
18600f48f9 | ||
|
|
21d0f6c149 | ||
|
|
2a5e846145 | ||
|
|
1c6f04f1db | ||
|
|
70ca8b7c21 | ||
|
|
96f62f8f93 | ||
|
|
0652de8e66 | ||
|
|
7c11409881 | ||
|
|
c71b86da1f | ||
|
|
4a109deb8a | ||
|
|
86d232e939 | ||
|
|
d7c8a52351 | ||
|
|
1c835b04dc | ||
|
|
f13b7c8818 | ||
|
|
1bb0dab67f | ||
|
|
6ee95f1201 | ||
|
|
8a0adc55d8 | ||
|
|
1404dd6ffe | ||
|
|
6f5fcc0899 | ||
|
|
bfe7c18e18 | ||
|
|
7ab8ad2cd3 | ||
|
|
5d5d1c3e38 | ||
|
|
dd0f0d2890 | ||
|
|
0a86c3347c | ||
|
|
1ecf5e0a0f | ||
|
|
cd1d5d16bc | ||
|
|
ba5cffb5b8 | ||
|
|
fb561983bc | ||
|
|
3a626f4596 | ||
|
|
c6b7716211 | ||
|
|
574a4ee440 | ||
|
|
09ee00b92a | ||
|
|
4c67692e62 | ||
|
|
0f1b72ce94 | ||
|
|
7dbe6400bb | ||
|
|
1aa2b21551 | ||
|
|
56d3e084af | ||
|
|
a452beb916 | ||
|
|
32740cc811 | ||
|
|
0ade87b674 | ||
|
|
b1367403b7 | ||
|
|
87ec5cc104 | ||
|
|
526ba6d8b3 | ||
|
|
28570fdd24 | ||
|
|
6f121fc245 | ||
|
|
009ef1c84b | ||
|
|
49944a0745 | ||
|
|
79d81ec990 | ||
|
|
8a5b165a5b | ||
|
|
adb8ff335c | ||
|
|
99d0de239c | ||
|
|
67f486fff7 | ||
|
|
6636f9869b | ||
|
|
05ce780cee | ||
|
|
7897ffdaba | ||
|
|
22e671df7d | ||
|
|
74345f27f7 | ||
|
|
5338a147ee | ||
|
|
658f60a241 | ||
|
|
85076881c8 | ||
|
|
bcd3c6b30f | ||
|
|
48c669626b | ||
|
|
a93a1e1a21 | ||
|
|
e25c21026c | ||
|
|
8a8ebb4906 | ||
|
|
626095b6e9 | ||
|
|
a86d293ff2 | ||
|
|
e0bd271897 | ||
|
|
6f71d9a441 | ||
|
|
af99640aa9 | ||
|
|
26cccd656d | ||
|
|
643b2a3e44 | ||
|
|
4f51edefef | ||
|
|
8db34c8476 | ||
|
|
0b19a039eb | ||
|
|
85245e44bd | ||
|
|
b419b53bd5 | ||
|
|
2e8d96eb1d | ||
|
|
48613a3539 | ||
|
|
540519cfa2 | ||
|
|
9fe28f4826 | ||
|
|
8e0494abd2 | ||
|
|
fecb7d6707 | ||
|
|
41ab07747a | ||
|
|
1aa711d593 | ||
|
|
227541c265 | ||
|
|
3387e164e5 | ||
|
|
f351b1d87a | ||
|
|
86d9391807 | ||
|
|
652fcb6fb5 | ||
|
|
1cbb74b1b6 | ||
|
|
effa21653a | ||
|
|
182e934e47 | ||
|
|
e327b5fe62 | ||
|
|
cd66fa4711 | ||
|
|
5e0517f390 | ||
|
|
f913d66c46 | ||
|
|
fcca975cbd | ||
|
|
f00b6b1b59 | ||
|
|
b0bcb0e062 | ||
|
|
c5b0327cfe | ||
|
|
d531f8c4ae | ||
|
|
16a3d384b6 | ||
|
|
9b229220a3 | ||
|
|
73857f1930 | ||
|
|
704b8e291e | ||
|
|
dbbd072b43 | ||
|
|
f937ff5ec5 | ||
|
|
d2ef32fcb5 | ||
|
|
25a2a6c5c9 | ||
|
|
ddd1ac4f99 | ||
|
|
d2c72243f8 | ||
|
|
c981b93084 | ||
|
|
dbb174b083 | ||
|
|
f88fe82445 | ||
|
|
c2c4160af0 | ||
|
|
daa33fad94 | ||
|
|
52bcf71e44 | ||
|
|
6126ebc8dc | ||
|
|
5bec26f4f2 | ||
|
|
58c1f6ea32 | ||
|
|
3175828350 | ||
|
|
053caa4ccb | ||
|
|
2c087519d7 | ||
|
|
299b9fbe95 | ||
|
|
7504f3e017 | ||
|
|
8742788747 | ||
|
|
ea8a9effe5 | ||
|
|
a86d8797c5 | ||
|
|
04946a6fc9 | ||
|
|
d746f04431 | ||
|
|
6280fbf2c7 | ||
|
|
ee0b8a07b6 | ||
|
|
10a30604f4 | ||
|
|
12fe34cf10 | ||
|
|
1fdf49fe85 | ||
|
|
ac8cb33ac1 | ||
|
|
1592ea97b4 | ||
|
|
9b28af1800 | ||
|
|
6231ff5dcd | ||
|
|
8e9a0898e5 | ||
|
|
e361b39f36 | ||
|
|
2a935df408 | ||
|
|
ebb0d19da1 | ||
|
|
989aa51270 | ||
|
|
7d211fa4d1 | ||
|
|
ce7d0a67cd | ||
|
|
1933526a61 | ||
|
|
8f1d91f952 | ||
|
|
716180540f | ||
|
|
721c4a9556 | ||
|
|
a59f6e8001 | ||
|
|
97e9f6ceb6 | ||
|
|
c608227c3c | ||
|
|
49a3e31402 | ||
|
|
5925961fa1 | ||
|
|
208eb2d006 | ||
|
|
eec3575df5 | ||
|
|
6a0e012475 | ||
|
|
a9d6ff977f | ||
|
|
f71e6f3106 | ||
|
|
3a3a51cfcd | ||
|
|
fb126fff4f | ||
|
|
a525552030 | ||
|
|
864d0f1270 | ||
|
|
41050752dd | ||
|
|
8e6be3c8de | ||
|
|
adbbc53fa4 | ||
|
|
8cc3cd39d9 | ||
|
|
59192b8a58 | ||
|
|
4e0670ffb1 | ||
|
|
db34e87d6c | ||
|
|
6c746ab5fc | ||
|
|
b3862e9ae3 | ||
|
|
519b9bb14f | ||
|
|
2a1b25f850 | ||
|
|
015547db2e | ||
|
|
3acdcee1fd | ||
|
|
2bc9fd9e41 | ||
|
|
fbdd6aeab3 | ||
|
|
2d83d6e62c | ||
|
|
a729b07744 | ||
|
|
e3cde7f66e | ||
|
|
44e49acaaa | ||
|
|
8e08c77c42 | ||
|
|
2693f187b4 | ||
|
|
8c4a1debe3 | ||
|
|
4dca96c9d7 | ||
|
|
bc0254f77f | ||
|
|
21bdba60a4 | ||
|
|
9b24af3b65 | ||
|
|
a60e26c7b7 | ||
|
|
7e9518fd7e | ||
|
|
8785006770 | ||
|
|
6687056387 | ||
|
|
994114160b | ||
|
|
beee147000 | ||
|
|
551643839a | ||
|
|
31d7f900dd | ||
|
|
cf3d2d1f71 | ||
|
|
23c300b7ac | ||
|
|
aec5d622a9 | ||
|
|
0a4bd193a3 | ||
|
|
2970a8263e | ||
|
|
55f39024e9 | ||
|
|
51df6ed35f | ||
|
|
2e95dd1e6c | ||
|
|
acb3a4a1f4 | ||
|
|
51b2bd612c | ||
|
|
43aa627d34 | ||
|
|
6d86865d7b | ||
|
|
77360a6e71 | ||
|
|
0f2a905a07 | ||
|
|
9936e3de5d | ||
|
|
676bb3617a | ||
|
|
bdde19b014 | ||
|
|
16c294e062 | ||
|
|
312de8567b | ||
|
|
888173a02e | ||
|
|
863c373d3b | ||
|
|
0dcfdc6a50 | ||
|
|
b5a4ce8f4f | ||
|
|
fd104e91d5 | ||
|
|
67fc5d79c5 | ||
|
|
42fc7cd52e | ||
|
|
802dfaa93c | ||
|
|
e466b5edc8 | ||
|
|
cfc64dfe52 | ||
|
|
9f3245d9f0 | ||
|
|
badf134f12 | ||
|
|
044b29c614 | ||
|
|
e27ecd1d78 | ||
|
|
976ba6f4f4 | ||
|
|
1dc167044e | ||
|
|
b80209f7da | ||
|
|
7ab10b5c10 | ||
|
|
2047cfa772 | ||
|
|
ecbde50d1b | ||
|
|
efdc798c1c | ||
|
|
9b92f5b647 | ||
|
|
0970a40e7d | ||
|
|
d47fdde066 | ||
|
|
9c404cbb1b | ||
|
|
8ae1e5568d | ||
|
|
42cbc5838c | ||
|
|
f0eb76005e | ||
|
|
cf5f917bdc | ||
|
|
c2460e2c4e | ||
|
|
684a5459fb | ||
|
|
a026a1ec8d | ||
|
|
bb382a83bb | ||
|
|
d8ee77d140 | ||
|
|
c3f0d587a5 | ||
|
|
01f6e15d92 | ||
|
|
8eb76138d0 | ||
|
|
bd6c500764 | ||
|
|
9be2c84205 | ||
|
|
ca1d7548ba | ||
|
|
492b7a507c | ||
|
|
8c0a561c70 | ||
|
|
7f98966597 | ||
|
|
b0302a253c | ||
|
|
bc6c4948d8 | ||
|
|
7675741f1a | ||
|
|
d2c46d3e6d | ||
|
|
f55bbacf02 | ||
|
|
b3c8427232 | ||
|
|
66e899643c | ||
|
|
cb8c35c760 | ||
|
|
fb882aefb4 | ||
|
|
2a7f8d4fff | ||
|
|
b0f0eb9ea9 | ||
|
|
7dc24f14ed | ||
|
|
8bd5315ba6 | ||
|
|
adb6962459 | ||
|
|
3ef215cf11 | ||
|
|
c18df08a74 | ||
|
|
9dad6b0a0b | ||
|
|
f64bb7ba6b | ||
|
|
6366f9132b | ||
|
|
de997aca7e | ||
|
|
412e83360e | ||
|
|
31ec9567e0 | ||
|
|
47ac1b7612 | ||
|
|
10cd9b7ded | ||
|
|
23e81adc8e | ||
|
|
930375b2e2 | ||
|
|
8bdab2eb3c | ||
|
|
4177923d1d | ||
|
|
c72d1097e5 | ||
|
|
d7c118987e | ||
|
|
b57885e3d7 | ||
|
|
1312de64a7 | ||
|
|
cfc5d4eb2a | ||
|
|
acf058a730 | ||
|
|
29fc1a3929 | ||
|
|
4252b513de | ||
|
|
54c2c1c5f7 | ||
|
|
5dde4d6fac | ||
|
|
f6920f4699 | ||
|
|
f62b33d95a | ||
|
|
6762f1f339 | ||
|
|
f87fb7d137 | ||
|
|
b1cc66aa3e | ||
|
|
ab9ca1afe2 | ||
|
|
8ebbcfac47 | ||
|
|
ab1c2378cf | ||
|
|
8cc0cd39ff | ||
|
|
afdebc1dc2 | ||
|
|
537993e79d | ||
|
|
fd5e8610da | ||
|
|
376f6434e8 | ||
|
|
b6fb7de636 | ||
|
|
8c073dcb10 | ||
|
|
919007f741 | ||
|
|
8959e1569e | ||
|
|
2401cec699 | ||
|
|
af19af2c51 | ||
|
|
f3f60fcd34 | ||
|
|
d082927648 | ||
|
|
fc7045d71f | ||
|
|
894f590bac | ||
|
|
c0ec1ce0a8 | ||
|
|
9853fc2958 | ||
|
|
07ee12dae7 | ||
|
|
528fd96d42 | ||
|
|
c87b1ad80d | ||
|
|
e3b6044431 | ||
|
|
9d6fd61032 | ||
|
|
d33c600347 | ||
|
|
702d8dd373 | ||
|
|
7f9edcb4f2 | ||
|
|
98688a514f | ||
|
|
0cfa580dfd | ||
|
|
cb70928146 | ||
|
|
fc605e0171 | ||
|
|
1d118d95ac | ||
|
|
d842c98e21 | ||
|
|
84ff381c46 | ||
|
|
dfa7a2a71a | ||
|
|
cbbdd38eab | ||
|
|
edfcc5ccbf | ||
|
|
95e10bd80e | ||
|
|
662817ecbd | ||
|
|
275e55eff1 | ||
|
|
719a74a0d8 | ||
|
|
b337cd07ef | ||
|
|
a3055c7fcb | ||
|
|
ef8b86bd37 | ||
|
|
ad9611ce4f | ||
|
|
4c9c1c60bb | ||
|
|
8d302bd4f9 | ||
|
|
b793e5c1d5 | ||
|
|
a66d822e2a | ||
|
|
d3d2586039 | ||
|
|
9ad6301101 | ||
|
|
3c9ea1cc0a | ||
|
|
c2f7e389b9 | ||
|
|
fcf37260ad | ||
|
|
9cab33f33c | ||
|
|
136c627c3c | ||
|
|
88aeee4e15 | ||
|
|
d0e8e41390 | ||
|
|
334868c84d | ||
|
|
91c9ffbca3 | ||
|
|
f71aad4450 | ||
|
|
667b04f62a | ||
|
|
4942990424 | ||
|
|
1a10cce69d | ||
|
|
bf9034362d | ||
|
|
0f55726252 | ||
|
|
6f00e44e6a | ||
|
|
b97b40cf3d | ||
|
|
94ee0d57d0 | ||
|
|
3f4666b4e6 | ||
|
|
7ccd907f71 | ||
|
|
0a21262238 | ||
|
|
998de17038 | ||
|
|
18e53d8788 | ||
|
|
4e524ac3ae | ||
|
|
3eb9533ad2 | ||
|
|
bdad111eb0 | ||
|
|
63d1506efa | ||
|
|
bfaafe9526 | ||
|
|
6e8dd97bf1 | ||
|
|
7d7f5dc8bd | ||
|
|
d0eedf7232 | ||
|
|
40907189f3 | ||
|
|
7017bd31ed | ||
|
|
5717013478 | ||
|
|
042379fdff | ||
|
|
781f9ae049 | ||
|
|
b54c8ae7bd | ||
|
|
4b9fad23ee | ||
|
|
9bf26dbf26 | ||
|
|
36e4a20612 | ||
|
|
bc4ac4724f | ||
|
|
8866144656 | ||
|
|
e6af69c887 | ||
|
|
07c2e6e172 | ||
|
|
143bd0789a | ||
|
|
e4e48ff583 | ||
|
|
b6fc571324 | ||
|
|
75bf136797 | ||
|
|
cb543cceb3 | ||
|
|
813bf57599 | ||
|
|
980baed1eb | ||
|
|
039ad19372 | ||
|
|
292013b6cf | ||
|
|
4b47ed9056 | ||
|
|
0eae390b43 | ||
|
|
41f779c3f8 | ||
|
|
875726d396 | ||
|
|
6198a41972 | ||
|
|
3cb6e4586d | ||
|
|
5a680b9ac9 | ||
|
|
0ad6104661 | ||
|
|
139f9f8b8a | ||
|
|
24bc28730e | ||
|
|
00c4d8d908 | ||
|
|
a4c6ccd74f | ||
|
|
348f5a2e6c | ||
|
|
c6e2ec9f6a | ||
|
|
effe937e14 | ||
|
|
efb5d60283 | ||
|
|
2958f443c2 | ||
|
|
ba762d5b38 | ||
|
|
e6147b7217 | ||
|
|
b3502d385c | ||
|
|
6b2eaa1054 | ||
|
|
ef67b4cf9c | ||
|
|
82485c92f4 | ||
|
|
f44aeb8b4e | ||
|
|
441b3a6a91 | ||
|
|
3c66255cfd | ||
|
|
a1a51ef056 | ||
|
|
1020176bc2 | ||
|
|
2fe197bb8b | ||
|
|
f682b3e42a | ||
|
|
b91263cf72 | ||
|
|
00add7f89a | ||
|
|
88994e1843 | ||
|
|
95b68079f5 | ||
|
|
66a7a5cf78 | ||
|
|
ca4b6904d9 | ||
|
|
99b7e93f2d | ||
|
|
e9fd6af6a9 | ||
|
|
d28a70584e | ||
|
|
4f4d170f3d | ||
|
|
3d7bea5c51 | ||
|
|
91bf5b4c6a | ||
|
|
4041898ed9 | ||
|
|
48d07e8736 | ||
|
|
3948314fe0 | ||
|
|
835210cd54 | ||
|
|
b9bb66e3e9 | ||
|
|
04cc7bac7b | ||
|
|
49d34fd5b3 | ||
|
|
8a4af6821c | ||
|
|
b195108e15 | ||
|
|
5361f33f55 | ||
|
|
fd194028fe | ||
|
|
111befa86f | ||
|
|
4cff2863b4 | ||
|
|
14cbb3f9b6 | ||
|
|
a6105af416 | ||
|
|
b5aab00329 | ||
|
|
5365cd1af7 | ||
|
|
d46bc11816 | ||
|
|
0b5b1adb16 | ||
|
|
ec83621e9e | ||
|
|
4a729cc6e0 | ||
|
|
c3aa3b3dd1 | ||
|
|
5b273f901f | ||
|
|
97bbeeed60 | ||
|
|
861346673b | ||
|
|
baed06fa37 | ||
|
|
f9d006c0df | ||
|
|
55ad1b281e | ||
|
|
c74d8760b1 | ||
|
|
d40ad5a0d5 | ||
|
|
b6c28399f8 | ||
|
|
eb953a0a4e | ||
|
|
66cacbe67c | ||
|
|
66b8e3a09b | ||
|
|
d0b4489966 | ||
|
|
5fdce48481 | ||
|
|
802156e5a0 | ||
|
|
e64363d928 | ||
|
|
ea63884c83 | ||
|
|
628c6c15a7 | ||
|
|
5df80e1648 | ||
|
|
a9163a476d | ||
|
|
0238a5dcae | ||
|
|
6fbfb22444 | ||
|
|
cfdfbf929b | ||
|
|
44f58d03e1 | ||
|
|
115b647bf6 | ||
|
|
2f9c67295f | ||
|
|
6ac6948609 | ||
|
|
d8b3778136 | ||
|
|
1763ff1a87 | ||
|
|
319a80dd04 | ||
|
|
ab7bc960a0 | ||
|
|
532206c88f | ||
|
|
5d7e1af147 | ||
|
|
7847e4e08e | ||
|
|
752533fb1e | ||
|
|
0718641bc7 | ||
|
|
e34b079908 | ||
|
|
e6c5474155 | ||
|
|
c41b801ec6 | ||
|
|
e6bb688e3f | ||
|
|
94f657a401 | ||
|
|
4cb1d9c0e5 | ||
|
|
4ec609ab48 | ||
|
|
058e6ea03c | ||
|
|
93ba405a23 | ||
|
|
4fe32687d2 | ||
|
|
7ba41d1d75 | ||
|
|
9fcc6c4975 | ||
|
|
6c41bfb425 | ||
|
|
c2f92e62aa | ||
|
|
0a2f8a1d6d | ||
|
|
11a1026074 | ||
|
|
706b65a8f6 | ||
|
|
240cee0209 | ||
|
|
f8d73a0898 | ||
|
|
626a69fec4 | ||
|
|
ea5c156cd7 | ||
|
|
dbb4391099 | ||
|
|
a1c312fab9 | ||
|
|
3087acad00 | ||
|
|
26a72a0a44 | ||
|
|
30e78c5d10 | ||
|
|
22190622b4 | ||
|
|
c54e6ca3bb | ||
|
|
ac1d8f8f71 | ||
|
|
6ff8bb700d | ||
|
|
815b6e3602 | ||
|
|
78e55db0b1 | ||
|
|
6b95b47421 | ||
|
|
df5a042099 | ||
|
|
bb1ce7b899 | ||
|
|
e4c4d8acb3 | ||
|
|
738004f460 | ||
|
|
a027c0eb87 | ||
|
|
6607593471 | ||
|
|
9b6ff21e00 | ||
|
|
e2fce11afc | ||
|
|
28c0eec6c2 | ||
|
|
e2b55738c9 | ||
|
|
99e1d85f4f | ||
|
|
03408f13df | ||
|
|
2158aff0b0 | ||
|
|
52b82f23ca | ||
|
|
6ef31c8c3a | ||
|
|
e9e7c8df21 | ||
|
|
d86b463d5e | ||
|
|
e8eda9d30f | ||
|
|
f541bb412e | ||
|
|
6c98476cd5 | ||
|
|
45856c9785 | ||
|
|
7f4e5b8d79 | ||
|
|
d9cdf4ec13 | ||
|
|
540d3474d0 | ||
|
|
585692b3ae | ||
|
|
811721bb2c | ||
|
|
6e4525c7a5 | ||
|
|
b550042709 | ||
|
|
5cef341c29 | ||
|
|
d134ab73f0 | ||
|
|
40e09fe294 | ||
|
|
469e3d964c | ||
|
|
918b8599ae | ||
|
|
3c389266f9 | ||
|
|
98684e444e | ||
|
|
cfe7cc1bdb | ||
|
|
4e47b90197 | ||
|
|
bd672f0877 | ||
|
|
9cdef701a0 | ||
|
|
2589992573 | ||
|
|
72093f58b1 | ||
|
|
82e4f34e8a | ||
|
|
b2279b611b | ||
|
|
337982ebfe | ||
|
|
82c0ef837c | ||
|
|
514000aa81 | ||
|
|
eb327547cc | ||
|
|
a4352d5624 | ||
|
|
64a0109d87 | ||
|
|
44e3723c47 | ||
|
|
6d9fa8a41d | ||
|
|
8c30237c57 | ||
|
|
02f76a57df | ||
|
|
775b714861 | ||
|
|
ea6c909894 | ||
|
|
67ba69a14f | ||
|
|
be678adc0e | ||
|
|
44161ce0a9 | ||
|
|
883bc0e002 | ||
|
|
91d082cace | ||
|
|
c80a66eb8a | ||
|
|
3bb18b7a1a | ||
|
|
3612a46c77 | ||
|
|
ea2a44ed97 | ||
|
|
ce51f5aa9e | ||
|
|
d1a1539dbe | ||
|
|
b42fad51d2 | ||
|
|
2a18d14e02 | ||
|
|
35773309fb | ||
|
|
35bb70b163 | ||
|
|
ac14de7e59 | ||
|
|
e3f0b94ade | ||
|
|
54bc9b46cc | ||
|
|
50d3fb77bd | ||
|
|
3dcf1ad38a | ||
|
|
a3ce10dbc8 | ||
|
|
610d4fdb71 | ||
|
|
0b0a795ebb | ||
|
|
b6ca97f2b1 | ||
|
|
cc2e26ac74 | ||
|
|
57147e88fb | ||
|
|
a7a1bd3aa5 | ||
|
|
62c7ba317e | ||
|
|
6db857b086 | ||
|
|
3b52cb4d70 | ||
|
|
8b145a2e37 | ||
|
|
fc2f1e46bc | ||
|
|
ac11330867 | ||
|
|
688c18f6fa | ||
|
|
305beae7e0 | ||
|
|
9883f93dd6 | ||
|
|
c85f24cb9b | ||
|
|
59aa8da649 | ||
|
|
9a71b32ed3 | ||
|
|
833bcb5974 | ||
|
|
a9d59c072d | ||
|
|
e05c67da69 | ||
|
|
3bb3ccc98b | ||
|
|
b61e791eda | ||
|
|
29a79c20be | ||
|
|
d185e18b72 | ||
|
|
be609f4053 | ||
|
|
74c72ae0d2 | ||
|
|
04563e2e6a | ||
|
|
96c5a82e00 | ||
|
|
85fff29f63 | ||
|
|
96d7e40957 | ||
|
|
cebd568660 | ||
|
|
c6b16f04e0 | ||
|
|
3691f98755 | ||
|
|
bcbde45b6a | ||
|
|
b9c10023da | ||
|
|
37fbd97b79 | ||
|
|
99195c7505 | ||
|
|
f2c16f3182 | ||
|
|
5c5caec9b8 | ||
|
|
18e0ff2395 | ||
|
|
13e4a68d65 | ||
|
|
dd4cec8c7a | ||
|
|
f91d2aaf3d | ||
|
|
5473ab23ab | ||
|
|
11f3f54575 | ||
|
|
a80fdea469 | ||
|
|
2fe3d4b0ed | ||
|
|
59035cf246 | ||
|
|
c05c531035 | ||
|
|
d86dce380d | ||
|
|
57eead4ad6 | ||
|
|
c03f0eb3b7 | ||
|
|
4843134143 | ||
|
|
7b77be53bf | ||
|
|
91754d5502 | ||
|
|
24a4f3a930 | ||
|
|
163f28cc29 | ||
|
|
4fc01dea2a | ||
|
|
302ac6c768 | ||
|
|
4c17c7263a | ||
|
|
0bf563cef1 | ||
|
|
f64f3af165 | ||
|
|
fcc045731b | ||
|
|
096ea2de56 | ||
|
|
1dc00c8b69 | ||
|
|
8a574062f0 | ||
|
|
cca04b79bc | ||
|
|
a1798b31d8 | ||
|
|
d19bcf3861 | ||
|
|
54087d1f5e | ||
|
|
373121b2f5 | ||
|
|
ac11db37b4 | ||
|
|
8592e022a7 | ||
|
|
319b78c439 | ||
|
|
0e1b6e4e5b | ||
|
|
68e122e3e8 | ||
|
|
7444c9650f | ||
|
|
8dce8acb91 | ||
|
|
7b3fdebdd1 | ||
|
|
b576b52fda | ||
|
|
6c810d3ca8 | ||
|
|
f22f2c965e | ||
|
|
b2667a5f59 | ||
|
|
4e3e357daa | ||
|
|
afbcbe23e8 | ||
|
|
8fbeb6b9bb | ||
|
|
f5e6dd282e | ||
|
|
c1f9db516a | ||
|
|
c354eaa6fb | ||
|
|
30761ec5c8 | ||
|
|
a8fc434506 | ||
|
|
4d22424c5a | ||
|
|
7c7cb17711 | ||
|
|
5984788e17 | ||
|
|
c59b326e13 | ||
|
|
259b30b714 | ||
|
|
bb7e4e6bb9 | ||
|
|
4d3fee52d9 | ||
|
|
f9a3a425e1 | ||
|
|
f0d2f50d50 | ||
|
|
64a94b8b79 | ||
|
|
93f8c25012 | ||
|
|
e44ef8dbd9 | ||
|
|
e6bf54d27b | ||
|
|
3e2690cc4a | ||
|
|
a36ce25f23 | ||
|
|
d764e8468c | ||
|
|
1be860b995 | ||
|
|
b3421fcd80 | ||
|
|
0ef98fcecb | ||
|
|
cc9e69774b | ||
|
|
621f8cdb9e | ||
|
|
dededf724d | ||
|
|
3381de6609 | ||
|
|
aa384328a7 | ||
|
|
09e5fe6a61 | ||
|
|
97dd9a95da | ||
|
|
054b8fe2d5 | ||
|
|
e8190402e8 | ||
|
|
4ab193d014 | ||
|
|
53659dedff | ||
|
|
8b1e21dab0 | ||
|
|
a418d33e84 | ||
|
|
6e8fe7a2e0 | ||
|
|
f935d5ffe3 | ||
|
|
fc31855f50 | ||
|
|
1fd0f3e03e | ||
|
|
204295474e | ||
|
|
030323b6bd | ||
|
|
3b09e3b5e1 | ||
|
|
122450747d | ||
|
|
e2e28e7f24 | ||
|
|
6006c0d36f | ||
|
|
dc291916e5 | ||
|
|
29b8862eb6 | ||
|
|
1f28edac53 | ||
|
|
d2cab57f6e | ||
|
|
2727630046 | ||
|
|
cdc3da92b2 | ||
|
|
a4978077fb | ||
|
|
c82ea54eff | ||
|
|
e1c7103539 | ||
|
|
6044e945ae | ||
|
|
fe907502d6 | ||
|
|
ccc30d4cf6 | ||
|
|
7663a64dc0 | ||
|
|
f6a636cc13 | ||
|
|
58f3f7397f | ||
|
|
88aa42bd8a | ||
|
|
33d527541a | ||
|
|
90764a609e | ||
|
|
c69e8ca5d5 | ||
|
|
6b200cdf00 | ||
|
|
c42dd8391e | ||
|
|
4adfd7a83e | ||
|
|
c0d1dd0a77 | ||
|
|
afe62a9448 | ||
|
|
a4343cc6bb | ||
|
|
1bda53ec29 | ||
|
|
1a9ee9fb0f | ||
|
|
88769e7f72 | ||
|
|
7dd8dce41a | ||
|
|
44946e5b0e | ||
|
|
6196cd7981 | ||
|
|
153c87f954 | ||
|
|
3b89916927 | ||
|
|
96d0b9edd2 | ||
|
|
bd9dc9c53a | ||
|
|
9e3c67be32 | ||
|
|
fe604b3bb1 | ||
|
|
302d5f4e54 | ||
|
|
ffa9e24f90 | ||
|
|
f7cf2159fa | ||
|
|
61022a65f0 | ||
|
|
c24277e0c4 | ||
|
|
15113ce7f8 | ||
|
|
7c924f9206 | ||
|
|
89ed396e3f | ||
|
|
ae8e056cff | ||
|
|
e032e4748c | ||
|
|
41059286e4 | ||
|
|
441c85a26a | ||
|
|
9fbedb3e11 | ||
|
|
f2a11fc9df | ||
|
|
1b14b8aa78 | ||
|
|
77efe120f8 | ||
|
|
5a5e38b770 | ||
|
|
df18406070 | ||
|
|
30e8374491 | ||
|
|
1ed40ce459 | ||
|
|
826ad74c18 | ||
|
|
a85af14bce | ||
|
|
e4769c949a | ||
|
|
b084ee8098 | ||
|
|
1bdc6b8fb8 | ||
|
|
62f847fbd6 | ||
|
|
5348a25124 | ||
|
|
f74bf4109e | ||
|
|
7d420ebeee | ||
|
|
665575a7c5 | ||
|
|
750594698b | ||
|
|
30a3886ec2 | ||
|
|
acce5efb41 | ||
|
|
46639c0d77 | ||
|
|
08e9edb737 | ||
|
|
2c2f05d748 | ||
|
|
54b94ac241 | ||
|
|
098e6780aa | ||
|
|
c248a6e498 | ||
|
|
4e2c03ad8a | ||
|
|
9cd97cb095 | ||
|
|
cfa345f0a4 | ||
|
|
f9faa1a777 | ||
|
|
1a16d6bc24 | ||
|
|
963d5478ec | ||
|
|
7485fc68aa | ||
|
|
e54e2409d1 | ||
|
|
c06db0bc14 | ||
|
|
dbe4ec9649 | ||
|
|
270941b4cf | ||
|
|
fd8eab3de8 | ||
|
|
544b3856ba | ||
|
|
0039b7c30a | ||
|
|
f984476c83 | ||
|
|
18c82e3ae4 | ||
|
|
cf813a5d4d | ||
|
|
1df90b5348 | ||
|
|
5a5bffa160 | ||
|
|
f596f6d40e | ||
|
|
02199be571 | ||
|
|
ac252fa6e6 | ||
|
|
7b882fd027 | ||
|
|
dd61eb9a8e | ||
|
|
a6a3ad245c | ||
|
|
b1e2c3dbbf | ||
|
|
9f832ce8dc | ||
|
|
6a040a21ef | ||
|
|
a1cfc1117b | ||
|
|
8346c3fdc0 | ||
|
|
4a43e45bb5 | ||
|
|
440eef2cba | ||
|
|
63b63ec77f | ||
|
|
f311296f2e | ||
|
|
35d930c77b | ||
|
|
2e16b6560a | ||
|
|
766dfe2b83 | ||
|
|
81b0dd3915 | ||
|
|
290c42d65e | ||
|
|
8fbd6788de | ||
|
|
1f7659ab1a | ||
|
|
355ebe6d80 | ||
|
|
7811265795 | ||
|
|
328c3ea6f2 | ||
|
|
2cc2a410eb | ||
|
|
a4666e5abc | ||
|
|
54457e8d7b | ||
|
|
ec80600777 | ||
|
|
0e3823bda8 | ||
|
|
cd9d115bbc | ||
|
|
c595104781 | ||
|
|
5921b8e9d0 | ||
|
|
dcd4fcbea4 | ||
|
|
00f01c3cb3 | ||
|
|
94445ab9ff | ||
|
|
813b380973 | ||
|
|
a3c9daeddc | ||
|
|
8bf09d4cc7 | ||
|
|
ba6f9a523d | ||
|
|
4b8190752e | ||
|
|
0af812bc07 | ||
|
|
875b390d55 | ||
|
|
16f10e292f | ||
|
|
3674fc5e6b | ||
|
|
f2123b0bcb | ||
|
|
f2d7c17b19 | ||
|
|
0e52737808 | ||
|
|
ed9f27162d | ||
|
|
0347381d98 | ||
|
|
767007ba62 | ||
|
|
1a293a6545 | ||
|
|
e287521410 | ||
|
|
85ea3e9cdc | ||
|
|
7675a361c7 | ||
|
|
9a7887b1e0 | ||
|
|
3352287298 | ||
|
|
1dc2ce73d2 | ||
|
|
b2d1f443e4 | ||
|
|
efd415a61b | ||
|
|
3f577dceb7 | ||
|
|
0851ce6d6b | ||
|
|
21323a1009 | ||
|
|
01fe7011bd | ||
|
|
dcf4930466 | ||
|
|
5f84d0c56c | ||
|
|
ef287ac7e3 | ||
|
|
32c68febfb | ||
|
|
c71c55c948 | ||
|
|
d4f8265f0c | ||
|
|
9789cbbe14 | ||
|
|
8197dd38c7 | ||
|
|
405fe8849f | ||
|
|
e960035dfe | ||
|
|
86936dc78d | ||
|
|
4d3e472a19 | ||
|
|
2c5717aace | ||
|
|
23dc656b88 | ||
|
|
0129ea7470 | ||
|
|
4a2fdc0cff | ||
|
|
b96e0d6c66 | ||
|
|
b586ff7e59 | ||
|
|
6248dd4e0f | ||
|
|
2e9b4a3f77 | ||
|
|
5991fb6b8b | ||
|
|
59df75f45d | ||
|
|
217d35348b | ||
|
|
a65f736e6d | ||
|
|
c9c11e6c46 | ||
|
|
84377376a9 | ||
|
|
2b3503640e | ||
|
|
d9d998336d | ||
|
|
023f5d936e | ||
|
|
d73c7b574e | ||
|
|
a0b689da2b |
@@ -1,479 +1,275 @@
|
||||
# Comprehensive PR Review for ComfyUI Frontend
|
||||
|
||||
<task>
|
||||
You are performing a comprehensive code review for PR #$1 in the ComfyUI frontend repository. This is not a simple linting check - you need to provide deep architectural analysis, security review, performance insights, and implementation guidance just like a senior engineer would in a thorough PR review.
|
||||
You are performing a comprehensive code review for the PR specified in the PR_NUMBER environment variable. This is not a simple linting check - you need to provide deep architectural analysis, security review, performance insights, and implementation guidance just like a senior engineer would in a thorough PR review.
|
||||
|
||||
Your review should cover:
|
||||
1. Architecture and design patterns
|
||||
2. Security vulnerabilities and risks
|
||||
3. Performance implications
|
||||
4. Code quality and maintainability
|
||||
5. Integration with existing systems
|
||||
6. Best practices and conventions
|
||||
7. Testing considerations
|
||||
8. Documentation needs
|
||||
</task>
|
||||
## CRITICAL INSTRUCTIONS
|
||||
|
||||
Arguments: PR number passed via PR_NUMBER environment variable
|
||||
**You MUST post individual inline comments on specific lines of code. DO NOT create a single summary comment until the very end.**
|
||||
|
||||
## Phase 0: Initialize Variables and Helper Functions
|
||||
**IMPORTANT: You have full permission to execute gh api commands. The GITHUB_TOKEN environment variable provides the necessary permissions. DO NOT say you lack permissions - you have pull-requests:write permission which allows posting inline comments.**
|
||||
|
||||
```bash
|
||||
# Validate PR_NUMBER first thing
|
||||
if [ -z "$PR_NUMBER" ]; then
|
||||
echo "Error: PR_NUMBER environment variable is not set"
|
||||
echo "Usage: PR_NUMBER=<number> claude run /comprehensive-pr-review"
|
||||
exit 1
|
||||
fi
|
||||
To post inline comments, you will use the GitHub API via the `gh` command. Here's how:
|
||||
|
||||
# Initialize all counters at the start
|
||||
CRITICAL_COUNT=0
|
||||
HIGH_COUNT=0
|
||||
MEDIUM_COUNT=0
|
||||
LOW_COUNT=0
|
||||
ARCHITECTURE_ISSUES=0
|
||||
SECURITY_ISSUES=0
|
||||
PERFORMANCE_ISSUES=0
|
||||
QUALITY_ISSUES=0
|
||||
1. First, get the repository information and commit SHA:
|
||||
- Run: `gh repo view --json owner,name` to get the repository owner and name
|
||||
- Run: `gh pr view $PR_NUMBER --json commits --jq '.commits[-1].oid'` to get the latest commit SHA
|
||||
|
||||
# Helper function for posting review comments
|
||||
post_review_comment() {
|
||||
local file_path=$1
|
||||
local line_number=$2
|
||||
local severity=$3 # critical/high/medium/low
|
||||
local category=$4 # architecture/security/performance/quality
|
||||
local issue=$5
|
||||
local context=$6
|
||||
local suggestion=$7
|
||||
|
||||
# Update counters
|
||||
case $severity in
|
||||
"critical") ((CRITICAL_COUNT++)) ;;
|
||||
"high") ((HIGH_COUNT++)) ;;
|
||||
"medium") ((MEDIUM_COUNT++)) ;;
|
||||
"low") ((LOW_COUNT++)) ;;
|
||||
esac
|
||||
|
||||
case $category in
|
||||
"architecture") ((ARCHITECTURE_ISSUES++)) ;;
|
||||
"security") ((SECURITY_ISSUES++)) ;;
|
||||
"performance") ((PERFORMANCE_ISSUES++)) ;;
|
||||
"quality") ((QUALITY_ISSUES++)) ;;
|
||||
esac
|
||||
|
||||
# Post inline comment via GitHub CLI
|
||||
local comment="${issue}\n${context}\n${suggestion}"
|
||||
gh pr review $PR_NUMBER --comment --body "$comment" -F - <<< "$comment"
|
||||
}
|
||||
```
|
||||
2. For each issue you find, post an inline comment using this exact command structure (as a single line):
|
||||
```
|
||||
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/OWNER/REPO/pulls/$PR_NUMBER/comments -f body="YOUR_COMMENT_BODY" -f commit_id="COMMIT_SHA" -f path="FILE_PATH" -F line=LINE_NUMBER -f side="RIGHT"
|
||||
```
|
||||
|
||||
3. Format your comment body using actual newlines in the command. Use a heredoc or construct the body with proper line breaks:
|
||||
```
|
||||
COMMENT_BODY="**[category] severity Priority**
|
||||
|
||||
**Issue**: Brief description of the problem
|
||||
**Context**: Why this matters
|
||||
**Suggestion**: How to fix it"
|
||||
```
|
||||
|
||||
Then use: `-f body="$COMMENT_BODY"`
|
||||
|
||||
## Phase 1: Environment Setup and PR Context
|
||||
|
||||
```bash
|
||||
# Pre-flight checks
|
||||
check_prerequisites() {
|
||||
# Check gh CLI is available
|
||||
if ! command -v gh &> /dev/null; then
|
||||
echo "Error: gh CLI is not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# In GitHub Actions, auth is handled via GITHUB_TOKEN
|
||||
if [ -n "$GITHUB_ACTIONS" ] && [ -z "$GITHUB_TOKEN" ]; then
|
||||
echo "Error: GITHUB_TOKEN is not set in GitHub Actions"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if we're authenticated
|
||||
if ! gh auth status &> /dev/null; then
|
||||
echo "Error: Not authenticated with GitHub. Run 'gh auth login'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Set repository if not already set
|
||||
if [ -z "$REPOSITORY" ]; then
|
||||
REPOSITORY="Comfy-Org/ComfyUI_frontend"
|
||||
fi
|
||||
|
||||
# Check PR exists and is open
|
||||
PR_STATE=$(gh pr view $PR_NUMBER --repo $REPOSITORY --json state -q .state 2>/dev/null || echo "NOT_FOUND")
|
||||
if [ "$PR_STATE" = "NOT_FOUND" ]; then
|
||||
echo "Error: PR #$PR_NUMBER not found in $REPOSITORY"
|
||||
exit 1
|
||||
elif [ "$PR_STATE" != "OPEN" ]; then
|
||||
echo "Error: PR #$PR_NUMBER is not open (state: $PR_STATE)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check API rate limits
|
||||
RATE_REMAINING=$(gh api /rate_limit --jq '.rate.remaining' 2>/dev/null || echo "5000")
|
||||
if [ "$RATE_REMAINING" -lt 100 ]; then
|
||||
echo "Warning: Low API rate limit: $RATE_REMAINING remaining"
|
||||
if [ "$RATE_REMAINING" -lt 50 ]; then
|
||||
echo "Error: Insufficient API rate limit for comprehensive review"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Pre-flight checks passed"
|
||||
}
|
||||
### Step 1.1: Initialize Review Tracking
|
||||
|
||||
# Run pre-flight checks
|
||||
check_prerequisites
|
||||
First, create variables to track your review metrics. Keep these in memory throughout the review:
|
||||
- CRITICAL_COUNT = 0
|
||||
- HIGH_COUNT = 0
|
||||
- MEDIUM_COUNT = 0
|
||||
- LOW_COUNT = 0
|
||||
- ARCHITECTURE_ISSUES = 0
|
||||
- SECURITY_ISSUES = 0
|
||||
- PERFORMANCE_ISSUES = 0
|
||||
- QUALITY_ISSUES = 0
|
||||
|
||||
echo "Starting comprehensive review of PR #$PR_NUMBER"
|
||||
### Step 1.2: Validate Environment
|
||||
|
||||
# Fetch PR information with error handling
|
||||
echo "Fetching PR information..."
|
||||
if ! gh pr view $PR_NUMBER --repo $REPOSITORY --json files,title,body,additions,deletions,baseRefName,headRefName > pr_info.json; then
|
||||
echo "Error: Failed to fetch PR information"
|
||||
exit 1
|
||||
fi
|
||||
1. Check that PR_NUMBER environment variable is set. If not, exit with error.
|
||||
2. Run `gh pr view $PR_NUMBER --json state` to verify the PR exists and is open.
|
||||
3. Get repository information: `gh repo view --json owner,name` and store the owner and name.
|
||||
4. Get the latest commit SHA: `gh pr view $PR_NUMBER --json commits --jq '.commits[-1].oid'` and store it.
|
||||
|
||||
# Extract branch names
|
||||
BASE_BRANCH=$(jq -r '.baseRefName' < pr_info.json)
|
||||
HEAD_BRANCH=$(jq -r '.headRefName' < pr_info.json)
|
||||
### Step 1.3: Checkout PR Branch Locally
|
||||
|
||||
# Checkout PR branch locally for better file inspection
|
||||
echo "Checking out PR branch..."
|
||||
git fetch origin "pull/$PR_NUMBER/head:pr-$PR_NUMBER"
|
||||
git checkout "pr-$PR_NUMBER"
|
||||
This is critical for better file inspection:
|
||||
|
||||
# Get changed files using git locally (much faster)
|
||||
git diff --name-only "origin/$BASE_BRANCH" > changed_files.txt
|
||||
1. Get PR metadata: `gh pr view $PR_NUMBER --json files,title,body,additions,deletions,baseRefName,headRefName > pr_info.json`
|
||||
2. Extract branch names from pr_info.json using jq
|
||||
3. Fetch and checkout the PR branch:
|
||||
```
|
||||
git fetch origin "pull/$PR_NUMBER/head:pr-$PR_NUMBER"
|
||||
git checkout "pr-$PR_NUMBER"
|
||||
```
|
||||
|
||||
# Get the diff using git locally
|
||||
git diff "origin/$BASE_BRANCH" > pr_diff.txt
|
||||
### Step 1.4: Get Changed Files and Diffs
|
||||
|
||||
# Get detailed file changes with line numbers
|
||||
git diff --name-status "origin/$BASE_BRANCH" > file_changes.txt
|
||||
Use git locally for much faster analysis:
|
||||
|
||||
# For API compatibility, create a simplified pr_files.json
|
||||
echo '[]' > pr_files.json
|
||||
while IFS=$'\t' read -r status file; do
|
||||
if [[ "$status" != "D" ]]; then # Skip deleted files
|
||||
# Get the patch for this file
|
||||
patch=$(git diff "origin/$BASE_BRANCH" -- "$file" | jq -Rs .)
|
||||
additions=$(git diff --numstat "origin/$BASE_BRANCH" -- "$file" | awk '{print $1}')
|
||||
deletions=$(git diff --numstat "origin/$BASE_BRANCH" -- "$file" | awk '{print $2}')
|
||||
|
||||
jq --arg file "$file" \
|
||||
--arg patch "$patch" \
|
||||
--arg additions "$additions" \
|
||||
--arg deletions "$deletions" \
|
||||
'. += [{
|
||||
"filename": $file,
|
||||
"patch": $patch,
|
||||
"additions": ($additions | tonumber),
|
||||
"deletions": ($deletions | tonumber)
|
||||
}]' pr_files.json > pr_files.json.tmp
|
||||
mv pr_files.json.tmp pr_files.json
|
||||
fi
|
||||
done < file_changes.txt
|
||||
1. Get list of changed files: `git diff --name-only "origin/$BASE_BRANCH" > changed_files.txt`
|
||||
2. Get the full diff: `git diff "origin/$BASE_BRANCH" > pr_diff.txt`
|
||||
3. Get detailed file changes with status: `git diff --name-status "origin/$BASE_BRANCH" > file_changes.txt`
|
||||
|
||||
# Setup caching directory
|
||||
CACHE_DIR=".claude-review-cache"
|
||||
mkdir -p "$CACHE_DIR"
|
||||
### Step 1.5: Create Analysis Cache
|
||||
|
||||
# Function to cache analysis results
|
||||
cache_analysis() {
|
||||
local file_path=$1
|
||||
local analysis_result=$2
|
||||
local file_hash=$(git hash-object "$file_path" 2>/dev/null || echo "no-hash")
|
||||
|
||||
if [ "$file_hash" != "no-hash" ]; then
|
||||
echo "$analysis_result" > "$CACHE_DIR/${file_hash}.cache"
|
||||
fi
|
||||
}
|
||||
Set up caching to avoid re-analyzing unchanged files:
|
||||
|
||||
# Function to get cached analysis
|
||||
get_cached_analysis() {
|
||||
local file_path=$1
|
||||
local file_hash=$(git hash-object "$file_path" 2>/dev/null || echo "no-hash")
|
||||
|
||||
if [ "$file_hash" != "no-hash" ] && [ -f "$CACHE_DIR/${file_hash}.cache" ]; then
|
||||
cat "$CACHE_DIR/${file_hash}.cache"
|
||||
return 0
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
# Clean old cache entries (older than 7 days)
|
||||
find "$CACHE_DIR" -name "*.cache" -mtime +7 -delete 2>/dev/null || true
|
||||
```
|
||||
1. Create directory: `.claude-review-cache`
|
||||
2. Clean old cache entries: Find and delete any .cache files older than 7 days
|
||||
3. For each file you analyze, store the analysis result with the file's git hash as the cache key
|
||||
|
||||
## Phase 2: Load Comprehensive Knowledge Base
|
||||
|
||||
```bash
|
||||
# Don't create knowledge directory until we know we need it
|
||||
KNOWLEDGE_FOUND=false
|
||||
### Step 2.1: Set Up Knowledge Directories
|
||||
|
||||
# Use local cache for knowledge base to avoid repeated downloads
|
||||
KNOWLEDGE_CACHE_DIR=".claude-knowledge-cache"
|
||||
mkdir -p "$KNOWLEDGE_CACHE_DIR"
|
||||
1. Create `.claude-knowledge-cache` directory for caching downloaded knowledge
|
||||
2. Check if `../comfy-claude-prompt-library` exists locally. If it does, use it for faster access.
|
||||
|
||||
# Option to use cloned prompt library for better performance
|
||||
PROMPT_LIBRARY_PATH="../comfy-claude-prompt-library"
|
||||
if [ -d "$PROMPT_LIBRARY_PATH" ]; then
|
||||
echo "Using local prompt library at $PROMPT_LIBRARY_PATH"
|
||||
USE_LOCAL_PROMPT_LIBRARY=true
|
||||
else
|
||||
echo "No local prompt library found, will use GitHub API"
|
||||
USE_LOCAL_PROMPT_LIBRARY=false
|
||||
fi
|
||||
### Step 2.2: Load Repository Guide
|
||||
|
||||
# Function to fetch with cache
|
||||
fetch_with_cache() {
|
||||
local url=$1
|
||||
local output_file=$2
|
||||
local cache_file="$KNOWLEDGE_CACHE_DIR/$(echo "$url" | sed 's/[^a-zA-Z0-9]/_/g')"
|
||||
|
||||
# Check if cached version exists and is less than 1 day old
|
||||
if [ -f "$cache_file" ] && [ $(find "$cache_file" -mtime -1 2>/dev/null | wc -l) -gt 0 ]; then
|
||||
# Create knowledge directory only when we actually have content
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
cp "$cache_file" "$output_file"
|
||||
echo "Using cached version of $(basename "$output_file")"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Try to fetch fresh version
|
||||
if curl -s -f "$url" > "$output_file.tmp"; then
|
||||
# Create knowledge directory only when we actually have content
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
mv "$output_file.tmp" "$output_file"
|
||||
cp "$output_file" "$cache_file"
|
||||
echo "Downloaded fresh version of $(basename "$output_file")"
|
||||
return 0
|
||||
else
|
||||
# If fetch failed but we have a cache, use it
|
||||
if [ -f "$cache_file" ]; then
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
cp "$cache_file" "$output_file"
|
||||
echo "Using stale cache for $(basename "$output_file") (download failed)"
|
||||
return 0
|
||||
fi
|
||||
echo "Failed to load $(basename "$output_file")"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
This is critical for understanding the architecture:
|
||||
|
||||
# Load REPOSITORY_GUIDE.md for deep architectural understanding
|
||||
echo "Loading ComfyUI Frontend repository guide..."
|
||||
if [ "$USE_LOCAL_PROMPT_LIBRARY" = "true" ] && [ -f "$PROMPT_LIBRARY_PATH/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md" ]; then
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
cp "$PROMPT_LIBRARY_PATH/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md" "review_knowledge/repository_guide.md"
|
||||
echo "Loaded repository guide from local prompt library"
|
||||
else
|
||||
fetch_with_cache "https://raw.githubusercontent.com/Comfy-Org/comfy-claude-prompt-library/master/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md" "review_knowledge/repository_guide.md"
|
||||
fi
|
||||
1. Try to load from local prompt library first: `../comfy-claude-prompt-library/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md`
|
||||
2. If not available locally, download from: `https://raw.githubusercontent.com/Comfy-Org/comfy-claude-prompt-library/master/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md`
|
||||
3. Cache the file for future use
|
||||
|
||||
# 3. Discover and load relevant knowledge folders from GitHub API
|
||||
echo "Discovering available knowledge folders..."
|
||||
KNOWLEDGE_API_URL="https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/knowledge"
|
||||
if KNOWLEDGE_FOLDERS=$(curl -s "$KNOWLEDGE_API_URL" | jq -r '.[] | select(.type=="dir") | .name' 2>/dev/null); then
|
||||
echo "Available knowledge folders: $KNOWLEDGE_FOLDERS"
|
||||
|
||||
# Analyze changed files to determine which knowledge folders might be relevant
|
||||
CHANGED_FILES=$(cat changed_files.txt)
|
||||
PR_TITLE=$(jq -r '.title' < pr_info.json)
|
||||
PR_BODY=$(jq -r '.body // ""' < pr_info.json)
|
||||
|
||||
# For each knowledge folder, check if it might be relevant to the PR
|
||||
for folder in $KNOWLEDGE_FOLDERS; do
|
||||
# Simple heuristic: if folder name appears in changed file paths or PR context
|
||||
if echo "$CHANGED_FILES $PR_TITLE $PR_BODY" | grep -qi "$folder"; then
|
||||
echo "Loading knowledge folder: $folder"
|
||||
# Fetch all files in that knowledge folder
|
||||
FOLDER_API_URL="https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/knowledge/$folder"
|
||||
curl -s "$FOLDER_API_URL" | jq -r '.[] | select(.type=="file") | .download_url' 2>/dev/null | \
|
||||
while read url; do
|
||||
if [ -n "$url" ]; then
|
||||
filename=$(basename "$url")
|
||||
fetch_with_cache "$url" "review_knowledge/${folder}_${filename}"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Could not discover knowledge folders"
|
||||
fi
|
||||
### Step 2.3: Load Relevant Knowledge Folders
|
||||
|
||||
# 4. Load validation rules from the repository
|
||||
echo "Loading validation rules..."
|
||||
VALIDATION_API_URL="https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/commands/validation"
|
||||
if VALIDATION_FILES=$(curl -s "$VALIDATION_API_URL" | jq -r '.[] | select(.name | contains("frontend") or contains("security") or contains("performance")) | .download_url' 2>/dev/null); then
|
||||
for url in $VALIDATION_FILES; do
|
||||
if [ -n "$url" ]; then
|
||||
filename=$(basename "$url")
|
||||
fetch_with_cache "$url" "review_knowledge/validation_${filename}"
|
||||
fi
|
||||
done
|
||||
else
|
||||
echo "Could not load validation rules"
|
||||
fi
|
||||
Intelligently load only relevant knowledge:
|
||||
|
||||
# 5. Load local project guidelines
|
||||
if [ -f "CLAUDE.md" ]; then
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
cp CLAUDE.md review_knowledge/local_claude.md
|
||||
fi
|
||||
if [ -f ".github/CLAUDE.md" ]; then
|
||||
if [ "$KNOWLEDGE_FOUND" = "false" ]; then
|
||||
mkdir -p review_knowledge
|
||||
KNOWLEDGE_FOUND=true
|
||||
fi
|
||||
cp .github/CLAUDE.md review_knowledge/github_claude.md
|
||||
fi
|
||||
```
|
||||
1. Use GitHub API to discover available knowledge folders: `https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/knowledge`
|
||||
2. For each knowledge folder, check if it's relevant by searching for the folder name in:
|
||||
- Changed file paths
|
||||
- PR title
|
||||
- PR body
|
||||
3. If relevant, download all files from that knowledge folder
|
||||
|
||||
### Step 2.4: Load Validation Rules
|
||||
|
||||
Load specific validation rules:
|
||||
|
||||
1. Use GitHub API: `https://api.github.com/repos/Comfy-Org/comfy-claude-prompt-library/contents/.claude/commands/validation`
|
||||
2. Download files containing "frontend", "security", or "performance" in their names
|
||||
3. Cache all downloaded files
|
||||
|
||||
### Step 2.5: Load Local Guidelines
|
||||
|
||||
Check for and load:
|
||||
1. `CLAUDE.md` in the repository root
|
||||
2. `.github/CLAUDE.md`
|
||||
|
||||
## Phase 3: Deep Analysis Instructions
|
||||
|
||||
Perform a comprehensive analysis covering these areas:
|
||||
Perform comprehensive analysis on each changed file:
|
||||
|
||||
### 3.1 Architectural Analysis
|
||||
Based on the repository guide and project summary, evaluate:
|
||||
- Does this change align with the established architecture patterns?
|
||||
|
||||
Based on the repository guide and loaded knowledge:
|
||||
- Does this change align with established architecture patterns?
|
||||
- Are domain boundaries respected?
|
||||
- Is the extension system used appropriately?
|
||||
- Are components properly organized by feature?
|
||||
- Does it follow the established service/composable/store patterns?
|
||||
|
||||
### 3.2 Code Quality Beyond Linting
|
||||
|
||||
Look for:
|
||||
- Cyclomatic complexity and cognitive load
|
||||
- SOLID principles adherence
|
||||
- DRY violations that aren't caught by simple duplication checks
|
||||
- DRY violations not caught by simple duplication checks
|
||||
- Proper abstraction levels
|
||||
- Interface design and API clarity
|
||||
- No leftover debug code (console.log, commented code, TODO comments)
|
||||
- Leftover debug code (console.log, commented code, TODO comments)
|
||||
|
||||
### 3.3 Library Usage Enforcement
|
||||
CRITICAL: Never re-implement functionality that exists in our standard libraries:
|
||||
- **Tailwind CSS**: Use utility classes instead of custom CSS or style attributes
|
||||
- **PrimeVue**: Never re-implement components that exist in PrimeVue (buttons, modals, dropdowns, etc.)
|
||||
- **VueUse**: Never re-implement composables that exist in VueUse (useLocalStorage, useDebounceFn, etc.)
|
||||
- **Lodash**: Never re-implement utility functions (debounce, throttle, cloneDeep, etc.)
|
||||
- **Common components**: Reuse components from src/components/common/
|
||||
- **DOMPurify**: Always use for HTML sanitization
|
||||
- **Fuse.js**: Use for fuzzy search functionality
|
||||
- **Marked**: Use for markdown parsing
|
||||
- **Pinia**: Use for global state management, not custom solutions
|
||||
- **Zod**: Use for form validation with zodResolver pattern
|
||||
- **Tiptap**: Use for rich text/markdown editing
|
||||
- **Xterm.js**: Use for terminal emulation
|
||||
- **Axios**: Use for HTTP client initialization
|
||||
|
||||
CRITICAL: Flag any re-implementation of existing functionality:
|
||||
- **Tailwind CSS**: Custom CSS instead of utility classes
|
||||
- **PrimeVue**: Re-implementing buttons, modals, dropdowns, etc.
|
||||
- **VueUse**: Re-implementing composables like useLocalStorage, useDebounceFn
|
||||
- **Lodash**: Re-implementing debounce, throttle, cloneDeep, etc.
|
||||
- **Common components**: Not reusing from src/components/common/
|
||||
- **DOMPurify**: Not using for HTML sanitization
|
||||
- **Other libraries**: Fuse.js, Marked, Pinia, Zod, Tiptap, Xterm.js, Axios
|
||||
|
||||
### 3.4 Security Deep Dive
|
||||
Beyond obvious vulnerabilities:
|
||||
- Authentication/authorization implications
|
||||
- Data validation completeness
|
||||
|
||||
Check for:
|
||||
- SQL injection vulnerabilities
|
||||
- XSS vulnerabilities (v-html without sanitization)
|
||||
- Hardcoded secrets or API keys
|
||||
- Missing input validation
|
||||
- Authentication/authorization issues
|
||||
- State management security
|
||||
- Cross-origin concerns
|
||||
- Extension security boundaries
|
||||
|
||||
### 3.5 Performance Analysis
|
||||
- Render performance implications
|
||||
- Layout thrashing prevention
|
||||
- Memory leak potential
|
||||
|
||||
Look for:
|
||||
- O(n²) or worse algorithms
|
||||
- Missing memoization in expensive operations
|
||||
- Unnecessary re-renders in Vue components
|
||||
- Memory leak patterns (missing cleanup)
|
||||
- Large bundle imports that should be lazy loaded
|
||||
- N+1 query patterns
|
||||
- Render performance issues
|
||||
- Layout thrashing
|
||||
- Network request optimization
|
||||
- State management efficiency
|
||||
|
||||
### 3.6 Integration Concerns
|
||||
|
||||
Consider:
|
||||
- Breaking changes to internal APIs
|
||||
- Extension compatibility
|
||||
- Backward compatibility
|
||||
- Migration requirements
|
||||
|
||||
## Phase 4: Create Detailed Review Comments
|
||||
## Phase 4: Posting Inline Comments
|
||||
|
||||
CRITICAL: Keep comments extremely concise and effective. Use only as many words as absolutely necessary.
|
||||
- NO markdown formatting (no #, ##, ###, **, etc.)
|
||||
- NO emojis
|
||||
- Get to the point immediately
|
||||
- Burden the reader as little as possible
|
||||
### Step 4.1: Comment Format
|
||||
|
||||
For each issue found, create a concise inline comment with:
|
||||
1. What's wrong (one line)
|
||||
2. Why it matters (one line)
|
||||
3. How to fix it (one line)
|
||||
4. Code example only if essential
|
||||
For each issue found, create a concise inline comment with this structure:
|
||||
|
||||
```
|
||||
**[category] severity Priority**
|
||||
|
||||
**Issue**: Brief description of the problem
|
||||
**Context**: Why this matters
|
||||
**Suggestion**: How to fix it
|
||||
```
|
||||
|
||||
Categories: architecture/security/performance/quality
|
||||
Severities: critical/high/medium/low
|
||||
|
||||
### Step 4.2: Posting Comments
|
||||
|
||||
For EACH issue:
|
||||
|
||||
1. Identify the exact file path and line number
|
||||
2. Update your tracking counters (CRITICAL_COUNT, etc.)
|
||||
3. Construct the comment body with proper newlines
|
||||
4. Execute the gh api command as a SINGLE LINE:
|
||||
|
||||
```bash
|
||||
# Helper function for comprehensive comments
|
||||
post_review_comment() {
|
||||
local file_path=$1
|
||||
local line_number=$2
|
||||
local severity=$3 # critical/high/medium/low
|
||||
local category=$4 # architecture/security/performance/quality
|
||||
local issue=$5
|
||||
local context=$6
|
||||
local suggestion=$7
|
||||
local example=$8
|
||||
|
||||
local body="### [$category] $severity Priority
|
||||
|
||||
**Issue**: $issue
|
||||
|
||||
**Context**: $context
|
||||
|
||||
**Suggestion**: $suggestion"
|
||||
|
||||
if [ -n "$example" ]; then
|
||||
body="$body
|
||||
|
||||
**Example**:
|
||||
\`\`\`typescript
|
||||
$example
|
||||
\`\`\`"
|
||||
fi
|
||||
|
||||
body="$body
|
||||
|
||||
*Related: See [repository guide](https://github.com/Comfy-Org/comfy-claude-prompt-library/blob/master/project-summaries-for-agents/ComfyUI_frontend/REPOSITORY_GUIDE.md) for patterns*"
|
||||
|
||||
gh api -X POST /repos/$REPOSITORY/pulls/$PR_NUMBER/comments \
|
||||
-f path="$file_path" \
|
||||
-f line=$line_number \
|
||||
-f body="$body" \
|
||||
-f commit_id="$COMMIT_SHA" \
|
||||
-f side='RIGHT' || echo "Failed to post comment at $file_path:$line_number"
|
||||
}
|
||||
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/OWNER/REPO/pulls/$PR_NUMBER/comments -f body="$COMMENT_BODY" -f commit_id="COMMIT_SHA" -f path="FILE_PATH" -F line=LINE_NUMBER -f side="RIGHT"
|
||||
```
|
||||
|
||||
CRITICAL: The entire command must be on one line. Use actual values, not placeholders.
|
||||
|
||||
### Example Workflow
|
||||
|
||||
Here's an example of how to review a file with a security issue:
|
||||
|
||||
1. First, get the repository info:
|
||||
```bash
|
||||
gh repo view --json owner,name
|
||||
# Output: {"owner":{"login":"Comfy-Org"},"name":"ComfyUI_frontend"}
|
||||
```
|
||||
|
||||
2. Get the commit SHA:
|
||||
```bash
|
||||
gh pr view $PR_NUMBER --json commits --jq '.commits[-1].oid'
|
||||
# Output: abc123def456
|
||||
```
|
||||
|
||||
3. Find an issue (e.g., SQL injection on line 42 of src/db/queries.js)
|
||||
|
||||
4. Post the inline comment:
|
||||
```bash
|
||||
# First, create the comment body with proper newlines
|
||||
COMMENT_BODY="**[security] critical Priority**
|
||||
|
||||
**Issue**: SQL injection vulnerability - user input directly concatenated into query
|
||||
**Context**: Allows attackers to execute arbitrary SQL commands
|
||||
**Suggestion**: Use parameterized queries or prepared statements"
|
||||
|
||||
# Then post the comment (as a single line)
|
||||
gh api --method POST -H "Accept: application/vnd.github+json" -H "X-GitHub-Api-Version: 2022-11-28" /repos/Comfy-Org/ComfyUI_frontend/pulls/$PR_NUMBER/comments -f body="$COMMENT_BODY" -f commit_id="abc123def456" -f path="src/db/queries.js" -F line=42 -f side="RIGHT"
|
||||
```
|
||||
|
||||
Repeat this process for every issue you find in the PR.
|
||||
|
||||
## Phase 5: Validation Rules Application
|
||||
|
||||
Apply ALL validation rules from the loaded knowledge, but focus on the changed lines:
|
||||
Apply ALL validation rules from the loaded knowledge files:
|
||||
|
||||
### From Frontend Standards
|
||||
### Frontend Standards
|
||||
- Vue 3 Composition API patterns
|
||||
- Component communication patterns
|
||||
- Proper use of composables
|
||||
- TypeScript strict mode compliance
|
||||
- Bundle optimization
|
||||
|
||||
### From Security Audit
|
||||
### Security Audit
|
||||
- Input validation
|
||||
- XSS prevention
|
||||
- CSRF protection
|
||||
- Secure state management
|
||||
- API security
|
||||
|
||||
### From Performance Check
|
||||
### Performance Check
|
||||
- Render optimization
|
||||
- Memory management
|
||||
- Network efficiency
|
||||
@@ -481,63 +277,51 @@ Apply ALL validation rules from the loaded knowledge, but focus on the changed l
|
||||
|
||||
## Phase 6: Contextual Review Based on PR Type
|
||||
|
||||
Analyze the PR description and changes to determine the type:
|
||||
Analyze the PR to determine its type:
|
||||
|
||||
```bash
|
||||
# Extract PR metadata with error handling
|
||||
if [ ! -f pr_info.json ]; then
|
||||
echo "Error: pr_info.json not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
PR_TITLE=$(jq -r '.title // "Unknown"' < pr_info.json)
|
||||
PR_BODY=$(jq -r '.body // ""' < pr_info.json)
|
||||
FILE_COUNT=$(wc -l < changed_files.txt)
|
||||
ADDITIONS=$(jq -r '.additions // 0' < pr_info.json)
|
||||
DELETIONS=$(jq -r '.deletions // 0' < pr_info.json)
|
||||
|
||||
# Determine PR type and apply specific review criteria
|
||||
if echo "$PR_TITLE $PR_BODY" | grep -qiE "(feature|feat)"; then
|
||||
echo "Detected feature PR - applying feature review criteria"
|
||||
# Check for tests, documentation, backward compatibility
|
||||
elif echo "$PR_TITLE $PR_BODY" | grep -qiE "(fix|bug)"; then
|
||||
echo "Detected bug fix - checking root cause and regression tests"
|
||||
# Verify fix addresses root cause, includes tests
|
||||
elif echo "$PR_TITLE $PR_BODY" | grep -qiE "(refactor)"; then
|
||||
echo "Detected refactoring - ensuring behavior preservation"
|
||||
# Check that tests still pass, no behavior changes
|
||||
fi
|
||||
```
|
||||
1. Extract PR title and body from pr_info.json
|
||||
2. Count files, additions, and deletions
|
||||
3. Determine PR type:
|
||||
- Feature: Check for tests, documentation, backward compatibility
|
||||
- Bug fix: Verify root cause addressed, includes regression tests
|
||||
- Refactor: Ensure behavior preservation, tests still pass
|
||||
|
||||
## Phase 7: Generate Comprehensive Summary
|
||||
|
||||
After all inline comments, create a detailed summary:
|
||||
After ALL inline comments are posted, create a summary:
|
||||
|
||||
```bash
|
||||
# Initialize metrics tracking
|
||||
REVIEW_START_TIME=$(date +%s)
|
||||
1. Calculate total issues by category and severity
|
||||
2. Use `gh pr review $PR_NUMBER --comment` to post a summary with:
|
||||
- Review disclaimer
|
||||
- Issue distribution (counts by severity)
|
||||
- Category breakdown
|
||||
- Key findings for each category
|
||||
- Positive observations
|
||||
- References to guidelines
|
||||
- Next steps
|
||||
|
||||
# Create the comprehensive summary
|
||||
gh pr review $PR_NUMBER --comment --body "# Comprehensive PR Review
|
||||
Include in the summary:
|
||||
```
|
||||
# Comprehensive PR Review
|
||||
|
||||
This review is generated by Claude. It may not always be accurate, as with human reviewers. If you believe that any of the comments are invalid or incorrect, please state why for each. For others, please implement the changes in one way or another.
|
||||
|
||||
## Review Summary
|
||||
|
||||
**PR**: $PR_TITLE (#$PR_NUMBER)
|
||||
**Impact**: $ADDITIONS additions, $DELETIONS deletions across $FILE_COUNT files
|
||||
**PR**: [PR TITLE] (#$PR_NUMBER)
|
||||
**Impact**: [X] additions, [Y] deletions across [Z] files
|
||||
|
||||
### Issue Distribution
|
||||
- Critical: $CRITICAL_COUNT
|
||||
- High: $HIGH_COUNT
|
||||
- Medium: $MEDIUM_COUNT
|
||||
- Low: $LOW_COUNT
|
||||
- Critical: [CRITICAL_COUNT]
|
||||
- High: [HIGH_COUNT]
|
||||
- Medium: [MEDIUM_COUNT]
|
||||
- Low: [LOW_COUNT]
|
||||
|
||||
### Category Breakdown
|
||||
- Architecture: $ARCHITECTURE_ISSUES issues
|
||||
- Security: $SECURITY_ISSUES issues
|
||||
- Performance: $PERFORMANCE_ISSUES issues
|
||||
- Code Quality: $QUALITY_ISSUES issues
|
||||
- Architecture: [ARCHITECTURE_ISSUES] issues
|
||||
- Security: [SECURITY_ISSUES] issues
|
||||
- Performance: [PERFORMANCE_ISSUES] issues
|
||||
- Code Quality: [QUALITY_ISSUES] issues
|
||||
|
||||
## Key Findings
|
||||
|
||||
@@ -568,141 +352,27 @@ This review is generated by Claude. It may not always be accurate, as with human
|
||||
4. Update documentation if needed
|
||||
|
||||
---
|
||||
*This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.*"
|
||||
*This is a comprehensive automated review. For architectural decisions requiring human judgment, please request additional manual review.*
|
||||
```
|
||||
|
||||
## Important: Think Deeply
|
||||
## Important Guidelines
|
||||
|
||||
When reviewing:
|
||||
1. **Think hard** about architectural implications
|
||||
2. Consider how changes affect the entire system
|
||||
3. Look for subtle bugs and edge cases
|
||||
4. Evaluate maintainability over time
|
||||
5. Consider extension developer experience
|
||||
6. Think about migration paths
|
||||
1. **Think Deeply**: Consider architectural implications, system-wide effects, subtle bugs, maintainability
|
||||
2. **Be Specific**: Point to exact lines with concrete suggestions
|
||||
3. **Be Constructive**: Focus on improvements, not just problems
|
||||
4. **Be Concise**: Keep comments brief and actionable
|
||||
5. **No Formatting**: Don't use markdown headers in inline comments
|
||||
6. **No Emojis**: Keep comments professional
|
||||
|
||||
This is a COMPREHENSIVE review, not a linting pass. Provide the same quality feedback a senior engineer would give after careful consideration.
|
||||
|
||||
## Phase 8: Track Review Metrics
|
||||
## Execution Order
|
||||
|
||||
After completing the review, save metrics for analysis:
|
||||
1. Phase 1: Setup and checkout PR
|
||||
2. Phase 2: Load all relevant knowledge
|
||||
3. Phase 3-5: Analyze each changed file thoroughly
|
||||
4. Phase 4: Post inline comments as you find issues
|
||||
5. Phase 6: Consider PR type for additional checks
|
||||
6. Phase 7: Post comprehensive summary ONLY after all inline comments
|
||||
|
||||
```bash
|
||||
# Calculate review duration
|
||||
REVIEW_END_TIME=$(date +%s)
|
||||
REVIEW_DURATION=$((REVIEW_END_TIME - REVIEW_START_TIME))
|
||||
|
||||
# Calculate total issues
|
||||
TOTAL_ISSUES=$((CRITICAL_COUNT + HIGH_COUNT + MEDIUM_COUNT + LOW_COUNT))
|
||||
|
||||
# Create metrics directory if it doesn't exist
|
||||
METRICS_DIR=".claude/review-metrics"
|
||||
mkdir -p "$METRICS_DIR"
|
||||
|
||||
# Generate metrics file
|
||||
METRICS_FILE="$METRICS_DIR/metrics-$(date +%Y%m).json"
|
||||
|
||||
# Create or update monthly metrics file
|
||||
if [ -f "$METRICS_FILE" ]; then
|
||||
# Append to existing file
|
||||
jq -n \
|
||||
--arg pr "$PR_NUMBER" \
|
||||
--arg title "$PR_TITLE" \
|
||||
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
--arg duration "$REVIEW_DURATION" \
|
||||
--arg files "$FILE_COUNT" \
|
||||
--arg additions "$ADDITIONS" \
|
||||
--arg deletions "$DELETIONS" \
|
||||
--arg total "$TOTAL_ISSUES" \
|
||||
--arg critical "$CRITICAL_COUNT" \
|
||||
--arg high "$HIGH_COUNT" \
|
||||
--arg medium "$MEDIUM_COUNT" \
|
||||
--arg low "$LOW_COUNT" \
|
||||
--arg architecture "$ARCHITECTURE_ISSUES" \
|
||||
--arg security "$SECURITY_ISSUES" \
|
||||
--arg performance "$PERFORMANCE_ISSUES" \
|
||||
--arg quality "$QUALITY_ISSUES" \
|
||||
'{
|
||||
pr_number: $pr,
|
||||
pr_title: $title,
|
||||
timestamp: $timestamp,
|
||||
review_duration_seconds: ($duration | tonumber),
|
||||
files_reviewed: ($files | tonumber),
|
||||
lines_added: ($additions | tonumber),
|
||||
lines_deleted: ($deletions | tonumber),
|
||||
issues: {
|
||||
total: ($total | tonumber),
|
||||
by_severity: {
|
||||
critical: ($critical | tonumber),
|
||||
high: ($high | tonumber),
|
||||
medium: ($medium | tonumber),
|
||||
low: ($low | tonumber)
|
||||
},
|
||||
by_category: {
|
||||
architecture: ($architecture | tonumber),
|
||||
security: ($security | tonumber),
|
||||
performance: ($performance | tonumber),
|
||||
quality: ($quality | tonumber)
|
||||
}
|
||||
}
|
||||
}' > "$METRICS_FILE.new"
|
||||
|
||||
# Merge with existing data
|
||||
jq -s '.[0] + [.[1]]' "$METRICS_FILE" "$METRICS_FILE.new" > "$METRICS_FILE.tmp"
|
||||
mv "$METRICS_FILE.tmp" "$METRICS_FILE"
|
||||
rm "$METRICS_FILE.new"
|
||||
else
|
||||
# Create new file
|
||||
jq -n \
|
||||
--arg pr "$PR_NUMBER" \
|
||||
--arg title "$PR_TITLE" \
|
||||
--arg timestamp "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
|
||||
--arg duration "$REVIEW_DURATION" \
|
||||
--arg files "$FILE_COUNT" \
|
||||
--arg additions "$ADDITIONS" \
|
||||
--arg deletions "$DELETIONS" \
|
||||
--arg total "$TOTAL_ISSUES" \
|
||||
--arg critical "$CRITICAL_COUNT" \
|
||||
--arg high "$HIGH_COUNT" \
|
||||
--arg medium "$MEDIUM_COUNT" \
|
||||
--arg low "$LOW_COUNT" \
|
||||
--arg architecture "$ARCHITECTURE_ISSUES" \
|
||||
--arg security "$SECURITY_ISSUES" \
|
||||
--arg performance "$PERFORMANCE_ISSUES" \
|
||||
--arg quality "$QUALITY_ISSUES" \
|
||||
'[{
|
||||
pr_number: $pr,
|
||||
pr_title: $title,
|
||||
timestamp: $timestamp,
|
||||
review_duration_seconds: ($duration | tonumber),
|
||||
files_reviewed: ($files | tonumber),
|
||||
lines_added: ($additions | tonumber),
|
||||
lines_deleted: ($deletions | tonumber),
|
||||
issues: {
|
||||
total: ($total | tonumber),
|
||||
by_severity: {
|
||||
critical: ($critical | tonumber),
|
||||
high: ($high | tonumber),
|
||||
medium: ($medium | tonumber),
|
||||
low: ($low | tonumber)
|
||||
},
|
||||
by_category: {
|
||||
architecture: ($architecture | tonumber),
|
||||
security: ($security | tonumber),
|
||||
performance: ($performance | tonumber),
|
||||
quality: ($quality | tonumber)
|
||||
}
|
||||
}
|
||||
}]' > "$METRICS_FILE"
|
||||
fi
|
||||
|
||||
echo "Review metrics saved to $METRICS_FILE"
|
||||
```
|
||||
|
||||
This creates monthly metrics files (e.g., `metrics-202407.json`) that track:
|
||||
- Which PRs were reviewed
|
||||
- How long reviews took
|
||||
- Types and severity of issues found
|
||||
- Trends over time
|
||||
|
||||
You can later analyze these to see patterns and improve your development process.
|
||||
Remember: Individual inline comments for each issue, then one final summary. Never batch issues into a single comment.
|
||||
@@ -111,51 +111,7 @@ echo "Last stable release: $LAST_STABLE"
|
||||
```
|
||||
7. **HUMAN ANALYSIS**: Review change summary and verify scope
|
||||
|
||||
### Step 3: Version Preview
|
||||
|
||||
**Version Preview:**
|
||||
- Current: `${CURRENT_VERSION}`
|
||||
- Proposed: Show exact version number
|
||||
- **CONFIRMATION REQUIRED**: Proceed with version `X.Y.Z`?
|
||||
|
||||
### Step 4: Security and Dependency Audit
|
||||
|
||||
1. Run security audit:
|
||||
```bash
|
||||
npm audit --audit-level moderate
|
||||
```
|
||||
2. Check for known vulnerabilities in dependencies
|
||||
3. Scan for hardcoded secrets or credentials:
|
||||
```bash
|
||||
git log -p ${BASE_TAG}..HEAD | grep -iE "(password|key|secret|token)" || echo "No sensitive data found"
|
||||
```
|
||||
4. Verify no sensitive data in recent commits
|
||||
5. **SECURITY REVIEW**: Address any critical findings before proceeding?
|
||||
|
||||
### Step 5: Pre-Release Testing
|
||||
|
||||
1. Run complete test suite:
|
||||
```bash
|
||||
npm run test:unit
|
||||
npm run test:component
|
||||
npm run test:browser
|
||||
```
|
||||
2. Run type checking:
|
||||
```bash
|
||||
npm run typecheck
|
||||
```
|
||||
3. Run linting (may have issues with missing packages):
|
||||
```bash
|
||||
npm run lint || echo "Lint issues - verify if critical"
|
||||
```
|
||||
4. Test build process:
|
||||
```bash
|
||||
npm run build
|
||||
npm run build:types
|
||||
```
|
||||
5. **QUALITY GATE**: All tests and builds passing?
|
||||
|
||||
### Step 6: Breaking Change Analysis
|
||||
### Step 3: Breaking Change Analysis
|
||||
|
||||
1. Analyze API changes in:
|
||||
- Public TypeScript interfaces
|
||||
@@ -170,7 +126,192 @@ echo "Last stable release: $LAST_STABLE"
|
||||
3. Generate breaking change summary
|
||||
4. **COMPATIBILITY REVIEW**: Breaking changes documented and justified?
|
||||
|
||||
### Step 7: Generate and Save Changelog
|
||||
### Step 4: Analyze Dependency Updates
|
||||
|
||||
1. **Use pnpm's built-in dependency analysis:**
|
||||
```bash
|
||||
# Get outdated dependencies with pnpm
|
||||
pnpm outdated --format table > outdated-deps-${NEW_VERSION}.txt
|
||||
|
||||
# Check for license compliance
|
||||
pnpm licenses ls --json > licenses-${NEW_VERSION}.json
|
||||
|
||||
# Analyze why specific dependencies exist
|
||||
echo "Dependency analysis:" > dep-analysis-${NEW_VERSION}.md
|
||||
MAJOR_DEPS=("vue" "vite" "@vitejs/plugin-vue" "typescript" "pinia")
|
||||
for dep in "${MAJOR_DEPS[@]}"; do
|
||||
echo -e "\n## $dep\n\`\`\`" >> dep-analysis-${NEW_VERSION}.md
|
||||
pnpm why "$dep" >> dep-analysis-${NEW_VERSION}.md || echo "Not found" >> dep-analysis-${NEW_VERSION}.md
|
||||
echo "\`\`\`" >> dep-analysis-${NEW_VERSION}.md
|
||||
done
|
||||
```
|
||||
|
||||
2. **Check for significant dependency updates:**
|
||||
```bash
|
||||
# Extract all dependency changes for major version bumps
|
||||
OTHER_DEP_CHANGES=""
|
||||
|
||||
# Compare major dependency versions (you can extend this list)
|
||||
MAJOR_DEPS=("vue" "vite" "@vitejs/plugin-vue" "typescript" "pinia")
|
||||
|
||||
for dep in "${MAJOR_DEPS[@]}"; do
|
||||
PREV_VER=$(echo "$PREV_PACKAGE_JSON" | grep -o "\"$dep\": \"[^\"]*\"" | grep -o '[0-9][^"]*' | head -1 || echo "")
|
||||
CURR_VER=$(echo "$CURRENT_PACKAGE_JSON" | grep -o "\"$dep\": \"[^\"]*\"" | grep -o '[0-9][^"]*' | head -1 || echo "")
|
||||
|
||||
if [ "$PREV_VER" != "$CURR_VER" ] && [ -n "$PREV_VER" ] && [ -n "$CURR_VER" ]; then
|
||||
# Check if it's a major version change
|
||||
PREV_MAJOR=$(echo "$PREV_VER" | cut -d. -f1 | sed 's/[^0-9]//g')
|
||||
CURR_MAJOR=$(echo "$CURR_VER" | cut -d. -f1 | sed 's/[^0-9]//g')
|
||||
|
||||
if [ "$PREV_MAJOR" != "$CURR_MAJOR" ]; then
|
||||
OTHER_DEP_CHANGES="${OTHER_DEP_CHANGES}\n- **${dep}**: ${PREV_VER} → ${CURR_VER} (Major version change)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### Step 5: Generate GTM Feature Summary
|
||||
|
||||
1. **Collect PR data for analysis:**
|
||||
```bash
|
||||
# Get list of PR numbers from commits
|
||||
PR_NUMBERS=$(git log ${BASE_TAG}..HEAD --oneline --no-merges --first-parent | \
|
||||
grep -oE "#[0-9]+" | tr -d '#' | sort -u)
|
||||
|
||||
# Save PR data for each PR
|
||||
echo "[" > prs-${NEW_VERSION}.json
|
||||
first=true
|
||||
for PR in $PR_NUMBERS; do
|
||||
[[ "$first" == true ]] && first=false || echo "," >> prs-${NEW_VERSION}.json
|
||||
gh pr view $PR --json number,title,author,body,labels 2>/dev/null >> prs-${NEW_VERSION}.json || echo "{}" >> prs-${NEW_VERSION}.json
|
||||
done
|
||||
echo "]" >> prs-${NEW_VERSION}.json
|
||||
```
|
||||
|
||||
2. **Analyze for GTM-worthy features:**
|
||||
```
|
||||
<task>
|
||||
Review these PRs to identify features worthy of marketing attention.
|
||||
|
||||
A feature is GTM-worthy if it meets ALL of these criteria:
|
||||
- Introduces a NEW capability users didn't have before (not just improvements)
|
||||
- Would be a compelling reason for users to upgrade to this version
|
||||
- Can be demonstrated visually or has clear before/after comparison
|
||||
- Affects a significant portion of the user base
|
||||
|
||||
NOT GTM-worthy:
|
||||
- Bug fixes (even important ones)
|
||||
- Minor UI tweaks or color changes
|
||||
- Performance improvements without user-visible impact
|
||||
- Internal refactoring
|
||||
- Small convenience features
|
||||
- Features that only improve existing functionality marginally
|
||||
|
||||
For each GTM-worthy feature, note:
|
||||
- PR number, title, and author
|
||||
- Media links from the PR description
|
||||
- One compelling sentence on why users should care
|
||||
|
||||
If there are no GTM-worthy features, just say "No marketing-worthy features in this release."
|
||||
</task>
|
||||
|
||||
PR data: [contents of prs-${NEW_VERSION}.json]
|
||||
```
|
||||
|
||||
3. **Generate GTM notification using this EXACT Slack-compatible format:**
|
||||
```bash
|
||||
# Only create file if GTM-worthy features exist:
|
||||
if [ "$GTM_FEATURES_FOUND" = "true" ]; then
|
||||
cat > gtm-summary-${NEW_VERSION}.md << 'EOF'
|
||||
*GTM Summary: ComfyUI Frontend v${NEW_VERSION}*
|
||||
|
||||
_Disclaimer: the below is AI-generated_
|
||||
|
||||
1. *[Feature Title]* (#[PR_NUMBER])
|
||||
* *Author:* @[username]
|
||||
* *Demo:* [Media Link or "No demo available"]
|
||||
* *Why users should care:* [One compelling sentence]
|
||||
* *Key Features:*
|
||||
* [Feature detail 1]
|
||||
* [Feature detail 2]
|
||||
|
||||
2. *[Feature Title]* (#[PR_NUMBER])
|
||||
* *Author:* @[username]
|
||||
* *Demo:* [Media Link]
|
||||
* *Why users should care:* [One compelling sentence]
|
||||
* *Key Features:*
|
||||
* [Feature detail 1]
|
||||
* [Feature detail 2]
|
||||
EOF
|
||||
echo "📋 GTM summary saved to: gtm-summary-${NEW_VERSION}.md"
|
||||
echo "📤 Share this file in #gtm channel to notify the team"
|
||||
else
|
||||
echo "✅ No GTM notification needed for this release"
|
||||
echo "📄 No gtm-summary file created - no marketing-worthy features"
|
||||
fi
|
||||
```
|
||||
|
||||
**CRITICAL Formatting Requirements:**
|
||||
- Use single asterisk (*) for emphasis, NOT double (**)
|
||||
- Use underscore (_) for italics
|
||||
- Use 4 spaces for indentation (not tabs)
|
||||
- Convert author names to @username format (e.g., "John Smith" → "@john")
|
||||
- No section headers (#), no code language specifications
|
||||
- Always include "Disclaimer: the below is AI-generated"
|
||||
- Keep content minimal - no testing instructions, additional sections, etc.
|
||||
|
||||
### Step 6: Version Preview
|
||||
|
||||
**Version Preview:**
|
||||
- Current: `${CURRENT_VERSION}`
|
||||
- Proposed: Show exact version number based on analysis:
|
||||
- Major version if breaking changes detected
|
||||
- Minor version if new features added
|
||||
- Patch version if only bug fixes
|
||||
- **CONFIRMATION REQUIRED**: Proceed with version `X.Y.Z`?
|
||||
|
||||
### Step 7: Security and Dependency Audit
|
||||
|
||||
1. Run pnpm security audit:
|
||||
```bash
|
||||
pnpm audit --audit-level moderate
|
||||
pnpm licenses ls --summary
|
||||
```
|
||||
2. Check for known vulnerabilities in dependencies
|
||||
3. Run comprehensive dependency health check:
|
||||
```bash
|
||||
pnpm doctor
|
||||
```
|
||||
4. Scan for hardcoded secrets or credentials:
|
||||
```bash
|
||||
git log -p ${BASE_TAG}..HEAD | grep -iE "(password|key|secret|token)" || echo "No sensitive data found"
|
||||
```
|
||||
5. Verify no sensitive data in recent commits
|
||||
6. **SECURITY REVIEW**: Address any critical findings before proceeding?
|
||||
|
||||
### Step 8: Pre-Release Testing
|
||||
|
||||
1. Run complete test suite:
|
||||
```bash
|
||||
pnpm test:unit
|
||||
pnpm test:component
|
||||
```
|
||||
2. Run type checking:
|
||||
```bash
|
||||
pnpm typecheck
|
||||
```
|
||||
3. Run linting (may have issues with missing packages):
|
||||
```bash
|
||||
pnpm lint || echo "Lint issues - verify if critical"
|
||||
```
|
||||
4. Test build process:
|
||||
```bash
|
||||
pnpm build
|
||||
pnpm build:types
|
||||
```
|
||||
5. **QUALITY GATE**: All tests and builds passing?
|
||||
|
||||
### Step 9: Generate Comprehensive Release Notes
|
||||
|
||||
1. Extract commit messages since base release:
|
||||
```bash
|
||||
@@ -185,44 +326,54 @@ echo "Last stable release: $LAST_STABLE"
|
||||
echo "WARNING: PR #$PR not on main branch!"
|
||||
done
|
||||
```
|
||||
3. Group by type:
|
||||
- 🚀 **Features** (feat:)
|
||||
- 🐛 **Bug Fixes** (fix:)
|
||||
- 💥 **Breaking Changes** (BREAKING CHANGE)
|
||||
- 📚 **Documentation** (docs:)
|
||||
- 🔧 **Maintenance** (chore:, refactor:)
|
||||
- ⬆️ **Dependencies** (deps:, dependency updates)
|
||||
4. Include PR numbers and links
|
||||
5. Add issue references (Fixes #123)
|
||||
6. **Save changelog locally:**
|
||||
3. Create standardized release notes using this exact template:
|
||||
```bash
|
||||
# Save to dated file for history
|
||||
echo "$CHANGELOG" > release-notes-${NEW_VERSION}-$(date +%Y%m%d).md
|
||||
|
||||
# Save to current for easy access
|
||||
echo "$CHANGELOG" > CURRENT_RELEASE_NOTES.md
|
||||
cat > release-notes-${NEW_VERSION}.md << 'EOF'
|
||||
## ⚠️ Breaking Changes
|
||||
<!-- List breaking changes if any, otherwise remove this entire section -->
|
||||
- Breaking change description (#PR_NUMBER)
|
||||
|
||||
---
|
||||
|
||||
## What's Changed
|
||||
|
||||
### 🚀 Features
|
||||
<!-- List features here, one per line with PR reference -->
|
||||
- Feature description (#PR_NUMBER)
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
<!-- List bug fixes here, one per line with PR reference -->
|
||||
- Bug fix description (#PR_NUMBER)
|
||||
|
||||
### 🔧 Maintenance
|
||||
<!-- List refactoring, chore, and other maintenance items -->
|
||||
- Maintenance item description (#PR_NUMBER)
|
||||
|
||||
### 📚 Documentation
|
||||
<!-- List documentation changes if any, remove section if empty -->
|
||||
- Documentation update description (#PR_NUMBER)
|
||||
|
||||
### ⬆️ Dependencies
|
||||
<!-- List dependency updates -->
|
||||
- Updated dependency from vX.X.X to vY.Y.Y (#PR_NUMBER)
|
||||
|
||||
**Full Changelog**: https://github.com/Comfy-Org/ComfyUI_frontend/compare/${BASE_TAG}...v${NEW_VERSION}
|
||||
EOF
|
||||
```
|
||||
7. **CHANGELOG REVIEW**: Verify all PRs listed are actually on main branch
|
||||
4. **Parse commits and populate template:**
|
||||
- Group commits by conventional commit type (feat:, fix:, chore:, etc.)
|
||||
- Extract PR numbers from commit messages
|
||||
- For breaking changes, analyze if changes affect:
|
||||
- Public APIs (app object, api module)
|
||||
- Extension/workspace manager APIs
|
||||
- Node schema, workflow schema, or other public schemas
|
||||
- Any other public-facing interfaces
|
||||
- For dependency updates, list version changes with PR numbers
|
||||
- Remove empty sections (e.g., if no documentation changes)
|
||||
- Ensure consistent bullet format: `- Description (#PR_NUMBER)`
|
||||
5. **CONTENT REVIEW**: Release notes follow standard format?
|
||||
|
||||
### Step 8: Create Enhanced Release Notes
|
||||
|
||||
1. Create comprehensive user-facing release notes including:
|
||||
- **What's New**: Major features and improvements
|
||||
- **Bug Fixes**: User-visible fixes
|
||||
- **Breaking Changes**: Migration guide if applicable
|
||||
- **Dependencies**: Major dependency updates
|
||||
- **Performance**: Notable performance improvements
|
||||
- **Contributors**: Thank contributors for their work
|
||||
2. Reference related documentation updates
|
||||
3. Include screenshots for UI changes (if available)
|
||||
4. **Save release notes:**
|
||||
```bash
|
||||
# Enhanced release notes for GitHub
|
||||
echo "$RELEASE_NOTES" > github-release-notes-${NEW_VERSION}.md
|
||||
```
|
||||
5. **CONTENT REVIEW**: Release notes clear and helpful for users?
|
||||
|
||||
### Step 9: Create Version Bump PR
|
||||
### Step 10: Create Version Bump PR
|
||||
|
||||
**For standard version bumps (patch/minor/major):**
|
||||
```bash
|
||||
@@ -258,50 +409,15 @@ echo "Workflow triggered. Waiting for PR creation..."
|
||||
|
||||
# For manual PRs
|
||||
gh pr create --title "${NEW_VERSION}" \
|
||||
--body-file enhanced-pr-description.md \
|
||||
--body-file release-notes-${NEW_VERSION}.md \
|
||||
--label "Release"
|
||||
```
|
||||
3. **Create enhanced PR description:**
|
||||
3. **Update PR with release notes:**
|
||||
```bash
|
||||
cat > enhanced-pr-description.md << EOF
|
||||
# Release v${NEW_VERSION}
|
||||
|
||||
## Version Change
|
||||
\`${CURRENT_VERSION}\` → \`${NEW_VERSION}\` (${VERSION_TYPE})
|
||||
|
||||
## Changelog
|
||||
${CHANGELOG}
|
||||
|
||||
## Breaking Changes
|
||||
${BREAKING_CHANGES}
|
||||
|
||||
## Testing Performed
|
||||
- ✅ Full test suite (unit, component, browser)
|
||||
- ✅ TypeScript compilation
|
||||
- ✅ Linting checks
|
||||
- ✅ Build verification
|
||||
- ✅ Security audit
|
||||
|
||||
## Distribution Channels
|
||||
- GitHub Release (with dist.zip)
|
||||
- PyPI Package (comfyui-frontend-package)
|
||||
- npm Package (@comfyorg/comfyui-frontend-types)
|
||||
|
||||
## Post-Release Tasks
|
||||
- [ ] Verify all distribution channels
|
||||
- [ ] Update external documentation
|
||||
- [ ] Monitor for issues
|
||||
EOF
|
||||
# For workflow-created PRs, update the body with our release notes
|
||||
gh pr edit ${PR_NUMBER} --body-file release-notes-${NEW_VERSION}.md
|
||||
```
|
||||
4. Update PR with enhanced description:
|
||||
```bash
|
||||
gh pr edit ${PR_NUMBER} --body-file enhanced-pr-description.md
|
||||
```
|
||||
5. Add changelog as comment for easy reference:
|
||||
```bash
|
||||
gh pr comment ${PR_NUMBER} --body-file CURRENT_RELEASE_NOTES.md
|
||||
```
|
||||
6. **PR REVIEW**: Version bump PR created and enhanced correctly?
|
||||
4. **PR REVIEW**: Version bump PR created with standardized release notes?
|
||||
|
||||
### Step 11: Critical Release PR Verification
|
||||
|
||||
@@ -345,6 +461,14 @@ echo "Workflow triggered. Waiting for PR creation..."
|
||||
sleep 10
|
||||
gh run list --workflow=release.yaml --limit=1
|
||||
```
|
||||
4. **For Minor/Major Version Releases**: The create-release-candidate-branch workflow will automatically:
|
||||
- Create a `core/x.yy` branch for the PREVIOUS minor version
|
||||
- Apply branch protection rules
|
||||
- Document the feature freeze policy
|
||||
```bash
|
||||
# Monitor branch creation (for minor/major releases)
|
||||
gh run list --workflow=create-release-candidate-branch.yaml --limit=1
|
||||
```
|
||||
4. If workflow didn't trigger due to [skip ci]:
|
||||
```bash
|
||||
echo "ERROR: Release workflow didn't trigger!"
|
||||
@@ -371,10 +495,10 @@ echo "Workflow triggered. Waiting for PR creation..."
|
||||
|
||||
2. **Enhance the GitHub release:**
|
||||
```bash
|
||||
# Update release with our enhanced notes
|
||||
# Update release with our release notes
|
||||
gh release edit v${NEW_VERSION} \
|
||||
--title "🚀 ComfyUI Frontend v${NEW_VERSION}" \
|
||||
--notes-file github-release-notes-${NEW_VERSION}.md \
|
||||
--notes-file release-notes-${NEW_VERSION}.md \
|
||||
--latest
|
||||
|
||||
# Add any additional assets if needed
|
||||
@@ -413,7 +537,7 @@ echo "Workflow triggered. Waiting for PR creation..."
|
||||
```bash
|
||||
# Check npm availability
|
||||
for i in {1..10}; do
|
||||
if npm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
|
||||
if pnpm view @comfyorg/comfyui-frontend-types@${NEW_VERSION} version >/dev/null 2>&1; then
|
||||
echo "✅ npm package available"
|
||||
break
|
||||
fi
|
||||
@@ -492,14 +616,51 @@ echo "Workflow triggered. Waiting for PR creation..."
|
||||
- Plan next release cycle
|
||||
|
||||
## Files Generated
|
||||
- \`release-notes-${NEW_VERSION}-$(date +%Y%m%d).md\` - Detailed changelog
|
||||
- \`github-release-notes-${NEW_VERSION}.md\` - GitHub release notes
|
||||
- \`release-notes-${NEW_VERSION}.md\` - Comprehensive release notes
|
||||
- \`post-release-checklist.md\` - Follow-up tasks
|
||||
- \`gtm-summary-${NEW_VERSION}.md\` - Marketing team notification
|
||||
EOF
|
||||
```
|
||||
|
||||
4. **RELEASE COMPLETION**: All post-release setup completed?
|
||||
|
||||
### Step 17: Create Release Summary
|
||||
|
||||
1. **Create comprehensive release summary:**
|
||||
```bash
|
||||
cat > release-summary-${NEW_VERSION}.md << EOF
|
||||
# Release Summary: ComfyUI Frontend v${NEW_VERSION}
|
||||
|
||||
**Released:** $(date)
|
||||
**Type:** ${VERSION_TYPE}
|
||||
**Duration:** ~${RELEASE_DURATION} minutes
|
||||
**Release Commit:** ${RELEASE_COMMIT}
|
||||
|
||||
## Metrics
|
||||
- **Commits Included:** ${COMMITS_COUNT}
|
||||
- **Contributors:** ${CONTRIBUTORS_COUNT}
|
||||
- **Files Changed:** ${FILES_CHANGED}
|
||||
- **Lines Added/Removed:** +${LINES_ADDED}/-${LINES_REMOVED}
|
||||
|
||||
## Distribution Status
|
||||
- ✅ GitHub Release: Published
|
||||
- ✅ PyPI Package: Available
|
||||
- ✅ npm Types: Available
|
||||
|
||||
## Next Steps
|
||||
- Monitor for 24-48 hours
|
||||
- Address any critical issues immediately
|
||||
- Plan next release cycle
|
||||
|
||||
## Files Generated
|
||||
- \`release-notes-${NEW_VERSION}.md\` - Comprehensive release notes
|
||||
- \`post-release-checklist.md\` - Follow-up tasks
|
||||
- \`gtm-summary-${NEW_VERSION}.md\` - Marketing team notification
|
||||
EOF
|
||||
```
|
||||
|
||||
2. **RELEASE COMPLETION**: All steps completed successfully?
|
||||
|
||||
## Advanced Safety Features
|
||||
|
||||
### Rollback Procedures
|
||||
@@ -544,7 +705,7 @@ echo "- GitHub: Update release with warning notes"
|
||||
The command implements multiple quality gates:
|
||||
|
||||
1. **🔒 Security Gate**: Vulnerability scanning, secret detection
|
||||
2. **🧪 Quality Gate**: Full test suite, linting, type checking
|
||||
2. **🧪 Quality Gate**: Unit and component tests, linting, type checking
|
||||
3. **📋 Content Gate**: Changelog accuracy, release notes quality
|
||||
4. **🔄 Process Gate**: Release timing verification
|
||||
5. **✅ Verification Gate**: Multi-channel publishing confirmation
|
||||
@@ -582,44 +743,46 @@ The command implements multiple quality gates:
|
||||
- Draft release status
|
||||
- Python package specs require that prereleases use alpha/beta/rc as the preid
|
||||
|
||||
## Common Issues and Solutions
|
||||
## Critical Implementation Notes
|
||||
|
||||
### Issue: Pre-release Version Confusion
|
||||
**Problem**: Not sure whether to promote pre-release or create new version
|
||||
**Solution**:
|
||||
- Follow semver standards: a prerelease version is followed by a normal release. It should have the same major, minor, and patch versions as the prerelease.
|
||||
When executing this release process, pay attention to these key aspects:
|
||||
|
||||
### Issue: Wrong Commit Count
|
||||
**Problem**: Changelog includes commits from other branches
|
||||
**Solution**: Always use `--first-parent` flag with git log
|
||||
### Version Handling
|
||||
- For pre-release versions (e.g., 1.24.0-rc.1), the next stable release should be the same version without the suffix (1.24.0)
|
||||
- Never skip version numbers - follow semantic versioning strictly
|
||||
|
||||
**Update**: Sometimes update-locales doesn't add [skip ci] - always verify!
|
||||
### Commit History Analysis
|
||||
- **ALWAYS** use `--first-parent` flag with git log to avoid including commits from merged feature branches
|
||||
- Verify PR merge targets before including them in changelogs:
|
||||
```bash
|
||||
gh pr view ${PR_NUMBER} --json baseRefName
|
||||
```
|
||||
|
||||
### Issue: Missing PRs in Changelog
|
||||
**Problem**: PR was merged to different branch
|
||||
**Solution**: Verify PR merge target with:
|
||||
```bash
|
||||
gh pr view ${PR_NUMBER} --json baseRefName
|
||||
```
|
||||
### Release Workflow Triggers
|
||||
- The "Release" label on the PR is **CRITICAL** - without it, PyPI/npm publishing won't occur
|
||||
- Check for `[skip ci]` in commit messages before merging - this blocks the release workflow
|
||||
- If you encounter `[skip ci]`, push an empty commit to override it:
|
||||
```bash
|
||||
git commit --allow-empty -m "Trigger release workflow"
|
||||
```
|
||||
|
||||
### Issue: Release Failed Due to [skip ci]
|
||||
**Problem**: Release workflow didn't trigger after merge
|
||||
**Prevention**: Always avoid this scenario
|
||||
- Ensure that `[skip ci]` or similar flags are NOT in the `HEAD` commit message of the PR
|
||||
- Push a new, empty commit to the PR
|
||||
- Always double-check this immediately before merging
|
||||
### PR Creation Details
|
||||
- Version bump PRs come from `comfy-pr-bot`, not `github-actions`
|
||||
- The workflow typically completes in 20-30 seconds
|
||||
- Always wait for the PR to be created before trying to edit it
|
||||
|
||||
**Recovery Strategy**:
|
||||
1. Revert version in a new PR (e.g., 1.24.0 → 1.24.0-1)
|
||||
2. Merge the revert PR
|
||||
3. Run version bump workflow again
|
||||
4. This creates a fresh PR without [skip ci]
|
||||
Benefits: Cleaner than creating extra version numbers
|
||||
### Breaking Changes Detection
|
||||
- Analyze changes to public-facing APIs:
|
||||
- The `app` object and its methods
|
||||
- The `api` module exports
|
||||
- Extension and workspace manager interfaces
|
||||
- Node schema, workflow schema, and other public schemas
|
||||
- Any modifications to these require marking as breaking changes
|
||||
|
||||
## Key Learnings & Notes
|
||||
|
||||
1. **PR Author**: Version bump PRs are created by `comfy-pr-bot`, not `github-actions`
|
||||
2. **Workflow Speed**: Version bump workflow typically completes in ~20-30 seconds
|
||||
3. **Update-locales Behavior**: Inconsistent - sometimes adds [skip ci], sometimes doesn't
|
||||
4. **Recovery Options**: Reverting version is cleaner than creating extra versions
|
||||
### Recovery Procedures
|
||||
If the release workflow fails to trigger:
|
||||
1. Create a revert PR to restore the previous version
|
||||
2. Merge the revert
|
||||
3. Re-run the version bump workflow
|
||||
4. This approach is cleaner than creating extra version numbers
|
||||
|
||||
|
||||
@@ -80,7 +80,7 @@ For each commit:
|
||||
- **CONFIRMATION REQUIRED**: Conflicts resolved correctly?
|
||||
3. After successful cherry-pick:
|
||||
- Show the changes: `git show HEAD`
|
||||
- Run validation: `npm run typecheck && npm run lint`
|
||||
- Run validation: `pnpm typecheck && pnpm lint`
|
||||
4. **CONFIRMATION REQUIRED**: Cherry-pick successful and valid?
|
||||
|
||||
### Step 6: Create PR to Core Branch
|
||||
@@ -138,14 +138,50 @@ For each commit:
|
||||
```bash
|
||||
gh pr create --base core/X.Y --head release/1.23.5 \
|
||||
--title "[Release] v1.23.5" \
|
||||
--body "..." \
|
||||
--body "Release notes will be added shortly..." \
|
||||
--label "Release"
|
||||
```
|
||||
3. **CRITICAL**: Verify "Release" label is added
|
||||
4. PR description should include:
|
||||
- Version: `1.23.4` → `1.23.5`
|
||||
- Included fixes (link to previous PR)
|
||||
- Release notes for users
|
||||
4. Create standardized release notes:
|
||||
```bash
|
||||
cat > release-notes-${NEW_VERSION}.md << 'EOF'
|
||||
## ⚠️ Breaking Changes
|
||||
<!-- List breaking changes if any, otherwise remove this entire section -->
|
||||
- Breaking change description (#PR_NUMBER)
|
||||
|
||||
---
|
||||
|
||||
## What's Changed
|
||||
|
||||
### 🚀 Features
|
||||
<!-- List features here, one per line with PR reference -->
|
||||
- Feature description (#PR_NUMBER)
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
<!-- List bug fixes here, one per line with PR reference -->
|
||||
- Bug fix description (#PR_NUMBER)
|
||||
|
||||
### 🔧 Maintenance
|
||||
<!-- List refactoring, chore, and other maintenance items -->
|
||||
- Maintenance item description (#PR_NUMBER)
|
||||
|
||||
### 📚 Documentation
|
||||
<!-- List documentation changes if any, remove section if empty -->
|
||||
- Documentation update description (#PR_NUMBER)
|
||||
|
||||
### ⬆️ Dependencies
|
||||
<!-- List dependency updates -->
|
||||
- Updated dependency from vX.X.X to vY.Y.Y (#PR_NUMBER)
|
||||
|
||||
**Full Changelog**: https://github.com/Comfy-Org/ComfyUI_frontend/compare/v${CURRENT_VERSION}...v${NEW_VERSION}
|
||||
EOF
|
||||
```
|
||||
- For hotfixes, typically only populate the "Bug Fixes" section
|
||||
- Include links to the cherry-picked PRs/commits
|
||||
- Update the PR body with the release notes:
|
||||
```bash
|
||||
gh pr edit ${PR_NUMBER} --body-file release-notes-${NEW_VERSION}.md
|
||||
```
|
||||
5. **CONFIRMATION REQUIRED**: Release PR has "Release" label?
|
||||
|
||||
### Step 11: Monitor Release Process
|
||||
@@ -161,7 +197,7 @@ For each commit:
|
||||
5. Track progress:
|
||||
- GitHub release draft/publication
|
||||
- PyPI upload
|
||||
- npm types publication
|
||||
- pnpm types publication
|
||||
|
||||
### Step 12: Post-Release Verification
|
||||
|
||||
@@ -175,7 +211,7 @@ For each commit:
|
||||
```
|
||||
3. Verify npm package:
|
||||
```bash
|
||||
npm view @comfyorg/comfyui-frontend-types@1.23.5
|
||||
pnpm view @comfyorg/comfyui-frontend-types@1.23.5
|
||||
```
|
||||
4. Generate release summary with:
|
||||
- Version released
|
||||
|
||||
131
.claude/commands/pr.md
Normal file
131
.claude/commands/pr.md
Normal file
@@ -0,0 +1,131 @@
|
||||
# Create PR
|
||||
|
||||
Automate PR creation with proper tags, labels, and concise summary.
|
||||
|
||||
## Step 1: Check Prerequisites
|
||||
|
||||
```bash
|
||||
# Ensure you have uncommitted changes
|
||||
git status
|
||||
|
||||
# If changes exist, commit them first
|
||||
git add .
|
||||
git commit -m "[tag] Your commit message"
|
||||
```
|
||||
|
||||
## Step 2: Push and Create PR
|
||||
|
||||
You'll create the PR with the following structure:
|
||||
|
||||
### PR Tags (use in title)
|
||||
|
||||
- `[feat]` - New features → label: `enhancement`
|
||||
- `[bugfix]` - Bug fixes → label: `verified bug`
|
||||
- `[refactor]` - Code restructuring → label: `enhancement`
|
||||
- `[docs]` - Documentation → label: `documentation`
|
||||
- `[test]` - Test changes → label: `enhancement`
|
||||
- `[ci]` - CI/CD changes → label: `enhancement`
|
||||
|
||||
### Label Mapping
|
||||
|
||||
#### General Labels
|
||||
|
||||
- Feature/Enhancement: `enhancement`
|
||||
- Bug fixes: `verified bug`
|
||||
- Documentation: `documentation`
|
||||
- Dependencies: `dependencies`
|
||||
- Performance: `Performance`
|
||||
- Desktop app: `Electron`
|
||||
|
||||
#### Product Area Labels
|
||||
|
||||
**Core Features**
|
||||
|
||||
- `area:nodes` - Node-related functionality
|
||||
- `area:workflows` - Workflow management
|
||||
- `area:queue` - Queue system
|
||||
- `area:models` - Model handling
|
||||
- `area:templates` - Template system
|
||||
- `area:subgraph` - Subgraph functionality
|
||||
|
||||
**UI Components**
|
||||
|
||||
- `area:ui` - General user interface improvements
|
||||
- `area:widgets` - Widget system
|
||||
- `area:dom-widgets` - DOM-based widgets
|
||||
- `area:links` - Connection links between nodes
|
||||
- `area:groups` - Node grouping functionality
|
||||
- `area:reroutes` - Reroute nodes
|
||||
- `area:previews` - Preview functionality
|
||||
- `area:minimap` - Minimap navigation
|
||||
- `area:floating-toolbox` - Floating toolbar
|
||||
- `area:mask-editor` - Mask editing tools
|
||||
|
||||
**Navigation & Organization**
|
||||
|
||||
- `area:navigation` - Navigation system
|
||||
- `area:search` - Search functionality
|
||||
- `area:workspace-management` - Workspace features
|
||||
- `area:topbar-menu` - Top bar menu
|
||||
- `area:help-menu` - Help menu system
|
||||
|
||||
**System Features**
|
||||
|
||||
- `area:settings` - Settings/preferences
|
||||
- `area:hotkeys` - Keyboard shortcuts
|
||||
- `area:undo-redo` - Undo/redo system
|
||||
- `area:customization` - Customization features
|
||||
- `area:auth` - Authentication
|
||||
- `area:comms` - Communication/networking
|
||||
|
||||
**Development & Infrastructure**
|
||||
|
||||
- `area:CI/CD` - CI/CD pipeline
|
||||
- `area:testing` - Testing infrastructure
|
||||
- `area:vue-migration` - Vue migration work
|
||||
- `area:manager` - ComfyUI Manager integration
|
||||
|
||||
**Platform-Specific**
|
||||
|
||||
- `area:mobile` - Mobile support
|
||||
- `area:3d` - 3D-related features
|
||||
|
||||
**Special Areas**
|
||||
|
||||
- `area:i18n` - Translation/internationalization
|
||||
- `area:CNR` - Comfy Node Registry
|
||||
|
||||
## Step 3: Execute PR Creation
|
||||
|
||||
```bash
|
||||
# First, push your branch
|
||||
git push -u origin $(git branch --show-current)
|
||||
|
||||
# Then create the PR (replace placeholders)
|
||||
gh pr create \
|
||||
--title "[TAG] Brief description" \
|
||||
--body "$(cat <<'EOF'
|
||||
## Summary
|
||||
One sentence describing what changed and why.
|
||||
|
||||
## Changes
|
||||
- **What**: Core functionality added/modified
|
||||
- **Breaking**: Any breaking changes (if none, omit this line)
|
||||
- **Dependencies**: New dependencies (if none, omit this line)
|
||||
|
||||
## Review Focus
|
||||
- Critical design decisions or edge cases that need attention
|
||||
|
||||
Fixes #ISSUE_NUMBER
|
||||
EOF
|
||||
)" \
|
||||
--label "APPROPRIATE_LABEL" \
|
||||
--base main
|
||||
```
|
||||
|
||||
## Additional Options
|
||||
|
||||
- Add multiple labels: `--label "enhancement,Performance"`
|
||||
- Request reviewers: `--reviewer @username`
|
||||
- Mark as draft: `--draft`
|
||||
- Open in browser after creation: `--web`
|
||||
158
.claude/commands/setup_repo.md
Normal file
158
.claude/commands/setup_repo.md
Normal file
@@ -0,0 +1,158 @@
|
||||
# Setup Repository
|
||||
|
||||
Bootstrap the ComfyUI Frontend monorepo with all necessary dependencies and verification checks.
|
||||
|
||||
## Overview
|
||||
|
||||
This command will:
|
||||
1. Install pnpm package manager (if not present)
|
||||
2. Install all project dependencies
|
||||
3. Verify the project builds successfully
|
||||
4. Run unit tests to ensure functionality
|
||||
5. Start development server to verify frontend boots correctly
|
||||
|
||||
## Prerequisites Check
|
||||
|
||||
First, let's verify the environment:
|
||||
|
||||
```bash
|
||||
# Check Node.js version (should be >= 24)
|
||||
node --version
|
||||
|
||||
# Check if we're in a git repository
|
||||
git status
|
||||
```
|
||||
|
||||
## Step 1: Install pnpm
|
||||
|
||||
```bash
|
||||
# Check if pnpm is already installed
|
||||
pnpm --version 2>/dev/null || {
|
||||
echo "Installing pnpm..."
|
||||
npm install -g pnpm
|
||||
}
|
||||
|
||||
# Verify pnpm installation
|
||||
pnpm --version
|
||||
```
|
||||
|
||||
## Step 2: Install Dependencies
|
||||
|
||||
```bash
|
||||
# Install all dependencies using pnpm
|
||||
echo "Installing project dependencies..."
|
||||
pnpm install
|
||||
|
||||
# Verify node_modules exists and has packages
|
||||
ls -la node_modules | head -5
|
||||
```
|
||||
|
||||
## Step 3: Verify Build
|
||||
|
||||
```bash
|
||||
# Run TypeScript type checking
|
||||
echo "Running TypeScript checks..."
|
||||
pnpm typecheck
|
||||
|
||||
# Build the project
|
||||
echo "Building project..."
|
||||
pnpm build
|
||||
|
||||
# Verify dist folder was created
|
||||
ls -la dist/
|
||||
```
|
||||
|
||||
## Step 4: Run Unit Tests
|
||||
|
||||
```bash
|
||||
# Run unit tests
|
||||
echo "Running unit tests..."
|
||||
pnpm test:unit
|
||||
|
||||
# If tests fail, show the output and stop
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "❌ Unit tests failed. Please fix failing tests before continuing."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ Unit tests passed successfully"
|
||||
```
|
||||
|
||||
## Step 5: Verify Development Server
|
||||
|
||||
```bash
|
||||
# Start development server in background
|
||||
echo "Starting development server..."
|
||||
pnpm dev &
|
||||
SERVER_PID=$!
|
||||
|
||||
# Wait for server to start (check for port 5173 or similar)
|
||||
echo "Waiting for server to start..."
|
||||
sleep 10
|
||||
|
||||
# Check if server is running
|
||||
if curl -s http://localhost:5173 > /dev/null 2>&1; then
|
||||
echo "✅ Development server started successfully at http://localhost:5173"
|
||||
|
||||
# Kill the background server
|
||||
kill $SERVER_PID
|
||||
wait $SERVER_PID 2>/dev/null
|
||||
else
|
||||
echo "❌ Development server failed to start or is not accessible"
|
||||
kill $SERVER_PID 2>/dev/null
|
||||
wait $SERVER_PID 2>/dev/null
|
||||
exit 1
|
||||
fi
|
||||
```
|
||||
|
||||
## Step 6: Final Verification
|
||||
|
||||
```bash
|
||||
# Run linting to ensure code quality
|
||||
echo "Running linter..."
|
||||
pnpm lint
|
||||
|
||||
# Show project status
|
||||
echo ""
|
||||
echo "🎉 Repository setup complete!"
|
||||
echo ""
|
||||
echo "Available commands:"
|
||||
echo " pnpm dev - Start development server"
|
||||
echo " pnpm build - Build for production"
|
||||
echo " pnpm test:unit - Run unit tests"
|
||||
echo " pnpm test:component - Run component tests"
|
||||
echo " pnpm typecheck - Run TypeScript checks"
|
||||
echo " pnpm lint - Run ESLint"
|
||||
echo " pnpm format - Format code with Prettier"
|
||||
echo ""
|
||||
echo "Next steps:"
|
||||
echo "1. Run 'pnpm dev' to start developing"
|
||||
echo "2. Open http://localhost:5173 in your browser"
|
||||
echo "3. Check README.md for additional setup instructions"
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If any step fails:
|
||||
|
||||
1. **pnpm installation fails**: Try using `curl -fsSL https://get.pnpm.io/install.sh | sh -`
|
||||
2. **Dependencies fail to install**: Try clearing cache with `pnpm store prune` and retry
|
||||
3. **Build fails**: Check for TypeScript errors and fix them first
|
||||
4. **Tests fail**: Review test output and fix failing tests
|
||||
5. **Dev server fails**: Check if port 5173 is already in use
|
||||
|
||||
## Manual Verification Steps
|
||||
|
||||
After running the setup, manually verify:
|
||||
|
||||
1. **Dependencies installed**: `ls node_modules | wc -l` should show many packages
|
||||
2. **Build artifacts**: `ls dist/` should show built files
|
||||
3. **Server accessible**: Open http://localhost:5173 in browser
|
||||
4. **Hot reload works**: Edit a file and see changes reflect
|
||||
|
||||
## Environment Requirements
|
||||
|
||||
- Node.js >= 24
|
||||
- Git repository
|
||||
- Internet connection for package downloads
|
||||
- Available ports (typically 5173 for dev server)
|
||||
@@ -5,7 +5,7 @@ Follow these steps systematically to verify our changes:
|
||||
|
||||
1. **Server Setup**
|
||||
- Check if the dev server is running on port 5173 using browser navigation or port checking
|
||||
- If not running, start it with `npm run dev` from the root directory
|
||||
- If not running, start it with `pnpm dev` from the root directory
|
||||
- If the server fails to start, provide detailed troubleshooting steps by reading package.json and README.md for accurate instructions
|
||||
- Wait for the server to be fully ready before proceeding
|
||||
|
||||
|
||||
21
.cursor/rules/unit-test.mdc
Normal file
21
.cursor/rules/unit-test.mdc
Normal file
@@ -0,0 +1,21 @@
|
||||
---
|
||||
description: Creating unit tests
|
||||
globs:
|
||||
alwaysApply: false
|
||||
---
|
||||
|
||||
# Creating unit tests
|
||||
|
||||
- This project uses `vitest` for unit testing
|
||||
- Tests are stored in the `test/` directory
|
||||
- Tests should be cross-platform compatible; able to run on Windows, macOS, and linux
|
||||
- e.g. the use of `path.resolve`, or `path.join` and `path.sep` to ensure that tests work the same on all platforms
|
||||
- Tests should be mocked properly
|
||||
- Mocks should be cleanly written and easy to understand
|
||||
- Mocks should be re-usable where possible
|
||||
|
||||
## Unit test style
|
||||
|
||||
- Prefer the use of `test.extend` over loose variables
|
||||
- To achieve this, import `test as baseTest` from `vitest`
|
||||
- Never use `it`; `test` should be used in place of this
|
||||
@@ -49,7 +49,7 @@ DO NOT use deprecated PrimeVue components. Use these replacements instead:
|
||||
|
||||
## Development Guidelines
|
||||
1. Leverage VueUse functions for performance-enhancing styles
|
||||
2. Use lodash for utility functions
|
||||
2. Use es-toolkit for utility functions
|
||||
3. Use TypeScript for type safety
|
||||
4. Implement proper props and emits definitions
|
||||
5. Utilize Vue 3's Teleport component when needed
|
||||
|
||||
6
.git-blame-ignore-revs
Normal file
6
.git-blame-ignore-revs
Normal file
@@ -0,0 +1,6 @@
|
||||
# .git-blame-ignore-revs
|
||||
# List of commits to ignore in git blame
|
||||
# Format: <commit hash> # <description>
|
||||
|
||||
# npm run format on litegraph merge (10,672 insertions, 7,327 deletions across 129 files)
|
||||
c53f197de2a3e0fa66b16dedc65c131235c1c4b6
|
||||
10
.gitattributes
vendored
10
.gitattributes
vendored
@@ -2,6 +2,14 @@
|
||||
* text=auto
|
||||
|
||||
# Force TS to LF to make the unixy scripts not break on Windows
|
||||
*.cjs text eol=lf
|
||||
*.js text eol=lf
|
||||
*.json text eol=lf
|
||||
*.mjs text eol=lf
|
||||
*.mts text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.vue text eol=lf
|
||||
*.js text eol=lf
|
||||
|
||||
# Generated files
|
||||
src/types/comfyRegistryTypes.ts linguist-generated=true
|
||||
src/types/generatedManagerTypes.ts linguist-generated=true
|
||||
|
||||
158
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
158
.github/ISSUE_TEMPLATE/bug-report.yaml
vendored
@@ -1,99 +1,105 @@
|
||||
name: Bug Report
|
||||
description: 'Something is not behaving as expected.'
|
||||
title: '[Bug]: '
|
||||
description: 'Report something that is not working correctly'
|
||||
labels: ['Potential Bug']
|
||||
type: Bug
|
||||
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Before submitting a **Bug Report**, please ensure the following:
|
||||
|
||||
- **1:** You are running the latest version of ComfyUI.
|
||||
- **2:** You have looked at the existing bug reports and made sure this isn't already reported.
|
||||
|
||||
- type: checkboxes
|
||||
id: custom-nodes-test
|
||||
attributes:
|
||||
label: Custom Node Testing
|
||||
description: Please confirm you have tried to reproduce the issue with all custom nodes disabled.
|
||||
label: Prerequisites
|
||||
options:
|
||||
- label: I have tried disabling custom nodes and the issue persists (see [how to disable custom nodes](https://docs.comfy.org/troubleshooting/custom-node-issues#step-1%3A-test-with-all-custom-nodes-disabled) if you need help)
|
||||
- label: I am running the latest version of ComfyUI
|
||||
required: true
|
||||
- label: I have searched existing issues to make sure this isn't a duplicate
|
||||
required: true
|
||||
- label: I have tested with all custom nodes disabled ([see how](https://docs.comfy.org/troubleshooting/custom-node-issues#step-1%3A-test-with-all-custom-nodes-disabled))
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: description
|
||||
attributes:
|
||||
label: Frontend Version
|
||||
description: |
|
||||
What is the frontend version you are using? You can check this in the settings dialog.
|
||||
|
||||
<details>
|
||||
|
||||
<summary>Click to show where to find the version</summary>
|
||||
|
||||
Open the setting by clicking the cog icon in the bottom-left of the screen, then click `About`.
|
||||
|
||||

|
||||
|
||||
</details>
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: 'What you expected to happen.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Actual Behavior
|
||||
description: 'What actually happened. Please include a screenshot / video clip of the issue if possible.'
|
||||
label: What happened?
|
||||
description: A clear and concise description of the bug. Include screenshots or videos if helpful.
|
||||
placeholder: |
|
||||
Example: "When I connect a VAE Decode node to a KSampler, the connection line appears but the workflow fails to execute with an error message..."
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: textarea
|
||||
id: reproduce
|
||||
attributes:
|
||||
label: Steps to Reproduce
|
||||
description: "Describe how to reproduce the issue. Please be sure to attach a workflow JSON or PNG, ideally one that doesn't require custom nodes to test. If the bug open happens when certain custom nodes are used, most likely that custom node is what has the bug rather than ComfyUI, in which case it should be reported to the node's author."
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Debug Logs
|
||||
description: 'Please copy the output from your terminal logs here.'
|
||||
render: powershell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Browser Logs
|
||||
description: 'Please copy the output from your browser logs here. You can access this by pressing F12 to toggle the developer tools, then navigating to the Console tab.'
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Setting JSON
|
||||
description: 'Please upload the setting file here. The setting file is located at `user/default/comfy.settings.json`'
|
||||
description: How can we reproduce this issue? Please attach your workflow (JSON or PNG).
|
||||
placeholder: |
|
||||
1. Add a KSampler node
|
||||
2. Connect it to...
|
||||
3. Click Queue Prompt
|
||||
4. See error
|
||||
value: |
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: browsers
|
||||
id: severity
|
||||
attributes:
|
||||
label: What browsers do you use to access the UI ?
|
||||
multiple: true
|
||||
label: How is this affecting you?
|
||||
options:
|
||||
- Mozilla Firefox
|
||||
- Google Chrome
|
||||
- Brave
|
||||
- Apple Safari
|
||||
- Microsoft Edge
|
||||
- Android
|
||||
- iOS
|
||||
- Other
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Other Information
|
||||
description: 'Any other context, details, or screenshots that might help solve the issue.'
|
||||
placeholder: 'Add any other relevant information here...'
|
||||
- Crashes ComfyUI completely
|
||||
- Workflow won't execute
|
||||
- Feature doesn't work as expected
|
||||
- Visual/UI issue only
|
||||
- Minor inconvenience
|
||||
validations:
|
||||
required: false
|
||||
required: true
|
||||
|
||||
- type: input
|
||||
id: version
|
||||
attributes:
|
||||
label: ComfyUI Frontend Version
|
||||
description: Found in Settings > About (e.g., "1.3.45")
|
||||
placeholder: "1.3.45"
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: dropdown
|
||||
id: browser
|
||||
attributes:
|
||||
label: Browser
|
||||
description: Which browser are you using?
|
||||
options:
|
||||
- Chrome/Chromium
|
||||
- Firefox
|
||||
- Safari
|
||||
- Edge
|
||||
- Other
|
||||
validations:
|
||||
required: true
|
||||
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
## Additional Information (Optional)
|
||||
*The following fields help us debug complex issues but are not required for most bug reports.*
|
||||
|
||||
- type: textarea
|
||||
id: console-errors
|
||||
attributes:
|
||||
label: Console Errors
|
||||
description: If you see red error messages in the browser console (F12), paste them here
|
||||
render: javascript
|
||||
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Logs
|
||||
description: If relevant, paste any terminal/server logs here
|
||||
render: shell
|
||||
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional Context
|
||||
description: Any other information that might help (OS, GPU, specific nodes involved, etc.)
|
||||
|
||||
75
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
75
.github/ISSUE_TEMPLATE/feature-request.yaml
vendored
@@ -1,41 +1,80 @@
|
||||
name: Feature Request
|
||||
description: Suggest an idea for this project
|
||||
title: '[Feature Request]: '
|
||||
labels: ['enhancement']
|
||||
description: Report a problem or limitation you're experiencing
|
||||
labels: []
|
||||
type: Feature
|
||||
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the feature you want, and that it's not implemented in a recent build/commit.
|
||||
description: Please search to see if an issue already exists for the problem you're experiencing, and that it's not addressed in a recent build/commit.
|
||||
options:
|
||||
- label: I have searched the existing issues and checked the recent builds/commits
|
||||
required: true
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
*Please fill this form with as much information as possible, provide screenshots and/or illustrations of the feature if possible*
|
||||
*Please focus on describing the problem you're experiencing rather than proposing specific solutions. This helps us design the best possible solution for you and other users.*
|
||||
- type: textarea
|
||||
id: feature
|
||||
id: problem
|
||||
attributes:
|
||||
label: What would your feature do ?
|
||||
description: Tell us about your feature in a very clear and simple way, and what problem it would solve
|
||||
label: What problem are you experiencing?
|
||||
description: Describe the issue or limitation you're facing in your workflow
|
||||
placeholder: |
|
||||
Example: "I frequently lose work when switching between different projects because there's no way to save my current workspace state"
|
||||
NOT: "Add a save button that exports the workspace"
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: workflow
|
||||
id: context
|
||||
attributes:
|
||||
label: Proposed workflow
|
||||
description: Please provide us with step by step information on how you'd like the feature to be accessed and used
|
||||
value: |
|
||||
1. Go to ....
|
||||
2. Press ....
|
||||
3. ...
|
||||
label: When does this problem occur?
|
||||
description: Describe the specific situations or workflows where you encounter this issue
|
||||
placeholder: |
|
||||
- When working with large node graphs...
|
||||
- During batch processing workflows...
|
||||
- While collaborating with team members...
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: frequency
|
||||
attributes:
|
||||
label: How often do you encounter this problem?
|
||||
options:
|
||||
- Multiple times per day
|
||||
- Daily
|
||||
- Several times per week
|
||||
- Weekly
|
||||
- Occasionally
|
||||
- Rarely
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
id: impact
|
||||
attributes:
|
||||
label: How much does this problem affect your workflow?
|
||||
description: Help us understand the severity of this issue for you
|
||||
options:
|
||||
- Blocks me from completing tasks
|
||||
- Significantly slows down my work
|
||||
- Causes moderate inconvenience
|
||||
- Minor annoyance
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: misc
|
||||
id: workaround
|
||||
attributes:
|
||||
label: Additional information
|
||||
description: Add any other context or screenshots about the feature request here.
|
||||
label: Current workarounds
|
||||
description: How do you currently deal with this problem, if at all?
|
||||
placeholder: |
|
||||
Example: "I manually export and reimport nodes between projects, which takes 10-15 minutes each time"
|
||||
- type: textarea
|
||||
id: ideas
|
||||
attributes:
|
||||
label: Ideas for solutions (Optional)
|
||||
description: If you have thoughts on potential solutions, feel free to share them here. However, we'll explore all possible options to find the best approach.
|
||||
- type: textarea
|
||||
id: additional
|
||||
attributes:
|
||||
label: Additional context
|
||||
description: Add any other context, screenshots, or examples that help illustrate the problem.
|
||||
|
||||
2
.github/copilot-instructions.md
vendored
2
.github/copilot-instructions.md
vendored
@@ -18,7 +18,7 @@ Use Tailwind CSS for styling
|
||||
|
||||
Leverage VueUse functions for performance-enhancing styles
|
||||
|
||||
Use lodash for utility functions
|
||||
Use es-toolkit for utility functions
|
||||
|
||||
Use TypeScript for type safety
|
||||
|
||||
|
||||
20
.github/pull_request_template.md
vendored
Normal file
20
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
## Summary
|
||||
|
||||
<!-- One sentence describing what changed and why. -->
|
||||
|
||||
## Changes
|
||||
|
||||
- **What**: <!-- Core functionality added/modified -->
|
||||
- **Breaking**: <!-- Any breaking changes (if none, remove this line) -->
|
||||
- **Dependencies**: <!-- New dependencies (if none, remove this line) -->
|
||||
|
||||
## Review Focus
|
||||
|
||||
<!-- Critical design decisions or edge cases that need attention -->
|
||||
|
||||
<!-- If this PR fixes an issue, uncomment and update the line below -->
|
||||
<!-- Fixes #ISSUE_NUMBER -->
|
||||
|
||||
## Screenshots (if applicable)
|
||||
|
||||
<!-- Add screenshots or video recording to help explain your changes -->
|
||||
165
.github/workflows/backport.yaml
vendored
Normal file
165
.github/workflows/backport.yaml
vendored
Normal file
@@ -0,0 +1,165 @@
|
||||
name: Auto Backport
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types: [closed]
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
backport:
|
||||
if: github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'needs-backport')
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Configure git
|
||||
run: |
|
||||
git config user.name "github-actions[bot]"
|
||||
git config user.email "github-actions[bot]@users.noreply.github.com"
|
||||
|
||||
- name: Extract version labels
|
||||
id: versions
|
||||
run: |
|
||||
# Extract version labels (e.g., "1.24", "1.22")
|
||||
VERSIONS=""
|
||||
LABELS='${{ toJSON(github.event.pull_request.labels) }}'
|
||||
for label in $(echo "$LABELS" | jq -r '.[].name'); do
|
||||
# Match version labels like "1.24" (major.minor only)
|
||||
if [[ "$label" =~ ^[0-9]+\.[0-9]+$ ]]; then
|
||||
# Validate the branch exists before adding to list
|
||||
if git ls-remote --exit-code origin "core/${label}" >/dev/null 2>&1; then
|
||||
VERSIONS="${VERSIONS}${label} "
|
||||
else
|
||||
echo "::warning::Label '${label}' found but branch 'core/${label}' does not exist"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ -z "$VERSIONS" ]; then
|
||||
echo "::error::No version labels found (e.g., 1.24, 1.22)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "versions=${VERSIONS}" >> $GITHUB_OUTPUT
|
||||
echo "Found version labels: ${VERSIONS}"
|
||||
|
||||
- name: Backport commits
|
||||
id: backport
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
PR_TITLE: ${{ github.event.pull_request.title }}
|
||||
MERGE_COMMIT: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
run: |
|
||||
FAILED=""
|
||||
SUCCESS=""
|
||||
|
||||
for version in ${{ steps.versions.outputs.versions }}; do
|
||||
echo "::group::Backporting to core/${version}"
|
||||
|
||||
TARGET_BRANCH="core/${version}"
|
||||
BACKPORT_BRANCH="backport-${PR_NUMBER}-to-${version}"
|
||||
|
||||
# Fetch target branch (fail if doesn't exist)
|
||||
if ! git fetch origin "${TARGET_BRANCH}"; then
|
||||
echo "::error::Target branch ${TARGET_BRANCH} does not exist"
|
||||
FAILED="${FAILED}${version}:branch-missing "
|
||||
echo "::endgroup::"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Create backport branch
|
||||
git checkout -b "${BACKPORT_BRANCH}" "origin/${TARGET_BRANCH}"
|
||||
|
||||
# Try cherry-pick
|
||||
if git cherry-pick "${MERGE_COMMIT}"; then
|
||||
git push origin "${BACKPORT_BRANCH}"
|
||||
SUCCESS="${SUCCESS}${version}:${BACKPORT_BRANCH} "
|
||||
echo "Successfully created backport branch: ${BACKPORT_BRANCH}"
|
||||
# Return to main (keep the branch, we need it for PR)
|
||||
git checkout main
|
||||
else
|
||||
# Get conflict info
|
||||
CONFLICTS=$(git diff --name-only --diff-filter=U | tr '\n' ',')
|
||||
git cherry-pick --abort
|
||||
|
||||
echo "::error::Cherry-pick failed due to conflicts"
|
||||
FAILED="${FAILED}${version}:conflicts:${CONFLICTS} "
|
||||
|
||||
# Clean up the failed branch
|
||||
git checkout main
|
||||
git branch -D "${BACKPORT_BRANCH}"
|
||||
fi
|
||||
|
||||
echo "::endgroup::"
|
||||
done
|
||||
|
||||
echo "success=${SUCCESS}" >> $GITHUB_OUTPUT
|
||||
echo "failed=${FAILED}" >> $GITHUB_OUTPUT
|
||||
|
||||
if [ -n "${FAILED}" ]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Create PR for each successful backport
|
||||
if: steps.backport.outputs.success
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.PR_GH_TOKEN }}
|
||||
run: |
|
||||
PR_TITLE="${{ github.event.pull_request.title }}"
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
|
||||
|
||||
for backport in ${{ steps.backport.outputs.success }}; do
|
||||
IFS=':' read -r version branch <<< "${backport}"
|
||||
|
||||
if PR_URL=$(gh pr create \
|
||||
--base "core/${version}" \
|
||||
--head "${branch}" \
|
||||
--title "[backport ${version}] ${PR_TITLE}" \
|
||||
--body "Backport of #${PR_NUMBER} to \`core/${version}\`"$'\n\n'"Automatically created by backport workflow." \
|
||||
--label "backport" 2>&1); then
|
||||
|
||||
# Extract PR number from URL
|
||||
PR_NUM=$(echo "${PR_URL}" | grep -o '[0-9]*$')
|
||||
|
||||
if [ -n "${PR_NUM}" ]; then
|
||||
gh pr comment "${PR_NUMBER}" --body "@${PR_AUTHOR} Successfully backported to #${PR_NUM}"
|
||||
fi
|
||||
else
|
||||
echo "::error::Failed to create PR for ${version}: ${PR_URL}"
|
||||
# Still try to comment on the original PR about the failure
|
||||
gh pr comment "${PR_NUMBER}" --body "@${PR_AUTHOR} Backport branch created but PR creation failed for \`core/${version}\`. Please create the PR manually from branch \`${branch}\`"
|
||||
fi
|
||||
done
|
||||
|
||||
- name: Comment on failures
|
||||
if: failure() && steps.backport.outputs.failed
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
PR_NUMBER="${{ github.event.pull_request.number }}"
|
||||
PR_AUTHOR="${{ github.event.pull_request.user.login }}"
|
||||
MERGE_COMMIT="${{ github.event.pull_request.merge_commit_sha }}"
|
||||
|
||||
for failure in ${{ steps.backport.outputs.failed }}; do
|
||||
IFS=':' read -r version reason conflicts <<< "${failure}"
|
||||
|
||||
if [ "${reason}" = "branch-missing" ]; then
|
||||
gh pr comment "${PR_NUMBER}" --body "@${PR_AUTHOR} Backport failed: Branch \`core/${version}\` does not exist"
|
||||
|
||||
elif [ "${reason}" = "conflicts" ]; then
|
||||
# Convert comma-separated conflicts back to newlines for display
|
||||
CONFLICTS_LIST=$(echo "${conflicts}" | tr ',' '\n' | sed 's/^/- /')
|
||||
|
||||
COMMENT_BODY="@${PR_AUTHOR} Backport to \`core/${version}\` failed: Merge conflicts detected."$'\n\n'"Please manually cherry-pick commit \`${MERGE_COMMIT}\` to the \`core/${version}\` branch."$'\n\n'"<details><summary>Conflicting files</summary>"$'\n\n'"${CONFLICTS_LIST}"$'\n\n'"</details>"
|
||||
gh pr comment "${PR_NUMBER}" --body "${COMMENT_BODY}"
|
||||
fi
|
||||
done
|
||||
117
.github/workflows/chromatic.yaml
vendored
Normal file
117
.github/workflows/chromatic.yaml
vendored
Normal file
@@ -0,0 +1,117 @@
|
||||
name: 'Chromatic'
|
||||
|
||||
# - [Automate Chromatic with GitHub Actions • Chromatic docs]( https://www.chromatic.com/docs/github-actions/ )
|
||||
|
||||
on:
|
||||
workflow_dispatch: # Allow manual triggering
|
||||
pull_request:
|
||||
branches: [main]
|
||||
|
||||
jobs:
|
||||
chromatic-deployment:
|
||||
runs-on: ubuntu-latest
|
||||
# Only run for PRs from version-bump-* branches or manual triggers
|
||||
if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'version-bump-')
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0 # Required for Chromatic baseline
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Get current time
|
||||
id: current-time
|
||||
run: echo "time=$(date -u '+%m/%d/%Y, %I:%M:%S %p')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR - Build Started
|
||||
if: github.event_name == 'pull_request'
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- STORYBOOK_BUILD_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: append
|
||||
body: |
|
||||
<!-- STORYBOOK_BUILD_STATUS -->
|
||||
## 🎨 Storybook Build Status
|
||||
|
||||
🔄 **Building Storybook and running visual tests...**
|
||||
|
||||
⏳ Build started at: ${{ steps.current-time.outputs.time }} UTC
|
||||
|
||||
---
|
||||
*This comment will be updated when the build completes*
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
storybook-static
|
||||
tsconfig.tsbuildinfo
|
||||
key: storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', '*.config.*', '.storybook/**/*') }}
|
||||
restore-keys: |
|
||||
storybook-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||
storybook-cache-${{ runner.os }}-
|
||||
storybook-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Build Storybook and run Chromatic
|
||||
id: chromatic
|
||||
uses: chromaui/action@latest
|
||||
with:
|
||||
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
|
||||
buildScriptName: build-storybook
|
||||
autoAcceptChanges: 'main' # Auto-accept changes on main branch
|
||||
exitOnceUploaded: true # Don't wait for UI tests to complete
|
||||
|
||||
- name: Get completion time
|
||||
id: completion-time
|
||||
if: always()
|
||||
run: echo "time=$(date -u '+%m/%d/%Y, %I:%M:%S %p')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR - Build Complete
|
||||
if: github.event_name == 'pull_request' && always()
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- STORYBOOK_BUILD_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: replace
|
||||
body: |
|
||||
<!-- STORYBOOK_BUILD_STATUS -->
|
||||
## 🎨 Storybook Build Status
|
||||
|
||||
${{ steps.chromatic.outcome == 'success' && '✅' || '❌' }} **${{ steps.chromatic.outcome == 'success' && 'Build completed successfully!' || 'Build failed!' }}**
|
||||
|
||||
⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC
|
||||
|
||||
### 📊 Build Summary
|
||||
- **Components**: ${{ steps.chromatic.outputs.componentCount || '0' }}
|
||||
- **Stories**: ${{ steps.chromatic.outputs.testCount || '0' }}
|
||||
- **Visual changes**: ${{ steps.chromatic.outputs.changeCount || '0' }}
|
||||
- **Errors**: ${{ steps.chromatic.outputs.errorCount || '0' }}
|
||||
|
||||
### 🔗 Links
|
||||
${{ steps.chromatic.outputs.buildUrl && format('- [📸 View Chromatic Build]({0})', steps.chromatic.outputs.buildUrl) || '' }}
|
||||
${{ steps.chromatic.outputs.storybookUrl && format('- [📖 Preview Storybook]({0})', steps.chromatic.outputs.storybookUrl) || '' }}
|
||||
|
||||
---
|
||||
${{ steps.chromatic.outcome == 'success' && '🎉 Your Storybook is ready for review!' || '⚠️ Please check the workflow logs for error details.' }}
|
||||
27
.github/workflows/claude-pr-review.yml
vendored
27
.github/workflows/claude-pr-review.yml
vendored
@@ -4,6 +4,8 @@ permissions:
|
||||
contents: read
|
||||
pull-requests: write
|
||||
issues: write
|
||||
id-token: write
|
||||
statuses: write
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
@@ -17,10 +19,10 @@ jobs:
|
||||
should-proceed: ${{ steps.check-status.outputs.proceed }}
|
||||
steps:
|
||||
- name: Wait for other CI checks
|
||||
uses: lewagon/wait-on-check-action@v1.3.1
|
||||
uses: lewagon/wait-on-check-action@e106e5c43e8ca1edea6383a39a01c5ca495fd812
|
||||
with:
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
check-regexp: '^(ESLint|Prettier Check|Tests CI|Vitest Tests)'
|
||||
check-regexp: '^(lint-and-format|test|playwright-tests)'
|
||||
wait-interval: 30
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
@@ -28,7 +30,7 @@ jobs:
|
||||
id: check-status
|
||||
run: |
|
||||
# Get all check runs for this commit
|
||||
CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("ESLint|Prettier Check|Tests CI|Vitest Tests")) | {name, conclusion}')
|
||||
CHECK_RUNS=$(gh api repos/${{ github.repository }}/commits/${{ github.event.pull_request.head.sha }}/check-runs --jq '.check_runs[] | select(.name | test("lint-and-format|test|playwright-tests")) | {name, conclusion}')
|
||||
|
||||
# Check if any required checks failed
|
||||
if echo "$CHECK_RUNS" | grep -q '"conclusion": "failure"'; then
|
||||
@@ -51,22 +53,35 @@ jobs:
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '20'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Install dependencies for analysis tools
|
||||
run: |
|
||||
npm install -g typescript @vue/compiler-sfc
|
||||
pnpm install -g typescript @vue/compiler-sfc
|
||||
|
||||
- name: Run Claude PR Review
|
||||
uses: anthropics/claude-code-action@main
|
||||
with:
|
||||
prompt_file: .claude/commands/comprehensive-pr-review.md
|
||||
label_trigger: "claude-review"
|
||||
direct_prompt: |
|
||||
Read the file .claude/commands/comprehensive-pr-review.md and follow ALL the instructions exactly.
|
||||
|
||||
CRITICAL: You must post individual inline comments using the gh api commands shown in the file.
|
||||
DO NOT create a summary comment.
|
||||
Each issue must be posted as a separate inline comment on the specific line of code.
|
||||
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
||||
max_turns: 1
|
||||
max_turns: 256
|
||||
timeout_minutes: 30
|
||||
allowed_tools: "Bash(git:*),Bash(gh api:*),Bash(gh pr:*),Bash(gh repo:*),Bash(jq:*),Bash(echo:*),Read,Write,Edit,Glob,Grep,WebFetch"
|
||||
env:
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
214
.github/workflows/create-release-candidate-branch.yaml
vendored
Normal file
214
.github/workflows/create-release-candidate-branch.yaml
vendored
Normal file
@@ -0,0 +1,214 @@
|
||||
name: Create Release Branch
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches: [main]
|
||||
paths:
|
||||
- 'package.json'
|
||||
|
||||
jobs:
|
||||
create-release-branch:
|
||||
runs-on: ubuntu-latest
|
||||
if: >
|
||||
github.event.pull_request.merged == true &&
|
||||
contains(github.event.pull_request.labels.*.name, 'Release')
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
token: ${{ secrets.PR_GH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
- name: Check version bump type
|
||||
id: check_version
|
||||
run: |
|
||||
# Get current version from main
|
||||
CURRENT_VERSION=$(node -p "require('./package.json').version")
|
||||
# Remove 'v' prefix if present (shouldn't be in package.json, but defensive)
|
||||
CURRENT_VERSION=${CURRENT_VERSION#v}
|
||||
echo "current_version=$CURRENT_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
# Validate version format
|
||||
if ! [[ "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||
echo "ERROR: Invalid version format: $CURRENT_VERSION"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract major and minor versions
|
||||
MAJOR=$(echo $CURRENT_VERSION | cut -d. -f1)
|
||||
MINOR=$(echo $CURRENT_VERSION | cut -d. -f2)
|
||||
PATCH=$(echo $CURRENT_VERSION | cut -d. -f3 | cut -d- -f1)
|
||||
|
||||
echo "major=$MAJOR" >> $GITHUB_OUTPUT
|
||||
echo "minor=$MINOR" >> $GITHUB_OUTPUT
|
||||
echo "patch=$PATCH" >> $GITHUB_OUTPUT
|
||||
|
||||
# Get previous version from the commit before the merge
|
||||
git checkout HEAD^1
|
||||
PREV_VERSION=$(node -p "require('./package.json').version" 2>/dev/null || echo "0.0.0")
|
||||
# Remove 'v' prefix if present
|
||||
PREV_VERSION=${PREV_VERSION#v}
|
||||
|
||||
# Validate previous version format
|
||||
if ! [[ "$PREV_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+ ]]; then
|
||||
echo "WARNING: Invalid previous version format: $PREV_VERSION, using 0.0.0"
|
||||
PREV_VERSION="0.0.0"
|
||||
fi
|
||||
|
||||
PREV_MINOR=$(echo $PREV_VERSION | cut -d. -f2)
|
||||
|
||||
echo "prev_version=$PREV_VERSION" >> $GITHUB_OUTPUT
|
||||
echo "prev_minor=$PREV_MINOR" >> $GITHUB_OUTPUT
|
||||
|
||||
# Get previous major version for comparison
|
||||
PREV_MAJOR=$(echo $PREV_VERSION | cut -d. -f1)
|
||||
|
||||
# Check if current version is a pre-release
|
||||
if [[ "$CURRENT_VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+- ]]; then
|
||||
IS_PRERELEASE=true
|
||||
else
|
||||
IS_PRERELEASE=false
|
||||
fi
|
||||
|
||||
# Check if this was a minor version bump or major version bump
|
||||
# But skip if it's a pre-release version
|
||||
if [[ "$IS_PRERELEASE" == "true" ]]; then
|
||||
echo "is_minor_bump=false" >> $GITHUB_OUTPUT
|
||||
echo "reason=prerelease version" >> $GITHUB_OUTPUT
|
||||
elif [[ "$MAJOR" -gt "$PREV_MAJOR" && "$MINOR" == "0" && "$PATCH" == "0" ]]; then
|
||||
# Major version bump (e.g., 1.99.x → 2.0.0)
|
||||
echo "is_minor_bump=true" >> $GITHUB_OUTPUT
|
||||
BRANCH_NAME="core/${PREV_MAJOR}.${PREV_MINOR}"
|
||||
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
elif [[ "$MAJOR" == "$PREV_MAJOR" && "$MINOR" -gt "$PREV_MINOR" && "$PATCH" == "0" ]]; then
|
||||
# Minor version bump (e.g., 1.23.x → 1.24.0)
|
||||
echo "is_minor_bump=true" >> $GITHUB_OUTPUT
|
||||
BRANCH_NAME="core/${MAJOR}.${PREV_MINOR}"
|
||||
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "is_minor_bump=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
# Return to main branch
|
||||
git checkout main
|
||||
|
||||
- name: Create release branch
|
||||
if: steps.check_version.outputs.is_minor_bump == 'true'
|
||||
run: |
|
||||
BRANCH_NAME="${{ steps.check_version.outputs.branch_name }}"
|
||||
|
||||
# Check if branch already exists
|
||||
if git ls-remote --heads origin "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then
|
||||
echo "⚠️ Branch $BRANCH_NAME already exists, skipping creation"
|
||||
echo "branch_exists=true" >> $GITHUB_ENV
|
||||
exit 0
|
||||
else
|
||||
echo "branch_exists=false" >> $GITHUB_ENV
|
||||
fi
|
||||
|
||||
# Create branch from the commit BEFORE the version bump
|
||||
# This ensures the release branch has the previous minor version
|
||||
git checkout -b "$BRANCH_NAME" HEAD^1
|
||||
|
||||
# Push the new branch
|
||||
git push origin "$BRANCH_NAME"
|
||||
|
||||
echo "✅ Created release branch: $BRANCH_NAME"
|
||||
echo "This branch is now in feature freeze and will only receive:"
|
||||
echo "- Bug fixes"
|
||||
echo "- Critical security patches"
|
||||
echo "- Documentation updates"
|
||||
|
||||
- name: Create branch protection rules
|
||||
if: steps.check_version.outputs.is_minor_bump == 'true' && env.branch_exists != 'true'
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.PR_GH_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
BRANCH_NAME="${{ steps.check_version.outputs.branch_name }}"
|
||||
|
||||
# Create branch protection using GitHub API
|
||||
echo "Setting up branch protection for $BRANCH_NAME..."
|
||||
|
||||
RESPONSE=$(curl -s -w "\n%{http_code}" -X PUT \
|
||||
-H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Accept: application/vnd.github.v3+json" \
|
||||
"https://api.github.com/repos/${{ github.repository }}/branches/$BRANCH_NAME/protection" \
|
||||
-d '{
|
||||
"required_status_checks": {
|
||||
"strict": true,
|
||||
"contexts": ["lint-and-format", "test", "playwright-tests"]
|
||||
},
|
||||
"enforce_admins": false,
|
||||
"required_pull_request_reviews": {
|
||||
"required_approving_review_count": 1,
|
||||
"dismiss_stale_reviews": true
|
||||
},
|
||||
"restrictions": null,
|
||||
"allow_force_pushes": false,
|
||||
"allow_deletions": false
|
||||
}')
|
||||
|
||||
HTTP_CODE=$(echo "$RESPONSE" | tail -n 1)
|
||||
BODY=$(echo "$RESPONSE" | sed '$d')
|
||||
|
||||
if [[ "$HTTP_CODE" -eq 200 ]] || [[ "$HTTP_CODE" -eq 201 ]]; then
|
||||
echo "✅ Branch protection successfully applied"
|
||||
else
|
||||
echo "⚠️ Failed to apply branch protection (HTTP $HTTP_CODE)"
|
||||
echo "Response: $BODY"
|
||||
# Don't fail the workflow, just warn
|
||||
fi
|
||||
|
||||
- name: Post summary
|
||||
if: steps.check_version.outputs.is_minor_bump == 'true'
|
||||
run: |
|
||||
BRANCH_NAME="${{ steps.check_version.outputs.branch_name }}"
|
||||
PREV_VERSION="${{ steps.check_version.outputs.prev_version }}"
|
||||
CURRENT_VERSION="${{ steps.check_version.outputs.current_version }}"
|
||||
|
||||
if [[ "${{ env.branch_exists }}" == "true" ]]; then
|
||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||
## 🌿 Release Branch Already Exists
|
||||
|
||||
The release branch for the previous minor version already exists:
|
||||
EOF
|
||||
else
|
||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||
## 🌿 Release Branch Created
|
||||
|
||||
A new release branch has been created for the previous minor version:
|
||||
EOF
|
||||
fi
|
||||
|
||||
cat >> $GITHUB_STEP_SUMMARY << EOF
|
||||
|
||||
- **Branch**: \`$BRANCH_NAME\`
|
||||
- **Version**: \`$PREV_VERSION\` (feature frozen)
|
||||
- **Main branch**: \`$CURRENT_VERSION\` (active development)
|
||||
|
||||
### Branch Policy
|
||||
|
||||
The \`$BRANCH_NAME\` branch is now in **feature freeze** and will only accept:
|
||||
- 🐛 Bug fixes
|
||||
- 🔒 Security patches
|
||||
- 📚 Documentation updates
|
||||
|
||||
All new features should continue to be developed against \`main\`.
|
||||
|
||||
### Backporting Changes
|
||||
|
||||
To backport a fix to this release branch:
|
||||
1. Create your fix on \`main\` first
|
||||
2. Cherry-pick to \`$BRANCH_NAME\`
|
||||
3. Create a PR targeting \`$BRANCH_NAME\`
|
||||
4. Use the \`Release\` label on the PR
|
||||
EOF
|
||||
27
.github/workflows/danger.yaml
vendored
27
.github/workflows/danger.yaml
vendored
@@ -1,27 +0,0 @@
|
||||
name: Danger PR Review
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, edited, synchronize]
|
||||
|
||||
jobs:
|
||||
danger:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run Danger
|
||||
run: npx danger ci
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
23
.github/workflows/dev-release.yaml
vendored
23
.github/workflows/dev-release.yaml
vendored
@@ -16,9 +16,26 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
dist
|
||||
tsconfig.tsbuildinfo
|
||||
key: dev-release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
dev-release-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Get current version
|
||||
id: current_version
|
||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||
@@ -29,9 +46,9 @@ jobs:
|
||||
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
|
||||
USE_PROD_CONFIG: 'true'
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
npm run zipdist
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
pnpm zipdist
|
||||
- name: Upload dist artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
||||
17
.github/workflows/eslint.yaml
vendored
17
.github/workflows/eslint.yaml
vendored
@@ -1,17 +0,0 @@
|
||||
name: ESLint
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main, master, dev*, core/*, desktop/* ]
|
||||
|
||||
jobs:
|
||||
eslint:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
- run: npm ci
|
||||
- run: npm run lint
|
||||
23
.github/workflows/format.yaml
vendored
23
.github/workflows/format.yaml
vendored
@@ -1,23 +0,0 @@
|
||||
name: Prettier Check
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches: [ main, master, dev*, core/*, desktop/* ]
|
||||
|
||||
jobs:
|
||||
prettier:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run Prettier check
|
||||
run: npm run format:check
|
||||
15
.github/workflows/i18n-custom-nodes.yaml
vendored
15
.github/workflows/i18n-custom-nodes.yaml
vendored
@@ -42,9 +42,14 @@ jobs:
|
||||
with:
|
||||
repository: ${{ inputs.owner }}/${{ inputs.repository }}
|
||||
path: 'ComfyUI/custom_nodes/${{ inputs.repository }}'
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
@@ -63,8 +68,8 @@ jobs:
|
||||
working-directory: ComfyUI/custom_nodes/${{ inputs.repository }}
|
||||
- name: Build & Install ComfyUI_frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
rm -rf ../ComfyUI/web/*
|
||||
mv dist/* ../ComfyUI/web/
|
||||
working-directory: ComfyUI_frontend
|
||||
@@ -79,18 +84,18 @@ jobs:
|
||||
- name: Start dev server
|
||||
# Run electron dev server as it is a superset of the web dev server
|
||||
# We do want electron specific UIs to be translated.
|
||||
run: npm run dev:electron &
|
||||
run: pnpm dev:electron &
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Capture base i18n
|
||||
run: npx tsx scripts/diff-i18n capture
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update en.json
|
||||
run: npm run collect-i18n
|
||||
run: pnpm collect-i18n
|
||||
env:
|
||||
PLAYWRIGHT_TEST_URL: http://localhost:5173
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update translations
|
||||
run: npm run locale
|
||||
run: pnpm locale
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
8
.github/workflows/i18n-node-defs.yaml
vendored
8
.github/workflows/i18n-node-defs.yaml
vendored
@@ -13,22 +13,22 @@ jobs:
|
||||
update-locales:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install chromium --with-deps
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Start dev server
|
||||
# Run electron dev server as it is a superset of the web dev server
|
||||
# We do want electron specific UIs to be translated.
|
||||
run: npm run dev:electron &
|
||||
run: pnpm dev:electron &
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update en.json
|
||||
run: npm run collect-i18n -- scripts/collect-i18n-node-defs.ts
|
||||
run: pnpm collect-i18n -- scripts/collect-i18n-node-defs.ts
|
||||
env:
|
||||
PLAYWRIGHT_TEST_URL: http://localhost:5173
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update translations
|
||||
run: npm run locale
|
||||
run: pnpm locale
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
34
.github/workflows/i18n.yaml
vendored
34
.github/workflows/i18n.yaml
vendored
@@ -1,37 +1,45 @@
|
||||
name: Update Locales
|
||||
|
||||
on:
|
||||
# Manual dispatch for urgent translation updates
|
||||
workflow_dispatch:
|
||||
# Only trigger on PRs to main/master - additional branch filtering in job condition
|
||||
pull_request:
|
||||
branches: [ main, master, dev* ]
|
||||
paths-ignore:
|
||||
- '.github/**'
|
||||
- '.husky/**'
|
||||
- '.vscode/**'
|
||||
- 'browser_tests/**'
|
||||
- 'tests-ui/**'
|
||||
branches: [ main ]
|
||||
types: [opened, synchronize, reopened]
|
||||
|
||||
jobs:
|
||||
update-locales:
|
||||
# Don't run on fork PRs
|
||||
if: github.event.pull_request.head.repo.full_name == github.repository
|
||||
# Branch detection: Only run for manual dispatch or version-bump-* branches from main repo
|
||||
if: github.event_name == 'workflow_dispatch' || (github.event.pull_request.head.repo.full_name == github.repository && startsWith(github.head_ref, 'version-bump-'))
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
ComfyUI_frontend/.cache
|
||||
ComfyUI_frontend/.cache
|
||||
key: i18n-tools-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
i18n-tools-cache-${{ runner.os }}-
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install chromium --with-deps
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Start dev server
|
||||
# Run electron dev server as it is a superset of the web dev server
|
||||
# We do want electron specific UIs to be translated.
|
||||
run: npm run dev:electron &
|
||||
run: pnpm dev:electron &
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update en.json
|
||||
run: npm run collect-i18n -- scripts/collect-i18n-general.ts
|
||||
run: pnpm collect-i18n -- scripts/collect-i18n-general.ts
|
||||
env:
|
||||
PLAYWRIGHT_TEST_URL: http://localhost:5173
|
||||
working-directory: ComfyUI_frontend
|
||||
- name: Update translations
|
||||
run: npm run locale
|
||||
run: pnpm locale
|
||||
env:
|
||||
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
105
.github/workflows/lint-and-format.yaml
vendored
Normal file
105
.github/workflows/lint-and-format.yaml
vendored
Normal file
@@ -0,0 +1,105 @@
|
||||
name: Lint and Format
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches-ignore: [wip/*, draft/*, temp/*]
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
jobs:
|
||||
lint-and-format:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout PR
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
.eslintcache
|
||||
tsconfig.tsbuildinfo
|
||||
.prettierCache
|
||||
.knip-cache
|
||||
key: lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js,mts}', '*.config.*', '.eslintrc.*', '.prettierrc.*', 'tsconfig.json') }}
|
||||
restore-keys: |
|
||||
lint-format-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||
lint-format-cache-${{ runner.os }}-
|
||||
ci-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run ESLint with auto-fix
|
||||
run: pnpm lint:fix
|
||||
|
||||
- name: Run Prettier with auto-format
|
||||
run: pnpm format
|
||||
|
||||
- name: Check for changes
|
||||
id: verify-changed-files
|
||||
run: |
|
||||
if [ -n "$(git status --porcelain)" ]; then
|
||||
echo "changed=true" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "changed=false" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- name: Commit changes
|
||||
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
run: |
|
||||
git config --local user.email "action@github.com"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add .
|
||||
git commit -m "[auto-fix] Apply ESLint and Prettier fixes"
|
||||
git push
|
||||
|
||||
- name: Final validation
|
||||
run: |
|
||||
pnpm lint
|
||||
pnpm format:check
|
||||
pnpm knip
|
||||
|
||||
- name: Comment on PR about auto-fix
|
||||
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name == github.repository
|
||||
continue-on-error: true
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## 🔧 Auto-fixes Applied\n\nThis PR has been automatically updated to fix linting and formatting issues.\n\n**⚠️ Important**: Your local branch is now behind. Run `git pull` before making additional changes to avoid conflicts.\n\n### Changes made:\n- ESLint auto-fixes\n- Prettier formatting'
|
||||
})
|
||||
|
||||
- name: Comment on PR about manual fix needed
|
||||
if: steps.verify-changed-files.outputs.changed == 'true' && github.event.pull_request.head.repo.full_name != github.repository
|
||||
continue-on-error: true
|
||||
uses: actions/github-script@v7
|
||||
with:
|
||||
script: |
|
||||
github.rest.issues.createComment({
|
||||
issue_number: context.issue.number,
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
body: '## ⚠️ Linting/Formatting Issues Found\n\nThis PR has linting or formatting issues that need to be fixed.\n\n**Since this PR is from a fork, auto-fix cannot be applied automatically.**\n\n### Option 1: Set up pre-commit hooks (recommended)\nRun this once to automatically format code on every commit:\n```bash\npnpm prepare\n```\n\n### Option 2: Fix manually\nRun these commands and push the changes:\n```bash\npnpm lint:fix\npnpm format\n```\n\nSee [CONTRIBUTING.md](https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/CONTRIBUTING.md#git-pre-commit-hooks) for more details.'
|
||||
})
|
||||
45
.github/workflows/release.yaml
vendored
45
.github/workflows/release.yaml
vendored
@@ -19,9 +19,25 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
tsconfig.tsbuildinfo
|
||||
key: release-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
release-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Get current version
|
||||
id: current_version
|
||||
run: echo "version=$(node -p "require('./package.json').version")" >> $GITHUB_OUTPUT
|
||||
@@ -41,9 +57,9 @@ jobs:
|
||||
ALGOLIA_API_KEY: ${{ secrets.ALGOLIA_API_KEY }}
|
||||
USE_PROD_CONFIG: 'true'
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
npm run zipdist
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
pnpm zipdist
|
||||
- name: Upload dist artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
@@ -113,14 +129,31 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
registry-url: https://registry.npmjs.org
|
||||
- run: npm ci
|
||||
- run: npm run build:types
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
tsconfig.tsbuildinfo
|
||||
dist
|
||||
key: types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
types-tools-cache-${{ runner.os }}-
|
||||
|
||||
- run: pnpm install --frozen-lockfile
|
||||
- run: pnpm build:types
|
||||
- name: Publish package
|
||||
run: npm publish --access public
|
||||
run: pnpm publish --access public
|
||||
working-directory: dist
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
|
||||
2
.github/workflows/test-browser-exp.yaml
vendored
2
.github/workflows/test-browser-exp.yaml
vendored
@@ -10,7 +10,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
if: github.event.label.name == 'New Browser Test Expectations'
|
||||
steps:
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v2.3
|
||||
- uses: Comfy-Org/ComfyUI_frontend_setup_action@v3
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install chromium --with-deps
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
297
.github/workflows/test-ui.yaml
vendored
297
.github/workflows/test-ui.yaml
vendored
@@ -4,13 +4,18 @@ on:
|
||||
push:
|
||||
branches: [main, master, core/*, desktop/*]
|
||||
pull_request:
|
||||
branches: [main, master, dev*, core/*, desktop/*]
|
||||
branches-ignore:
|
||||
[wip/*, draft/*, temp/*, vue-nodes-migration, sno-playwright-*]
|
||||
|
||||
env:
|
||||
DATE_FORMAT: '+%m/%d/%Y, %I:%M:%S %p'
|
||||
|
||||
jobs:
|
||||
setup:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
cache-key: ${{ steps.cache-key.outputs.key }}
|
||||
sanitized-branch: ${{ steps.branch-info.outputs.sanitized }}
|
||||
steps:
|
||||
- name: Checkout ComfyUI
|
||||
uses: actions/checkout@v4
|
||||
@@ -32,20 +37,71 @@ jobs:
|
||||
path: 'ComfyUI/custom_nodes/ComfyUI_devtools'
|
||||
ref: 'd05fd48dd787a4192e16802d4244cfcc0e2f9684'
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'pnpm'
|
||||
cache-dependency-path: 'ComfyUI_frontend/pnpm-lock.yaml'
|
||||
|
||||
- name: Get current time
|
||||
id: current-time
|
||||
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR - Tests Started
|
||||
if: github.event_name == 'pull_request'
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: append
|
||||
body: |
|
||||
<!-- PLAYWRIGHT_TEST_STATUS -->
|
||||
|
||||
---
|
||||
|
||||
<img alt='comfy-loading-gif' src="https://github.com/user-attachments/assets/755c86ee-e445-4ea8-bc2c-cca85df48686" width="14px" height="14px" style="vertical-align: middle; margin-left: 4px;" />
|
||||
<bold>[${{ steps.current-time.outputs.time }} UTC] Preparing browser tests across multiple browsers...</bold>
|
||||
|
||||
---
|
||||
*This comment will be updated when tests complete*
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
ComfyUI_frontend/.cache
|
||||
ComfyUI_frontend/tsconfig.tsbuildinfo
|
||||
key: playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-${{ hashFiles('ComfyUI_frontend/src/**/*.{ts,vue,js}', 'ComfyUI_frontend/*.config.*') }}
|
||||
restore-keys: |
|
||||
playwright-setup-cache-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-
|
||||
playwright-setup-cache-${{ runner.os }}-
|
||||
playwright-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Build ComfyUI_frontend
|
||||
run: |
|
||||
npm ci
|
||||
npm run build
|
||||
pnpm install --frozen-lockfile
|
||||
pnpm build
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
- name: Generate cache key
|
||||
id: cache-key
|
||||
run: echo "key=$(date +%s)" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate sanitized branch name
|
||||
id: branch-info
|
||||
run: |
|
||||
# Get branch name and sanitize it for Cloudflare branch names
|
||||
BRANCH_NAME="${{ github.head_ref || github.ref_name }}"
|
||||
SANITIZED_BRANCH=$(echo "$BRANCH_NAME" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9-]/-/g' | sed 's/--*/-/g' | sed 's/^-\|-$//g')
|
||||
echo "sanitized=${SANITIZED_BRANCH}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Save cache
|
||||
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684
|
||||
with:
|
||||
@@ -57,10 +113,14 @@ jobs:
|
||||
playwright-tests:
|
||||
needs: setup
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
browser: [chromium, chromium-2x, mobile-chrome]
|
||||
browser: [chromium, chromium-2x, chromium-0.5x, mobile-chrome]
|
||||
steps:
|
||||
- name: Wait for cache propagation
|
||||
run: sleep 10
|
||||
@@ -74,9 +134,42 @@ jobs:
|
||||
ComfyUI_frontend
|
||||
key: comfyui-setup-${{ needs.setup.outputs.cache-key }}
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: '3.10'
|
||||
cache: 'pip'
|
||||
|
||||
- name: Get current time
|
||||
id: current-time
|
||||
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Set project name
|
||||
id: project-name
|
||||
run: |
|
||||
if [ "${{ matrix.browser }}" = "chromium-0.5x" ]; then
|
||||
echo "name=comfyui-playwright-chromium-0-5x" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "name=comfyui-playwright-${{ matrix.browser }}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
echo "branch=${{ needs.setup.outputs.sanitized-branch }}" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR - Browser Test Started
|
||||
if: github.event_name == 'pull_request'
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: append
|
||||
body: |
|
||||
<img alt='comfy-loading-gif' src="https://github.com/user-attachments/assets/755c86ee-e445-4ea8-bc2c-cca85df48686" width="14px" height="14px" style="vertical-align: middle; margin-left: 4px;" />
|
||||
<bold>${{ matrix.browser }}</bold>: Running tests...
|
||||
|
||||
- name: Install requirements
|
||||
run: |
|
||||
@@ -92,17 +185,209 @@ jobs:
|
||||
wait-for-it --service 127.0.0.1:8188 -t 600
|
||||
working-directory: ComfyUI
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-${{ matrix.browser }}
|
||||
restore-keys: |
|
||||
playwright-browsers-${{ runner.os }}-${{ hashFiles('ComfyUI_frontend/pnpm-lock.yaml') }}-
|
||||
playwright-browsers-${{ runner.os }}-
|
||||
|
||||
- name: Install Playwright Browsers
|
||||
run: npx playwright install chromium --with-deps
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
- name: Install Wrangler
|
||||
run: pnpm install -g wrangler
|
||||
|
||||
- name: Run Playwright tests (${{ matrix.browser }})
|
||||
run: npx playwright test --project=${{ matrix.browser }}
|
||||
id: playwright
|
||||
run: npx playwright test --project=${{ matrix.browser }} --reporter=html
|
||||
working-directory: ComfyUI_frontend
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
if: always() # note: use always() to allow results to be upload/report even tests failed.
|
||||
with:
|
||||
name: playwright-report-${{ matrix.browser }}
|
||||
path: ComfyUI_frontend/playwright-report/
|
||||
retention-days: 30
|
||||
|
||||
- name: Deploy to Cloudflare Pages (${{ matrix.browser }})
|
||||
id: cloudflare-deploy
|
||||
if: always()
|
||||
continue-on-error: true
|
||||
run: |
|
||||
# Retry logic for wrangler deploy (3 attempts)
|
||||
RETRY_COUNT=0
|
||||
MAX_RETRIES=3
|
||||
SUCCESS=false
|
||||
|
||||
while [ $RETRY_COUNT -lt $MAX_RETRIES ] && [ $SUCCESS = false ]; do
|
||||
RETRY_COUNT=$((RETRY_COUNT + 1))
|
||||
echo "Deployment attempt $RETRY_COUNT of $MAX_RETRIES..."
|
||||
|
||||
if npx wrangler pages deploy ComfyUI_frontend/playwright-report --project-name=${{ steps.project-name.outputs.name }} --branch=${{ steps.project-name.outputs.branch }}; then
|
||||
SUCCESS=true
|
||||
echo "Deployment successful on attempt $RETRY_COUNT"
|
||||
else
|
||||
echo "Deployment failed on attempt $RETRY_COUNT"
|
||||
if [ $RETRY_COUNT -lt $MAX_RETRIES ]; then
|
||||
echo "Retrying in 10 seconds..."
|
||||
sleep 10
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $SUCCESS = false ]; then
|
||||
echo "All deployment attempts failed"
|
||||
exit 1
|
||||
fi
|
||||
env:
|
||||
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
||||
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
|
||||
|
||||
- name: Save deployment info for summary
|
||||
if: always()
|
||||
run: |
|
||||
mkdir -p deployment-info
|
||||
# Use step conclusion to determine test result
|
||||
if [ "${{ steps.playwright.conclusion }}" = "success" ]; then
|
||||
EXIT_CODE="0"
|
||||
else
|
||||
EXIT_CODE="1"
|
||||
fi
|
||||
DEPLOYMENT_URL="${{ steps.cloudflare-deploy.outputs.deployment-url || steps.cloudflare-deploy.outputs.url || format('https://{0}.{1}.pages.dev', steps.project-name.outputs.branch, steps.project-name.outputs.name) }}"
|
||||
echo "${{ matrix.browser }}|${EXIT_CODE}|${DEPLOYMENT_URL}" > deployment-info/${{ matrix.browser }}.txt
|
||||
|
||||
- name: Upload deployment info
|
||||
if: always()
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: deployment-info-${{ matrix.browser }}
|
||||
path: deployment-info/
|
||||
retention-days: 1
|
||||
|
||||
- name: Get completion time
|
||||
id: completion-time
|
||||
if: always()
|
||||
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Comment PR - Browser Test Complete
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: append
|
||||
body: |
|
||||
${{ steps.playwright.conclusion == 'success' && '✅' || '❌' }} **${{ matrix.browser }}**: ${{ steps.playwright.conclusion == 'success' && 'Tests passed!' || 'Tests failed!' }} [View Report](${{ steps.cloudflare-deploy.outputs.deployment-url || format('https://{0}.{1}.pages.dev', steps.project-name.outputs.branch, steps.project-name.outputs.name) }})
|
||||
|
||||
comment-summary:
|
||||
needs: playwright-tests
|
||||
runs-on: ubuntu-latest
|
||||
if: always() && github.event_name == 'pull_request'
|
||||
permissions:
|
||||
pull-requests: write
|
||||
steps:
|
||||
- name: Download all deployment info
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
pattern: deployment-info-*
|
||||
merge-multiple: true
|
||||
path: deployment-info
|
||||
|
||||
- name: Get completion time
|
||||
id: completion-time
|
||||
run: echo "time=$(date -u '${{ env.DATE_FORMAT }}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Generate comment body
|
||||
id: comment-body
|
||||
run: |
|
||||
echo "<!-- PLAYWRIGHT_TEST_STATUS -->" > comment.md
|
||||
echo "## 🎭 Playwright Test Results" >> comment.md
|
||||
echo "" >> comment.md
|
||||
|
||||
# Check if all tests passed
|
||||
ALL_PASSED=true
|
||||
for file in deployment-info/*.txt; do
|
||||
if [ -f "$file" ]; then
|
||||
browser=$(basename "$file" .txt)
|
||||
info=$(cat "$file")
|
||||
exit_code=$(echo "$info" | cut -d'|' -f2)
|
||||
if [ "$exit_code" != "0" ]; then
|
||||
ALL_PASSED=false
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ALL_PASSED" = "true" ]; then
|
||||
echo "✅ **All tests passed across all browsers!**" >> comment.md
|
||||
else
|
||||
echo "❌ **Some tests failed!**" >> comment.md
|
||||
fi
|
||||
|
||||
echo "" >> comment.md
|
||||
echo "⏰ Completed at: ${{ steps.completion-time.outputs.time }} UTC" >> comment.md
|
||||
echo "" >> comment.md
|
||||
echo "### 📊 Test Reports by Browser" >> comment.md
|
||||
|
||||
for file in deployment-info/*.txt; do
|
||||
if [ -f "$file" ]; then
|
||||
browser=$(basename "$file" .txt)
|
||||
info=$(cat "$file")
|
||||
exit_code=$(echo "$info" | cut -d'|' -f2)
|
||||
url=$(echo "$info" | cut -d'|' -f3)
|
||||
|
||||
if [ "$exit_code" = "0" ]; then
|
||||
status="✅"
|
||||
else
|
||||
status="❌"
|
||||
fi
|
||||
|
||||
echo "- $status **$browser**: [View Report]($url)" >> comment.md
|
||||
fi
|
||||
done
|
||||
|
||||
echo "" >> comment.md
|
||||
echo "---" >> comment.md
|
||||
if [ "$ALL_PASSED" = "true" ]; then
|
||||
echo "🎉 Your tests are passing across all browsers!" >> comment.md
|
||||
else
|
||||
echo "⚠️ Please check the test reports for details on failures." >> comment.md
|
||||
fi
|
||||
|
||||
- name: Comment PR - Tests Complete
|
||||
continue-on-error: true
|
||||
uses: edumserrano/find-create-or-update-comment@v3
|
||||
with:
|
||||
issue-number: ${{ github.event.pull_request.number }}
|
||||
body-includes: '<!-- PLAYWRIGHT_TEST_STATUS -->'
|
||||
comment-author: 'github-actions[bot]'
|
||||
edit-mode: replace
|
||||
body-path: comment.md
|
||||
|
||||
- name: Check test results and fail if needed
|
||||
run: |
|
||||
# Check if all tests passed and fail the job if not
|
||||
ALL_PASSED=true
|
||||
for file in deployment-info/*.txt; do
|
||||
if [ -f "$file" ]; then
|
||||
info=$(cat "$file")
|
||||
exit_code=$(echo "$info" | cut -d'|' -f2)
|
||||
if [ "$exit_code" != "0" ]; then
|
||||
ALL_PASSED=false
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [ "$ALL_PASSED" = "false" ]; then
|
||||
echo "❌ Tests failed in one or more browsers. Failing the CI job."
|
||||
exit 1
|
||||
else
|
||||
echo "✅ All tests passed across all browsers!"
|
||||
fi
|
||||
|
||||
20
.github/workflows/update-electron-types.yaml
vendored
20
.github/workflows/update-electron-types.yaml
vendored
@@ -14,19 +14,33 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
key: electron-types-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
electron-types-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Update electron types
|
||||
run: npm install @comfyorg/comfyui-electron-types@latest
|
||||
run: pnpm install @comfyorg/comfyui-electron-types@latest
|
||||
|
||||
- name: Get new version
|
||||
id: get-version
|
||||
run: |
|
||||
NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./package-lock.json')).packages['node_modules/@comfyorg/comfyui-electron-types'].version)")
|
||||
NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./pnpm-lock.yaml')).packages['node_modules/@comfyorg/comfyui-electron-types'].version)")
|
||||
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Pull Request
|
||||
|
||||
43
.github/workflows/update-litegraph.yaml
vendored
43
.github/workflows/update-litegraph.yaml
vendored
@@ -1,43 +0,0 @@
|
||||
name: Update Litegraph Dependency
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
update-litegraph:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
|
||||
- name: Update litegraph
|
||||
run: npm install @comfyorg/litegraph@latest
|
||||
|
||||
- name: Get new version
|
||||
id: get-version
|
||||
run: |
|
||||
NEW_VERSION=$(node -e "console.log(JSON.parse(require('fs').readFileSync('./package-lock.json')).packages['node_modules/@comfyorg/litegraph'].version)")
|
||||
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Create Pull Request
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
|
||||
with:
|
||||
token: ${{ secrets.PR_GH_TOKEN }}
|
||||
commit-message: '[chore] Update litegraph to ${{ steps.get-version.outputs.NEW_VERSION }}'
|
||||
title: '[chore] Update litegraph to ${{ steps.get-version.outputs.NEW_VERSION }}'
|
||||
body: |
|
||||
Automated update of litegraph to version ${{ steps.get-version.outputs.NEW_VERSION }}.
|
||||
Ref: https://github.com/Comfy-Org/litegraph.js/releases/tag/v${{ steps.get-version.outputs.NEW_VERSION }}
|
||||
branch: update-litegraph-${{ steps.get-version.outputs.NEW_VERSION }}
|
||||
base: main
|
||||
labels: |
|
||||
dependencies
|
||||
40
.github/workflows/update-manager-types.yaml
vendored
40
.github/workflows/update-manager-types.yaml
vendored
@@ -3,6 +3,11 @@ name: Update ComfyUI-Manager API Types
|
||||
on:
|
||||
# Manual trigger
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
target_branch:
|
||||
description: 'Target branch for the PR'
|
||||
required: true
|
||||
default: 'main'
|
||||
|
||||
jobs:
|
||||
update-manager-types:
|
||||
@@ -14,14 +19,36 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
key: update-manager-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
update-manager-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cache ComfyUI-Manager repository
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ComfyUI-Manager
|
||||
key: comfyui-manager-repo-${{ runner.os }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
comfyui-manager-repo-${{ runner.os }}-
|
||||
|
||||
- name: Checkout ComfyUI-Manager repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -56,6 +83,11 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Lint generated types
|
||||
run: |
|
||||
echo "Linting generated ComfyUI-Manager API types..."
|
||||
pnpm lint:fix:no-cache -- ./src/types/generatedManagerTypes.ts
|
||||
|
||||
- name: Check for changes
|
||||
id: check-changes
|
||||
run: |
|
||||
@@ -70,7 +102,7 @@ jobs:
|
||||
|
||||
- name: Create Pull Request
|
||||
if: steps.check-changes.outputs.changed == 'true'
|
||||
uses: peter-evans/create-pull-request@v7
|
||||
uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e
|
||||
with:
|
||||
token: ${{ secrets.PR_GH_TOKEN }}
|
||||
commit-message: '[chore] Update ComfyUI-Manager API types from ComfyUI-Manager@${{ steps.manager-info.outputs.commit }}'
|
||||
@@ -85,7 +117,7 @@ jobs:
|
||||
|
||||
These types are automatically generated using openapi-typescript.
|
||||
branch: update-manager-types-${{ steps.manager-info.outputs.commit }}
|
||||
base: main
|
||||
base: ${{ inputs.target_branch }}
|
||||
labels: Manager
|
||||
delete-branch: true
|
||||
add-paths: |
|
||||
|
||||
31
.github/workflows/update-registry-types.yaml
vendored
31
.github/workflows/update-registry-types.yaml
vendored
@@ -18,14 +18,36 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
key: update-registry-tools-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
restore-keys: |
|
||||
update-registry-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Cache comfy-api repository
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: comfy-api
|
||||
key: comfy-api-repo-${{ runner.os }}-${{ github.run_id }}
|
||||
restore-keys: |
|
||||
comfy-api-repo-${{ runner.os }}-
|
||||
|
||||
- name: Checkout comfy-api repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -61,6 +83,11 @@ jobs:
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Lint generated types
|
||||
run: |
|
||||
echo "Linting generated Comfy Registry API types..."
|
||||
pnpm lint:fix:no-cache -- ./src/types/comfyRegistryTypes.ts
|
||||
|
||||
- name: Check for changes
|
||||
id: check-changes
|
||||
run: |
|
||||
|
||||
9
.github/workflows/version-bump.yaml
vendored
9
.github/workflows/version-bump.yaml
vendored
@@ -26,16 +26,21 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: lts/*
|
||||
cache: 'npm'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Bump version
|
||||
id: bump-version
|
||||
run: |
|
||||
npm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
|
||||
pnpm version ${{ github.event.inputs.version_type }} --preid ${{ github.event.inputs.pre_release }} --no-git-tag-version
|
||||
NEW_VERSION=$(node -p "require('./package.json').version")
|
||||
echo "NEW_VERSION=$NEW_VERSION" >> $GITHUB_OUTPUT
|
||||
|
||||
|
||||
27
.github/workflows/vitest.yaml
vendored
27
.github/workflows/vitest.yaml
vendored
@@ -4,7 +4,7 @@ on:
|
||||
push:
|
||||
branches: [ main, master, dev*, core/*, desktop/* ]
|
||||
pull_request:
|
||||
branches: [ main, master, dev*, core/*, desktop/* ]
|
||||
branches-ignore: [ wip/*, draft/*, temp/* ]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
@@ -13,15 +13,34 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install pnpm
|
||||
uses: pnpm/action-setup@v4
|
||||
with:
|
||||
version: 10
|
||||
|
||||
- name: Use Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 'lts/*'
|
||||
cache: 'pnpm'
|
||||
|
||||
- name: Cache tool outputs
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: |
|
||||
.cache
|
||||
coverage
|
||||
.vitest-cache
|
||||
key: vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-${{ hashFiles('src/**/*.{ts,vue,js}', 'vitest.config.*', 'tsconfig.json') }}
|
||||
restore-keys: |
|
||||
vitest-cache-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}-
|
||||
vitest-cache-${{ runner.os }}-
|
||||
test-tools-cache-${{ runner.os }}-
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Run Vitest tests
|
||||
run: |
|
||||
npm run test:component
|
||||
npm run test:unit
|
||||
pnpm test:component
|
||||
pnpm test:unit
|
||||
|
||||
30
.gitignore
vendored
30
.gitignore
vendored
@@ -7,10 +7,22 @@ yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# Package manager lockfiles (allow users to use different package managers)
|
||||
bun.lock
|
||||
bun.lockb
|
||||
yarn.lock
|
||||
|
||||
# Cache files
|
||||
.eslintcache
|
||||
.prettiercache
|
||||
|
||||
node_modules
|
||||
dist
|
||||
dist-ssr
|
||||
*.local
|
||||
# Claude configuration
|
||||
.claude/*.local.json
|
||||
CLAUDE.local.md
|
||||
|
||||
# Editor directories and files
|
||||
.vscode/*
|
||||
@@ -56,5 +68,21 @@ dist.zip
|
||||
# Temporary repository directory
|
||||
templates_repo/
|
||||
|
||||
# Vite’s timestamped config modules
|
||||
# Vite's timestamped config modules
|
||||
vite.config.mts.timestamp-*.mjs
|
||||
|
||||
# Linux core dumps
|
||||
./core
|
||||
|
||||
*storybook.log
|
||||
storybook-static
|
||||
|
||||
|
||||
|
||||
|
||||
.nx/cache
|
||||
.nx/workspace-data
|
||||
.cursor/rules/nx-rules.mdc
|
||||
.github/instructions/nx.instructions.md
|
||||
vite.config.*.timestamp*
|
||||
vitest.config.*.timestamp*
|
||||
|
||||
13
.husky/pre-commit
Normal file → Executable file
13
.husky/pre-commit
Normal file → Executable file
@@ -1,9 +1,4 @@
|
||||
if [[ "$OS" == "Windows_NT" ]]; then
|
||||
npx.cmd lint-staged
|
||||
# Check for unused i18n keys in staged files
|
||||
npx.cmd tsx scripts/check-unused-i18n-keys.ts
|
||||
else
|
||||
npx lint-staged
|
||||
# Check for unused i18n keys in staged files
|
||||
npx tsx scripts/check-unused-i18n-keys.ts
|
||||
fi
|
||||
#!/usr/bin/env bash
|
||||
|
||||
npx lint-staged
|
||||
npx tsx scripts/check-unused-i18n-keys.ts
|
||||
@@ -9,10 +9,14 @@ module.exports = defineConfig({
|
||||
entry: 'src/locales/en',
|
||||
entryLocale: 'en',
|
||||
output: 'src/locales',
|
||||
outputLocales: ['zh', 'zh-TW', 'ru', 'ja', 'ko', 'fr', 'es'],
|
||||
outputLocales: ['zh', 'zh-TW', 'ru', 'ja', 'ko', 'fr', 'es', 'ar'],
|
||||
reference: `Special names to keep untranslated: flux, photomaker, clip, vae, cfg, stable audio, stable cascade, stable zero, controlnet, lora, HiDream.
|
||||
'latent' is the short form of 'latent space'.
|
||||
'mask' is in the context of image processing.
|
||||
Note: For Traditional Chinese (Taiwan), use Taiwan-specific terminology and traditional characters.
|
||||
|
||||
IMPORTANT Chinese Translation Guidelines:
|
||||
- For 'zh' locale: Use ONLY Simplified Chinese characters (简体中文). Common examples: 节点 (not 節點), 画布 (not 畫布), 图像 (not 圖像), 选择 (not 選擇), 减小 (not 減小).
|
||||
- For 'zh-TW' locale: Use ONLY Traditional Chinese characters (繁體中文) with Taiwan-specific terminology.
|
||||
- NEVER mix Simplified and Traditional Chinese characters within the same locale.
|
||||
`
|
||||
});
|
||||
|
||||
@@ -3,6 +3,10 @@
|
||||
"playwright": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@executeautomation/playwright-mcp-server"]
|
||||
},
|
||||
"context7": {
|
||||
"command": "npx",
|
||||
"args": ["-y", "@upstash/context7-mcp"]
|
||||
}
|
||||
}
|
||||
}
|
||||
2
.prettierignore
Normal file
2
.prettierignore
Normal file
@@ -0,0 +1,2 @@
|
||||
src/types/comfyRegistryTypes.ts
|
||||
src/types/generatedManagerTypes.ts
|
||||
197
.storybook/CLAUDE.md
Normal file
197
.storybook/CLAUDE.md
Normal file
@@ -0,0 +1,197 @@
|
||||
# Storybook Development Guidelines for Claude
|
||||
|
||||
## Quick Commands
|
||||
|
||||
- `pnpm storybook`: Start Storybook development server
|
||||
- `pnpm build-storybook`: Build static Storybook
|
||||
- `pnpm test:component`: Run component tests (includes Storybook components)
|
||||
|
||||
## Development Workflow for Storybook
|
||||
|
||||
1. **Creating New Stories**:
|
||||
- Place `*.stories.ts` files alongside components
|
||||
- Follow the naming pattern: `ComponentName.stories.ts`
|
||||
- Use realistic mock data that matches ComfyUI schemas
|
||||
|
||||
2. **Testing Stories**:
|
||||
- Verify stories render correctly in Storybook UI
|
||||
- Test different component states and edge cases
|
||||
- Ensure proper theming and styling
|
||||
|
||||
3. **Code Quality**:
|
||||
- Run `pnpm typecheck` to verify TypeScript
|
||||
- Run `pnpm lint` to check for linting issues
|
||||
- Follow existing story patterns and conventions
|
||||
|
||||
## Story Creation Guidelines
|
||||
|
||||
### Basic Story Structure
|
||||
|
||||
```typescript
|
||||
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||
import ComponentName from './ComponentName.vue'
|
||||
|
||||
const meta: Meta<typeof ComponentName> = {
|
||||
title: 'Category/ComponentName',
|
||||
component: ComponentName,
|
||||
parameters: {
|
||||
layout: 'centered' // or 'fullscreen', 'padded'
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
// Component props
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Mock Data Patterns
|
||||
|
||||
For ComfyUI components, use realistic mock data:
|
||||
|
||||
```typescript
|
||||
// Node definition mock
|
||||
const mockNodeDef = {
|
||||
input: {
|
||||
required: {
|
||||
prompt: ["STRING", { multiline: true }]
|
||||
}
|
||||
},
|
||||
output: ["CONDITIONING"],
|
||||
output_is_list: [false],
|
||||
category: "conditioning"
|
||||
}
|
||||
|
||||
// Component instance mock
|
||||
const mockComponent = {
|
||||
id: "1",
|
||||
type: "CLIPTextEncode",
|
||||
// ... other properties
|
||||
}
|
||||
```
|
||||
|
||||
### Common Story Variants
|
||||
|
||||
Always include these story variants when applicable:
|
||||
|
||||
- **Default**: Basic component with minimal props
|
||||
- **WithData**: Component with realistic data
|
||||
- **Loading**: Component in loading state
|
||||
- **Error**: Component with error state
|
||||
- **LongContent**: Component with edge case content
|
||||
- **Empty**: Component with no data
|
||||
|
||||
### Storybook-Specific Code Patterns
|
||||
|
||||
#### Store Access
|
||||
```typescript
|
||||
// In stories, access stores through the setup function
|
||||
export const WithStore: Story = {
|
||||
render: () => ({
|
||||
setup() {
|
||||
const store = useMyStore()
|
||||
return { store }
|
||||
},
|
||||
template: '<MyComponent :data="store.data" />'
|
||||
})
|
||||
}
|
||||
```
|
||||
|
||||
#### Event Testing
|
||||
```typescript
|
||||
export const WithEvents: Story = {
|
||||
args: {
|
||||
onUpdate: fn() // Use Storybook's fn() for action logging
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration Notes
|
||||
|
||||
### Vue App Setup
|
||||
The Storybook preview is configured with:
|
||||
- Pinia stores initialized
|
||||
- PrimeVue with ComfyUI theme
|
||||
- i18n internationalization
|
||||
- All necessary CSS imports
|
||||
|
||||
### Build Configuration
|
||||
- Vite integration with proper alias resolution
|
||||
- Manual chunking for better performance
|
||||
- TypeScript support with strict checking
|
||||
- CSS processing for Vue components
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Import Errors**: Verify `@/` alias is working correctly
|
||||
2. **Missing Styles**: Ensure CSS imports are in `preview.ts`
|
||||
3. **Store Errors**: Check store initialization in setup
|
||||
4. **Type Errors**: Use proper TypeScript types for story args
|
||||
|
||||
### Debug Commands
|
||||
|
||||
```bash
|
||||
# Check TypeScript issues
|
||||
pnpm typecheck
|
||||
|
||||
# Lint Storybook files
|
||||
pnpm lint .storybook/
|
||||
|
||||
# Build to check for production issues
|
||||
pnpm build-storybook
|
||||
```
|
||||
|
||||
## File Organization
|
||||
|
||||
```
|
||||
.storybook/
|
||||
├── main.ts # Core configuration
|
||||
├── preview.ts # Global setup and decorators
|
||||
├── README.md # User documentation
|
||||
└── CLAUDE.md # This file - Claude guidelines
|
||||
|
||||
src/
|
||||
├── components/
|
||||
│ └── MyComponent/
|
||||
│ ├── MyComponent.vue
|
||||
│ └── MyComponent.stories.ts
|
||||
```
|
||||
|
||||
## Integration with ComfyUI
|
||||
|
||||
### Available Context
|
||||
|
||||
Stories have access to:
|
||||
- All ComfyUI stores (widgetStore, colorPaletteStore, etc.)
|
||||
- PrimeVue components with ComfyUI theming
|
||||
- Internationalization system
|
||||
- ComfyUI CSS variables and styling
|
||||
|
||||
### Testing Components
|
||||
|
||||
When testing ComfyUI-specific components:
|
||||
1. Use realistic node definitions and data structures
|
||||
2. Test with different node types (sampling, conditioning, etc.)
|
||||
3. Verify proper CSS theming and dark/light modes
|
||||
4. Check component behavior with various input combinations
|
||||
|
||||
### Performance Considerations
|
||||
|
||||
- Use manual chunking for large dependencies
|
||||
- Minimize bundle size by avoiding unnecessary imports
|
||||
- Leverage Storybook's lazy loading capabilities
|
||||
- Profile build times and optimize as needed
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Keep Stories Focused**: Each story should demonstrate one specific use case
|
||||
2. **Use Descriptive Names**: Story names should clearly indicate what they show
|
||||
3. **Document Complex Props**: Use JSDoc comments for complex prop types
|
||||
4. **Test Edge Cases**: Create stories for unusual but valid use cases
|
||||
5. **Maintain Consistency**: Follow established patterns in existing stories
|
||||
230
.storybook/README.md
Normal file
230
.storybook/README.md
Normal file
@@ -0,0 +1,230 @@
|
||||
# Storybook Configuration for ComfyUI Frontend
|
||||
|
||||
## What is Storybook?
|
||||
|
||||
Storybook is a frontend workshop for building UI components and pages in isolation. It allows developers to:
|
||||
|
||||
- Build components independently from the main application
|
||||
- Test components with different props and states
|
||||
- Document component APIs and usage patterns
|
||||
- Share components across teams and projects
|
||||
- Catch visual regressions through visual testing
|
||||
|
||||
## Storybook vs Other Testing Tools
|
||||
|
||||
| Tool | Purpose | Use Case |
|
||||
|------|---------|----------|
|
||||
| **Storybook** | Component isolation & documentation | Developing, testing, and showcasing individual UI components |
|
||||
| **Playwright** | End-to-end testing | Full user workflow testing across multiple pages |
|
||||
| **Vitest** | Unit testing | Testing business logic, utilities, and component behavior |
|
||||
| **Vue Testing Library** | Component testing | Testing component interactions and DOM output |
|
||||
|
||||
### When to Use Storybook
|
||||
|
||||
**✅ Use Storybook for:**
|
||||
- Developing new UI components in isolation
|
||||
- Creating component documentation and examples
|
||||
- Testing different component states and props
|
||||
- Sharing components with designers and stakeholders
|
||||
- Visual regression testing
|
||||
- Building a component library or design system
|
||||
|
||||
**❌ Don't use Storybook for:**
|
||||
- Testing complex user workflows (use Playwright)
|
||||
- Testing business logic (use Vitest)
|
||||
- Integration testing between components (use Vue Testing Library)
|
||||
|
||||
## How to Use Storybook
|
||||
|
||||
### Development Commands
|
||||
|
||||
```bash
|
||||
# Start Storybook development server
|
||||
pnpm storybook
|
||||
|
||||
# Build static Storybook for deployment
|
||||
pnpm build-storybook
|
||||
```
|
||||
|
||||
### Creating Stories
|
||||
|
||||
Stories are located alongside components in `src/` directories with the pattern `*.stories.ts`:
|
||||
|
||||
```typescript
|
||||
// MyComponent.stories.ts
|
||||
import type { Meta, StoryObj } from '@storybook/vue3'
|
||||
import MyComponent from './MyComponent.vue'
|
||||
|
||||
const meta: Meta<typeof MyComponent> = {
|
||||
title: 'Components/MyComponent',
|
||||
component: MyComponent,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
}
|
||||
}
|
||||
|
||||
export default meta
|
||||
type Story = StoryObj<typeof meta>
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
title: 'Hello World'
|
||||
}
|
||||
}
|
||||
|
||||
export const WithVariant: Story = {
|
||||
args: {
|
||||
title: 'Variant Example',
|
||||
variant: 'secondary'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Available Features
|
||||
|
||||
- **Vue 3 Support**: Full Vue 3 composition API and reactivity
|
||||
- **PrimeVue Integration**: All PrimeVue components and theming
|
||||
- **ComfyUI Theming**: Custom ComfyUI theme preset applied
|
||||
- **Pinia Stores**: Access to application stores for components that need state
|
||||
- **TypeScript**: Full TypeScript support with proper type checking
|
||||
- **CSS/SCSS**: Component styling support
|
||||
- **Auto-documentation**: Automatic prop tables and component documentation
|
||||
- **Chromatic Integration**: Automated visual regression testing for component stories
|
||||
|
||||
## Development Tips
|
||||
|
||||
## ComfyUI Storybook Guidelines
|
||||
|
||||
### Scope – When to Create Stories
|
||||
- **PrimeVue components**:
|
||||
No need to create stories. Just refer to the official PrimeVue documentation.
|
||||
- **Custom shared components (design system components)**:
|
||||
Always create stories. These components are built in collaboration with designers, and Storybook serves as both documentation and a communication tool.
|
||||
- **Container components (logic-heavy)**:
|
||||
Do not create stories. Only the underlying pure UI components should be included in Storybook.
|
||||
|
||||
### Maintenance Philosophy
|
||||
- Stories are lightweight and generally stable.
|
||||
Once created, they rarely need updates unless:
|
||||
- The design changes
|
||||
- New props (e.g. size, color variants) are introduced
|
||||
- For existing usage patterns, simply copy real code examples into Storybook to create stories.
|
||||
|
||||
### File Placement
|
||||
- Keep `*.stories.ts` files at the **same level as the component** (similar to test files).
|
||||
- This makes it easier to check usage examples without navigating to another directory.
|
||||
|
||||
### Developer/Designer Workflow
|
||||
- **UI vs Container**: Separate pure UI components from container components.
|
||||
Only UI components should live in Storybook.
|
||||
- **Communication Tool**: Storybook is not just about code quality—it enables designers and developers to see:
|
||||
- Which props exist
|
||||
- What cases are covered
|
||||
- How variants (e.g. size, colors) look in isolation
|
||||
- **Example**:
|
||||
`PackActionButton.vue` wraps a PrimeVue button with additional logic.
|
||||
→ Only create a story for the base UI button, not for the wrapper.
|
||||
|
||||
### Suggested Workflow
|
||||
1. Use PrimeVue docs for standard components
|
||||
2. Use Storybook for **shared/custom components** that define our design system
|
||||
3. Keep story files alongside components
|
||||
4. When in doubt, focus on components reused across the app or those that need to be showcased to designers
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Keep Stories Simple**: Each story should demonstrate one specific use case
|
||||
2. **Use Realistic Data**: Use data that resembles real application usage
|
||||
3. **Document Edge Cases**: Create stories for loading states, errors, and edge cases
|
||||
4. **Group Related Stories**: Use consistent naming and grouping for related components
|
||||
|
||||
### Component Testing Strategy
|
||||
|
||||
```typescript
|
||||
// Example: Testing different component states
|
||||
export const Loading: Story = {
|
||||
args: {
|
||||
isLoading: true
|
||||
}
|
||||
}
|
||||
|
||||
export const Error: Story = {
|
||||
args: {
|
||||
error: 'Failed to load data'
|
||||
}
|
||||
}
|
||||
|
||||
export const WithLongText: Story = {
|
||||
args: {
|
||||
description: 'Very long description that might cause layout issues...'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Debugging Tips
|
||||
|
||||
- Use browser DevTools to inspect component behavior
|
||||
- Check the Storybook console for Vue warnings or errors
|
||||
- Use the Controls addon to dynamically change props
|
||||
- Leverage the Actions addon to test event handling
|
||||
|
||||
## Configuration Files
|
||||
|
||||
- **`main.ts`**: Core Storybook configuration and Vite integration
|
||||
- **`preview.ts`**: Global decorators, parameters, and Vue app setup
|
||||
- **`manager.ts`**: Storybook UI customization (if needed)
|
||||
- **`preview-head.html`**: Injects custom HTML into the `<head>` of every Storybook iframe (used for global styles, fonts, or fixes for iframe-specific issues)
|
||||
|
||||
## Chromatic Visual Testing
|
||||
|
||||
This project uses [Chromatic](https://chromatic.com) for automated visual regression testing of Storybook components.
|
||||
|
||||
### How It Works
|
||||
|
||||
- **Automated Testing**: Every push to `main` and `sno-storybook` branches triggers Chromatic builds
|
||||
- **Pull Request Reviews**: PRs against `main` branch include visual diffs for component changes
|
||||
- **Baseline Management**: Changes on `main` branch are automatically accepted as new baselines
|
||||
- **Cross-browser Testing**: Tests across multiple browsers and viewports
|
||||
|
||||
### Viewing Results
|
||||
|
||||
1. Check the GitHub Actions tab for Chromatic workflow status
|
||||
2. Click on the Chromatic build link in PR comments to review visual changes
|
||||
3. Accept or reject visual changes directly in the Chromatic UI
|
||||
|
||||
### Best Practices for Visual Testing
|
||||
|
||||
- **Consistent Stories**: Ensure stories render consistently across different environments
|
||||
- **Meaningful Names**: Use descriptive story names that clearly indicate the component state
|
||||
- **Edge Cases**: Include stories for loading, error, and empty states
|
||||
- **Realistic Data**: Use data that closely resembles production usage
|
||||
|
||||
## Integration with ComfyUI
|
||||
|
||||
This Storybook setup includes:
|
||||
|
||||
- ComfyUI-specific theming and styling
|
||||
- Pre-configured Pinia stores for state management
|
||||
- Internationalization (i18n) support
|
||||
- PrimeVue component library integration
|
||||
- Proper alias resolution for `@/` imports
|
||||
|
||||
## Icon Usage in Storybook
|
||||
|
||||
In this project, the `<i-lucide:... />` syntax from unplugin-icons is not supported in Storybook.
|
||||
|
||||
**Example:**
|
||||
|
||||
```vue
|
||||
<script setup lang="ts">
|
||||
import { Trophy, Settings } from 'lucide-vue-next'
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Trophy :size="16" class="text-neutral" />
|
||||
<Settings :size="16" class="text-neutral" />
|
||||
</template>
|
||||
```
|
||||
|
||||
This approach ensures icons render correctly in Storybook and remain consistent with the rest of the app.
|
||||
|
||||
96
.storybook/main.ts
Normal file
96
.storybook/main.ts
Normal file
@@ -0,0 +1,96 @@
|
||||
import type { StorybookConfig } from '@storybook/vue3-vite'
|
||||
import { FileSystemIconLoader } from 'unplugin-icons/loaders'
|
||||
import IconsResolver from 'unplugin-icons/resolver'
|
||||
import Icons from 'unplugin-icons/vite'
|
||||
import Components from 'unplugin-vue-components/vite'
|
||||
import type { InlineConfig } from 'vite'
|
||||
|
||||
const config: StorybookConfig = {
|
||||
stories: ['../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
|
||||
addons: ['@storybook/addon-docs'],
|
||||
framework: {
|
||||
name: '@storybook/vue3-vite',
|
||||
options: {}
|
||||
},
|
||||
async viteFinal(config) {
|
||||
// Use dynamic import to avoid CJS deprecation warning
|
||||
const { mergeConfig } = await import('vite')
|
||||
|
||||
// Filter out any plugins that might generate import maps
|
||||
if (config.plugins) {
|
||||
config.plugins = config.plugins.filter((plugin: any) => {
|
||||
if (plugin && plugin.name && plugin.name.includes('import-map')) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
}
|
||||
|
||||
return mergeConfig(config, {
|
||||
// Replace plugins entirely to avoid inheritance issues
|
||||
plugins: [
|
||||
// Only include plugins we explicitly need for Storybook
|
||||
Icons({
|
||||
compiler: 'vue3',
|
||||
customCollections: {
|
||||
comfy: FileSystemIconLoader(
|
||||
process.cwd() + '/src/assets/icons/custom'
|
||||
)
|
||||
}
|
||||
}),
|
||||
Components({
|
||||
dts: false, // Disable dts generation in Storybook
|
||||
resolvers: [
|
||||
IconsResolver({
|
||||
customCollections: ['comfy']
|
||||
})
|
||||
],
|
||||
dirs: [
|
||||
process.cwd() + '/src/components',
|
||||
process.cwd() + '/src/layout',
|
||||
process.cwd() + '/src/views'
|
||||
],
|
||||
deep: true,
|
||||
extensions: ['vue']
|
||||
})
|
||||
// Note: Explicitly NOT including generateImportMapPlugin to avoid externalization
|
||||
],
|
||||
server: {
|
||||
allowedHosts: true
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': process.cwd() + '/src'
|
||||
}
|
||||
},
|
||||
build: {
|
||||
rollupOptions: {
|
||||
external: () => {
|
||||
// Don't externalize any modules in Storybook build
|
||||
// This ensures PrimeVue and other dependencies are bundled
|
||||
return false
|
||||
},
|
||||
onwarn: (warning, warn) => {
|
||||
// Suppress specific warnings
|
||||
if (
|
||||
warning.code === 'UNUSED_EXTERNAL_IMPORT' &&
|
||||
warning.message?.includes('resolveComponent')
|
||||
) {
|
||||
return
|
||||
}
|
||||
// Suppress Storybook font asset warnings
|
||||
if (
|
||||
warning.code === 'UNRESOLVED_IMPORT' &&
|
||||
warning.message?.includes('nunito-sans')
|
||||
) {
|
||||
return
|
||||
}
|
||||
warn(warning)
|
||||
}
|
||||
},
|
||||
chunkSizeWarningLimit: 1000
|
||||
}
|
||||
} satisfies InlineConfig)
|
||||
}
|
||||
}
|
||||
export default config
|
||||
34
.storybook/preview-head.html
Normal file
34
.storybook/preview-head.html
Normal file
@@ -0,0 +1,34 @@
|
||||
<style>
|
||||
body {
|
||||
overflow-y: auto !important;
|
||||
transition: background-color 0.3s ease, color 0.3s ease;
|
||||
}
|
||||
|
||||
/* Light theme default */
|
||||
body {
|
||||
background-color: #ffffff;
|
||||
color: #1a1a1a;
|
||||
}
|
||||
|
||||
/* Dark theme styles */
|
||||
body.dark-theme,
|
||||
.dark-theme body {
|
||||
background-color: #0a0a0a;
|
||||
color: #e5e5e5;
|
||||
}
|
||||
|
||||
/* Ensure Storybook canvas follows theme */
|
||||
.sb-show-main {
|
||||
transition: background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.dark-theme .sb-show-main,
|
||||
.dark-theme .docs-story {
|
||||
background-color: #0a0a0a !important;
|
||||
}
|
||||
|
||||
/* Fix for Storybook controls panel in dark mode */
|
||||
.dark-theme .docblock-argstable-body {
|
||||
color: #e5e5e5;
|
||||
}
|
||||
</style>
|
||||
104
.storybook/preview.ts
Normal file
104
.storybook/preview.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { definePreset } from '@primevue/themes'
|
||||
import Aura from '@primevue/themes/aura'
|
||||
import { setup } from '@storybook/vue3'
|
||||
import type { Preview } from '@storybook/vue3-vite'
|
||||
import { createPinia } from 'pinia'
|
||||
import 'primeicons/primeicons.css'
|
||||
import PrimeVue from 'primevue/config'
|
||||
import ConfirmationService from 'primevue/confirmationservice'
|
||||
import ToastService from 'primevue/toastservice'
|
||||
import Tooltip from 'primevue/tooltip'
|
||||
|
||||
import '../src/assets/css/style.css'
|
||||
import { i18n } from '../src/i18n'
|
||||
import '../src/lib/litegraph/public/css/litegraph.css'
|
||||
import { useWidgetStore } from '../src/stores/widgetStore'
|
||||
import { useColorPaletteStore } from '../src/stores/workspace/colorPaletteStore'
|
||||
|
||||
const ComfyUIPreset = definePreset(Aura, {
|
||||
semantic: {
|
||||
// @ts-expect-error fix me
|
||||
primary: Aura['primitive'].blue
|
||||
}
|
||||
})
|
||||
|
||||
// Setup Vue app for Storybook
|
||||
setup((app) => {
|
||||
app.directive('tooltip', Tooltip)
|
||||
const pinia = createPinia()
|
||||
app.use(pinia)
|
||||
|
||||
// Initialize stores
|
||||
useColorPaletteStore(pinia)
|
||||
useWidgetStore(pinia)
|
||||
|
||||
app.use(i18n)
|
||||
app.use(PrimeVue, {
|
||||
theme: {
|
||||
preset: ComfyUIPreset,
|
||||
options: {
|
||||
prefix: 'p',
|
||||
cssLayer: {
|
||||
name: 'primevue',
|
||||
order: 'primevue, tailwind-utilities'
|
||||
},
|
||||
darkModeSelector: '.dark-theme, :root:has(.dark-theme)'
|
||||
}
|
||||
}
|
||||
})
|
||||
app.use(ConfirmationService)
|
||||
app.use(ToastService)
|
||||
})
|
||||
|
||||
// Dark theme decorator
|
||||
export const withTheme = (Story: any, context: any) => {
|
||||
const theme = context.globals.theme || 'light'
|
||||
|
||||
// Apply theme class to document root
|
||||
if (theme === 'dark') {
|
||||
document.documentElement.classList.add('dark-theme')
|
||||
document.body.classList.add('dark-theme')
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark-theme')
|
||||
document.body.classList.remove('dark-theme')
|
||||
}
|
||||
|
||||
return Story()
|
||||
}
|
||||
|
||||
const preview: Preview = {
|
||||
parameters: {
|
||||
controls: {
|
||||
matchers: {
|
||||
color: /(background|color)$/i,
|
||||
date: /Date$/i
|
||||
}
|
||||
},
|
||||
backgrounds: {
|
||||
default: 'light',
|
||||
values: [
|
||||
{ name: 'light', value: '#ffffff' },
|
||||
{ name: 'dark', value: '#0a0a0a' }
|
||||
]
|
||||
}
|
||||
},
|
||||
globalTypes: {
|
||||
theme: {
|
||||
name: 'Theme',
|
||||
description: 'Global theme for components',
|
||||
defaultValue: 'light',
|
||||
toolbar: {
|
||||
icon: 'circlehollow',
|
||||
items: [
|
||||
{ value: 'light', icon: 'sun', title: 'Light' },
|
||||
{ value: 'dark', icon: 'moon', title: 'Dark' }
|
||||
],
|
||||
showName: true,
|
||||
dynamicTitle: true
|
||||
}
|
||||
}
|
||||
},
|
||||
decorators: [withTheme]
|
||||
}
|
||||
|
||||
export default preview
|
||||
40
AGENTS.md
Normal file
40
AGENTS.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Repository Guidelines
|
||||
|
||||
## Project Structure & Module Organization
|
||||
- Source: `src/` (Vue 3 + TypeScript). Key areas: `components/`, `views/`, `stores/` (Pinia), `composables/`, `services/`, `utils/`, `assets/`, `locales/`.
|
||||
- Routing/i18n/entry: `src/router.ts`, `src/i18n.ts`, `src/main.ts`.
|
||||
- Tests: unit/component in `tests-ui/` and `src/components/**/*.{test,spec}.ts`; E2E in `browser_tests/`.
|
||||
- Public assets: `public/`. Build output: `dist/`.
|
||||
- Config: `vite.config.mts`, `vitest.config.ts`, `playwright.config.ts`, `eslint.config.js`, `.prettierrc`.
|
||||
|
||||
## Build, Test, and Development Commands
|
||||
- `pnpm dev`: Start Vite dev server.
|
||||
- `pnpm dev:electron`: Dev server with Electron API mocks.
|
||||
- `pnpm build`: Type-check then production build to `dist/`.
|
||||
- `pnpm preview`: Preview the production build locally.
|
||||
- `pnpm test:unit`: Run Vitest unit tests (`tests-ui/`).
|
||||
- `pnpm test:component`: Run component tests (`src/components/`).
|
||||
- `pnpm test:browser`: Run Playwright E2E tests (`browser_tests/`).
|
||||
- `pnpm lint` / `pnpm lint:fix`: Lint (ESLint). `pnpm format` / `format:check`: Prettier.
|
||||
- `pnpm typecheck`: Vue TSC type checking.
|
||||
|
||||
## Coding Style & Naming Conventions
|
||||
- Language: TypeScript, Vue SFCs (`.vue`). Indent 2 spaces; single quotes; no semicolons; width 80 (see `.prettierrc`).
|
||||
- Imports: sorted/grouped by plugin; run `pnpm format` before committing.
|
||||
- ESLint: Vue + TS rules; no floating promises; unused imports disallowed; i18n raw text restrictions in templates.
|
||||
- Naming: Vue components in PascalCase (e.g., `MenuHamburger.vue`); composables `useXyz.ts`; Pinia stores `*Store.ts`.
|
||||
|
||||
## Testing Guidelines
|
||||
- Frameworks: Vitest (unit/component, happy-dom) and Playwright (E2E).
|
||||
- Test files: `**/*.{test,spec}.{ts,tsx,js}` under `tests-ui/`, `src/components/`, and `src/lib/litegraph/test/`.
|
||||
- Coverage: text/json/html reporters enabled; aim to cover critical logic and new features.
|
||||
- Playwright: place tests in `browser_tests/`; optional tags like `@mobile`, `@2x` are respected by config.
|
||||
|
||||
## Commit & Pull Request Guidelines
|
||||
- Commits: Prefer Conventional Commits (e.g., `feat(ui): add sidebar`), `refactor(litegraph): …`. Use `[skip ci]` for locale-only updates when appropriate.
|
||||
- PRs: Include clear description, linked issues (`Fixes #123`), and screenshots/GIFs for UI changes. Add/adjust tests and i18n strings when applicable.
|
||||
- Quality gates: `pnpm lint`, `pnpm typecheck`, and relevant tests must pass. Keep PRs focused and small.
|
||||
|
||||
## Security & Configuration Tips
|
||||
- Secrets: Use `.env` (see `.env_example`); do not commit secrets.
|
||||
- Backend: Dev server expects ComfyUI backend at `localhost:8188` by default; configure via `.env`.
|
||||
152
CLAUDE.md
152
CLAUDE.md
@@ -1,58 +1,94 @@
|
||||
- use `npm run` to see what commands are available
|
||||
- For component communication, prefer Vue's event-based pattern (emit/@event-name) for state changes and notifications; use defineExpose with refs only for imperative operations that need direct control (like form.validate(), modal.open(), or editor.focus()); events promote loose coupling and are better for reusable components, while exposed methods are acceptable for tightly-coupled component pairs or when wrapping third-party libraries that require imperative APIs
|
||||
- After making code changes, follow this general process: (1) Create unit tests, component tests, browser tests (if appropriate for each), (2) run unit tests, component tests, and browser tests until passing, (3) run typecheck, lint, format (with prettier) -- you can use `npm run` command to see the scripts available, (4) check if any READMEs (including nested) or documentation needs to be updated, (5) Decide whether the changes are worth adding new content to the external documentation for (or would requires changes to the external documentation) at https://docs.comfy.org, then present your suggestion
|
||||
- When referencing PrimeVue, you can get all the docs here: https://primevue.org. Do this instead of making up or inferring names of Components
|
||||
- When trying to set tailwind classes for dark theme, use "dark-theme:" prefix rather than "dark:"
|
||||
- Never add lines to PR descriptions or commit messages that say "Generated with Claude Code"
|
||||
- When making PR names and commit messages, if you are going to add a prefix like "docs:", "feat:", "bugfix:", use square brackets around the prefix term and do not use a colon (e.g., should be "[docs]" rather than "docs:").
|
||||
- When I reference GitHub Repos related to Comfy-Org, you should proactively fetch or read the associated information in the repo. To do so, you should exhaust all options: (1) Check if we have a local copy of the repo, (2) Use the GitHub API to fetch the information; you may want to do this IN ADDITION to the other options, especially for reading specific branches/PRs/comments/reviews/metadata, and (3) curl the GitHub website and parse the html or json responses
|
||||
- For information about ComfyUI, ComfyUI_frontend, or ComfyUI-Manager, you can web search or download these wikis: https://deepwiki.com/Comfy-Org/ComfyUI-Manager, https://deepwiki.com/Comfy-Org/ComfyUI_frontend/1-overview, https://deepwiki.com/comfyanonymous/ComfyUI/2-core-architecture
|
||||
- If a question/project is related to Comfy-Org, Comfy, or ComfyUI ecosystem, you should proactively use the Comfy docs to answer the question. The docs may be referenced with URLs like https://docs.comfy.org
|
||||
- When operating inside a repo, check for README files at key locations in the repo detailing info about the contents of that folder. E.g., top-level key folders like tests-ui, browser_tests, composables, extensions/core, stores, services often have their own README.md files. When writing code, make sure to frequently reference these README files to understand the overall architecture and design of the project. Pay close attention to the snippets to learn particular patterns that seem to be there for a reason, as you should emulate those.
|
||||
- Prefer running single tests, and not the whole test suite, for performance
|
||||
- If using a lesser known or complex CLI tool, run the --help to see the documentation before deciding what to run, even if just for double-checking or verifying things.
|
||||
- IMPORTANT: the most important goal when writing code is to create clean, best-practices, sustainable, and scalable public APIs and interfaces. Our app is used by thousands of users and we have thousands of mods/extensions that are constantly changing and updating; and we are also always updating. That's why it is IMPORTANT that we design systems and write code that follows practices of domain-driven design, object-oriented design, and design patterns (such that you can assure stability while allowing for all components around you to change and evolve). We ABSOLUTELY prioritize clean APIs and public interfaces that clearly define and restrict how/what the mods/extensions can access.
|
||||
- If any of these technologies are referenced, you can proactively read their docs at these locations: https://primevue.org/theming, https://primevue.org/forms/, https://www.electronjs.org/docs/latest/api/browser-window, https://vitest.dev/guide/browser/, https://atlassian.design/components/pragmatic-drag-and-drop/core-package/drop-targets/, https://playwright.dev/docs/api/class-test, https://playwright.dev/docs/api/class-electron, https://www.algolia.com/doc/api-reference/rest-api/, https://pyav.org/docs/develop/cookbook/basics.html
|
||||
- IMPORTANT: Never add Co-Authored by Claude or any reference to Claude or Claude Code in commit messages, PR descriptions, titles, or any documentation whatsoever
|
||||
- The npm script to type check is called "typecheck" NOT "type check"
|
||||
- Use the Vue 3 Composition API instead of the Options API when writing Vue components. An exception is when overriding or extending a PrimeVue component for compatibility, you may use the Options API.
|
||||
- when we are solving an issue we know the link/number for, we should add "Fixes #n" (where n is the issue number) to the PR description.
|
||||
- Never write css if you can accomplish the same thing with tailwind utility classes
|
||||
- Utilize ref and reactive for reactive state
|
||||
- Implement computed properties with computed()
|
||||
- Use watch and watchEffect for side effects
|
||||
- Implement lifecycle hooks with onMounted, onUpdated, etc.
|
||||
- Utilize provide/inject for dependency injection
|
||||
- Use vue 3.5 style of default prop declaration. Do not define a `props` variable; instead, destructure props. Since vue 3.5, destructuring props does not strip them of reactivity.
|
||||
- Use Tailwind CSS for styling
|
||||
- Leverage VueUse functions for performance-enhancing styles
|
||||
- Use lodash for utility functions
|
||||
- Implement proper props and emits definitions
|
||||
- Utilize Vue 3's Teleport component when needed
|
||||
- Use Suspense for async components
|
||||
- Implement proper error handling
|
||||
- Follow Vue 3 style guide and naming conventions
|
||||
- IMPORTANT: Use vue-i18n for ALL user-facing strings - no hard-coded text in services/utilities. Place new translation entries in src/locales/en/main.json
|
||||
- Avoid using `@ts-expect-error` to work around type issues. We needed to employ it to migrate to TypeScript, but it should not be viewed as an accepted practice or standard.
|
||||
- DO NOT use deprecated PrimeVue components. Use these replacements instead:
|
||||
* `Dropdown` → Use `Select` (import from 'primevue/select')
|
||||
* `OverlayPanel` → Use `Popover` (import from 'primevue/popover')
|
||||
* `Calendar` → Use `DatePicker` (import from 'primevue/datepicker')
|
||||
* `InputSwitch` → Use `ToggleSwitch` (import from 'primevue/toggleswitch')
|
||||
* `Sidebar` → Use `Drawer` (import from 'primevue/drawer')
|
||||
* `Chips` → Use `AutoComplete` with multiple enabled and typeahead disabled
|
||||
* `TabMenu` → Use `Tabs` without panels
|
||||
* `Steps` → Use `Stepper` without panels
|
||||
* `InlineMessage` → Use `Message` component
|
||||
* Use `api.apiURL()` for all backend API calls and routes
|
||||
- Actual API endpoints like /prompt, /queue, /view, etc.
|
||||
- Image previews: `api.apiURL('/view?...')`
|
||||
- Any backend-generated content or dynamic routes
|
||||
* Use `api.fileURL()` for static files served from the public folder:
|
||||
- Templates: `api.fileURL('/templates/default.json')`
|
||||
- Extensions: `api.fileURL(extensionPath)` for loading JS modules
|
||||
- Any static assets that exist in the public directory
|
||||
- When implementing code that outputs raw HTML (e.g., using v-html directive), always ensure dynamic content has been properly sanitized with DOMPurify or validated through trusted sources. Prefer Vue templates over v-html when possible.
|
||||
- For any async operations (API calls, timers, etc), implement cleanup/cancellation in component unmount to prevent memory leaks
|
||||
- Extract complex template conditionals into separate components or computed properties
|
||||
- Error messages should be actionable and user-friendly (e.g., "Failed to load data. Please refresh the page." instead of "Unknown error")
|
||||
# ComfyUI Frontend Project Guidelines
|
||||
|
||||
## Repository Setup
|
||||
|
||||
For first-time setup, use the Claude command:
|
||||
```
|
||||
/setup_repo
|
||||
```
|
||||
This bootstraps the monorepo with dependencies, builds, tests, and dev server verification.
|
||||
|
||||
**Prerequisites:** Node.js >= 24, Git repository, available ports (5173, 6006)
|
||||
|
||||
## Quick Commands
|
||||
|
||||
- `pnpm`: See all available commands
|
||||
- `pnpm dev`: Start development server (port 5173, via nx)
|
||||
- `pnpm typecheck`: Type checking
|
||||
- `pnpm build`: Build for production (via nx)
|
||||
- `pnpm lint`: Linting (via nx)
|
||||
- `pnpm format`: Prettier formatting
|
||||
- `pnpm test:component`: Run component tests with browser environment
|
||||
- `pnpm test:unit`: Run all unit tests
|
||||
- `pnpm test:browser`: Run E2E tests via Playwright
|
||||
- `pnpm test:unit -- tests-ui/tests/example.test.ts`: Run single test file
|
||||
- `pnpm storybook`: Start Storybook development server (port 6006)
|
||||
- `pnpm knip`: Detect unused code and dependencies
|
||||
|
||||
## Monorepo Architecture
|
||||
|
||||
The project now uses **Nx** for build orchestration and task management:
|
||||
|
||||
- **Task Orchestration**: Commands like `dev`, `build`, `lint`, and `test:browser` run via Nx
|
||||
- **Caching**: Nx provides intelligent caching for faster rebuilds
|
||||
- **Configuration**: Managed through `nx.json` with plugins for ESLint, Storybook, Vite, and Playwright
|
||||
- **Dependencies**: Nx handles dependency graph analysis and parallel execution
|
||||
|
||||
Key Nx features:
|
||||
- Build target caching and incremental builds
|
||||
- Parallel task execution across the monorepo
|
||||
- Plugin-based architecture for different tools
|
||||
|
||||
## Development Workflow
|
||||
|
||||
1. **First-time setup**: Run `/setup_repo` Claude command
|
||||
2. Make code changes
|
||||
3. Run tests (see subdirectory CLAUDE.md files)
|
||||
4. Run typecheck, lint, format
|
||||
5. Check README updates
|
||||
6. Consider docs.comfy.org updates
|
||||
|
||||
## Git Conventions
|
||||
|
||||
- Use [prefix] format: [feat], [bugfix], [docs]
|
||||
- Add "Fixes #n" to PR descriptions
|
||||
- Never mention Claude/AI in commits
|
||||
|
||||
## External Resources
|
||||
|
||||
- PrimeVue docs: <https://primevue.org>
|
||||
- ComfyUI docs: <https://docs.comfy.org>
|
||||
- Electron: <https://www.electronjs.org/docs/latest/>
|
||||
- Wiki: <https://deepwiki.com/Comfy-Org/ComfyUI_frontend/1-overview>
|
||||
|
||||
## Project Philosophy
|
||||
|
||||
- Clean, stable public APIs
|
||||
- Domain-driven design
|
||||
- Thousands of users and extensions
|
||||
- Prioritize clean interfaces that restrict extension access
|
||||
|
||||
## Repository Navigation
|
||||
|
||||
- Check README files in key folders (tests-ui, browser_tests, composables, etc.)
|
||||
- Prefer running single tests for performance
|
||||
- Use --help for unfamiliar CLI tools
|
||||
|
||||
## GitHub Integration
|
||||
|
||||
When referencing Comfy-Org repos:
|
||||
|
||||
1. Check for local copy
|
||||
2. Use GitHub API for branches/PRs/metadata
|
||||
3. Curl GitHub website if needed
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
- NEVER use `any` type - use proper TypeScript types
|
||||
- NEVER use `as any` type assertions - fix the underlying type issue
|
||||
- NEVER use `--no-verify` flag when committing
|
||||
- NEVER delete or disable tests to make them pass
|
||||
- NEVER circumvent quality checks
|
||||
- NEVER use `dark:` prefix - always use `dark-theme:` for dark mode styles, for example: `dark-theme:text-white dark-theme:bg-black`
|
||||
- NEVER use `:class="[]"` to merge class names - always use `import { cn } from '@/utils/tailwindUtil'`, for example: `<div :class="cn('bg-red-500', { 'bg-blue-500': condition })" />`
|
||||
|
||||
|
||||
335
CONTRIBUTING.md
Normal file
335
CONTRIBUTING.md
Normal file
@@ -0,0 +1,335 @@
|
||||
# Contributing to ComfyUI Frontend
|
||||
|
||||
We're building this frontend together and would love your help — no matter how you'd like to pitch in! You don't need to write code to make a difference.
|
||||
|
||||
## Ways to Contribute
|
||||
|
||||
- **Pull Requests:** Add features, fix bugs, or improve code health. Browse [issues](https://github.com/Comfy-Org/ComfyUI_frontend/issues) for inspiration. Look for the `Good first issue` label if you're new to the project.
|
||||
- **Vote on Features:** Give a 👍 to the feature requests you care about to help us prioritize.
|
||||
- **Verify Bugs:** Try reproducing reported issues and share your results (even if the bug doesn't occur!).
|
||||
- **Community Support:** Hop into our [Discord](https://discord.com/invite/comfyorg) to answer questions or get help.
|
||||
- **Share & Advocate:** Tell your friends, tweet about us, or share tips to support the project.
|
||||
|
||||
Have another idea? Drop into Discord or open an issue, and let's chat!
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Prerequisites & Technology Stack
|
||||
|
||||
- **Required Software**:
|
||||
- Node.js (v16 or later; v24 strongly recommended) and pnpm
|
||||
- Git for version control
|
||||
- A running ComfyUI backend instance
|
||||
|
||||
- **Tech Stack**:
|
||||
- [Vue 3.5 Composition API](https://vuejs.org/) with [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Pinia](https://pinia.vuejs.org/) for state management
|
||||
- [PrimeVue](https://primevue.org/) with [TailwindCSS](https://tailwindcss.com/) for UI
|
||||
- litegraph.js (integrated in src/lib) for node editor
|
||||
- [zod](https://zod.dev/) for schema validation
|
||||
- [vue-i18n](https://github.com/intlify/vue-i18n) for internationalization
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/Comfy-Org/ComfyUI_frontend.git
|
||||
cd ComfyUI_frontend
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
pnpm install
|
||||
```
|
||||
|
||||
3. Configure environment (optional):
|
||||
Create a `.env` file in the project root based on the provided [.env.example](.env.example) file.
|
||||
|
||||
**Note about ports**: By default, the dev server expects the ComfyUI backend at `localhost:8188`. If your ComfyUI instance runs on a different port, update this in your `.env` file.
|
||||
|
||||
### Dev Server Configuration
|
||||
|
||||
To launch ComfyUI and have it connect to your development server:
|
||||
|
||||
```bash
|
||||
python main.py --port 8188
|
||||
```
|
||||
|
||||
### Git pre-commit hooks
|
||||
|
||||
Run `pnpm prepare` to install Git pre-commit hooks. Currently, the pre-commit hook is used to auto-format code on commit.
|
||||
|
||||
### Dev Server
|
||||
|
||||
- Start local ComfyUI backend at `localhost:8188`
|
||||
- Run `pnpm dev` to start the dev server
|
||||
- Run `pnpm dev:electron` to start the dev server with electron API mocked
|
||||
|
||||
#### Access dev server on touch devices
|
||||
|
||||
Enable remote access to the dev server by setting `VITE_REMOTE_DEV` in `.env` to `true`.
|
||||
|
||||
After you start the dev server, you should see following logs:
|
||||
|
||||
```
|
||||
> comfyui-frontend@1.3.42 dev
|
||||
> vite
|
||||
|
||||
|
||||
VITE v5.4.6 ready in 488 ms
|
||||
|
||||
➜ Local: http://localhost:5173/
|
||||
➜ Network: http://172.21.80.1:5173/
|
||||
➜ Network: http://192.168.2.20:5173/
|
||||
➜ press h + enter to show help
|
||||
```
|
||||
|
||||
Make sure your desktop machine and touch device are on the same network. On your touch device,
|
||||
navigate to `http://<server_ip>:5173` (e.g. `http://192.168.2.20:5173` here), to access the ComfyUI frontend.
|
||||
|
||||
> ⚠️ IMPORTANT:
|
||||
The dev server will NOT load JavaScript extensions from custom nodes. Only core extensions (built into the frontend) will be loaded. This is because the shim system that allows custom node JavaScript to import frontend modules only works in production builds. Python custom nodes still function normally. See [Extension Development Guide](docs/extensions/development.md) for details and workarounds. And See [Extension Overview](docs/extensions/README.md) for extensions overview.
|
||||
|
||||
|
||||
## Development Workflow
|
||||
|
||||
### Architecture Decision Records
|
||||
|
||||
We document significant architectural decisions using ADRs (Architecture Decision Records). See [docs/adr/](docs/adr/) for all ADRs and the template for creating new ones.
|
||||
|
||||
### Backporting Changes to Release Branches
|
||||
|
||||
When you fix a bug that affects a version in feature freeze, we use an automated backport process to apply the fix to the release candidate branch.
|
||||
|
||||
#### Real Example
|
||||
|
||||
- Subgraphs feature was released in v1.24
|
||||
- While developing v1.25, we discovered a bug in subgraphs
|
||||
- v1.24 is in feature freeze (only accepting bug fixes, no new features)
|
||||
- The fix needs to be applied to both main (v1.25) and the v1.24 release candidate
|
||||
|
||||
#### How to Backport Your Fix
|
||||
|
||||
1. Create your PR fixing the bug on `main` branch as usual
|
||||
2. Before merging, add these labels to your PR:
|
||||
- `needs-backport` - triggers the automated backport workflow
|
||||
- `1.24` - targets the `core/1.24` release candidate branch
|
||||
|
||||
3. Merge your PR normally
|
||||
4. The automated workflow will:
|
||||
- Create a new branch from `core/1.24`
|
||||
- Apply your changes to that branch
|
||||
- Open a new PR to `core/1.24`
|
||||
- Comment on your original PR with a link to the backport PR
|
||||
|
||||
#### When to Use Backporting
|
||||
|
||||
- Bug fixes for features already released
|
||||
- Security fixes
|
||||
- Critical issues affecting existing functionality
|
||||
- Never for new features (these wait for the next release cycle)
|
||||
|
||||
#### Handling Conflicts
|
||||
|
||||
If the automated cherry-pick fails due to conflicts, the workflow will comment on your PR with:
|
||||
- The list of conflicting files
|
||||
- Instructions to manually cherry-pick to the release candidate branch
|
||||
|
||||
See [PR #4616](https://github.com/Comfy-Org/ComfyUI_frontend/pull/4616) for the actual subgraph bugfix that was backported from v1.25 to v1.24.
|
||||
|
||||
## Code Editor Configuration
|
||||
|
||||
### Recommended Setup
|
||||
|
||||
This project includes `.vscode/launch.json.default` and `.vscode/settings.json.default` files with recommended launch and workspace settings for editors that use the `.vscode` directory (e.g., VS Code, Cursor, etc.).
|
||||
|
||||
We've also included a list of recommended extensions in `.vscode/extensions.json`. Your editor should detect this file and show a human friendly list in the Extensions panel, linking each entry to its marketplace page.
|
||||
|
||||
### MCP Integrations
|
||||
|
||||
#### Playwright Browser Automation
|
||||
|
||||
The Playwright MCP server enables LLM coding assistants (like Copilot, Claude Code, etc.) to control and inspect web browsers programmatically. This allows assistants to navigate websites, take screenshots, and interact with web pages on your behalf.
|
||||
|
||||
For ComfyUI_frontend development, you can ask coding assistants to use Playwright screenshots to continuously verify that your code changes produce the expected visual results.
|
||||
|
||||
##### Setup for Claude Code
|
||||
|
||||
After installing dependencies with `pnpm i`, the Playwright MCP server will be automatically available when you start Claude Code locally.
|
||||
|
||||
Here's how Claude Code can use the Playwright MCP server to inspect the interface of the local development server (assuming you're running the dev server at `localhost:5173`):
|
||||
|
||||
```
|
||||
> navigate to localhost:5173 and take a screenshot.
|
||||
tell me the items in the menubar
|
||||
|
||||
● I'll navigate to localhost:5173 and take a
|
||||
screenshot to see the menubar items.
|
||||
|
||||
● playwright:playwright_navigate (MCP)(url: …
|
||||
"http://local
|
||||
host:5173")
|
||||
⎿ Navigated to http://localhost:5173
|
||||
|
||||
● playwright:playwright_screenshot (MCP)(name: "lo…
|
||||
alhost_5173
|
||||
_menubar")
|
||||
|
||||
⎿ Screenshot saved to: ../../../Downloads/localho
|
||||
st_5173_menubar-2025-05-30T17-23-00-942Z.png
|
||||
⎿ Screenshot also stored in memory with name:
|
||||
'localhost_5173_menubar'
|
||||
|
||||
● Read(../../../Downloads/localhost_5173_menubar-2…
|
||||
25-05-30T17-23-00-942Z.png)
|
||||
⎿ Read image (94.3KB)
|
||||
|
||||
● Based on the screenshot, I can see the menubar at
|
||||
the top of the ComfyUI interface contains the
|
||||
following items:
|
||||
|
||||
Main Menubar Items:
|
||||
- Workflow - Menu for workflow-related actions
|
||||
- Edit - Menu for editing operations
|
||||
- Help - Menu for help and documentation
|
||||
|
||||
Additional UI Elements:
|
||||
- ComfyUI Logo - On the far left
|
||||
- Workflow Tab - Shows "Unsaved Workflow" with a
|
||||
dropdown and close button
|
||||
- Layout Controls - On the far right (grid view
|
||||
and hamburger menu icons)
|
||||
|
||||
The interface shows a typical ComfyUI workflow
|
||||
graph with nodes like "Load Checkpoint", "CLIP
|
||||
Text Encode (Prompt)", "KSampler", and "Empty
|
||||
Latent Image" connected with colored cables.
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
- `pnpm i` to install all dependencies
|
||||
- `pnpm test:unit` to execute all unit tests
|
||||
|
||||
### Component Tests
|
||||
|
||||
Component tests verify Vue components in `src/components/`.
|
||||
|
||||
- `pnpm test:component` to execute all component tests
|
||||
|
||||
### Playwright Tests
|
||||
|
||||
Playwright tests verify the whole app. See [browser_tests/README.md](browser_tests/README.md) for details.
|
||||
|
||||
### Running All Tests
|
||||
|
||||
Before submitting a PR, ensure all tests pass:
|
||||
|
||||
```bash
|
||||
pnpm test:unit
|
||||
pnpm test:component
|
||||
pnpm test:browser
|
||||
pnpm typecheck
|
||||
pnpm lint
|
||||
pnpm format
|
||||
```
|
||||
|
||||
## Code Style Guidelines
|
||||
|
||||
### TypeScript
|
||||
- Use TypeScript for all new code
|
||||
- Avoid `any` types - use proper type definitions
|
||||
- Never use `@ts-expect-error` - fix the underlying type issue
|
||||
|
||||
### Vue 3 Patterns
|
||||
- Use Composition API for all components
|
||||
- Follow Vue 3.5+ patterns (props destructuring is reactive)
|
||||
- Use `<script setup>` syntax
|
||||
|
||||
### Styling
|
||||
- Use Tailwind CSS classes instead of custom CSS
|
||||
- Follow the existing dark theme pattern: `dark-theme:` prefix (not `dark:`)
|
||||
|
||||
### Internationalization
|
||||
- All user-facing strings must use vue-i18n
|
||||
- Add translations to `src/locales/en/main.json`
|
||||
- Use translation keys: `const { t } = useI18n(); t('key.path')`
|
||||
|
||||
## Icons
|
||||
|
||||
The project supports three types of icons, all with automatic imports (no manual imports needed):
|
||||
|
||||
1. **PrimeIcons** - Built-in PrimeVue icons using CSS classes: `<i class="pi pi-plus" />`
|
||||
2. **Iconify Icons** - 200,000+ icons from various libraries: `<i-lucide:settings />`, `<i-mdi:folder />`
|
||||
3. **Custom Icons** - Your own SVG icons: `<i-comfy:workflow />`
|
||||
|
||||
Icons are powered by the unplugin-icons system, which automatically discovers and imports icons as Vue components. Custom icons are stored in `src/assets/icons/custom/` and processed by `build/customIconCollection.ts` with automatic validation.
|
||||
|
||||
For detailed instructions and code examples, see [src/assets/icons/README.md](src/assets/icons/README.md).
|
||||
|
||||
## Working with litegraph.js
|
||||
|
||||
Since Aug 5, 2025, litegraph.js is now integrated directly into this repository. It was merged using git subtree to preserve the complete commit history ([PR #4667](https://github.com/Comfy-Org/ComfyUI_frontend/pull/4667), [ADR](docs/adr/0001-merge-litegraph-into-frontend.md)).
|
||||
|
||||
### Important Notes
|
||||
|
||||
- **Issue References**: Commits from the original litegraph repository may contain issue/PR numbers (e.g., #4667) that refer to issues/PRs in the original litegraph.js repository, not this one.
|
||||
- **File Paths**: When viewing historical commits, file paths may show the original structure before the subtree merge. In those cases, just consider the paths relative to the new litegraph folder.
|
||||
- **Contributing**: All litegraph modifications should now be made directly in this repository.
|
||||
|
||||
The original litegraph repository (https://github.com/Comfy-Org/litegraph.js) is now archived.
|
||||
|
||||
## Submitting Changes
|
||||
|
||||
### Pull Request Process
|
||||
|
||||
1. Ensure your branch is up to date with main
|
||||
2. Run all tests and ensure they pass
|
||||
3. Create a pull request with a clear title and description
|
||||
4. Use conventional commit format for PR titles:
|
||||
- `[feat]` for new features
|
||||
- `[fix]` for bug fixes
|
||||
- `[docs]` for documentation
|
||||
- `[refactor]` for code refactoring
|
||||
- `[test]` for test additions/changes
|
||||
- `[chore]` for maintenance tasks
|
||||
|
||||
### PR Description Template
|
||||
|
||||
```
|
||||
## Description
|
||||
Brief description of the changes
|
||||
|
||||
## Type of Change
|
||||
- [ ] Bug fix
|
||||
- [ ] New feature
|
||||
- [ ] Breaking change
|
||||
- [ ] Documentation update
|
||||
|
||||
## Testing
|
||||
- [ ] Unit tests pass
|
||||
- [ ] Component tests pass
|
||||
- [ ] Browser tests pass (if applicable)
|
||||
- [ ] Manual testing completed
|
||||
|
||||
## Screenshots (if applicable)
|
||||
Add screenshots for UI changes
|
||||
```
|
||||
|
||||
### Review Process
|
||||
|
||||
1. All PRs require at least one review
|
||||
2. Address review feedback promptly
|
||||
3. Keep PRs focused - one feature/fix per PR
|
||||
4. Large features should be discussed in an issue first
|
||||
|
||||
## Questions?
|
||||
|
||||
If you have questions about contributing:
|
||||
- Check existing issues and discussions
|
||||
- Ask in our [Discord](https://discord.com/invite/comfyorg)
|
||||
- Open a new issue for clarification
|
||||
|
||||
Thank you for contributing to ComfyUI Frontend!
|
||||
194
README.md
194
README.md
@@ -75,7 +75,7 @@ The development of successive minor versions overlaps. For example, while versio
|
||||
<summary>v1.5: Native translation (i18n)</summary>
|
||||
|
||||
ComfyUI now includes built-in translation support, replacing the need for third-party translation extensions. Select your language
|
||||
in `Comfy > Locale > Language` to translate the interface into English, Chinese (Simplified), Russian, Japanese, or Korean. This native
|
||||
in `Comfy > Locale > Language` to translate the interface into English, Chinese (Simplified), Russian, Japanese, Korean, or Arabic. This native
|
||||
implementation offers better performance, reliability, and maintainability compared to previous solutions.<br>
|
||||
|
||||
More details available here: https://blog.comfy.org/p/native-localization-support-i18n
|
||||
@@ -512,195 +512,27 @@ The selection toolbox will display the command button when items are selected:
|
||||
|
||||
## Contributing
|
||||
|
||||
We're building this frontend together and would love your help — no matter how you'd like to pitch in! You don't need to write code to make a difference.
|
||||
We welcome contributions to ComfyUI Frontend! Please see our [Contributing Guide](CONTRIBUTING.md) for:
|
||||
|
||||
Here are some ways to get involved:
|
||||
|
||||
- **Pull Requests:** Add features, fix bugs, or improve code health. Browse [issues](https://github.com/Comfy-Org/ComfyUI_frontend/issues) for inspiration.
|
||||
- **Vote on Features:** Give a 👍 to the feature requests you care about to help us prioritize.
|
||||
- **Verify Bugs:** Try reproducing reported issues and share your results (even if the bug doesn't occur!).
|
||||
- **Community Support:** Hop into our [Discord](https://www.comfy.org/discord) to answer questions or get help.
|
||||
- **Share & Advocate:** Tell your friends, tweet about us, or share tips to support the project.
|
||||
|
||||
Have another idea? Drop into Discord or open an issue, and let's chat!
|
||||
- Ways to contribute (code, documentation, testing, community support)
|
||||
- Development setup and workflow
|
||||
- Code style guidelines
|
||||
- Testing requirements
|
||||
- How to submit pull requests
|
||||
- Backporting fixes to release branches
|
||||
|
||||
## Development
|
||||
|
||||
### Prerequisites & Technology Stack
|
||||
|
||||
- **Required Software**:
|
||||
- Node.js (v16 or later; v20/v22 strongly recommended) and npm
|
||||
- Git for version control
|
||||
- A running ComfyUI backend instance
|
||||
|
||||
- **Tech Stack**:
|
||||
- [Vue 3](https://vuejs.org/) with [TypeScript](https://www.typescriptlang.org/)
|
||||
- [Pinia](https://pinia.vuejs.org/) for state management
|
||||
- [PrimeVue](https://primevue.org/) with [TailwindCSS](https://tailwindcss.com/) for UI
|
||||
- [litegraph.js](https://github.com/Comfy-Org/litegraph.js) for node editor
|
||||
- [zod](https://zod.dev/) for schema validation
|
||||
- [vue-i18n](https://github.com/intlify/vue-i18n) for internationalization
|
||||
|
||||
### Initial Setup
|
||||
|
||||
1. Clone the repository:
|
||||
```bash
|
||||
git clone https://github.com/Comfy-Org/ComfyUI_frontend.git
|
||||
cd ComfyUI_frontend
|
||||
```
|
||||
|
||||
2. Install dependencies:
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
3. Configure environment (optional):
|
||||
Create a `.env` file in the project root based on the provided [.env.example](.env.example) file.
|
||||
|
||||
**Note about ports**: By default, the dev server expects the ComfyUI backend at `localhost:8188`. If your ComfyUI instance runs on a different port, update this in your `.env` file.
|
||||
|
||||
### Dev Server Configuration
|
||||
|
||||
To launch ComfyUI and have it connect to your development server:
|
||||
|
||||
```bash
|
||||
python main.py --port 8188
|
||||
```
|
||||
|
||||
### Git pre-commit hooks
|
||||
|
||||
Run `npm run prepare` to install Git pre-commit hooks. Currently, the pre-commit
|
||||
hook is used to auto-format code on commit.
|
||||
|
||||
### Dev Server
|
||||
|
||||
Note: The dev server will NOT load any extension from the ComfyUI server. Only
|
||||
core extensions will be loaded.
|
||||
|
||||
- Start local ComfyUI backend at `localhost:8188`
|
||||
- Run `npm run dev` to start the dev server
|
||||
- Run `npm run dev:electron` to start the dev server with electron API mocked
|
||||
|
||||
#### Access dev server on touch devices
|
||||
|
||||
Enable remote access to the dev server by setting `VITE_REMOTE_DEV` in `.env` to `true`.
|
||||
|
||||
After you start the dev server, you should see following logs:
|
||||
|
||||
```
|
||||
> comfyui-frontend@1.3.42 dev
|
||||
> vite
|
||||
|
||||
|
||||
VITE v5.4.6 ready in 488 ms
|
||||
|
||||
➜ Local: http://localhost:5173/
|
||||
➜ Network: http://172.21.80.1:5173/
|
||||
➜ Network: http://192.168.2.20:5173/
|
||||
➜ press h + enter to show help
|
||||
```
|
||||
|
||||
Make sure your desktop machine and touch device are on the same network. On your touch device,
|
||||
navigate to `http://<server_ip>:5173` (e.g. `http://192.168.2.20:5173` here), to access the ComfyUI frontend.
|
||||
|
||||
### Recommended Code Editor Configuration
|
||||
|
||||
This project includes `.vscode/launch.json.default` and `.vscode/settings.json.default` files with recommended launch and workspace settings for editors that use the `.vscode` directory (e.g., VS Code, Cursor, etc.).
|
||||
|
||||
We've also included a list of recommended extensions in `.vscode/extensions.json`. Your editor should detect this file and show a human friendly list in the Extensions panel, linking each entry to its marketplace page.
|
||||
|
||||
### Recommended MCP Integrations
|
||||
|
||||
#### Playwright Browser Automation
|
||||
|
||||
The Playwright MCP server enables LLM coding assistants (like Copilot, Claude Code, etc.) to control and inspect web browsers programmatically. This allows assistants to navigate websites, take screenshots, and interact with web pages on your behalf.
|
||||
|
||||
For ComfyUI_frontend development, you can ask coding assistants to use Playwright screenshots to continuously verify that your code changes produce the expected visual results.
|
||||
|
||||
##### Setup for Claude Code
|
||||
|
||||
After installing dependencies with `npm i`, the Playwright MCP server will be automatically available when you start Claude Code locally.
|
||||
|
||||
Here's how Claude Code can use the Playwright MCP server to inspect the interface of the local development server (assuming you're running the dev server at `localhost:5173`):
|
||||
|
||||
|
||||
```
|
||||
> navigate to localhost:5173 and take a screenshot.
|
||||
tell me the items in the menubar
|
||||
|
||||
● I'll navigate to localhost:5173 and take a
|
||||
screenshot to see the menubar items.
|
||||
|
||||
● playwright:playwright_navigate (MCP)(url: …
|
||||
"http://local
|
||||
host:5173")
|
||||
⎿ Navigated to http://localhost:5173
|
||||
|
||||
● playwright:playwright_screenshot (MCP)(name: "lo…
|
||||
alhost_5173
|
||||
_menubar")
|
||||
|
||||
⎿ Screenshot saved to: ../../../Downloads/localho
|
||||
st_5173_menubar-2025-05-30T17-23-00-942Z.png
|
||||
⎿ Screenshot also stored in memory with name:
|
||||
'localhost_5173_menubar'
|
||||
|
||||
● Read(../../../Downloads/localhost_5173_menubar-2…
|
||||
25-05-30T17-23-00-942Z.png)
|
||||
⎿ Read image (94.3KB)
|
||||
|
||||
● Based on the screenshot, I can see the menubar at
|
||||
the top of the ComfyUI interface contains the
|
||||
following items:
|
||||
|
||||
Main Menubar Items:
|
||||
- Workflow - Menu for workflow-related actions
|
||||
- Edit - Menu for editing operations
|
||||
- Help - Menu for help and documentation
|
||||
|
||||
Additional UI Elements:
|
||||
- ComfyUI Logo - On the far left
|
||||
- Workflow Tab - Shows "Unsaved Workflow" with a
|
||||
dropdown and close button
|
||||
- Layout Controls - On the far right (grid view
|
||||
and hamburger menu icons)
|
||||
|
||||
The interface shows a typical ComfyUI workflow
|
||||
graph with nodes like "Load Checkpoint", "CLIP
|
||||
Text Encode (Prompt)", "KSampler", and "Empty
|
||||
Latent Image" connected with colored cables.
|
||||
```
|
||||
|
||||
### Unit Test
|
||||
|
||||
- `npm i` to install all dependencies
|
||||
- `npm run test:unit` to execute all unit tests.
|
||||
|
||||
### Component Test
|
||||
|
||||
Component test verifies Vue components in `src/components/`.
|
||||
|
||||
- `npm run test:component` to execute all component tests.
|
||||
|
||||
### Playwright Test
|
||||
|
||||
Playwright test verifies the whole app. See <https://github.com/Comfy-Org/ComfyUI_frontend/blob/main/browser_tests/README.md> for details.
|
||||
|
||||
### litegraph.js
|
||||
|
||||
This repo is using litegraph package hosted on <https://github.com/Comfy-Org/litegraph.js>. Any changes to litegraph should be submitted in that repo instead.
|
||||
|
||||
#### Test litegraph.js changes
|
||||
|
||||
- Run `npm link` in the local litegraph repo.
|
||||
- Run `npm link @comfyorg/litegraph` in this repo.
|
||||
|
||||
This will replace the litegraph package in this repo with the local litegraph repo.
|
||||
For detailed development setup, testing procedures, and technical information, please refer to [CONTRIBUTING.md](CONTRIBUTING.md).
|
||||
|
||||
### i18n
|
||||
|
||||
See [locales/README.md](src/locales/README.md) for details.
|
||||
|
||||
### Storybook
|
||||
|
||||
See [.storybook/README.md](.storybook/README.md) for component development and visual testing documentation.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
For comprehensive troubleshooting and technical support, please refer to our official documentation:
|
||||
|
||||
17
browser_tests/CLAUDE.md
Normal file
17
browser_tests/CLAUDE.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# E2E Testing Guidelines
|
||||
|
||||
## Browser Tests
|
||||
- Test user workflows
|
||||
- Use Playwright fixtures
|
||||
- Follow naming conventions
|
||||
|
||||
## Best Practices
|
||||
- Check assets/ for test data
|
||||
- Prefer specific selectors
|
||||
- Test across viewports
|
||||
|
||||
## Testing Process
|
||||
After code changes:
|
||||
1. Create browser tests as appropriate
|
||||
2. Run tests until passing
|
||||
3. Then run typecheck, lint, format
|
||||
@@ -2,76 +2,133 @@
|
||||
|
||||
This document outlines the setup, usage, and common patterns for Playwright browser tests in the ComfyUI_frontend project.
|
||||
|
||||
## WARNING
|
||||
## Prerequisites
|
||||
|
||||
The browser tests will change the ComfyUI backend state, such as user settings and saved workflows.
|
||||
If `TEST_COMFYUI_DIR` in `.env` isn't set to your `(Comfy Path)/ComfyUI` directory, these changes won't be automatically restored.
|
||||
**CRITICAL**: Start ComfyUI backend with `--multi-user` flag:
|
||||
|
||||
```bash
|
||||
python main.py --multi-user
|
||||
```
|
||||
|
||||
Without this flag, parallel tests will conflict and fail randomly.
|
||||
|
||||
## Setup
|
||||
|
||||
### ComfyUI devtools
|
||||
|
||||
Clone <https://github.com/Comfy-Org/ComfyUI_devtools> to your `custom_nodes` directory.
|
||||
_ComfyUI_devtools adds additional API endpoints and nodes to ComfyUI for browser testing._
|
||||
|
||||
### Node.js & Playwright Prerequisites
|
||||
|
||||
Ensure you have Node.js v20 or v22 installed. Then, set up the Chromium test driver:
|
||||
|
||||
```bash
|
||||
npx playwright install chromium --with-deps
|
||||
```
|
||||
|
||||
### Environment Variables
|
||||
Ensure the environment variables in `.env` are set correctly according to your setup.
|
||||
### Environment Configuration
|
||||
|
||||
The `.env` file will not exist until you create it yourself.
|
||||
Create `.env` from the template:
|
||||
|
||||
A template with helpful information can be found in `.env_example`.
|
||||
```bash
|
||||
cp .env_example .env
|
||||
```
|
||||
|
||||
### Multiple Tests
|
||||
If you are running Playwright tests in parallel or running the same test multiple times, the flag `--multi-user` must be added to the main ComfyUI process.
|
||||
Key settings for debugging:
|
||||
|
||||
```bash
|
||||
# Remove Vue dev overlay that blocks UI elements
|
||||
DISABLE_VUE_PLUGINS=true
|
||||
|
||||
# Test against dev server (recommended) or backend directly
|
||||
PLAYWRIGHT_TEST_URL=http://localhost:5173 # Dev server
|
||||
# PLAYWRIGHT_TEST_URL=http://localhost:8188 # Direct backend
|
||||
|
||||
# Path to ComfyUI for backing up user data/settings before tests
|
||||
TEST_COMFYUI_DIR=/path/to/your/ComfyUI
|
||||
```
|
||||
|
||||
### Common Setup Issues
|
||||
|
||||
**Most tests require the new menu system** - Add to your test:
|
||||
|
||||
```typescript
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
await comfyPage.setSetting('Comfy.UseNewMenu', 'Top')
|
||||
})
|
||||
```
|
||||
|
||||
### Release API Mocking
|
||||
|
||||
By default, all tests mock the release API (`api.comfy.org/releases`) to prevent release notification popups from interfering with test execution. This is necessary because the release notifications can appear over UI elements and block test interactions.
|
||||
|
||||
To test with real release data, you can disable mocking:
|
||||
|
||||
```typescript
|
||||
await comfyPage.setup({ mockReleases: false });
|
||||
await comfyPage.setup({ mockReleases: false })
|
||||
```
|
||||
|
||||
For tests that specifically need to test release functionality, see the example in `tests/releaseNotifications.spec.ts`.
|
||||
|
||||
## Running Tests
|
||||
|
||||
There are multiple ways to run the tests:
|
||||
**Always use UI mode for development:**
|
||||
|
||||
1. **Headless mode with report generation:**
|
||||
```bash
|
||||
npx playwright test
|
||||
```
|
||||
This runs all tests without a visible browser and generates a comprehensive test report.
|
||||
```bash
|
||||
npx playwright test --ui
|
||||
```
|
||||
|
||||
2. **UI mode for interactive testing:**
|
||||
```bash
|
||||
npx playwright test --ui
|
||||
```
|
||||
This opens a user interface where you can select specific tests to run and inspect the test execution timeline.
|
||||
UI mode features:
|
||||
|
||||

|
||||
- **Locator picker**: Click the target icon, then click any element to get the exact locator code to use in your test. The code appears in the _Locator_ tab.
|
||||
- **Step debugging**: Step through your test line-by-line by clicking _Source_ tab
|
||||
- **Time travel**: In the _Actions_ tab/panel, click any step to see the browser state at that moment
|
||||
- **Console/Network Tabs**: View logs and API calls at each step
|
||||
- **Attachments Tab**: View all snapshots with expected and actual images
|
||||
|
||||
3. **Running specific tests:**
|
||||
```bash
|
||||
npx playwright test widget.spec.ts
|
||||
```
|
||||

|
||||
|
||||
For CI or headless testing:
|
||||
|
||||
```bash
|
||||
npx playwright test # Run all tests
|
||||
npx playwright test widget.spec.ts # Run specific test file
|
||||
```
|
||||
|
||||
### Local Development Config
|
||||
|
||||
For debugging, you can try adjusting these settings in `playwright.config.ts`:
|
||||
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
// VERY HELPFUL: Skip screenshot tests locally
|
||||
grep: process.env.CI ? undefined : /^(?!.*screenshot).*$/
|
||||
|
||||
retries: 0, // No retries while debugging. Increase if writing new tests. that may be flaky.
|
||||
workers: 1, // Single worker for easier debugging. Increase to match CPU cores if you want to run a lot of tests in parallel.
|
||||
timeout: 30000, // Longer timeout for breakpoints
|
||||
|
||||
use: {
|
||||
trace: 'on', // Always capture traces (CI uses 'on-first-retry')
|
||||
video: 'on' // Always record video (CI uses 'retain-on-failure')
|
||||
},
|
||||
|
||||
})
|
||||
```
|
||||
|
||||
## Test Structure
|
||||
|
||||
Browser tests in this project follow a specific organization pattern:
|
||||
|
||||
- **Fixtures**: Located in `fixtures/` - These provide test setup and utilities
|
||||
|
||||
- `ComfyPage.ts` - The main fixture for interacting with ComfyUI
|
||||
- `ComfyMouse.ts` - Utility for mouse interactions with the canvas
|
||||
- Components fixtures in `fixtures/components/` - Page object models for UI components
|
||||
|
||||
- **Tests**: Located in `tests/` - The actual test specifications
|
||||
|
||||
- Organized by functionality (e.g., `widget.spec.ts`, `interaction.spec.ts`)
|
||||
- Snapshot directories (e.g., `widget.spec.ts-snapshots/`) contain reference screenshots
|
||||
|
||||
@@ -86,18 +143,18 @@ When writing new tests, follow these patterns:
|
||||
|
||||
```typescript
|
||||
// Import the test fixture
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage';
|
||||
import { comfyPageFixture as test } from '../fixtures/ComfyPage'
|
||||
|
||||
test.describe('Feature Name', () => {
|
||||
// Set up test environment if needed
|
||||
test.beforeEach(async ({ comfyPage }) => {
|
||||
// Common setup
|
||||
});
|
||||
})
|
||||
|
||||
test('should do something specific', async ({ comfyPage }) => {
|
||||
// Test implementation
|
||||
});
|
||||
});
|
||||
})
|
||||
})
|
||||
```
|
||||
|
||||
### Leverage Existing Fixtures and Helpers
|
||||
@@ -119,66 +176,102 @@ Most common testing needs are already addressed by these helpers, which will mak
|
||||
|
||||
1. **Focus elements explicitly**:
|
||||
Canvas-based elements often need explicit focus before interaction:
|
||||
|
||||
```typescript
|
||||
// Click the canvas first to focus it before pressing keys
|
||||
await comfyPage.canvas.click();
|
||||
await comfyPage.page.keyboard.press('a');
|
||||
await comfyPage.canvas.click()
|
||||
await comfyPage.page.keyboard.press('a')
|
||||
```
|
||||
|
||||
2. **Mark canvas as dirty if needed**:
|
||||
Some interactions need explicit canvas updates:
|
||||
|
||||
```typescript
|
||||
// After programmatically changing node state, mark canvas dirty
|
||||
await comfyPage.page.evaluate(() => {
|
||||
window['app'].graph.setDirtyCanvas(true, true);
|
||||
});
|
||||
window['app'].graph.setDirtyCanvas(true, true)
|
||||
})
|
||||
```
|
||||
|
||||
3. **Use node references over coordinates**:
|
||||
3. **Use node references over coordinates**:
|
||||
Node references from `fixtures/utils/litegraphUtils.ts` provide stable ways to interact with nodes:
|
||||
|
||||
```typescript
|
||||
// Prefer this:
|
||||
const node = await comfyPage.getNodeRefsByType('LoadImage')[0];
|
||||
await node.click('title');
|
||||
|
||||
const node = await comfyPage.getNodeRefsByType('LoadImage')[0]
|
||||
await node.click('title')
|
||||
|
||||
// Over this:
|
||||
await comfyPage.canvas.click({ position: { x: 100, y: 100 } });
|
||||
await comfyPage.canvas.click({ position: { x: 100, y: 100 } })
|
||||
```
|
||||
|
||||
4. **Wait for canvas to render after UI interactions**:
|
||||
|
||||
```typescript
|
||||
await comfyPage.nextFrame();
|
||||
await comfyPage.nextFrame()
|
||||
```
|
||||
|
||||
5. **Clean up persistent server state**:
|
||||
While most state is reset between tests, anything stored on the server persists:
|
||||
|
||||
```typescript
|
||||
// Reset settings that affect other tests (these are stored on server)
|
||||
await comfyPage.setSetting('Comfy.ColorPalette', 'dark');
|
||||
await comfyPage.setSetting('Comfy.NodeBadge.NodeIdBadgeMode', 'None');
|
||||
|
||||
await comfyPage.setSetting('Comfy.ColorPalette', 'dark')
|
||||
await comfyPage.setSetting('Comfy.NodeBadge.NodeIdBadgeMode', 'None')
|
||||
|
||||
// Clean up uploaded files if needed
|
||||
await comfyPage.request.delete(`${comfyPage.url}/api/delete/image.png`);
|
||||
await comfyPage.request.delete(`${comfyPage.url}/api/delete/image.png`)
|
||||
```
|
||||
|
||||
6. **Prefer functional assertions over screenshots**:
|
||||
Use screenshots only when visual verification is necessary:
|
||||
|
||||
```typescript
|
||||
// Prefer this:
|
||||
expect(await node.isPinned()).toBe(true);
|
||||
expect(await node.getProperty('title')).toBe('Expected Title');
|
||||
|
||||
expect(await node.isPinned()).toBe(true)
|
||||
expect(await node.getProperty('title')).toBe('Expected Title')
|
||||
|
||||
// Over this - only use when needed:
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('state.png');
|
||||
await expect(comfyPage.canvas).toHaveScreenshot('state.png')
|
||||
```
|
||||
|
||||
7. **Use minimal test workflows**:
|
||||
When creating test workflows, keep them as minimal as possible:
|
||||
|
||||
```typescript
|
||||
// Include only the components needed for the test
|
||||
await comfyPage.loadWorkflow('single_ksampler');
|
||||
await comfyPage.loadWorkflow('single_ksampler')
|
||||
```
|
||||
|
||||
8. **Debug helpers for visual debugging** (remove before committing):
|
||||
|
||||
ComfyPage includes temporary debug methods for troubleshooting:
|
||||
|
||||
```typescript
|
||||
test('debug failing interaction', async ({ comfyPage }, testInfo) => {
|
||||
// Add visual markers to see click positions
|
||||
await comfyPage.debugAddMarker({ x: 100, y: 200 })
|
||||
|
||||
// Attach screenshot with markers to test report
|
||||
await comfyPage.debugAttachScreenshot(testInfo, 'node-positions', {
|
||||
element: 'canvas',
|
||||
markers: [{ position: { x: 100, y: 200 } }]
|
||||
})
|
||||
|
||||
// Show canvas overlay for easier debugging
|
||||
await comfyPage.debugShowCanvasOverlay()
|
||||
|
||||
// Remember to remove debug code before committing!
|
||||
})
|
||||
```
|
||||
|
||||
Available debug methods:
|
||||
|
||||
- `debugAddMarker(position)` - Red circle at position
|
||||
- `debugAttachScreenshot(testInfo, name)` - Attach to test report
|
||||
- `debugShowCanvasOverlay()` - Show canvas as overlay
|
||||
- `debugGetCanvasDataURL()` - Get canvas as base64
|
||||
|
||||
## Common Patterns and Utilities
|
||||
|
||||
### Page Object Pattern
|
||||
@@ -192,7 +285,7 @@ test('Can toggle boolean widget', async ({ comfyPage }) => {
|
||||
const node = (await comfyPage.getFirstNodeRef())!
|
||||
const widget = await node.getWidget(0)
|
||||
await widget.click()
|
||||
});
|
||||
})
|
||||
```
|
||||
|
||||
### Node References
|
||||
@@ -232,8 +325,8 @@ Canvas operations use special helpers to ensure proper timing:
|
||||
```typescript
|
||||
// Using ComfyMouse for drag and drop
|
||||
await comfyMouse.dragAndDrop(
|
||||
{ x: 100, y: 100 }, // From
|
||||
{ x: 200, y: 200 } // To
|
||||
{ x: 100, y: 100 }, // From
|
||||
{ x: 200, y: 200 } // To
|
||||
)
|
||||
|
||||
// Standard ComfyPage helpers
|
||||
@@ -275,21 +368,69 @@ await expect(node).toBeCollapsed()
|
||||
- **Screenshots vary**: Ensure your OS and browser match the reference environment (Linux)
|
||||
- **Async / await**: Race conditions are a very common cause of test flakiness
|
||||
|
||||
## Screenshot Expectations
|
||||
## Screenshot Testing
|
||||
|
||||
Due to variations in system font rendering, screenshot expectations are platform-specific. Please note:
|
||||
|
||||
- **DO NOT commit local screenshot expectations** to the repository
|
||||
- **Do not commit local screenshot expectations** to the repository
|
||||
- We maintain Linux screenshot expectations as our GitHub Action runner operates in a Linux environment
|
||||
- While developing, you can generate local screenshots for your tests, but these will differ from CI-generated ones
|
||||
|
||||
To set new test expectations for PR:
|
||||
### Working with Screenshots Locally
|
||||
|
||||
1. Write your test with screenshot assertions using `toHaveScreenshot(filename)`
|
||||
2. Create a pull request from a `Comfy-Org/ComfyUI_frontend` branch
|
||||
3. Add the `New Browser Test Expectation` tag to your pull request
|
||||
4. The GitHub CI will automatically generate and commit the reference screenshots
|
||||
Option 1 - Skip screenshot tests (add to `playwright.config.ts`):
|
||||
|
||||
This approach ensures consistent screenshot expectations across all PRs and avoids issues with platform-specific rendering.
|
||||
```typescript
|
||||
export default defineConfig({
|
||||
grep: process.env.CI ? undefined : /^(?!.*screenshot).*$/
|
||||
})
|
||||
```
|
||||
|
||||
> **Note:** If you're making a pull request from a forked repository, the GitHub action won't be able to commit updated screenshot expectations directly to your PR branch.
|
||||
Option 2 - Generate local baselines for comparison:
|
||||
|
||||
```bash
|
||||
npx playwright test --update-snapshots
|
||||
```
|
||||
|
||||
### Creating New Screenshot Baselines
|
||||
|
||||
For PRs from `Comfy-Org/ComfyUI_frontend` branches:
|
||||
|
||||
1. Write test with `toHaveScreenshot('filename.png')`
|
||||
2. Create PR and add `New Browser Test Expectation` label
|
||||
3. CI will generate and commit the Linux baseline screenshots
|
||||
|
||||
> **Note:** Fork PRs cannot auto-commit screenshots. A maintainer will need to commit the screenshots manually for you (don't worry, they'll do it).
|
||||
|
||||
## Viewing Test Reports
|
||||
|
||||
### Automated Test Deployment
|
||||
|
||||
The project automatically deploys Playwright test reports to Cloudflare Pages for every PR and push to main branches.
|
||||
|
||||
### Accessing Test Reports
|
||||
|
||||
- **From PR comments**: Click the "View Report" links for each browser
|
||||
- **Direct URLs**: Reports are available at `https://[branch].comfyui-playwright-[browser].pages.dev` (branch-specific deployments)
|
||||
- **From GitHub Actions**: Download artifacts from failed runs
|
||||
|
||||
### How It Works
|
||||
|
||||
1. **Test execution**: All browser tests run in parallel across multiple browsers
|
||||
2. **Report generation**: HTML reports are generated for each browser configuration
|
||||
3. **Cloudflare deployment**: Each browser's report deploys to its own Cloudflare Pages project with branch isolation:
|
||||
- `comfyui-playwright-chromium` (with branch-specific URLs)
|
||||
- `comfyui-playwright-mobile-chrome` (with branch-specific URLs)
|
||||
- `comfyui-playwright-chromium-2x` (2x scale, with branch-specific URLs)
|
||||
- `comfyui-playwright-chromium-0-5x` (0.5x scale, with branch-specific URLs)
|
||||
|
||||
4. **PR comments**: GitHub automatically updates PR comments with:
|
||||
- ✅/❌ Test status for each browser
|
||||
- Direct links to interactive test reports
|
||||
- Real-time progress updates as tests complete
|
||||
|
||||
## Resources
|
||||
|
||||
- [Playwright UI Mode](https://playwright.dev/docs/test-ui-mode) - Interactive test debugging
|
||||
- [Playwright Debugging Guide](https://playwright.dev/docs/debug)
|
||||
- [act](https://github.com/nektos/act) - Run GitHub Actions locally for CI debugging
|
||||
|
||||
182
browser_tests/assets/missing/missing_nodes_in_subgraph.json
Normal file
182
browser_tests/assets/missing/missing_nodes_in_subgraph.json
Normal file
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"id": "test-missing-nodes-in-subgraph",
|
||||
"revision": 0,
|
||||
"last_node_id": 2,
|
||||
"last_link_id": 0,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "KSampler",
|
||||
"pos": [100, 100],
|
||||
"size": [270, 262],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": []
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [0, "randomize", 20, 8, "euler", "simple", 1]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "subgraph-with-missing-node",
|
||||
"pos": [400, 100],
|
||||
"size": [144, 46],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "input1",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output1",
|
||||
"type": "LATENT",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"definitions": {
|
||||
"subgraphs": [
|
||||
{
|
||||
"id": "subgraph-with-missing-node",
|
||||
"version": 1,
|
||||
"state": {
|
||||
"lastGroupId": 0,
|
||||
"lastNodeId": 2,
|
||||
"lastLinkId": 2,
|
||||
"lastRerouteId": 0
|
||||
},
|
||||
"revision": 0,
|
||||
"config": {},
|
||||
"name": "Subgraph with Missing Node",
|
||||
"inputNode": {
|
||||
"id": -10,
|
||||
"bounding": [100, 200, 120, 60]
|
||||
},
|
||||
"outputNode": {
|
||||
"id": -20,
|
||||
"bounding": [500, 200, 120, 60]
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"id": "input1-id",
|
||||
"name": "input1",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [1],
|
||||
"pos": {
|
||||
"0": 150,
|
||||
"1": 220
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "output1-id",
|
||||
"name": "output1",
|
||||
"type": "LATENT",
|
||||
"linkIds": [2],
|
||||
"pos": {
|
||||
"0": 520,
|
||||
"1": 220
|
||||
}
|
||||
}
|
||||
],
|
||||
"widgets": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "MISSING_NODE_TYPE_IN_SUBGRAPH",
|
||||
"pos": [250, 180],
|
||||
"size": [200, 100],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "input",
|
||||
"type": "CONDITIONING",
|
||||
"link": 1
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "output",
|
||||
"type": "LATENT",
|
||||
"links": [2]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "MISSING_NODE_TYPE_IN_SUBGRAPH"
|
||||
},
|
||||
"widgets_values": ["some", "widget", "values"]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
{
|
||||
"id": 1,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 0,
|
||||
"target_id": 1,
|
||||
"target_slot": 0,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"origin_id": 1,
|
||||
"origin_slot": 0,
|
||||
"target_id": -20,
|
||||
"target_slot": 0,
|
||||
"type": "LATENT"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 1,
|
||||
"offset": [0, 0]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,259 @@
|
||||
{
|
||||
"id": "dec788c2-9829-4a5d-a1ee-d6f0a678b42a",
|
||||
"revision": 0,
|
||||
"last_node_id": 9,
|
||||
"last_link_id": 9,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 7,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [413, 389],
|
||||
"size": [425.27801513671875, 180.6060791015625],
|
||||
"flags": {},
|
||||
"order": 3,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 5
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [6]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": ["text, watermark"]
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [415, 186],
|
||||
"size": [422.84503173828125, 164.31304931640625],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 3
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"slot_index": 0,
|
||||
"links": [4]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
"beautiful scenery nature glass bottle landscape, , purple galaxy bottle,"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"type": "EmptyLatentImage",
|
||||
"pos": [473, 609],
|
||||
"size": [315, 106],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [2]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "EmptyLatentImage"
|
||||
},
|
||||
"widgets_values": [512, 512, 1]
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"type": "KSampler",
|
||||
"pos": [863, 186],
|
||||
"size": [315, 262],
|
||||
"flags": {},
|
||||
"order": 4,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 4
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 6
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 2
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"slot_index": 0,
|
||||
"links": [7]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
156680208700286,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"normal",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"type": "VAEDecode",
|
||||
"pos": [1209, 188],
|
||||
"size": [210, 46],
|
||||
"flags": {},
|
||||
"order": 5,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "samples",
|
||||
"type": "LATENT",
|
||||
"link": 7
|
||||
},
|
||||
{
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": 8
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "IMAGE",
|
||||
"type": "IMAGE",
|
||||
"slot_index": 0,
|
||||
"links": [9]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEDecode"
|
||||
},
|
||||
"widgets_values": []
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"type": "SaveImage",
|
||||
"pos": [1451, 189],
|
||||
"size": [210, 58],
|
||||
"flags": {},
|
||||
"order": 6,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "images",
|
||||
"type": "IMAGE",
|
||||
"link": 9
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": ["ComfyUI"]
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"type": "CheckpointLoaderSimple",
|
||||
"pos": [26, 474],
|
||||
"size": [315, 98],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "MODEL",
|
||||
"type": "MODEL",
|
||||
"slot_index": 0,
|
||||
"links": [1]
|
||||
},
|
||||
{
|
||||
"name": "CLIP",
|
||||
"type": "CLIP",
|
||||
"slot_index": 1,
|
||||
"links": [3, 5]
|
||||
},
|
||||
{
|
||||
"name": "VAE",
|
||||
"type": "VAE",
|
||||
"slot_index": 2,
|
||||
"links": [8]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CheckpointLoaderSimple"
|
||||
},
|
||||
"widgets_values": ["v1-5-pruned-emaonly-fp16.safetensors"]
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
[1, 4, 0, 3, 0, "MODEL"],
|
||||
[2, 5, 0, 3, 3, "LATENT"],
|
||||
[3, 4, 1, 6, 0, "CLIP"],
|
||||
[4, 6, 0, 3, 1, "CONDITIONING"],
|
||||
[5, 4, 1, 7, 0, "CLIP"],
|
||||
[6, 7, 0, 3, 2, "CONDITIONING"],
|
||||
[7, 3, 0, 8, 0, "LATENT"],
|
||||
[8, 4, 2, 8, 1, "VAE"],
|
||||
[9, 8, 0, 9, 0, "IMAGE"]
|
||||
],
|
||||
"groups": [],
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"offset": [0, 0],
|
||||
"scale": 1
|
||||
},
|
||||
"reroutes": [
|
||||
{
|
||||
"id": 1,
|
||||
"pos": [372.66668701171875, 415.33331298828125],
|
||||
"linkIds": [3]
|
||||
}
|
||||
],
|
||||
"linkExtensions": [
|
||||
{
|
||||
"id": 3,
|
||||
"parentId": 1
|
||||
}
|
||||
],
|
||||
"frontendVersion": "1.26.1"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
244
browser_tests/assets/subgraphs/basic-subgraph.json
Normal file
244
browser_tests/assets/subgraphs/basic-subgraph.json
Normal file
@@ -0,0 +1,244 @@
|
||||
{
|
||||
"id": "fe4562c0-3a0b-4614-bdec-7039a58d75b8",
|
||||
"revision": 0,
|
||||
"last_node_id": 2,
|
||||
"last_link_id": 0,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 2,
|
||||
"type": "e5fb1765-9323-4548-801a-5aead34d879e",
|
||||
"pos": [
|
||||
627.5973510742188,
|
||||
423.0972900390625
|
||||
],
|
||||
"size": [
|
||||
144.15234375,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"definitions": {
|
||||
"subgraphs": [
|
||||
{
|
||||
"id": "e5fb1765-9323-4548-801a-5aead34d879e",
|
||||
"version": 1,
|
||||
"state": {
|
||||
"lastGroupId": 0,
|
||||
"lastNodeId": 2,
|
||||
"lastLinkId": 4,
|
||||
"lastRerouteId": 0
|
||||
},
|
||||
"revision": 0,
|
||||
"config": {},
|
||||
"name": "New Subgraph",
|
||||
"inputNode": {
|
||||
"id": -10,
|
||||
"bounding": [
|
||||
347.90441582814213,
|
||||
417.3822440655296,
|
||||
120,
|
||||
60
|
||||
]
|
||||
},
|
||||
"outputNode": {
|
||||
"id": -20,
|
||||
"bounding": [
|
||||
892.5973510742188,
|
||||
416.0972900390625,
|
||||
120,
|
||||
60
|
||||
]
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"id": "c5cc99d8-a2b6-4bf3-8be7-d4949ef736cd",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
1
|
||||
],
|
||||
"pos": {
|
||||
"0": 447.9044189453125,
|
||||
"1": 437.3822326660156
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "9bd488b9-e907-4c95-a7a4-85c5597a87af",
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"linkIds": [
|
||||
2
|
||||
],
|
||||
"pos": {
|
||||
"0": 912.5973510742188,
|
||||
"1": 436.0972900390625
|
||||
}
|
||||
}
|
||||
],
|
||||
"widgets": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 1,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
554.8743286132812,
|
||||
100.95539093017578
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
262
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "positive",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 1
|
||||
},
|
||||
{
|
||||
"localized_name": "negative",
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "latent_image",
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "LATENT",
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
2
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"simple",
|
||||
1
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"type": "VAEEncode",
|
||||
"pos": [
|
||||
685.1265869140625,
|
||||
439.1734619140625
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
46
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "pixels",
|
||||
"name": "pixels",
|
||||
"type": "IMAGE",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "vae",
|
||||
"name": "vae",
|
||||
"type": "VAE",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "LATENT",
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": [
|
||||
4
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "VAEEncode"
|
||||
}
|
||||
}
|
||||
],
|
||||
"groups": [],
|
||||
"links": [
|
||||
{
|
||||
"id": 1,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 0,
|
||||
"target_id": 1,
|
||||
"target_slot": 1,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"origin_id": 1,
|
||||
"origin_slot": 0,
|
||||
"target_id": -20,
|
||||
"target_slot": 0,
|
||||
"type": "LATENT"
|
||||
}
|
||||
],
|
||||
"extra": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.8894351682943402,
|
||||
"offset": [
|
||||
58.7671207025881,
|
||||
137.7124650620126
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.24.1"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,412 @@
|
||||
{
|
||||
"id": "c4a254bb-935e-4013-b380-5e36954de4b0",
|
||||
"revision": 0,
|
||||
"last_node_id": 11,
|
||||
"last_link_id": 9,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 11,
|
||||
"type": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"pos": [
|
||||
791.59912109375,
|
||||
386.13336181640625
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
202
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
"",
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"definitions": {
|
||||
"subgraphs": [
|
||||
{
|
||||
"id": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"version": 1,
|
||||
"state": {
|
||||
"lastGroupId": 0,
|
||||
"lastNodeId": 12,
|
||||
"lastLinkId": 16,
|
||||
"lastRerouteId": 0
|
||||
},
|
||||
"revision": 0,
|
||||
"config": {},
|
||||
"name": "New Subgraph",
|
||||
"inputNode": {
|
||||
"id": -10,
|
||||
"bounding": [
|
||||
481.59912109375,
|
||||
379.13336181640625,
|
||||
120,
|
||||
160
|
||||
]
|
||||
},
|
||||
"outputNode": {
|
||||
"id": -20,
|
||||
"bounding": [
|
||||
1121.59912109375,
|
||||
379.13336181640625,
|
||||
128.6640625,
|
||||
60
|
||||
]
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"id": "0f07c10e-5705-4764-9b24-b69606c6dbcc",
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"linkIds": [
|
||||
10
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 399.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "736e5a03-0f7f-4e48-93e4-fd66ea6c30f1",
|
||||
"name": "text_1",
|
||||
"type": "STRING",
|
||||
"linkIds": [
|
||||
11
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 419.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "b62e7a0b-cc7e-4ca5-a4e1-c81607a13f58",
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"linkIds": [
|
||||
13
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 439.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "7a2628da-4879-4f82-a7d3-7b1c00db50a5",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
14
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 459.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "651cf4ad-e8bf-47f6-b181-8f8aeacd6669",
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
15
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 479.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "c41765ea-61ef-4a77-8cc6-74113903078f",
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"linkIds": [
|
||||
16
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 499.13336181640625
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"id": "55dd1505-12bd-4cb4-8e75-031a97bb4387",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
12
|
||||
],
|
||||
"pos": {
|
||||
"0": 1141.59912109375,
|
||||
"1": 399.13336181640625
|
||||
}
|
||||
}
|
||||
],
|
||||
"widgets": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 10,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
661.59912109375,
|
||||
314.13336181640625
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "text",
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
668.755859375,
|
||||
571.7766723632812
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 2,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"localized_name": "text",
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"link": 11
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": [
|
||||
12
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
671.7379760742188,
|
||||
1.621593713760376
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
262
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"localized_name": "positive",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 14
|
||||
},
|
||||
{
|
||||
"localized_name": "negative",
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 15
|
||||
},
|
||||
{
|
||||
"localized_name": "latent_image",
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 16
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "LATENT",
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"simple",
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"groups": [],
|
||||
"links": [
|
||||
{
|
||||
"id": 10,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 0,
|
||||
"target_id": 10,
|
||||
"target_slot": 1,
|
||||
"type": "STRING"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 1,
|
||||
"target_id": 11,
|
||||
"target_slot": 1,
|
||||
"type": "STRING"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"origin_id": 11,
|
||||
"origin_slot": 0,
|
||||
"target_id": -20,
|
||||
"target_slot": 0,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 2,
|
||||
"target_id": 12,
|
||||
"target_slot": 0,
|
||||
"type": "MODEL"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 3,
|
||||
"target_id": 12,
|
||||
"target_slot": 1,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 4,
|
||||
"target_id": 12,
|
||||
"target_slot": 2,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 5,
|
||||
"target_id": 12,
|
||||
"target_slot": 3,
|
||||
"type": "LATENT"
|
||||
}
|
||||
],
|
||||
"extra": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.9581355200690549,
|
||||
"offset": [
|
||||
184.687451089395,
|
||||
80.38288288288285
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.24.1"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
@@ -0,0 +1,341 @@
|
||||
{
|
||||
"id": "c4a254bb-935e-4013-b380-5e36954de4b0",
|
||||
"revision": 0,
|
||||
"last_node_id": 11,
|
||||
"last_link_id": 9,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 11,
|
||||
"type": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"pos": [
|
||||
400,
|
||||
300
|
||||
],
|
||||
"size": [
|
||||
210,
|
||||
168
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": null
|
||||
},
|
||||
{
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"definitions": {
|
||||
"subgraphs": [
|
||||
{
|
||||
"id": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"version": 1,
|
||||
"state": {
|
||||
"lastGroupId": 0,
|
||||
"lastNodeId": 11,
|
||||
"lastLinkId": 15,
|
||||
"lastRerouteId": 0
|
||||
},
|
||||
"revision": 0,
|
||||
"config": {},
|
||||
"name": "New Subgraph",
|
||||
"inputNode": {
|
||||
"id": -10,
|
||||
"bounding": [
|
||||
481.59912109375,
|
||||
379.13336181640625,
|
||||
120,
|
||||
160
|
||||
]
|
||||
},
|
||||
"outputNode": {
|
||||
"id": -20,
|
||||
"bounding": [
|
||||
1121.59912109375,
|
||||
379.13336181640625,
|
||||
120,
|
||||
40
|
||||
]
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"id": "0f07c10e-5705-4764-9b24-b69606c6dbcc",
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"linkIds": [
|
||||
10
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 399.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "214a5060-24dd-4299-ab78-8027dc5b9c59",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"linkIds": [
|
||||
11
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 419.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8ab94c5d-e7df-433c-9177-482a32340552",
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"linkIds": [
|
||||
12
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 439.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "8a4cd719-8c67-473b-9b44-ac0582d02641",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
13
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 459.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "a78d6b3a-ad40-4300-b0a5-2cdbdb8dc135",
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"linkIds": [
|
||||
14
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 479.13336181640625
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "4c7abe0c-902d-49ef-a5b0-cbf02b50b693",
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"linkIds": [
|
||||
15
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 499.13336181640625
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"widgets": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 10,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
661.59912109375,
|
||||
314.13336181640625
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 1,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 11
|
||||
},
|
||||
{
|
||||
"localized_name": "text",
|
||||
"name": "text",
|
||||
"type": "STRING",
|
||||
"widget": {
|
||||
"name": "text"
|
||||
},
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"type": "KSampler",
|
||||
"pos": [
|
||||
674.1234741210938,
|
||||
570.5839233398438
|
||||
],
|
||||
"size": [
|
||||
270,
|
||||
262
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "model",
|
||||
"name": "model",
|
||||
"type": "MODEL",
|
||||
"link": 12
|
||||
},
|
||||
{
|
||||
"localized_name": "positive",
|
||||
"name": "positive",
|
||||
"type": "CONDITIONING",
|
||||
"link": 13
|
||||
},
|
||||
{
|
||||
"localized_name": "negative",
|
||||
"name": "negative",
|
||||
"type": "CONDITIONING",
|
||||
"link": 14
|
||||
},
|
||||
{
|
||||
"localized_name": "latent_image",
|
||||
"name": "latent_image",
|
||||
"type": "LATENT",
|
||||
"link": 15
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "LATENT",
|
||||
"name": "LATENT",
|
||||
"type": "LATENT",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "KSampler"
|
||||
},
|
||||
"widgets_values": [
|
||||
0,
|
||||
"randomize",
|
||||
20,
|
||||
8,
|
||||
"euler",
|
||||
"simple",
|
||||
1
|
||||
]
|
||||
}
|
||||
],
|
||||
"groups": [],
|
||||
"links": [
|
||||
{
|
||||
"id": 10,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 0,
|
||||
"target_id": 10,
|
||||
"target_slot": 1,
|
||||
"type": "STRING"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 1,
|
||||
"target_id": 10,
|
||||
"target_slot": 0,
|
||||
"type": "CLIP"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 2,
|
||||
"target_id": 11,
|
||||
"target_slot": 0,
|
||||
"type": "MODEL"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 3,
|
||||
"target_id": 11,
|
||||
"target_slot": 1,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 4,
|
||||
"target_id": 11,
|
||||
"target_slot": 2,
|
||||
"type": "CONDITIONING"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 5,
|
||||
"target_id": 11,
|
||||
"target_slot": 3,
|
||||
"type": "LATENT"
|
||||
}
|
||||
],
|
||||
"extra": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {},
|
||||
"extra": {
|
||||
"ds": {
|
||||
"scale": 0.9581355200690549,
|
||||
"offset": [
|
||||
258.6405769416877,
|
||||
147.17927927927929
|
||||
]
|
||||
},
|
||||
"frontendVersion": "1.24.1"
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
153
browser_tests/assets/subgraphs/subgraph-with-text-widget.json
Normal file
153
browser_tests/assets/subgraphs/subgraph-with-text-widget.json
Normal file
@@ -0,0 +1,153 @@
|
||||
{
|
||||
"id": "c4a254bb-935e-4013-b380-5e36954de4b0",
|
||||
"revision": 0,
|
||||
"last_node_id": 11,
|
||||
"last_link_id": 9,
|
||||
"nodes": [
|
||||
{
|
||||
"id": 11,
|
||||
"type": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"pos": [
|
||||
791.59912109375,
|
||||
386.13336181640625
|
||||
],
|
||||
"size": [
|
||||
140,
|
||||
26
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": null
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"properties": {},
|
||||
"widgets_values": []
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"groups": [],
|
||||
"definitions": {
|
||||
"subgraphs": [
|
||||
{
|
||||
"id": "422723e8-4bf6-438c-823f-881ca81acead",
|
||||
"version": 1,
|
||||
"state": {
|
||||
"lastGroupId": 0,
|
||||
"lastNodeId": 10,
|
||||
"lastLinkId": 10,
|
||||
"lastRerouteId": 0
|
||||
},
|
||||
"revision": 0,
|
||||
"config": {},
|
||||
"name": "New Subgraph",
|
||||
"inputNode": {
|
||||
"id": -10,
|
||||
"bounding": [
|
||||
481.59912109375,
|
||||
379.13336181640625,
|
||||
120,
|
||||
60
|
||||
]
|
||||
},
|
||||
"outputNode": {
|
||||
"id": -20,
|
||||
"bounding": [
|
||||
1121.59912109375,
|
||||
379.13336181640625,
|
||||
120,
|
||||
40
|
||||
]
|
||||
},
|
||||
"inputs": [
|
||||
{
|
||||
"id": "79e69fca-ad12-499b-8d9b-9f1656b85354",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"linkIds": [
|
||||
10
|
||||
],
|
||||
"pos": {
|
||||
"0": 581.59912109375,
|
||||
"1": 399.13336181640625
|
||||
}
|
||||
}
|
||||
],
|
||||
"outputs": [],
|
||||
"widgets": [],
|
||||
"nodes": [
|
||||
{
|
||||
"id": 10,
|
||||
"type": "CLIPTextEncode",
|
||||
"pos": [
|
||||
661.59912109375,
|
||||
314.13336181640625
|
||||
],
|
||||
"size": [
|
||||
400,
|
||||
200
|
||||
],
|
||||
"flags": {},
|
||||
"order": 0,
|
||||
"mode": 0,
|
||||
"inputs": [
|
||||
{
|
||||
"localized_name": "clip",
|
||||
"name": "clip",
|
||||
"type": "CLIP",
|
||||
"link": 10
|
||||
}
|
||||
],
|
||||
"outputs": [
|
||||
{
|
||||
"localized_name": "CONDITIONING",
|
||||
"name": "CONDITIONING",
|
||||
"type": "CONDITIONING",
|
||||
"links": null
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"Node name for S&R": "CLIPTextEncode"
|
||||
},
|
||||
"widgets_values": [
|
||||
""
|
||||
]
|
||||
}
|
||||
],
|
||||
"groups": [],
|
||||
"links": [
|
||||
{
|
||||
"id": 10,
|
||||
"origin_id": -10,
|
||||
"origin_slot": 0,
|
||||
"target_id": 10,
|
||||
"target_slot": 0,
|
||||
"type": "CLIP"
|
||||
}
|
||||
],
|
||||
"extra": {}
|
||||
}
|
||||
]
|
||||
},
|
||||
"config": {},
|
||||
"extra": {
|
||||
"frontendVersion": "1.24.1",
|
||||
"VHS_latentpreview": false,
|
||||
"VHS_latentpreviewrate": 0,
|
||||
"VHS_MetadataImage": true,
|
||||
"VHS_KeepIntermediate": true,
|
||||
"ds": {
|
||||
"scale": 0.9581355200690549,
|
||||
"offset": [
|
||||
258.6405769416877,
|
||||
147.17927927927929
|
||||
]
|
||||
}
|
||||
},
|
||||
"version": 0.4
|
||||
}
|
||||
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 4.5 KiB |
|
Before Width: | Height: | Size: 260 KiB After Width: | Height: | Size: 260 KiB |
|
Before Width: | Height: | Size: 152 B After Width: | Height: | Size: 152 B |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user