Compare commits
5006 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
794c7b0895 | ||
|
|
85d7d17f8d | ||
|
|
e08dd865b8 | ||
|
|
a2d1c45cb4 | ||
|
|
a0eb9ce5bf | ||
|
|
dbc5d90bda | ||
|
|
e2682b9a45 | ||
|
|
e21dedd9ba | ||
|
|
9ade3ce18e | ||
|
|
e938163cca | ||
|
|
ab18470596 | ||
|
|
cd542d452a | ||
|
|
e9b92254a7 | ||
|
|
7a2d47fbee | ||
|
|
3a575e21e5 | ||
|
|
fb19d721c8 | ||
|
|
ee9c0ff8ba | ||
|
|
88dd98da71 | ||
|
|
57cbd6e121 | ||
|
|
0ec451d274 | ||
|
|
2658d10d3a | ||
|
|
be13e430dc | ||
|
|
3f89ecb03b | ||
|
|
cac55d63d1 | ||
|
|
9643e178dc | ||
|
|
cb63d5b19f | ||
|
|
b674f9a068 | ||
|
|
343dbb7490 | ||
|
|
e95a63befd | ||
|
|
63098d52cb | ||
|
|
a3546ecfa5 | ||
|
|
516700c45f | ||
|
|
661e636f40 | ||
|
|
9615e9d465 | ||
|
|
c49341c740 | ||
|
|
41b4b7d612 | ||
|
|
41ff44ecfc | ||
|
|
aeefe064a4 | ||
|
|
61e60518bd | ||
|
|
66c8d6208c | ||
|
|
21fa9cdf6a | ||
|
|
8642c3a699 | ||
|
|
e0e041dea7 | ||
|
|
c1d0010c4a | ||
|
|
85d7d2a87f | ||
|
|
7f54082cfa | ||
|
|
d6ce0e15bb | ||
|
|
e7dd63887e | ||
|
|
4044a1a309 | ||
|
|
0a538f3274 | ||
|
|
c1beb6d14c | ||
|
|
b6775d0543 | ||
|
|
611fbfc558 | ||
|
|
ba0e0a7b8f | ||
|
|
0b24393480 | ||
|
|
40cd3bea08 | ||
|
|
f1b3f9ac25 | ||
|
|
081f7c6241 | ||
|
|
ab8d0e85d2 | ||
|
|
33ced6aba0 | ||
|
|
27dec9adf8 | ||
|
|
b372f0a7f8 | ||
|
|
b80f3b9995 | ||
|
|
bfd5bd45f1 | ||
|
|
22a581ff5f | ||
|
|
b9c9d9d187 | ||
|
|
3304889e39 | ||
|
|
13a813c703 | ||
|
|
285b82d76e | ||
|
|
5b32269e81 | ||
|
|
11a9f56d5a | ||
|
|
4257a0b809 | ||
|
|
8572b0b5e4 | ||
|
|
d76264b05d | ||
|
|
4a2f1d19a6 | ||
|
|
6fd24be817 | ||
|
|
f9b9248d45 | ||
|
|
7e94cef894 | ||
|
|
d3b2f61b09 | ||
|
|
0aa6e01571 | ||
|
|
f72ebdecd6 | ||
|
|
8b9c901f8c | ||
|
|
bc77387f58 | ||
|
|
b3885c16e3 | ||
|
|
61838ed0dc | ||
|
|
c3c28d6b3b | ||
|
|
bedbdba511 | ||
|
|
2e62e31e0c | ||
|
|
d735d1d4b3 | ||
|
|
744f7133d9 | ||
|
|
7617ab7bfd | ||
|
|
7127d2aca5 | ||
|
|
070e01720d | ||
|
|
ab3caff2d0 | ||
|
|
c8c140a9d6 | ||
|
|
634784840e | ||
|
|
923ee81055 | ||
|
|
24e2773198 | ||
|
|
e087af08b2 | ||
|
|
b3158671ee | ||
|
|
a0e6ece014 | ||
|
|
8a63cf6f63 | ||
|
|
f5e0598738 | ||
|
|
b867e9dd82 | ||
|
|
9d0aa81004 | ||
|
|
ea2dd0819a | ||
|
|
b064ae303f | ||
|
|
3f248973ad | ||
|
|
11f7531346 | ||
|
|
029f319454 | ||
|
|
554a76dd97 | ||
|
|
0d401ccf69 | ||
|
|
b5bdc783bb | ||
|
|
c2dec3ff19 | ||
|
|
20a7422cca | ||
|
|
810c47681d | ||
|
|
cb2e008c75 | ||
|
|
caf769a1cc | ||
|
|
20e12d68da | ||
|
|
3fbd0587ac | ||
|
|
bfd00a53a9 | ||
|
|
6c1b0c380c | ||
|
|
336ad9383e | ||
|
|
6ce7553230 | ||
|
|
a7514171da | ||
|
|
a89e4c67a0 | ||
|
|
53f95b78c6 | ||
|
|
df721618f3 | ||
|
|
870be0ebb8 | ||
|
|
483f718012 | ||
|
|
9f128ba5b7 | ||
|
|
6ed1c9ac6b | ||
|
|
7b5d30bab4 | ||
|
|
1bf173ed19 | ||
|
|
488992b1b2 | ||
|
|
cfeabb11b3 | ||
|
|
73e030549e | ||
|
|
1810916414 | ||
|
|
d77599f4a0 | ||
|
|
eb858b00f6 | ||
|
|
a5dcd7ee42 | ||
|
|
c1f0016bcf | ||
|
|
dd311d8d29 | ||
|
|
e7cc710016 | ||
|
|
3cc8c89ddb | ||
|
|
1cc683cd14 | ||
|
|
8d8f9e57d4 | ||
|
|
c9e0becfc8 | ||
|
|
0915d78f2e | ||
|
|
0081152d42 | ||
|
|
085eedc314 | ||
|
|
bf9023d2ce | ||
|
|
ccdd68d4ff | ||
|
|
25b354fbbe | ||
|
|
6a6fe28645 | ||
|
|
4d2424d326 | ||
|
|
09c9d96313 | ||
|
|
c61c30355f | ||
|
|
f5fa276383 | ||
|
|
9ebf9f577d | ||
|
|
faadfa79a9 | ||
|
|
75e698ea9b | ||
|
|
8650d04715 | ||
|
|
f2641606a6 | ||
|
|
b273218637 | ||
|
|
4b67db0dd8 | ||
|
|
56cadd897a | ||
|
|
9ca4b1098b | ||
|
|
208e32eb00 | ||
|
|
25ee45e4c3 | ||
|
|
6e7d5dabb9 | ||
|
|
63fffa9843 | ||
|
|
d05e5b5d4f | ||
|
|
f53fecc699 | ||
|
|
2c189b3c93 | ||
|
|
c304643b86 | ||
|
|
e0f2398a31 | ||
|
|
bf92d47c2c | ||
|
|
ae8c540013 | ||
|
|
903a535dd6 | ||
|
|
57b5bfc30d | ||
|
|
417c2862e9 | ||
|
|
0bb8070779 | ||
|
|
1f0dc529ce | ||
|
|
2aa4644825 | ||
|
|
41f77fba8c | ||
|
|
6c62424ce4 | ||
|
|
7213e51e3c | ||
|
|
96ece7bbd8 | ||
|
|
8ea319a68f | ||
|
|
97a6be8dc9 | ||
|
|
4fc61d4d44 | ||
|
|
10c7c15894 | ||
|
|
1f914ebadb | ||
|
|
0251b3d8f9 | ||
|
|
3bd28aa269 | ||
|
|
9ff6a864a4 | ||
|
|
3e0512ba59 | ||
|
|
d3f51690ed | ||
|
|
b496da2e50 | ||
|
|
4768eb27a1 | ||
|
|
b8c1e0ec38 | ||
|
|
322697d1e0 | ||
|
|
775797732d | ||
|
|
70f261c79e | ||
|
|
c69fcda6b7 | ||
|
|
fc8ba633c4 | ||
|
|
b2f3de5eff | ||
|
|
25e2981ef7 | ||
|
|
e138ed2e26 | ||
|
|
15d717ec6c | ||
|
|
2967bf400d | ||
|
|
a0ed458050 | ||
|
|
1792df7570 | ||
|
|
296dd33d4d | ||
|
|
3f27c7b789 | ||
|
|
06ecfb52b0 | ||
|
|
1436448b68 | ||
|
|
544c091179 | ||
|
|
7baf3f5ebb | ||
|
|
fb3bc88edb | ||
|
|
6a401a8233 | ||
|
|
97ecc8c871 | ||
|
|
3eaf1b5d18 | ||
|
|
512c40a97b | ||
|
|
9e01f775d5 | ||
|
|
64f41c7173 | ||
|
|
e39a38ab66 | ||
|
|
25aa1b3132 | ||
|
|
575d57efd4 | ||
|
|
8c0ed88dbe | ||
|
|
e08852d817 | ||
|
|
9523b6b392 | ||
|
|
d1d5934cee | ||
|
|
ed499bd9df | ||
|
|
8f8e463a28 | ||
|
|
3b752b0fb5 | ||
|
|
428f0b3517 | ||
|
|
fa419b9892 | ||
|
|
df89609b3e | ||
|
|
a8e858bb15 | ||
|
|
97e9aaf6db | ||
|
|
de56caaba2 | ||
|
|
59c32bc4bb | ||
|
|
2e04c70855 | ||
|
|
34d08bdea9 | ||
|
|
500c848422 | ||
|
|
e686680a81 | ||
|
|
79b9cce118 | ||
|
|
37b925f974 | ||
|
|
3431b3a007 | ||
|
|
cd99cf6079 | ||
|
|
0efb8bc2e2 | ||
|
|
74b5570411 | ||
|
|
79d8c489ae | ||
|
|
34b50346a0 | ||
|
|
3cb81c506c | ||
|
|
9d276403f4 | ||
|
|
bdc5fd50ac | ||
|
|
f512817f02 | ||
|
|
cb771d8c9a | ||
|
|
8dc29681ff | ||
|
|
2a2058f789 | ||
|
|
858d800d6d | ||
|
|
f877dd80da | ||
|
|
935dcd2876 | ||
|
|
a8d38e4d48 | ||
|
|
5893a3d95d | ||
|
|
99d251cbb1 | ||
|
|
102b9605bf | ||
|
|
129d0c26cf | ||
|
|
6957f2c901 | ||
|
|
73fada0560 | ||
|
|
eda11d24b8 | ||
|
|
ecdb8a73bd | ||
|
|
be2e78fe8a | ||
|
|
5d2bc5055e | ||
|
|
bf7ed63282 | ||
|
|
2a36299f1d | ||
|
|
1ee15c55e9 | ||
|
|
89d5eade51 | ||
|
|
595532922e | ||
|
|
84e679c871 | ||
|
|
aea0cc6fd0 | ||
|
|
7ed25d10b4 | ||
|
|
5163d60f67 | ||
|
|
05d96777cb | ||
|
|
a4edff132e | ||
|
|
67de9922b1 | ||
|
|
6c33986659 | ||
|
|
bb678e1987 | ||
|
|
b5c870bdb4 | ||
|
|
2c0899220e | ||
|
|
7f5edf116e | ||
|
|
7737d04fcc | ||
|
|
4d53e43dee | ||
|
|
b39f7d7a31 | ||
|
|
fbd5cb1098 | ||
|
|
fab46b2725 | ||
|
|
16ab46898b | ||
|
|
dd8d968506 | ||
|
|
cb30673e37 | ||
|
|
8e9e853a49 | ||
|
|
4774d6168b | ||
|
|
5dd6e87c42 | ||
|
|
8622b7b88c | ||
|
|
f2b47ebc34 | ||
|
|
0455163a92 | ||
|
|
0aaf1966dd | ||
|
|
f3fd4f20d5 | ||
|
|
fa3d78eb0a | ||
|
|
f50e0957f2 | ||
|
|
5f12a70c41 | ||
|
|
7cb87d7185 | ||
|
|
5439daad78 | ||
|
|
4fde6a2a57 | ||
|
|
e20c5f0eb9 | ||
|
|
28f60f059d | ||
|
|
67c446f8b2 | ||
|
|
20a7b137b6 | ||
|
|
a0ebcc200d | ||
|
|
d8a103495f | ||
|
|
963e82ec03 | ||
|
|
24438c9f3e | ||
|
|
845cefcb67 | ||
|
|
808c84df15 | ||
|
|
55b02def4e | ||
|
|
c60d549184 | ||
|
|
db8851aa9a | ||
|
|
a62daf7c8d | ||
|
|
f6cf255d19 | ||
|
|
abbc0430f8 | ||
|
|
8a21e8291f | ||
|
|
78160ca54b | ||
|
|
99863e6c7c | ||
|
|
312e6a9240 | ||
|
|
bfb6fac112 | ||
|
|
8729f9cdf3 | ||
|
|
fd6e22de75 | ||
|
|
6dd1d4f1e3 | ||
|
|
5fdff36113 | ||
|
|
c65b1aee20 | ||
|
|
938de94638 | ||
|
|
d513667c3f | ||
|
|
59fadaefa7 | ||
|
|
eb67904747 | ||
|
|
a56fd4d430 | ||
|
|
43d9ae3f2b | ||
|
|
795b75c861 | ||
|
|
1b9166bb24 | ||
|
|
50d8596104 | ||
|
|
05f3b9b416 | ||
|
|
3ab76d795f | ||
|
|
e6b7a6d74e | ||
|
|
f91eec298d | ||
|
|
3b2296960d | ||
|
|
b947a41ec3 | ||
|
|
1ba03d358a | ||
|
|
607c5babcb | ||
|
|
d96e9e39a0 | ||
|
|
a979e843df | ||
|
|
dd9911a883 | ||
|
|
8d20dae571 | ||
|
|
298a69758c | ||
|
|
265a8c90b3 | ||
|
|
bb998cce65 | ||
|
|
d4fa0b2b61 | ||
|
|
84f6b9ae52 | ||
|
|
f88a61bd8c | ||
|
|
bfd72acdb7 | ||
|
|
c0017a446a | ||
|
|
2487a3f499 | ||
|
|
ab9fbeae92 | ||
|
|
c8553a953d | ||
|
|
5619ce706f | ||
|
|
79e9b39964 | ||
|
|
41ad71c69f | ||
|
|
f1126f96fc | ||
|
|
7a46faa747 | ||
|
|
fc51371e55 | ||
|
|
9b1023c861 | ||
|
|
4592c40f4e | ||
|
|
567965ed50 | ||
|
|
acd2e28600 | ||
|
|
f2ac96a4c8 | ||
|
|
6a1693dcc6 | ||
|
|
b3b717d183 | ||
|
|
8fdbf36add | ||
|
|
f80a004ef6 | ||
|
|
36b7490f07 | ||
|
|
295d13a421 | ||
|
|
2711f8a613 | ||
|
|
41f7cd80b6 | ||
|
|
9a5267893e | ||
|
|
bd526715ea | ||
|
|
7b5d512e30 | ||
|
|
02d708f961 | ||
|
|
8fa4f9d555 | ||
|
|
8eb157d11d | ||
|
|
6a8971baab | ||
|
|
4953b2a860 | ||
|
|
a8e10a11f5 | ||
|
|
bf050e7301 | ||
|
|
beacb925f4 | ||
|
|
6f32222675 | ||
|
|
e2e5a3c198 | ||
|
|
a989a6bafc | ||
|
|
b8d701a56b | ||
|
|
2574d2f1f7 | ||
|
|
56947b47b8 | ||
|
|
8fe4b398cd | ||
|
|
5a3bff0630 | ||
|
|
27f459fff2 | ||
|
|
f954dac6a3 | ||
|
|
c1eace1d2e | ||
|
|
081e9d9204 | ||
|
|
5b81fd1ae3 | ||
|
|
895d09d04a | ||
|
|
a0f7599aa5 | ||
|
|
003f07b6a2 | ||
|
|
5d04af5d8d | ||
|
|
45422c0cf1 | ||
|
|
d7a27be0f2 | ||
|
|
1546a0bf23 | ||
|
|
9a429e48b2 | ||
|
|
5f4a7b6514 | ||
|
|
22da73bc0a | ||
|
|
f6482d5563 | ||
|
|
1fa8b45542 | ||
|
|
4f9a505e4c | ||
|
|
3c930bc172 | ||
|
|
11120774c3 | ||
|
|
532ac17049 | ||
|
|
891abbef44 | ||
|
|
30af657041 | ||
|
|
5441b3050f | ||
|
|
63e8c3d11f | ||
|
|
b5b7c10e94 | ||
|
|
715e368e80 | ||
|
|
54e4587eb4 | ||
|
|
c2a454ee0d | ||
|
|
7e6a94b163 | ||
|
|
03a8d28289 | ||
|
|
d71eb249ba | ||
|
|
69fb59c899 | ||
|
|
787d9b2dac | ||
|
|
20eb1fd7c1 | ||
|
|
9c709ac2f8 | ||
|
|
c1b8c2c534 | ||
|
|
0db605ef36 | ||
|
|
462f1e30f3 | ||
|
|
a4bed869dd | ||
|
|
b4e97540f3 | ||
|
|
e02179371b | ||
|
|
ec828d9993 | ||
|
|
aed32274ad | ||
|
|
fe2ebaed5b | ||
|
|
34e0e8f41a | ||
|
|
c3ae467da1 | ||
|
|
c74c98e4ff | ||
|
|
ea1a302fb1 | ||
|
|
b32a2f0eac | ||
|
|
729607fb68 | ||
|
|
7e06f188c4 | ||
|
|
f574a2caf6 | ||
|
|
dccc7acc73 | ||
|
|
908c408847 | ||
|
|
c19afe3496 | ||
|
|
a8addfb8b7 | ||
|
|
8dc39e144b | ||
|
|
e19b72965d | ||
|
|
17e9393e96 | ||
|
|
11072dcee3 | ||
|
|
dc31abeedd | ||
|
|
ede91aee21 | ||
|
|
1365b139ba | ||
|
|
972ad7012d | ||
|
|
491573946f | ||
|
|
3f05c90c14 | ||
|
|
2d17b29909 | ||
|
|
8e1c071f14 | ||
|
|
169820f8e7 | ||
|
|
199a43302e | ||
|
|
fd5704d128 | ||
|
|
2c8a7c0e7d | ||
|
|
83c5121b39 | ||
|
|
e4589968d5 | ||
|
|
9da6353a0a | ||
|
|
27650682f8 | ||
|
|
1642385558 | ||
|
|
c53a78e4d7 | ||
|
|
72a3d5623b | ||
|
|
10145f63c0 | ||
|
|
3f66824512 | ||
|
|
7ddc78a7d0 | ||
|
|
0f2ffc0856 | ||
|
|
d09f7abd2d | ||
|
|
8260b84477 | ||
|
|
71d7d1f163 | ||
|
|
3e87c14cb7 | ||
|
|
e37d817b19 | ||
|
|
6d54842fd7 | ||
|
|
e7ac9a0b8c | ||
|
|
9a8adfa445 | ||
|
|
72ad711cab | ||
|
|
4abe45a8e4 | ||
|
|
67df48e170 | ||
|
|
2f8fbf8a3e | ||
|
|
7ef57e5ad7 | ||
|
|
99ae84ade7 | ||
|
|
3f17dded78 | ||
|
|
422c39f6a1 | ||
|
|
c45594a3b5 | ||
|
|
33635792e8 | ||
|
|
016c5eb159 | ||
|
|
b2cbc94357 | ||
|
|
30f6b829a0 | ||
|
|
8dcc83b732 | ||
|
|
3e516d7f9b | ||
|
|
756e7034dc | ||
|
|
58bfe3f4a6 | ||
|
|
27ef110197 | ||
|
|
041502c285 | ||
|
|
24d38e58ca | ||
|
|
2271cc74fd | ||
|
|
7e940791a4 | ||
|
|
b30e808784 | ||
|
|
1fa0e2463b | ||
|
|
dedd99fed0 | ||
|
|
46e6aa621f | ||
|
|
b24d7d686b | ||
|
|
4fc624bf6f | ||
|
|
fe0944c057 | ||
|
|
712b630331 | ||
|
|
e17cb5601c | ||
|
|
bf5a1bd83d | ||
|
|
852e58e62d | ||
|
|
f3c25b4524 | ||
|
|
5e097c4cb5 | ||
|
|
2583ef1f90 | ||
|
|
f71c556db8 | ||
|
|
587d6547bd | ||
|
|
ae78b48f1b | ||
|
|
a91e862358 | ||
|
|
648f1f0c4d | ||
|
|
dd22535ef8 | ||
|
|
beb1de9545 | ||
|
|
0127ca4a5d | ||
|
|
5340d893e1 | ||
|
|
d528569268 | ||
|
|
3ff3c1cbef | ||
|
|
9146da919c | ||
|
|
c037dcf502 | ||
|
|
903abe0b16 | ||
|
|
4d2afa9dbe | ||
|
|
974f01f3b6 | ||
|
|
f7aa34bda1 | ||
|
|
efe0688b29 | ||
|
|
04719048ea | ||
|
|
2e4699b6a6 | ||
|
|
4026cc3a8b | ||
|
|
201f3187ae | ||
|
|
c1a56258e0 | ||
|
|
6bd8b705be | ||
|
|
7d8f3e3e2c | ||
|
|
5db4bb9c83 | ||
|
|
cbd4ceb48b | ||
|
|
d289faead6 | ||
|
|
75f880efca | ||
|
|
5d16951788 | ||
|
|
d763279734 | ||
|
|
f021dcc365 | ||
|
|
88348f3231 | ||
|
|
50f15f6f83 | ||
|
|
8c4914c2eb | ||
|
|
c3c1afa1cd | ||
|
|
999fca4bda | ||
|
|
3c0615ea4a | ||
|
|
38a2289995 | ||
|
|
394a77e611 | ||
|
|
cc0758268e | ||
|
|
e80ee038a8 | ||
|
|
c38af44f77 | ||
|
|
321c3d55ee | ||
|
|
d9a7a6975c | ||
|
|
ed0942d768 | ||
|
|
c06bf4cf65 | ||
|
|
27e738bcc7 | ||
|
|
9e33bdc029 | ||
|
|
b2574a7388 | ||
|
|
102dc88eef | ||
|
|
b75761f044 | ||
|
|
67cd1dc16d | ||
|
|
d51b186dc5 | ||
|
|
d1c2c06e65 | ||
|
|
f452618612 | ||
|
|
027f36d790 | ||
|
|
aaf4d85521 | ||
|
|
4d04820aa9 | ||
|
|
70dc3edb70 | ||
|
|
a29ddb0872 | ||
|
|
03feb833c2 | ||
|
|
36c04bdc1f | ||
|
|
08f175634b | ||
|
|
820f32a875 | ||
|
|
535db2216d | ||
|
|
5d8b42a381 | ||
|
|
83f25c9462 | ||
|
|
d0441a3409 | ||
|
|
2295a1328a | ||
|
|
534a5772a9 | ||
|
|
0975880eba | ||
|
|
c519ec2a1e | ||
|
|
4348e36a75 | ||
|
|
8e7df85e57 | ||
|
|
91d35ff15f | ||
|
|
800f7f5361 | ||
|
|
340cd7a6df | ||
|
|
8e47ca01a2 | ||
|
|
a3cc232da8 | ||
|
|
deb74eaf87 | ||
|
|
e0e3413209 | ||
|
|
4c8aad4ebb | ||
|
|
fdf98c1c21 | ||
|
|
813a717ce9 | ||
|
|
2e3cd38034 | ||
|
|
438a6f03b1 | ||
|
|
563d22a209 | ||
|
|
6947d41101 | ||
|
|
2e1f38f4b4 | ||
|
|
553761a8a7 | ||
|
|
97848b7018 | ||
|
|
e6a4121918 | ||
|
|
13352db959 | ||
|
|
cfaa913877 | ||
|
|
c66928f4f0 | ||
|
|
b16d89862d | ||
|
|
a0741af53c | ||
|
|
30bca0279e | ||
|
|
1f7d82a0bd | ||
|
|
1b31f2ccc9 | ||
|
|
65229b7d29 | ||
|
|
0fbdbc5a86 | ||
|
|
bfc500dfe7 | ||
|
|
86a51d1684 | ||
|
|
0eac87ba25 | ||
|
|
85f08bf062 | ||
|
|
837f6d07fd | ||
|
|
3f16756d35 | ||
|
|
6295521022 | ||
|
|
fb11a89635 | ||
|
|
4a8bdb61af | ||
|
|
292269e4a1 | ||
|
|
253623c263 | ||
|
|
5b3b789726 | ||
|
|
8155afaa4e | ||
|
|
095be4dd83 | ||
|
|
85a0e7f9ce | ||
|
|
1f8978e61e | ||
|
|
aafbd91dc4 | ||
|
|
5e6d05da53 | ||
|
|
0e80f7bc36 | ||
|
|
daea3045d8 | ||
|
|
6b0cd3142b | ||
|
|
fe88c1f418 | ||
|
|
cc1a262757 | ||
|
|
1f6d319959 | ||
|
|
3ab9ce57a4 | ||
|
|
1630b3f4fa | ||
|
|
5692e56287 | ||
|
|
b2c9d541a4 | ||
|
|
2ba939f586 | ||
|
|
538e5224e1 | ||
|
|
b6f660ee26 | ||
|
|
4f7abdc58b | ||
|
|
6d48587320 | ||
|
|
85592330e2 | ||
|
|
e8114d5d3e | ||
|
|
fc5dc103b8 | ||
|
|
9e787d4c31 | ||
|
|
487f4d1c22 | ||
|
|
b6fc94d2e0 | ||
|
|
327315068c | ||
|
|
d26c4cc450 | ||
|
|
465e14530f | ||
|
|
27dbf50d80 | ||
|
|
1198b0e922 | ||
|
|
d5354838e6 | ||
|
|
8d7aabb29e | ||
|
|
55afea6641 | ||
|
|
0aa9b3882c | ||
|
|
b6636c1b33 | ||
|
|
dd198e2246 | ||
|
|
22b15e7cc1 | ||
|
|
34229ac4c3 | ||
|
|
4308f38d53 | ||
|
|
d2c5016988 | ||
|
|
950209e4c7 | ||
|
|
2810cb4f3f | ||
|
|
83a55e6d42 | ||
|
|
4171740a65 | ||
|
|
eb27fb81c9 | ||
|
|
98c998b838 | ||
|
|
feb3dc53cb | ||
|
|
049935b60b | ||
|
|
9d68631a74 | ||
|
|
8b7958bbb6 | ||
|
|
b403afc692 | ||
|
|
383e395535 | ||
|
|
e1bb4efbda | ||
|
|
7cbdd88364 | ||
|
|
02c6d57e76 | ||
|
|
67d0601fef | ||
|
|
a15be81f08 | ||
|
|
b192881de0 | ||
|
|
509d81b012 | ||
|
|
9cfcc1f72a | ||
|
|
6018181a35 | ||
|
|
fbeeb0a5c3 | ||
|
|
7fdcbd70d0 | ||
|
|
aad724d1a8 | ||
|
|
ebf49e189b | ||
|
|
d63a356da5 | ||
|
|
274271f80a | ||
|
|
4c03293c97 | ||
|
|
89afe5614b | ||
|
|
c61bb6df99 | ||
|
|
146bfe33d0 | ||
|
|
313e4620a4 | ||
|
|
0cc6f5d23a | ||
|
|
28a2385104 | ||
|
|
5038dd93a1 | ||
|
|
316a1b6292 | ||
|
|
06fc790387 | ||
|
|
381073c764 | ||
|
|
ae5702abf0 | ||
|
|
0415c75e9d | ||
|
|
2c3a354009 | ||
|
|
28465bb1a6 | ||
|
|
fd6e34b0c4 | ||
|
|
6dd3a6af57 | ||
|
|
78167274b1 | ||
|
|
7f6c42b853 | ||
|
|
fce245316a | ||
|
|
77981e1f01 | ||
|
|
700c48816c | ||
|
|
04ac2c476f | ||
|
|
a48e9e5a49 | ||
|
|
2d124b8f36 | ||
|
|
a16c83a51c | ||
|
|
20f65744a4 | ||
|
|
53284913fa | ||
|
|
865fdb4c9a | ||
|
|
8ba5f214fb | ||
|
|
cd63d475ad | ||
|
|
f3e4d311d3 | ||
|
|
23597cec0a | ||
|
|
641ad86f1d | ||
|
|
d2e7ee7232 | ||
|
|
8b359ac378 | ||
|
|
b2f01d90c9 | ||
|
|
068a41d8e6 | ||
|
|
70051fe5f2 | ||
|
|
af9aa8df76 | ||
|
|
b5592d6f91 | ||
|
|
ea219b8c5b | ||
|
|
df1787a833 | ||
|
|
9417f76547 | ||
|
|
b8b8b85c8b | ||
|
|
39af981753 | ||
|
|
02810a821f | ||
|
|
9c742fc313 | ||
|
|
984e5aa953 | ||
|
|
1264551c8a | ||
|
|
41561b1dc1 | ||
|
|
db2971a5d9 | ||
|
|
134142453c | ||
|
|
29c4dc2f2b | ||
|
|
8e3bbea28b | ||
|
|
fbda167795 | ||
|
|
eb9089a3ec | ||
|
|
cf1c863525 | ||
|
|
49902e915b | ||
|
|
2b83c4bb42 | ||
|
|
0afefdefec | ||
|
|
513bf1c312 | ||
|
|
9fe0925f92 | ||
|
|
b2cd9f35ce | ||
|
|
d9018ff7bb | ||
|
|
2567f75a55 | ||
|
|
c500bc53ee | ||
|
|
7c9dc58791 | ||
|
|
8e5cee8d06 | ||
|
|
c0cca6f238 | ||
|
|
534bc291bc | ||
|
|
b2faee1248 | ||
|
|
36eb9fd89a | ||
|
|
4767ca00e2 | ||
|
|
2e450082be | ||
|
|
755ac8de7a | ||
|
|
8099e23dfb | ||
|
|
deb2c7f921 | ||
|
|
a296498102 | ||
|
|
8828d53fd7 | ||
|
|
1b3ccb41c0 | ||
|
|
eb802e01a6 | ||
|
|
698e6d274a | ||
|
|
d5b65d2910 | ||
|
|
dd7bb45af8 | ||
|
|
aaa6cdf574 | ||
|
|
91163b657a | ||
|
|
be07eb606b | ||
|
|
d03db34406 | ||
|
|
827d865b9b | ||
|
|
8fa03b6478 | ||
|
|
b4cb599c27 | ||
|
|
b939428949 | ||
|
|
afed0f86ea | ||
|
|
fa1430f1a8 | ||
|
|
b57525fabe | ||
|
|
8dd9905606 | ||
|
|
976c195a71 | ||
|
|
cdc1e286a4 | ||
|
|
5dd984e21f | ||
|
|
39f94615c6 | ||
|
|
c5f44440b3 | ||
|
|
737533d3db | ||
|
|
90ca4ef236 | ||
|
|
3fb08b35ab | ||
|
|
13212ec6e5 | ||
|
|
f04e19a001 | ||
|
|
d73f46742a | ||
|
|
5fa9d980f3 | ||
|
|
06e3a4eb4c | ||
|
|
d632f6e95f | ||
|
|
78d83a9f24 | ||
|
|
584a1182c0 | ||
|
|
ddf5acc9ef | ||
|
|
49f14fdd98 | ||
|
|
80fb83a431 | ||
|
|
bd2102ac20 | ||
|
|
ecb0a564fe | ||
|
|
9da4452311 | ||
|
|
5c8eb2603f | ||
|
|
6ea221f67e | ||
|
|
9b77397563 | ||
|
|
5f63b65017 | ||
|
|
1f8b5e583f | ||
|
|
c6bb72ca85 | ||
|
|
00d7bb5c84 | ||
|
|
0f33cfb647 | ||
|
|
5013fb703a | ||
|
|
92fc5a65ee | ||
|
|
3b31cb444b | ||
|
|
fa266c315e | ||
|
|
99d685a27a | ||
|
|
79ebba3319 | ||
|
|
482ebf07cf | ||
|
|
c8fc81655b | ||
|
|
65e0500094 | ||
|
|
0635405c64 | ||
|
|
9475349028 | ||
|
|
c26cf84d15 | ||
|
|
6e444c2129 | ||
|
|
c184868ee4 | ||
|
|
764468333a | ||
|
|
6040ddebd3 | ||
|
|
ffb9cd9ed4 | ||
|
|
a96b6ff8cc | ||
|
|
10e6f73dc3 | ||
|
|
4606250025 | ||
|
|
0b37b43932 | ||
|
|
8f6042d342 | ||
|
|
28eb577ee9 | ||
|
|
dbac204a35 | ||
|
|
be0b6f7e48 | ||
|
|
b108f47c7b | ||
|
|
a28ad43a50 | ||
|
|
1891b404c0 | ||
|
|
18b59372aa | ||
|
|
b18851a0ff | ||
|
|
eb6fcd5229 | ||
|
|
a8ca6f442f | ||
|
|
c81c2dfe19 | ||
|
|
82765be52d | ||
|
|
5666f55117 | ||
|
|
0557912621 | ||
|
|
1cb7861af3 | ||
|
|
1733b75837 | ||
|
|
101fc39e0f | ||
|
|
2cf2cfac45 | ||
|
|
6606eee222 | ||
|
|
2ac1caa944 | ||
|
|
47d5c70d02 | ||
|
|
2cbe4355fc | ||
|
|
c087f6fe10 | ||
|
|
18ca7518c3 | ||
|
|
0939bf8ff7 | ||
|
|
77a0119309 | ||
|
|
5f7a2e671c | ||
|
|
bd22cf47df | ||
|
|
64d4499627 | ||
|
|
4d250f6ee8 | ||
|
|
4951c74712 | ||
|
|
6610c58c7c | ||
|
|
1e16325daa | ||
|
|
8492e6be56 | ||
|
|
43a2cab245 | ||
|
|
c80ce12f93 | ||
|
|
19182c83f3 | ||
|
|
9cb5dceb38 | ||
|
|
f9291a8e1f | ||
|
|
1160f36fe4 | ||
|
|
13ce5b46fe | ||
|
|
5516a4e19a | ||
|
|
216dfb9caa | ||
|
|
186728d584 | ||
|
|
4b70246543 | ||
|
|
f8652ac2ef | ||
|
|
369905d689 | ||
|
|
bbf6c95f42 | ||
|
|
8636289f79 | ||
|
|
c50efca62d | ||
|
|
9c813a8fb6 | ||
|
|
d421ae08f3 | ||
|
|
f0000f429a | ||
|
|
1f0e0ca725 | ||
|
|
7124a5a95b | ||
|
|
1d2d9d6e30 | ||
|
|
2d82b9dde9 | ||
|
|
a8a14f8e32 | ||
|
|
6ad6125546 | ||
|
|
7e89bfa22e | ||
|
|
3f849eba16 | ||
|
|
fb72bb2b96 | ||
|
|
dd4ebe3400 | ||
|
|
a50d82b3c9 | ||
|
|
393433fb45 | ||
|
|
1443a294dc | ||
|
|
bb5e3b0dc2 | ||
|
|
f270a9331d | ||
|
|
16eaa3abc3 | ||
|
|
9fa30934b1 | ||
|
|
5d1faf68ac | ||
|
|
2b2d20e06e | ||
|
|
8fbf5c2b41 | ||
|
|
44cfd1d5cb | ||
|
|
1b26e17dc9 | ||
|
|
e093d73077 | ||
|
|
a82eabfe9d | ||
|
|
06b488221e | ||
|
|
c4b07a935d | ||
|
|
9d7e75c02a | ||
|
|
a5d4c45cda | ||
|
|
c5d09133e5 | ||
|
|
209bda2bac | ||
|
|
4a072f4664 | ||
|
|
3c4b6b84a9 | ||
|
|
4819dfca35 | ||
|
|
076cdc759f | ||
|
|
644ce7926c | ||
|
|
5df20e73df | ||
|
|
8c255460ec | ||
|
|
6d79a4a5b6 | ||
|
|
ece9852a78 | ||
|
|
56d24f0faa | ||
|
|
c9fdd600c1 | ||
|
|
378522e7db | ||
|
|
3622dfe4ac | ||
|
|
483d08c895 | ||
|
|
44571648bf | ||
|
|
4474bfaa41 | ||
|
|
12bc0109d2 | ||
|
|
bdfe683918 | ||
|
|
93397d6e4e | ||
|
|
8fe42b4762 | ||
|
|
fedc622288 | ||
|
|
6f44b64d1f | ||
|
|
b0308c22be | ||
|
|
bea5399cb1 | ||
|
|
b9a6b2091d | ||
|
|
717a967484 | ||
|
|
7a0e3a80bb | ||
|
|
9d1cbecc24 | ||
|
|
01ad287670 | ||
|
|
4b38d0c1f9 | ||
|
|
d2ea0ecd8d | ||
|
|
3f2c19afab | ||
|
|
41f6ba8e42 | ||
|
|
882465c6ea | ||
|
|
6d2c88466f | ||
|
|
b8794be86e | ||
|
|
cce4fc77b5 | ||
|
|
2d99d87fca | ||
|
|
d47ac23c8f | ||
|
|
9fa9b9c910 | ||
|
|
10a910e6ff | ||
|
|
1c3f8d9a0a | ||
|
|
b3eb622e51 | ||
|
|
76d735c02d | ||
|
|
1f7298b38c | ||
|
|
7dc62637fd | ||
|
|
ca5a98257f | ||
|
|
4256969c5c | ||
|
|
2690cab677 | ||
|
|
8ffd2ca107 | ||
|
|
0a7e8b5d74 | ||
|
|
5eacadd4e2 | ||
|
|
072779ada3 | ||
|
|
213e75b06e | ||
|
|
79502dc7cd | ||
|
|
f21335bcb2 | ||
|
|
57a5d5621c | ||
|
|
cd7f1c23ff | ||
|
|
959553e478 | ||
|
|
fd3ece06df | ||
|
|
a37cf0c9d9 | ||
|
|
aaf67c8497 | ||
|
|
14f606aea7 | ||
|
|
3a6c8b357e | ||
|
|
223a7f31e3 | ||
|
|
6dde923bac | ||
|
|
b7e500bcfc | ||
|
|
8645c240c8 | ||
|
|
2e8038f341 | ||
|
|
34e2639a19 | ||
|
|
47277c4794 | ||
|
|
cb6f7dd5e7 | ||
|
|
cf8581b56e | ||
|
|
a2e36cd11b | ||
|
|
1a3a084868 | ||
|
|
acd73e79c9 | ||
|
|
d4af3c8695 | ||
|
|
92258e51e4 | ||
|
|
785e15386b | ||
|
|
8040e1162a | ||
|
|
26c26ea902 | ||
|
|
667181452c | ||
|
|
8e720a9641 | ||
|
|
3a3c310437 | ||
|
|
62c0cec4d2 | ||
|
|
5648ffc225 | ||
|
|
41f87f5279 | ||
|
|
7b27b04677 | ||
|
|
6329101c4c | ||
|
|
6187001eef | ||
|
|
25f6b212e5 | ||
|
|
61ba2d37de | ||
|
|
920fa0d928 | ||
|
|
a3ac0b47ef | ||
|
|
e748d55818 | ||
|
|
9b13a57ad7 | ||
|
|
156f09bf4d | ||
|
|
21bcd8b6b1 | ||
|
|
ae9c61f55a | ||
|
|
c54adb2f8c | ||
|
|
a9d5d68a17 | ||
|
|
1cb03e6a0a | ||
|
|
063172cb2e | ||
|
|
f660cad1bb | ||
|
|
acd1053e48 | ||
|
|
4df56477f0 | ||
|
|
8bf1e7bca8 | ||
|
|
0618c671d8 | ||
|
|
2ed7cf62fb | ||
|
|
81ece4d572 | ||
|
|
ff4fa6e54d | ||
|
|
e7f2bafe49 | ||
|
|
7e5f6766d2 | ||
|
|
18141f4fc4 | ||
|
|
f9f850d250 | ||
|
|
1eaa7c15e6 | ||
|
|
a693a8b33f | ||
|
|
0298b9aaac | ||
|
|
35c777ac49 | ||
|
|
21cfccb16e | ||
|
|
9188bd9770 | ||
|
|
95425fc1f0 | ||
|
|
5b5e04477a | ||
|
|
d876608b0a | ||
|
|
df8386d9b7 | ||
|
|
6bd8ed03fe | ||
|
|
a2ad9a9448 | ||
|
|
2950677756 | ||
|
|
44b8acdab3 | ||
|
|
45af71ad9a | ||
|
|
13c3f2ef4d | ||
|
|
f20e957f4b | ||
|
|
aba29b26b5 | ||
|
|
f106e04c04 | ||
|
|
0b191398e3 | ||
|
|
d216bbd0a3 | ||
|
|
6d0ed2ea83 | ||
|
|
ac8f4b041c | ||
|
|
9f08f171a1 | ||
|
|
356a53b816 | ||
|
|
67a8d95c34 | ||
|
|
7c5c1439df | ||
|
|
8719d7d67c | ||
|
|
a62c796d14 | ||
|
|
ae9b6ae999 | ||
|
|
1c9916bed0 | ||
|
|
691d2f8c00 | ||
|
|
8b4b199f89 | ||
|
|
6292eb9a43 | ||
|
|
499a7aaebb | ||
|
|
8742d4b87e | ||
|
|
200346f101 | ||
|
|
d101e659f4 | ||
|
|
2c66ac9eff | ||
|
|
903ee9fad3 | ||
|
|
ba46e54248 | ||
|
|
1fb6e69345 | ||
|
|
23e8443342 | ||
|
|
d158336851 | ||
|
|
447d8ce540 | ||
|
|
7d6633975c | ||
|
|
2ab9ea47af | ||
|
|
cf04339d30 | ||
|
|
8647b7247e | ||
|
|
1101402b97 | ||
|
|
c4c134b858 | ||
|
|
3101a55d48 | ||
|
|
b55e7474c3 | ||
|
|
57db7d773d | ||
|
|
3ddf53fa24 | ||
|
|
0aefa8a990 | ||
|
|
7c0d464b19 | ||
|
|
048e090978 | ||
|
|
14313d1512 | ||
|
|
0f367d3ee8 | ||
|
|
2032f0e6ce | ||
|
|
c20df2883a | ||
|
|
a8fe77ed04 | ||
|
|
996f3cafd3 | ||
|
|
988c9dff77 | ||
|
|
3b3fda017e | ||
|
|
69be149305 | ||
|
|
da5f35cff8 | ||
|
|
d696354a08 | ||
|
|
8518cdee98 | ||
|
|
2f3ece2b72 | ||
|
|
06334aa8d3 | ||
|
|
c960ec66ee | ||
|
|
ad85f77a19 | ||
|
|
5ac09b533a | ||
|
|
0fe243c076 | ||
|
|
77321ebe91 | ||
|
|
5921597d4a | ||
|
|
57d76f6739 | ||
|
|
bd29aa9f6a | ||
|
|
ab56e09cb7 | ||
|
|
faf3a1e9f6 | ||
|
|
6c16a8e0f5 | ||
|
|
c455caf515 | ||
|
|
312e7cfdd4 | ||
|
|
e753544ddf | ||
|
|
5d45612436 | ||
|
|
988d0eddf1 | ||
|
|
050f952ee2 | ||
|
|
97a4d66caa | ||
|
|
ed255f4de3 | ||
|
|
c0af24a43d | ||
|
|
c742146f82 | ||
|
|
276abf5024 | ||
|
|
38341f6483 | ||
|
|
95f10986d1 | ||
|
|
fe163921c7 | ||
|
|
342b0566f9 | ||
|
|
5dee0bf042 | ||
|
|
3c2b1477cd | ||
|
|
e3b9d8d01a | ||
|
|
cd5e49ef71 | ||
|
|
5f62da6aea | ||
|
|
a1ed7f5623 | ||
|
|
cd06d9a550 | ||
|
|
6c3d8e7bc6 | ||
|
|
2c8c6b7266 | ||
|
|
ed7fe3b884 | ||
|
|
e0f5c81eac | ||
|
|
22059e455f | ||
|
|
460fd2bc24 | ||
|
|
f079593bf0 | ||
|
|
46b11fb618 | ||
|
|
cb7490ccb2 | ||
|
|
e93aaad32b | ||
|
|
e2b5619cc6 | ||
|
|
9160028ef7 | ||
|
|
1140533f1b | ||
|
|
9b8fc7e376 | ||
|
|
8e46d58491 | ||
|
|
4e1150211d | ||
|
|
b01cde3cad | ||
|
|
d4fc6c4ad6 | ||
|
|
e3d4cede79 | ||
|
|
2d34952cd2 | ||
|
|
fc417dc5e8 | ||
|
|
baf2d88e38 | ||
|
|
db85ad6819 | ||
|
|
40a5cfefa1 | ||
|
|
42cdaa80ea | ||
|
|
5ce25aade7 | ||
|
|
171aa2a571 | ||
|
|
47708e7e7e | ||
|
|
5e2aa06b4a | ||
|
|
9c72a5291e | ||
|
|
e3b9e4047f | ||
|
|
6ba980ec49 | ||
|
|
60b4a0975e | ||
|
|
8e94b78133 | ||
|
|
017ddf49f1 | ||
|
|
48cc2068b6 | ||
|
|
3d113d29f2 | ||
|
|
81b85f259f | ||
|
|
5a7bfe0d4e | ||
|
|
379d5a25d3 | ||
|
|
14b39007d3 | ||
|
|
11de600874 | ||
|
|
ae1a25dd2c | ||
|
|
3f4abcd49e | ||
|
|
194913f303 | ||
|
|
f13a64d23e | ||
|
|
d4a22633eb | ||
|
|
c5281a66ad | ||
|
|
559d77c5ba | ||
|
|
e6236388f3 | ||
|
|
f06db95103 | ||
|
|
dbf59f78e6 | ||
|
|
7c1851c150 | ||
|
|
10441bdaca | ||
|
|
3cc3b2307c | ||
|
|
477f850b36 | ||
|
|
1c5ffb9a72 | ||
|
|
b1324999f0 | ||
|
|
de6ed69a32 | ||
|
|
7bbc3129cc | ||
|
|
599f8d11e4 | ||
|
|
cf0306db47 | ||
|
|
839232774e | ||
|
|
8c84d631b1 | ||
|
|
5805af9e15 | ||
|
|
7a0c3f9f86 | ||
|
|
14c1b1a6b0 | ||
|
|
d02c88c6d1 | ||
|
|
7d004beea6 | ||
|
|
9ec4bbe5f5 | ||
|
|
65a813becb | ||
|
|
cadcc36ae6 | ||
|
|
374749adae | ||
|
|
a9dff6c13c | ||
|
|
7b54852a6e | ||
|
|
b3620cc7ec | ||
|
|
42d8f369fd | ||
|
|
6c996e9f71 | ||
|
|
2be0694fe0 | ||
|
|
40330c3a11 | ||
|
|
341591faf2 | ||
|
|
6a95bd30ec | ||
|
|
a801a3985e | ||
|
|
3938ea4dd0 | ||
|
|
fef0c72802 | ||
|
|
3aef20c244 | ||
|
|
812b758c35 | ||
|
|
099c78d6cc | ||
|
|
573ade93dc | ||
|
|
78266f45a6 | ||
|
|
75e4bbebec | ||
|
|
ac44791470 | ||
|
|
a2dc3d34ac | ||
|
|
8741685e2b | ||
|
|
c778f533b2 | ||
|
|
61c90a1ea2 | ||
|
|
5b2800b6a4 | ||
|
|
c0cca4c07a | ||
|
|
1d72408609 | ||
|
|
96e502e472 | ||
|
|
86c3ac52b7 | ||
|
|
86dc72ed4e | ||
|
|
ace1fd7c17 | ||
|
|
4621b799cd | ||
|
|
bfc79662d1 | ||
|
|
4451389e9e | ||
|
|
025927fb48 | ||
|
|
febb8675c5 | ||
|
|
61b9d02a8b | ||
|
|
f17ec115b6 | ||
|
|
3a30e3d4a5 | ||
|
|
d60ec14bcb | ||
|
|
9a8044cf54 | ||
|
|
eae877c1c3 | ||
|
|
492538908a | ||
|
|
b55c34e2fc | ||
|
|
37f174cddd | ||
|
|
bc99a267e3 | ||
|
|
49eb0f257f | ||
|
|
0b248ef283 | ||
|
|
b1b7d01617 | ||
|
|
fd77fbef52 | ||
|
|
2e2b5160f6 | ||
|
|
f11933d6b2 | ||
|
|
37ad6fabe4 | ||
|
|
1f5e8de22a | ||
|
|
c7c06afaee | ||
|
|
3a8de2ce18 | ||
|
|
c8d0d91185 | ||
|
|
ed567fa6fe | ||
|
|
eeddf0e67b | ||
|
|
52fd69bafe | ||
|
|
c45d5108c6 | ||
|
|
c2dbac937a | ||
|
|
ec7d066f21 | ||
|
|
a53162be7d | ||
|
|
240b361744 | ||
|
|
fd1323a48e | ||
|
|
a7696d23fd | ||
|
|
2924283358 | ||
|
|
5651411fd0 | ||
|
|
949ee00cba | ||
|
|
f6024dcdde | ||
|
|
993d0b5595 | ||
|
|
2468a95d17 | ||
|
|
ff65eadf63 | ||
|
|
04b131a993 | ||
|
|
57ecb37f1b | ||
|
|
118f9e254c | ||
|
|
523aab61f9 | ||
|
|
0612bb7685 | ||
|
|
d9dbfafe62 | ||
|
|
b0260a4efb | ||
|
|
e5bff7196a | ||
|
|
0388d09e53 | ||
|
|
236f867b2c | ||
|
|
a81145b72b | ||
|
|
6e9217bad2 | ||
|
|
67ff79c24d | ||
|
|
065026b2b6 | ||
|
|
c1c1940f12 | ||
|
|
15551fd302 | ||
|
|
85edb100f2 | ||
|
|
cbf8324eba | ||
|
|
bae7d65b73 | ||
|
|
aa90218ec8 | ||
|
|
8b68e28ac4 | ||
|
|
47e543629f | ||
|
|
4994e03ef5 | ||
|
|
0a5f73c87e | ||
|
|
fc44803337 | ||
|
|
9704a69797 | ||
|
|
10760560b2 | ||
|
|
ad34fd7656 | ||
|
|
b0000976f6 | ||
|
|
c57f736e71 | ||
|
|
a6226b1562 | ||
|
|
c0fa6b48dd | ||
|
|
5a9c113087 | ||
|
|
e8b65d056f | ||
|
|
37cd9fd7ae | ||
|
|
100ac35cc4 | ||
|
|
049e1c554b | ||
|
|
92a3832d5c | ||
|
|
7373292684 | ||
|
|
8468faf501 | ||
|
|
cbb3536df5 | ||
|
|
eb7d392b8b | ||
|
|
139e3d019c | ||
|
|
8d520703d6 | ||
|
|
1a5a94785d | ||
|
|
859fb683d6 | ||
|
|
723afc0c67 | ||
|
|
2047e83fd4 | ||
|
|
367f2415c5 | ||
|
|
ed871686af | ||
|
|
fd462c8b43 | ||
|
|
8a76b6745f | ||
|
|
d6e89d748d | ||
|
|
bf2a0b16f4 | ||
|
|
eb8d647c64 | ||
|
|
1785703cf4 | ||
|
|
8d07acde61 | ||
|
|
151c0f1bb1 | ||
|
|
425441d169 | ||
|
|
2f8b81bf0b | ||
|
|
0396ab628d | ||
|
|
9d970c5144 | ||
|
|
29ee69f83e | ||
|
|
d7c5c1e32e | ||
|
|
814b4c0f20 | ||
|
|
c90bac04b4 | ||
|
|
2d0552fa91 | ||
|
|
8090f327fb | ||
|
|
5efaf89e4d | ||
|
|
f6947f115d | ||
|
|
000ad30f03 | ||
|
|
9b7b779d08 | ||
|
|
4d394a0414 | ||
|
|
779d4a0662 | ||
|
|
a1cb277151 | ||
|
|
c5c687fa73 | ||
|
|
b9fe65d96f | ||
|
|
83ec1baab7 | ||
|
|
0c6d1ba23b | ||
|
|
5229c333b7 | ||
|
|
8de2ad89c0 | ||
|
|
48c4721488 | ||
|
|
6ce4499536 | ||
|
|
6dc1c63999 | ||
|
|
0ffca6862a | ||
|
|
93c2d17fe1 | ||
|
|
536232e10d | ||
|
|
1f4b36ff60 | ||
|
|
d8942c308f | ||
|
|
630704fb4f | ||
|
|
e2dd43be18 | ||
|
|
0fb37f2742 | ||
|
|
890d9aa903 | ||
|
|
cc2f8c3755 | ||
|
|
b9f6b200c1 | ||
|
|
947f6a5524 | ||
|
|
cf5660595d | ||
|
|
919dea3090 | ||
|
|
cdbb0b29fe | ||
|
|
bf44131e35 | ||
|
|
3a8f31e5eb | ||
|
|
a506b5cf7b | ||
|
|
e582a68b68 | ||
|
|
4a38da39e8 | ||
|
|
016ac63148 | ||
|
|
68812f153b | ||
|
|
f69ad1f383 | ||
|
|
9387e52e27 | ||
|
|
60d7dcf47a | ||
|
|
68f04c3c34 | ||
|
|
f3d660cbb9 | ||
|
|
352b1f45db | ||
|
|
e042c72bb9 | ||
|
|
ec1f86d1cc | ||
|
|
7c3db92544 | ||
|
|
a0b5f39112 | ||
|
|
fc54a0f42a | ||
|
|
146a389a7a | ||
|
|
36a945e603 | ||
|
|
ad8ff52580 | ||
|
|
b0c846c67c | ||
|
|
b572cb56cc | ||
|
|
fd240682c8 | ||
|
|
835e0818f4 | ||
|
|
60efc65b52 | ||
|
|
d1a8b12458 | ||
|
|
39adf83470 | ||
|
|
54060409e8 | ||
|
|
266adf8842 | ||
|
|
a9268b8621 | ||
|
|
c7e1861fc8 | ||
|
|
b60463736f | ||
|
|
ae6039da5b | ||
|
|
b173c84ff3 | ||
|
|
5912022f4b | ||
|
|
0f366341d3 | ||
|
|
9a80854c95 | ||
|
|
a49c7378a9 | ||
|
|
c7ac7db049 | ||
|
|
c49fcd0e5d | ||
|
|
ff634daa7e | ||
|
|
784d7ab53c | ||
|
|
f67c39ea94 | ||
|
|
aa5399df04 | ||
|
|
81928e2117 | ||
|
|
8a936cb486 | ||
|
|
eae44520cc | ||
|
|
64c964002d | ||
|
|
4cec7f83ae | ||
|
|
25940eea86 | ||
|
|
fd5773a10c | ||
|
|
368dc1a3a6 | ||
|
|
7c5a093f47 | ||
|
|
6dd10ca425 | ||
|
|
3c45873ad3 | ||
|
|
dbdec8cd3c | ||
|
|
29f63a1a8d | ||
|
|
e4ff6aaeb1 | ||
|
|
95a231f878 | ||
|
|
5776cbd03d | ||
|
|
bfa81e08d2 | ||
|
|
4b27fc1ce7 | ||
|
|
6c6a4d347e | ||
|
|
21062888d6 | ||
|
|
9256730649 | ||
|
|
2bc4f60643 | ||
|
|
760e6de95f | ||
|
|
a9dfd34d0c | ||
|
|
962546b56a | ||
|
|
b2124c076c | ||
|
|
12dd55f9db | ||
|
|
c0d5b2cfb8 | ||
|
|
ec40d5a3e3 | ||
|
|
4982ef6ce1 | ||
|
|
197e8c5334 | ||
|
|
9bac8ae0c8 | ||
|
|
cee84c8506 | ||
|
|
94862dc3fa | ||
|
|
deed869a88 | ||
|
|
71b664adeb | ||
|
|
8a31a0a1fc | ||
|
|
addaf967e7 | ||
|
|
7f70e4907f | ||
|
|
d799ab2382 | ||
|
|
684bf0d80c | ||
|
|
171f62e07b | ||
|
|
ee540d64ec | ||
|
|
b1250c737f | ||
|
|
f7d0541bf9 | ||
|
|
2c3548b54c | ||
|
|
eba1d2624e | ||
|
|
b59d714f32 | ||
|
|
e8daf87e08 | ||
|
|
cb4d90a1cd | ||
|
|
431e95d450 | ||
|
|
c632c03a4d | ||
|
|
0af8b49ab2 | ||
|
|
0e0d460e2e | ||
|
|
074f3aeaa8 | ||
|
|
bf879318f9 | ||
|
|
ef72e3b071 | ||
|
|
d0f5bec3e0 | ||
|
|
2ed16f1232 | ||
|
|
225aa616de | ||
|
|
264c1f3c78 | ||
|
|
4c44d4aa59 | ||
|
|
e54c9d2c31 | ||
|
|
728cb53ff4 | ||
|
|
c2ba5dfddc | ||
|
|
079327f3d1 | ||
|
|
f1d823a52c | ||
|
|
09b260e263 | ||
|
|
704d887f35 | ||
|
|
1982d5d83a | ||
|
|
e9c5d2fb6b | ||
|
|
ae2d2da2c1 | ||
|
|
0b436c70c3 | ||
|
|
f9668a5407 | ||
|
|
777619925a | ||
|
|
a72f5b37f4 | ||
|
|
c9c4a749a8 | ||
|
|
c996542a0c | ||
|
|
54c32cc5be | ||
|
|
0e58ef12b3 | ||
|
|
8af10567af | ||
|
|
4af5fac05e | ||
|
|
d802e76038 | ||
|
|
e0ddb619fd | ||
|
|
881a0c484f | ||
|
|
b3028961c3 | ||
|
|
a1f305edb4 | ||
|
|
e7c57a1c04 | ||
|
|
33195dcf02 | ||
|
|
b100e025b3 | ||
|
|
8d6a3a92f9 | ||
|
|
b76a759a68 | ||
|
|
c053047814 | ||
|
|
f6842abe93 | ||
|
|
b5385a6b3c | ||
|
|
06f04f757a | ||
|
|
bc7338bee6 | ||
|
|
64139d6fc3 | ||
|
|
8217cc7455 | ||
|
|
daadbb6915 | ||
|
|
c0cb774f73 | ||
|
|
6e3a910555 | ||
|
|
11382aa429 | ||
|
|
8956558d27 | ||
|
|
beab18dc86 | ||
|
|
5fed27537d | ||
|
|
a319b47b8c | ||
|
|
5a47bbd31d | ||
|
|
ab34c77b42 | ||
|
|
5f693fee2f | ||
|
|
5f6e1d7b5c | ||
|
|
fb9df9865e | ||
|
|
777466a744 | ||
|
|
b124594c9c | ||
|
|
215475d080 | ||
|
|
d39d56f67d | ||
|
|
4d34520232 | ||
|
|
2f1bccd869 | ||
|
|
5947ae3f04 | ||
|
|
3b206b9b3e | ||
|
|
8036ccc8f4 | ||
|
|
71956484ff | ||
|
|
8b41331457 | ||
|
|
9702df6d32 | ||
|
|
a9dfa9a1b4 | ||
|
|
5c1a71274d | ||
|
|
df6643fc73 | ||
|
|
f702fa2d14 | ||
|
|
be5a4dbdda | ||
|
|
633c712678 | ||
|
|
9f4cefd92a | ||
|
|
b6c22d78a7 | ||
|
|
d3c0b6d288 | ||
|
|
29f634e48f | ||
|
|
5582e9f326 | ||
|
|
1d2dfcf20f | ||
|
|
f84f9db434 | ||
|
|
a1cecb3f2b | ||
|
|
5ec41b1500 | ||
|
|
8faabcf831 | ||
|
|
09a72dbcc5 | ||
|
|
0b6f2c828f | ||
|
|
d923677bd6 | ||
|
|
0edeaed550 | ||
|
|
29f17bd05b | ||
|
|
68e16f8825 | ||
|
|
5e9ca4413f | ||
|
|
c804633e37 | ||
|
|
e7fea47bef | ||
|
|
0ba8df95ca | ||
|
|
73839ab2e6 | ||
|
|
ffbb3bcf01 | ||
|
|
26eaa73192 | ||
|
|
54cd0b6000 | ||
|
|
8dda232d76 | ||
|
|
834e9fc184 | ||
|
|
be8a417c17 | ||
|
|
7a175e4fab | ||
|
|
75f7b69613 | ||
|
|
bf20db015c | ||
|
|
c142a79d65 | ||
|
|
b909a6f6fc | ||
|
|
bb66ea69f7 | ||
|
|
ae73d2d342 | ||
|
|
55e89be0c6 | ||
|
|
be7eb8f370 | ||
|
|
c2b6dce941 | ||
|
|
e5a94e969d | ||
|
|
850c054797 | ||
|
|
d583d140c7 | ||
|
|
fece6ce14f | ||
|
|
f73ee4158b | ||
|
|
a73870f22e | ||
|
|
49d9da6891 | ||
|
|
168968f1b9 | ||
|
|
c5e062a25f | ||
|
|
8a93324e83 | ||
|
|
af99843189 | ||
|
|
ffbf594d1b | ||
|
|
ba9986905b | ||
|
|
04745e17c8 | ||
|
|
356170dea7 | ||
|
|
54f31c1f0c | ||
|
|
76ccb72d95 | ||
|
|
41fbd69956 | ||
|
|
df9e03bf40 | ||
|
|
98e1f8f3ed | ||
|
|
22ce427855 | ||
|
|
f56b112cec | ||
|
|
1693bdf559 | ||
|
|
05415f77ef | ||
|
|
e0d1031f17 | ||
|
|
18b0aa4a13 | ||
|
|
d2244b4db4 | ||
|
|
2c9329368c | ||
|
|
2ef9e4abd1 | ||
|
|
96c60310f1 | ||
|
|
20602eca52 | ||
|
|
f78dd81ccc | ||
|
|
4eb157bf7e | ||
|
|
5bf232771d | ||
|
|
36ac5a1332 | ||
|
|
57e9742f59 | ||
|
|
e9d973d496 | ||
|
|
703d7f0f2b | ||
|
|
a433538aa3 | ||
|
|
46450cf922 | ||
|
|
298b465d9a | ||
|
|
b1e2bf0e6c | ||
|
|
f756f0fbd2 | ||
|
|
e1093e39e2 | ||
|
|
e55533a2f4 | ||
|
|
a015642c9e | ||
|
|
7b872266f7 | ||
|
|
34d400e8d7 | ||
|
|
912097c157 | ||
|
|
13e63be3ce | ||
|
|
e6aecafb8b | ||
|
|
8d506f283b | ||
|
|
9bb524882d | ||
|
|
2c86d2ebb4 | ||
|
|
283094dcfb | ||
|
|
ec5aa09e54 | ||
|
|
d57e18111d | ||
|
|
8c837b36e4 | ||
|
|
67dd674b69 | ||
|
|
6b3f0f8b39 | ||
|
|
727b3e598d | ||
|
|
46cf803665 | ||
|
|
e7b6858113 | ||
|
|
9f5041bd68 | ||
|
|
ed3b2eab9c | ||
|
|
dd9d512b9b | ||
|
|
16f645dc9d | ||
|
|
bbee7e0e0a | ||
|
|
2b648194e0 | ||
|
|
01f1b2bc6a | ||
|
|
4a9c428f3c | ||
|
|
079f50508a | ||
|
|
0748c3fb4f | ||
|
|
1aef41eba9 | ||
|
|
c673db3ecd | ||
|
|
f0e5d194ee | ||
|
|
43c7dfca05 | ||
|
|
1d9776aa5a | ||
|
|
4acec85d40 | ||
|
|
c7f377367d | ||
|
|
4ad8769a77 | ||
|
|
b7750f8172 | ||
|
|
c29dba481b | ||
|
|
c66181a50d | ||
|
|
c34a5ed7fd | ||
|
|
2282bc310f | ||
|
|
d5ccac5333 | ||
|
|
4cb8e00353 | ||
|
|
c82e2030f2 | ||
|
|
6bd5307664 | ||
|
|
52668e07b7 | ||
|
|
cdfc59df2e | ||
|
|
805c400798 | ||
|
|
50d745c29f | ||
|
|
85df9cbba9 | ||
|
|
29251e84fb | ||
|
|
801394b84b | ||
|
|
8ece98ff2e | ||
|
|
66c925150e | ||
|
|
20f6071b95 | ||
|
|
c543cb1c88 | ||
|
|
aa91da426e | ||
|
|
d3819bc77e | ||
|
|
9869ffa2b5 | ||
|
|
3fd6a01d58 | ||
|
|
2f5ed0760e | ||
|
|
e87dc69716 | ||
|
|
557dc5b914 | ||
|
|
676a44820e | ||
|
|
a896503b68 | ||
|
|
cd3f23df2a | ||
|
|
c3e496ff4a | ||
|
|
d2ee2ea9f2 | ||
|
|
e9203d21fc | ||
|
|
13357c7b77 | ||
|
|
917b3b3ff0 | ||
|
|
5b11590a28 | ||
|
|
8bc7021a6f | ||
|
|
c7752c1100 | ||
|
|
95ad921f49 | ||
|
|
ad73fa05c7 | ||
|
|
8f88be70cb | ||
|
|
32266df424 | ||
|
|
9a5f15d907 | ||
|
|
3ca26f4526 | ||
|
|
25140f102f | ||
|
|
fce59cfbae | ||
|
|
be2df0416a | ||
|
|
3e06d66288 | ||
|
|
cd53d89ef2 | ||
|
|
88c47f4157 | ||
|
|
f4f8b43255 | ||
|
|
20a2ca833e | ||
|
|
6f648f07db | ||
|
|
1bfa382d9d | ||
|
|
3e1a179767 | ||
|
|
d03c8d91ed | ||
|
|
4f1617e9b6 | ||
|
|
623ae16748 | ||
|
|
24d846b00f | ||
|
|
47ca62e0f3 | ||
|
|
8a8e4e4945 | ||
|
|
44dce9e36f | ||
|
|
dc7b7ddebc | ||
|
|
75da8a7880 | ||
|
|
82a81ffe7d | ||
|
|
f18e4c1656 | ||
|
|
ccd8185f59 | ||
|
|
308c6613d8 | ||
|
|
569c26d18b | ||
|
|
bc05cadbc2 | ||
|
|
479850f32e | ||
|
|
b63d026edc | ||
|
|
980666cc8f | ||
|
|
07b72bb47e | ||
|
|
16d0675ee0 | ||
|
|
374e9252f7 | ||
|
|
533cb18d09 | ||
|
|
c0b05f9a34 | ||
|
|
3c44b626ab | ||
|
|
6811819475 | ||
|
|
e17b8f8b85 | ||
|
|
1a24056c04 | ||
|
|
4768111d59 | ||
|
|
ee4d54e5ad | ||
|
|
91c175fcad | ||
|
|
8b2db21839 | ||
|
|
3ef7b18fe6 | ||
|
|
3a8a5d9724 | ||
|
|
670cc182a9 | ||
|
|
188f1664cf | ||
|
|
f0ee9e8caa | ||
|
|
d3c6b6f68a | ||
|
|
3008f9a9c3 | ||
|
|
d0a4631dfd | ||
|
|
03c069c40e | ||
|
|
cae08a7fcd | ||
|
|
649858cf1d | ||
|
|
1fbf122261 | ||
|
|
38e5f06913 | ||
|
|
a6d04d4281 | ||
|
|
1856449815 | ||
|
|
37ab5233a8 | ||
|
|
41d3222eba | ||
|
|
4791dabde7 | ||
|
|
0165d0f1ae | ||
|
|
634247f6db | ||
|
|
c928c45c6b | ||
|
|
bccb862a16 | ||
|
|
7bccf8e3e0 | ||
|
|
de0edefbd7 | ||
|
|
209e87c8b6 | ||
|
|
03e32cf5a2 | ||
|
|
94149406c9 | ||
|
|
767fdef7b9 | ||
|
|
2cc25cdc6a | ||
|
|
8e7ae52bd8 | ||
|
|
207970f51f | ||
|
|
05e6a2ab8f | ||
|
|
7079d22504 | ||
|
|
7591625336 | ||
|
|
ff6f299b6b | ||
|
|
cbf3acdd02 | ||
|
|
16e3cf109b | ||
|
|
a58c2ff9b1 | ||
|
|
6d1b35afa5 | ||
|
|
4a00bcaec9 | ||
|
|
b072a11c3e | ||
|
|
6f3270952d | ||
|
|
ce4c09bf39 | ||
|
|
b6a749f0e9 | ||
|
|
5275aa94ba | ||
|
|
1b3189b83b | ||
|
|
f9e920ce37 | ||
|
|
b761ac266a | ||
|
|
c885e66366 | ||
|
|
c749fb52d7 | ||
|
|
36417e2b81 | ||
|
|
405a0acffe | ||
|
|
9468c830be | ||
|
|
3913f4bbb4 | ||
|
|
9f7407869f | ||
|
|
c41ed00541 | ||
|
|
f2040c931f | ||
|
|
a0249173d2 | ||
|
|
4f8aaa07f9 | ||
|
|
51824e90ff | ||
|
|
3cdad35ae6 | ||
|
|
62027ba60e | ||
|
|
874609f674 | ||
|
|
72d8bae552 | ||
|
|
3b1bfdb02a | ||
|
|
75c3b4845e | ||
|
|
d24e30ec28 | ||
|
|
6d8fd5435e | ||
|
|
1c184f8339 | ||
|
|
d8181027d3 | ||
|
|
5395cf92ee | ||
|
|
5a1a06f6fe | ||
|
|
0932744558 | ||
|
|
934029a094 | ||
|
|
0aab4f694f | ||
|
|
dc40aab97a | ||
|
|
d9c6992a73 | ||
|
|
5ee0d85dfc | ||
|
|
4b970831b3 | ||
|
|
255662d424 | ||
|
|
b7112f939f | ||
|
|
28fc229779 | ||
|
|
6583968b20 | ||
|
|
d25f12e666 | ||
|
|
650275150a | ||
|
|
073b60e81b | ||
|
|
40ba332b1b | ||
|
|
8c61c76b4d | ||
|
|
b8719928da | ||
|
|
2609ba9288 | ||
|
|
81a9f2b1e8 | ||
|
|
4e64064326 | ||
|
|
2eafe03235 | ||
|
|
c291d3be7a | ||
|
|
f2efa32681 | ||
|
|
ea8991cdf5 | ||
|
|
5367cf144d | ||
|
|
589210319f | ||
|
|
0bb2416e03 | ||
|
|
9892332d2d | ||
|
|
dabe8c7915 | ||
|
|
6ba0837025 | ||
|
|
5752a78f40 | ||
|
|
57f854edec | ||
|
|
c41f6eab4d | ||
|
|
a20e0441a7 | ||
|
|
6e14cd51e9 | ||
|
|
aa401ad6ca | ||
|
|
b8955f18b8 | ||
|
|
a9344cde32 | ||
|
|
c23db5d052 | ||
|
|
8581cfdab7 | ||
|
|
a8315dc0f7 | ||
|
|
75f4bcf155 | ||
|
|
54d1941bc8 | ||
|
|
a03dd4894c | ||
|
|
c01896d58c | ||
|
|
d61abef91e | ||
|
|
be33dd85e7 | ||
|
|
83326a2c3d | ||
|
|
48b2a1eb6b | ||
|
|
5dd33bb455 | ||
|
|
b14f28c509 | ||
|
|
8f321e5687 | ||
|
|
aeda7f8532 | ||
|
|
ff16b9dea7 | ||
|
|
67778b4022 | ||
|
|
5a71390b3d | ||
|
|
823a3772fe | ||
|
|
bfdce5a65c | ||
|
|
56ea1c109d | ||
|
|
ae646e71d9 | ||
|
|
210e96452b | ||
|
|
a9cb7597d6 | ||
|
|
d2120fdf62 | ||
|
|
7d9ed7dfe6 | ||
|
|
f770dedb7f | ||
|
|
d541ef0980 | ||
|
|
2e6a271561 | ||
|
|
fa672a3e8b | ||
|
|
208ee525b7 | ||
|
|
8ac14bb462 | ||
|
|
f1a973b1c6 | ||
|
|
a7a974b41e | ||
|
|
5a2646d951 | ||
|
|
9d9570fd71 | ||
|
|
86b5ca7b79 | ||
|
|
616f1ccb09 | ||
|
|
155d4d4932 | ||
|
|
1eaaf2f58e | ||
|
|
de60d726c1 | ||
|
|
00ac7b9c9d | ||
|
|
571373bd0c | ||
|
|
090cceca70 | ||
|
|
a9975abb12 | ||
|
|
b7cd6c1b11 | ||
|
|
d1c76d940d | ||
|
|
6abc29f5f0 | ||
|
|
37e472c377 | ||
|
|
0b24d4481e | ||
|
|
7c631a47d2 | ||
|
|
8a3f31b37a | ||
|
|
e900050d5b | ||
|
|
826cebc1c8 | ||
|
|
b245b67999 | ||
|
|
e8d40fb369 | ||
|
|
b252c68072 | ||
|
|
38ddf58a5f | ||
|
|
003e90d369 | ||
|
|
a59fa105de | ||
|
|
9106b8cf2f | ||
|
|
11c8e281d8 | ||
|
|
d2fd934b5e | ||
|
|
bf1f9307df | ||
|
|
3257a438f6 | ||
|
|
5b539f090d | ||
|
|
08efce2d30 | ||
|
|
2375838424 | ||
|
|
2c718daf3c | ||
|
|
171e92ce23 | ||
|
|
19fd0b1684 | ||
|
|
d477d790d1 | ||
|
|
17c6c35ea9 | ||
|
|
58d2ba2622 | ||
|
|
832ed56213 | ||
|
|
cc6ef6637f | ||
|
|
dfccb2f813 | ||
|
|
3a6798d6b0 | ||
|
|
fd1ff8fffd | ||
|
|
3fac3ab859 | ||
|
|
2b9209a859 | ||
|
|
92165a04a6 | ||
|
|
a269b3d6e9 | ||
|
|
4f9e2a25d5 | ||
|
|
2d152662cf | ||
|
|
aaf1a2973e | ||
|
|
233859cb8d | ||
|
|
12c46e576c | ||
|
|
1e1a345bfa | ||
|
|
47885e1d90 | ||
|
|
89f7b26703 | ||
|
|
b6eabf0d53 | ||
|
|
fcf773d077 | ||
|
|
bc23f61970 | ||
|
|
431795036f | ||
|
|
e56b8fb99c | ||
|
|
0a40369688 | ||
|
|
5ad32a69ad | ||
|
|
c780b3b60f | ||
|
|
e0c04bcc41 | ||
|
|
dff9c1620c | ||
|
|
a460667826 | ||
|
|
e56454ed41 | ||
|
|
ca5cb4677a | ||
|
|
ae19aaf296 | ||
|
|
45710b3af1 | ||
|
|
4b66df45fc | ||
|
|
e1e6975728 | ||
|
|
c1adfa0c5d | ||
|
|
689a0a36e0 | ||
|
|
edacc94a74 | ||
|
|
c72fddfea0 | ||
|
|
aaf6e8c8f0 | ||
|
|
f8c92eaece | ||
|
|
e4f4294601 | ||
|
|
bb3a2f75c5 | ||
|
|
1f19dbd72c | ||
|
|
c4c39d30ec | ||
|
|
1e3dd15269 | ||
|
|
3a76af7b46 | ||
|
|
ae91fde698 | ||
|
|
1a758ac4a2 | ||
|
|
588d5624d2 | ||
|
|
c26e1ba9b8 | ||
|
|
cb184d6301 | ||
|
|
80cccf6864 | ||
|
|
69379c3560 | ||
|
|
9e56ae2e11 | ||
|
|
5c2b2f5e81 | ||
|
|
544798207c | ||
|
|
b76d2571f9 | ||
|
|
4b458035f0 | ||
|
|
6f585e367a | ||
|
|
c3079c9061 | ||
|
|
68e003526c | ||
|
|
9d12326136 | ||
|
|
50c60fa24a | ||
|
|
af453a119c | ||
|
|
fb87a14638 | ||
|
|
ce5bca182c | ||
|
|
42901f018d | ||
|
|
6dc4d8ad97 | ||
|
|
6e4d02b874 | ||
|
|
1716acc427 | ||
|
|
b2ae6d8fc0 | ||
|
|
a483967f00 | ||
|
|
08a4c7746b | ||
|
|
11bfebe13f | ||
|
|
a4ede50fa4 | ||
|
|
bcb483fe57 | ||
|
|
4669332bc9 | ||
|
|
7c3088de2c | ||
|
|
2d583532fd | ||
|
|
761a672e09 | ||
|
|
02cb007537 | ||
|
|
4b11cca96b | ||
|
|
cf22f8331c | ||
|
|
9c2fcc283e | ||
|
|
cf7d0fbb3e | ||
|
|
6c24921eb6 | ||
|
|
491fabdf84 | ||
|
|
e735f1fc4c | ||
|
|
615e5166d0 | ||
|
|
93bba4b570 | ||
|
|
a8f836dbcf | ||
|
|
839654b343 | ||
|
|
06c5b1a48e | ||
|
|
2dfe252029 | ||
|
|
412ada7775 | ||
|
|
89996fe94c | ||
|
|
26a2dca117 | ||
|
|
399bea9c20 | ||
|
|
5b64bbec28 | ||
|
|
4cff3ee8e4 | ||
|
|
d883a09b97 | ||
|
|
d0d9a6ac68 | ||
|
|
573cf539f3 | ||
|
|
550d5a7886 | ||
|
|
82dd647877 | ||
|
|
fef8589dca | ||
|
|
86722702df | ||
|
|
c4d69e16a6 | ||
|
|
fb1fa5d9fa | ||
|
|
8cc10bcd16 | ||
|
|
e72627aa79 | ||
|
|
6b800f6b22 | ||
|
|
e61c82041f | ||
|
|
3b919c4c5a | ||
|
|
4e651fc394 | ||
|
|
690ff31ed4 | ||
|
|
e7f927a895 | ||
|
|
cf36a4b31d | ||
|
|
788f1577b0 | ||
|
|
3196c9c69c | ||
|
|
6ff5d39f0f | ||
|
|
160b4c9f83 | ||
|
|
3990ce5f6f | ||
|
|
d905078245 | ||
|
|
afcd46a4c0 | ||
|
|
99ca799859 | ||
|
|
87fab4d643 | ||
|
|
8beed8cb04 | ||
|
|
ecbc05aed6 | ||
|
|
4fd3c7314a | ||
|
|
0a4de51eb9 | ||
|
|
16abb01689 | ||
|
|
ee572e7b70 | ||
|
|
2f0689bf5f | ||
|
|
7113d05f93 | ||
|
|
b053212cba | ||
|
|
2c12d15ac0 | ||
|
|
e31ff19972 | ||
|
|
fc6a3cef35 | ||
|
|
5e5f0ff488 | ||
|
|
2e23acc137 | ||
|
|
18a93a48c8 | ||
|
|
6bba0c2a56 | ||
|
|
1d108baeff | ||
|
|
06912cd7c1 | ||
|
|
b73cd1ac70 | ||
|
|
85aee81b4f | ||
|
|
b7836e7468 | ||
|
|
43cb0814b1 | ||
|
|
048b62d255 | ||
|
|
703db19eea | ||
|
|
7a570724ee | ||
|
|
158cfe2fff | ||
|
|
7b712e1e87 | ||
|
|
3f08f67d1e | ||
|
|
0693d0c34a | ||
|
|
da3d1099ec | ||
|
|
8b0ddf74f2 | ||
|
|
98214151af | ||
|
|
21b2a3f7c4 | ||
|
|
4dbc5c1722 | ||
|
|
1ace98c4d8 | ||
|
|
d800ae4571 | ||
|
|
a5a04535ec | ||
|
|
b6bf8b6f3d | ||
|
|
d78984ca0d | ||
|
|
e3c7e5935f | ||
|
|
3af0fabc87 | ||
|
|
15b246e31a | ||
|
|
8a3f1c13bb | ||
|
|
22647bbba2 | ||
|
|
5002fde520 | ||
|
|
04126b7100 | ||
|
|
a3b3625435 | ||
|
|
d43588a97e | ||
|
|
9bac2c2c62 | ||
|
|
5b7c2f33df | ||
|
|
6f303717e7 | ||
|
|
a853d8eb60 | ||
|
|
6177b1d3c4 | ||
|
|
77aa6106b5 | ||
|
|
09ea167300 | ||
|
|
9ed433499c | ||
|
|
40c9741396 | ||
|
|
b115e0875e | ||
|
|
6c1065bdd7 | ||
|
|
21bc3aaef1 | ||
|
|
95bfd47f92 | ||
|
|
03fb98df2f | ||
|
|
90a3319825 | ||
|
|
f339ea98fb | ||
|
|
738909db35 | ||
|
|
3f23513ca6 | ||
|
|
345c34a6c6 | ||
|
|
e79107eec0 | ||
|
|
a26feb091d | ||
|
|
67926881e8 | ||
|
|
aca353709f | ||
|
|
3726340b7f | ||
|
|
1425bf6467 | ||
|
|
f562911bc4 | ||
|
|
6e076772c2 | ||
|
|
f69bf283bd | ||
|
|
7bf45926d8 | ||
|
|
995140c666 | ||
|
|
f3882facd6 | ||
|
|
246c0257d7 | ||
|
|
678e1ae4db | ||
|
|
02afcd4c3c | ||
|
|
b2e09375eb | ||
|
|
9aeac5b16c | ||
|
|
97a0265bd8 | ||
|
|
20295eda92 | ||
|
|
fdfdc5d90c | ||
|
|
0687c1a816 | ||
|
|
342ee4a68b | ||
|
|
865bd99df0 | ||
|
|
20b5ee931f | ||
|
|
4870d001d5 | ||
|
|
715c0b02ad | ||
|
|
1458840124 | ||
|
|
75ccfcba58 | ||
|
|
e0c1592b8d | ||
|
|
228d1bfd69 | ||
|
|
635fe6f3ab | ||
|
|
82b6bfac47 | ||
|
|
1cc3671930 | ||
|
|
15985d6106 | ||
|
|
5fc838158c | ||
|
|
0d4ca83f5f | ||
|
|
ad35d8cb1b | ||
|
|
75a3690310 | ||
|
|
375044022a | ||
|
|
daac5f8ccc | ||
|
|
08f3cd3cad | ||
|
|
401dcb85c9 | ||
|
|
16429b781e | ||
|
|
ed1d6fe90b | ||
|
|
5864bb359a | ||
|
|
6be18800ac | ||
|
|
8c4c502576 | ||
|
|
86ca1cc939 | ||
|
|
cf67e5982e | ||
|
|
4b3b431749 | ||
|
|
f7ae670d3e | ||
|
|
06c7cb2e0d | ||
|
|
ce5fd9807d | ||
|
|
beee851fc8 | ||
|
|
97cc8df3a1 | ||
|
|
47e6aa93cf | ||
|
|
0a39dfc819 | ||
|
|
f10a0ead76 | ||
|
|
2f82d784f6 | ||
|
|
445633e1f3 | ||
|
|
a08b365b04 | ||
|
|
16c09008c0 | ||
|
|
ee02d83e83 | ||
|
|
68c56fb564 | ||
|
|
99e167563b | ||
|
|
85b5973a34 | ||
|
|
b0fbd842c2 | ||
|
|
19b847569f | ||
|
|
3a0b8d0b0c | ||
|
|
76ceb80a72 | ||
|
|
0aa2d91512 | ||
|
|
b931fea9f5 | ||
|
|
7e5fdb03dc | ||
|
|
f689beb8e8 | ||
|
|
5b092db083 | ||
|
|
5f2648c93e | ||
|
|
fbffed7ffb | ||
|
|
2aae85be24 | ||
|
|
2f194796c6 | ||
|
|
648535f99b | ||
|
|
886737374a | ||
|
|
555cdb2395 | ||
|
|
59dfde114c | ||
|
|
f5ac2b1cd7 | ||
|
|
8ea79cbb4a | ||
|
|
e4bc729151 | ||
|
|
d51b4e8a38 | ||
|
|
d60ea9c08e | ||
|
|
4979045fb6 | ||
|
|
b0e4b3be64 | ||
|
|
1f82854620 | ||
|
|
6afaab9979 | ||
|
|
5362069adb | ||
|
|
cafc393de5 | ||
|
|
b7a99de099 | ||
|
|
bdbb31cb7a | ||
|
|
ecb6179ff0 | ||
|
|
9cfd0eb596 | ||
|
|
c8bd81b30c | ||
|
|
bb0077d470 | ||
|
|
65a93f7a68 | ||
|
|
c6c820c33e | ||
|
|
9a6ad95e0a | ||
|
|
a5ee07c69e | ||
|
|
5c34099d24 | ||
|
|
738cd35a32 | ||
|
|
a1d16363b9 | ||
|
|
298f899ae9 | ||
|
|
678213f31c | ||
|
|
662b17f748 | ||
|
|
ea9cbe1fd6 | ||
|
|
46d751181a | ||
|
|
f35ae6f596 | ||
|
|
91ed2d6c54 | ||
|
|
7b317571a5 | ||
|
|
32f788270a | ||
|
|
c2c1106503 | ||
|
|
16e51b7ce3 | ||
|
|
f18aa0de9f | ||
|
|
1ad6d8d4f9 | ||
|
|
158e6f5bdf | ||
|
|
85fbda17fa | ||
|
|
e8274e1c6f | ||
|
|
1766b289dd | ||
|
|
23ec306ea9 | ||
|
|
ba7b0b4071 | ||
|
|
e3ffb460d0 | ||
|
|
52ee89f7ba | ||
|
|
f583740541 | ||
|
|
e7ba190fbe | ||
|
|
94637de7ff | ||
|
|
0a0a5d8a96 | ||
|
|
b8c160f22b | ||
|
|
5f682fe8ef | ||
|
|
5220bd7762 | ||
|
|
7fb269ff04 | ||
|
|
a237928bf9 | ||
|
|
0f1abb75a1 | ||
|
|
0112488cdd | ||
|
|
0006e98d44 | ||
|
|
0f056060fc | ||
|
|
ee8b612ca7 | ||
|
|
943e96e176 | ||
|
|
8945580d1d | ||
|
|
1139ae97b9 | ||
|
|
2a062809e3 | ||
|
|
a1c6b46f39 | ||
|
|
025e3956dd | ||
|
|
a2394c2b59 | ||
|
|
e8cb8fc799 | ||
|
|
1eabe5ad50 | ||
|
|
5a0edfe4d7 | ||
|
|
2f5099fbba | ||
|
|
173cd745eb | ||
|
|
a4bf8967c4 | ||
|
|
85824b6908 | ||
|
|
70c621225e | ||
|
|
890dedad69 | ||
|
|
62518c0843 | ||
|
|
44750ec641 | ||
|
|
343809f489 | ||
|
|
9acf110b42 | ||
|
|
5eec882f14 | ||
|
|
fb97216bca | ||
|
|
01437abc7e | ||
|
|
8f7df1627a | ||
|
|
dfd08b6c85 | ||
|
|
5a63a92b5c | ||
|
|
944b9f7b19 | ||
|
|
a9bbcfad00 | ||
|
|
e609efad07 | ||
|
|
f441217c31 | ||
|
|
bcd6c0a3a0 | ||
|
|
4f664db460 | ||
|
|
fd2dc00e21 | ||
|
|
18f3d81410 | ||
|
|
ec934009ad | ||
|
|
bf64aa02ee | ||
|
|
0ae8afb535 | ||
|
|
a33bc988b7 | ||
|
|
e2ccef3334 | ||
|
|
95226cd273 | ||
|
|
99d6710e0b | ||
|
|
c189521c0a | ||
|
|
91eabfa87a | ||
|
|
b6ade86b5b | ||
|
|
fbc2c66d08 | ||
|
|
f7fbcce42e | ||
|
|
90e2a7bd3f | ||
|
|
0928581960 | ||
|
|
334345f73f | ||
|
|
a6a88791f2 | ||
|
|
3e56bcb804 | ||
|
|
93ae4cde40 | ||
|
|
5f03f0d144 | ||
|
|
f6a7c1868f | ||
|
|
bb8ef76156 | ||
|
|
7c80701fe2 | ||
|
|
17fa75759a | ||
|
|
7f07d6bfca | ||
|
|
1bedf1eab6 | ||
|
|
0e0c6dd8ce | ||
|
|
9d467be009 | ||
|
|
d917e42dcb | ||
|
|
d3aeefb327 | ||
|
|
4d87285876 | ||
|
|
42f527b006 | ||
|
|
c75e564391 | ||
|
|
c00ab76168 | ||
|
|
fcd775ba0b | ||
|
|
0ba855e8c1 | ||
|
|
4262a7b8aa | ||
|
|
b107ca3c25 | ||
|
|
f60a6f9fc7 | ||
|
|
ee3f456009 | ||
|
|
0cc334d2de | ||
|
|
69504c0ec4 | ||
|
|
fcea5fd3ae | ||
|
|
0bb463acc2 | ||
|
|
c3ec7929b9 | ||
|
|
b64e56e40c | ||
|
|
1e33702c79 | ||
|
|
15f86f2026 | ||
|
|
3cd5fcbbe5 | ||
|
|
6c588ead84 | ||
|
|
7a8716b465 | ||
|
|
3cf6330845 | ||
|
|
8d59c75e6a | ||
|
|
efe9448944 | ||
|
|
b9b82b48cd | ||
|
|
13e5a14867 | ||
|
|
d2ea5904b5 | ||
|
|
bfa2dcc2a3 | ||
|
|
82d2e495d7 | ||
|
|
abc5058b0b | ||
|
|
65cc377e17 | ||
|
|
1b4fe28b01 | ||
|
|
fa2c98cb0d | ||
|
|
ed91deca37 | ||
|
|
e6f13d4cf3 | ||
|
|
8eb7859a47 | ||
|
|
edc3d29d74 | ||
|
|
07550539ef | ||
|
|
f2ea2e60fc | ||
|
|
5468734b33 | ||
|
|
6ea82815fd | ||
|
|
0872507484 | ||
|
|
c23c23f542 | ||
|
|
4144fb67a2 | ||
|
|
65921275f6 | ||
|
|
a94a3b9244 | ||
|
|
951bd54aae | ||
|
|
bef6f0ce92 | ||
|
|
884e7eab6c | ||
|
|
ec49fa7546 | ||
|
|
fb75199f52 | ||
|
|
123abdce36 | ||
|
|
6c27f5b9d5 | ||
|
|
e609c19d96 | ||
|
|
ec63f41e73 | ||
|
|
1da2f63f16 | ||
|
|
47e3f06e94 | ||
|
|
60584fcd4d | ||
|
|
a096e1b19f | ||
|
|
576432d380 | ||
|
|
c13aabdbdc | ||
|
|
d6be9938ad | ||
|
|
d6d4c4dfe9 | ||
|
|
adb3ee3b0d | ||
|
|
93bc04605e | ||
|
|
29ad7da211 | ||
|
|
ea60812f81 | ||
|
|
69e047f69e | ||
|
|
f9ce80da1d | ||
|
|
bfd4cb6a9b | ||
|
|
2084349da9 | ||
|
|
b7a30c80be | ||
|
|
9e4505a18e | ||
|
|
138825d6b4 | ||
|
|
1ddb560979 | ||
|
|
ae5990e1dc | ||
|
|
6c540b917f | ||
|
|
f4266ebaa0 | ||
|
|
c211f817ae | ||
|
|
d8db4a0e6b | ||
|
|
015a800d90 | ||
|
|
02b1b0473c | ||
|
|
385a88fad3 | ||
|
|
3c4eee38cd | ||
|
|
9c87f0d089 | ||
|
|
d46429165f | ||
|
|
40d72b6af2 | ||
|
|
228fa9ff8d | ||
|
|
fb802a0ea7 | ||
|
|
0541976cea | ||
|
|
f8311a98c7 | ||
|
|
bdda40443c | ||
|
|
8b182a2201 | ||
|
|
03cc38c06f | ||
|
|
164f8e3c91 | ||
|
|
e1024b017a | ||
|
|
4b2c340d84 | ||
|
|
27b8b014ea | ||
|
|
fd94e0bc12 | ||
|
|
d7633c8bca | ||
|
|
d8117201d0 | ||
|
|
816a347d4c | ||
|
|
1b4b0a3739 | ||
|
|
138f1f0b55 | ||
|
|
efb274ecbd | ||
|
|
e9c650f38a | ||
|
|
1ef1171742 | ||
|
|
8e64cf9cca | ||
|
|
df7deec952 | ||
|
|
5e3173ac5a | ||
|
|
d42af58d88 | ||
|
|
8bb50ac347 | ||
|
|
b858fdcf54 | ||
|
|
20615dc619 | ||
|
|
cbd313d18d | ||
|
|
7f8135f1ba | ||
|
|
76915db34a | ||
|
|
29efce94ed | ||
|
|
e9fafea0ac | ||
|
|
fd7751756f | ||
|
|
d04cea4724 | ||
|
|
46f5c903e4 | ||
|
|
f94bafd44f | ||
|
|
afe1a18779 | ||
|
|
1fc57f4325 | ||
|
|
fdc3c610aa | ||
|
|
2eef45125e | ||
|
|
7c62431e4c | ||
|
|
d26d2c90f5 | ||
|
|
e835e58695 | ||
|
|
e3c3967465 | ||
|
|
680053d1a3 | ||
|
|
80052ed221 | ||
|
|
c37250eb06 | ||
|
|
042d496497 | ||
|
|
2c1a9775e1 | ||
|
|
87b3a32814 | ||
|
|
61d4738a84 | ||
|
|
b266ee5072 | ||
|
|
1b9cd0e04f | ||
|
|
8478892383 | ||
|
|
fc5d6fae63 | ||
|
|
ff0c25d49f | ||
|
|
d6274a0e52 | ||
|
|
c47a44096c | ||
|
|
9cebf53ea4 | ||
|
|
46e7f2354e | ||
|
|
97d4737efb | ||
|
|
a6e96c7066 | ||
|
|
0d34ff530b | ||
|
|
e2e6c44097 | ||
|
|
750beb343f | ||
|
|
4c73593c8a | ||
|
|
4c594535a6 | ||
|
|
64f94848ea | ||
|
|
3b5b2ce9c6 | ||
|
|
d00431f51c | ||
|
|
e6c267338c | ||
|
|
85a0644593 | ||
|
|
a91f4867c4 | ||
|
|
420ef47b66 | ||
|
|
cc665c838f | ||
|
|
22901fd402 | ||
|
|
0b95e687f7 | ||
|
|
5a4f152d52 | ||
|
|
f1637135a8 | ||
|
|
4999195a14 | ||
|
|
3d25f4b624 | ||
|
|
df37362516 | ||
|
|
a7135bc17b | ||
|
|
e92963357f | ||
|
|
257c12e79f | ||
|
|
233b935393 | ||
|
|
23571113f6 | ||
|
|
cf0bcb1897 | ||
|
|
6ca100fd15 | ||
|
|
ebf145f432 | ||
|
|
f9240bc248 | ||
|
|
71840b9aa5 | ||
|
|
7fc9a611d0 | ||
|
|
69c8626f80 | ||
|
|
b3b6ac9a04 | ||
|
|
b219aefb20 | ||
|
|
d150c290fb | ||
|
|
81810afdf8 | ||
|
|
783ee55658 | ||
|
|
d2dbddd5a4 | ||
|
|
e4ee29f95e | ||
|
|
0da0b73dc8 | ||
|
|
064110d940 | ||
|
|
a76ff09d6e | ||
|
|
348884a912 | ||
|
|
07ef28dbca | ||
|
|
a3116603c7 | ||
|
|
1ce95fcab5 | ||
|
|
b625a95e22 | ||
|
|
b45a658b01 | ||
|
|
0376a3626d | ||
|
|
ce4c738898 | ||
|
|
fd4d53b35e | ||
|
|
de9754904a | ||
|
|
7cc1b46903 | ||
|
|
70d6fb4e15 | ||
|
|
174377e0fe | ||
|
|
fb78980e56 | ||
|
|
fd5276eb0b | ||
|
|
a56f24a75d | ||
|
|
51d3af5dd2 | ||
|
|
43038be819 | ||
|
|
a4f7a0013e | ||
|
|
3396306457 | ||
|
|
989f9cd9e6 | ||
|
|
5e1bb213c1 | ||
|
|
33785829c1 | ||
|
|
82d3751f80 | ||
|
|
c3d7d3baae | ||
|
|
e87f82cf21 | ||
|
|
9c6d8be648 | ||
|
|
c3d7ba0255 | ||
|
|
614d2855ea | ||
|
|
a94013e8d6 | ||
|
|
7d2cfdf401 | ||
|
|
acd43e2657 | ||
|
|
c8193ed6bc | ||
|
|
78812bb9c4 | ||
|
|
b1be315b12 | ||
|
|
2dc26b378d | ||
|
|
27d685e77c | ||
|
|
710f567c40 | ||
|
|
29ca9701c2 | ||
|
|
09552d7e90 | ||
|
|
3f8107db49 | ||
|
|
73332cd4f0 | ||
|
|
2445eacac5 | ||
|
|
15f5d969c4 | ||
|
|
32dc6ef93d | ||
|
|
402dd042ae | ||
|
|
012b6b91ea | ||
|
|
a7596090c4 | ||
|
|
c1a1939ade | ||
|
|
73604e7f11 | ||
|
|
a7cba78972 | ||
|
|
30f2a99592 | ||
|
|
53a93d3e54 | ||
|
|
b30c71462c | ||
|
|
dfc69c1d41 | ||
|
|
84b9d42799 | ||
|
|
c96b00db75 | ||
|
|
21115455b0 | ||
|
|
d00e2b6dbf | ||
|
|
3431805b73 | ||
|
|
2f787394b0 | ||
|
|
e4372f72cf | ||
|
|
aa70598d7a | ||
|
|
2c4ec37fb1 | ||
|
|
bea7b1bb98 | ||
|
|
e17fda5e2a | ||
|
|
f34377d8a9 | ||
|
|
af281d4277 | ||
|
|
1888f24f46 | ||
|
|
e29792803b | ||
|
|
774b9073a1 | ||
|
|
41fd854f2d | ||
|
|
78282416d1 | ||
|
|
3da40a1fed | ||
|
|
c968fdf0f3 | ||
|
|
52c01e93e9 | ||
|
|
4b7a065bae | ||
|
|
7932b40420 | ||
|
|
66b50e3799 | ||
|
|
71780d5e04 | ||
|
|
45bf04d592 | ||
|
|
6f161fd717 | ||
|
|
0ca91888d2 | ||
|
|
c18eb9f361 | ||
|
|
f9b2b423af | ||
|
|
57d00bb726 | ||
|
|
e60cedd170 | ||
|
|
1dbec24253 | ||
|
|
dc1bb0596a | ||
|
|
cc9a1638f6 | ||
|
|
9447c8ccd4 | ||
|
|
a37ca84c28 | ||
|
|
8ff1ffa54e | ||
|
|
b3204cc1c4 | ||
|
|
447fa003ff | ||
|
|
6a8407aca8 | ||
|
|
c4a00bc6df | ||
|
|
0a728d17cb | ||
|
|
c8e01f42cd | ||
|
|
0e8f6c1070 | ||
|
|
7d760c3a57 | ||
|
|
8ae3d1ef97 | ||
|
|
696e267623 | ||
|
|
3ea717978a | ||
|
|
e3b0469908 | ||
|
|
bddb574f5f | ||
|
|
b969659b97 | ||
|
|
8b765ba34d | ||
|
|
6944796c8e | ||
|
|
04d289bb95 | ||
|
|
c34dfc18ac | ||
|
|
c319c21579 | ||
|
|
f237f3bc3a | ||
|
|
6a48ea4cca | ||
|
|
da67591173 | ||
|
|
b784ea807f | ||
|
|
6463e7b0cb | ||
|
|
cc1ec875e3 | ||
|
|
6d6d3498cf | ||
|
|
30cd25eead | ||
|
|
53fe99dc8a | ||
|
|
321af210c2 | ||
|
|
f700832f00 | ||
|
|
c657b1c901 | ||
|
|
07ea05aa37 | ||
|
|
67a753e5fb | ||
|
|
af46f0b818 | ||
|
|
8f2baba838 | ||
|
|
41578afca1 | ||
|
|
b3fa7241d7 | ||
|
|
9eb3902f63 | ||
|
|
485a457e04 | ||
|
|
c696a595dd | ||
|
|
f4339b51e1 | ||
|
|
5d55c08e36 | ||
|
|
accef0aeb6 | ||
|
|
73b4ecc351 | ||
|
|
f4b7224aaa | ||
|
|
a682ace80a | ||
|
|
8de148249b | ||
|
|
0bb4ced6ae | ||
|
|
b22ec72400 | ||
|
|
b8be41911f | ||
|
|
a361a60429 | ||
|
|
e11ebf6af8 | ||
|
|
6c9d66e06b | ||
|
|
f4ce0caac6 | ||
|
|
62f0356506 | ||
|
|
d692dd8952 | ||
|
|
b59b678555 | ||
|
|
047c826a91 | ||
|
|
4ea2a59865 | ||
|
|
1caa02ef69 | ||
|
|
8637599c13 | ||
|
|
9858c5384c | ||
|
|
44877bd0e8 | ||
|
|
57dc8d23ba | ||
|
|
f782a96c3c | ||
|
|
fdb6c4fd42 | ||
|
|
c7753beb44 | ||
|
|
1a01f4adf6 | ||
|
|
ff502ebdee | ||
|
|
bf8e7de854 | ||
|
|
b389b80436 | ||
|
|
59f93c3c9c | ||
|
|
d54d1bc888 | ||
|
|
3b85a3b269 | ||
|
|
61b3ab2e4a | ||
|
|
5182126876 | ||
|
|
15e530c007 | ||
|
|
ca8b551696 | ||
|
|
3e1e20e827 | ||
|
|
2c3e8dbcb2 | ||
|
|
1515970c39 | ||
|
|
1ce75aa717 | ||
|
|
6bd424ff83 | ||
|
|
9602681745 | ||
|
|
b5ff021b86 | ||
|
|
79943278e9 | ||
|
|
43038ecd99 | ||
|
|
96faca2b87 | ||
|
|
b652cb9c65 | ||
|
|
8127421856 | ||
|
|
dc731d26f2 | ||
|
|
52f9e2db96 | ||
|
|
9368a5a2d2 | ||
|
|
928652344d | ||
|
|
d82bf598dc | ||
|
|
cf0e6acc80 | ||
|
|
813841f2b2 | ||
|
|
c8ab762d89 | ||
|
|
e5f9eebb51 | ||
|
|
03fe225df7 | ||
|
|
48b7dd3aa0 | ||
|
|
90c365a26c | ||
|
|
f2f195e855 | ||
|
|
ec42c8fcff | ||
|
|
d8228382b0 | ||
|
|
114fcfecc9 | ||
|
|
3fe45bcf7e | ||
|
|
b8a4803824 | ||
|
|
0858dbdc03 | ||
|
|
ec82ee91a9 | ||
|
|
4e1e261a51 | ||
|
|
5d8a7ba05c | ||
|
|
4004daf191 | ||
|
|
0b05a7c021 | ||
|
|
d23fb1287c | ||
|
|
a5d9530c41 | ||
|
|
89a180a876 | ||
|
|
819c28a805 | ||
|
|
7a18b330ca | ||
|
|
8d1101c7eb | ||
|
|
de070ed4ef | ||
|
|
1ca388de7b | ||
|
|
f69de39a09 | ||
|
|
77a88bacd7 | ||
|
|
78d42bd505 | ||
|
|
0789b95561 | ||
|
|
4b191edbc1 | ||
|
|
4532c42f64 | ||
|
|
c025d431e4 | ||
|
|
e858a3dc05 | ||
|
|
0a80fb6850 | ||
|
|
20ea608045 | ||
|
|
c395c8b67a | ||
|
|
ae97eafff5 | ||
|
|
cae4d382ec | ||
|
|
5853587bbb | ||
|
|
66c0790f98 | ||
|
|
ca74bcd41e | ||
|
|
5cf21e2003 | ||
|
|
75d6fa56c5 | ||
|
|
ef5f3938ca | ||
|
|
37ee3c5ca8 | ||
|
|
a89aab3a42 | ||
|
|
1068f8bc86 | ||
|
|
58dfc6d95d | ||
|
|
83bc341b88 | ||
|
|
501e1a903e | ||
|
|
1218e9219a | ||
|
|
930e8ec184 | ||
|
|
7432d3e9d3 | ||
|
|
847e485fb4 | ||
|
|
5b7a458b42 | ||
|
|
7f785be3b8 | ||
|
|
386632051d | ||
|
|
ead471ceb1 | ||
|
|
833a185855 | ||
|
|
ecfdd6d193 | ||
|
|
40942f6759 | ||
|
|
ad3359f785 | ||
|
|
63d4442a54 | ||
|
|
838ffcdf74 | ||
|
|
f6db2f72d7 | ||
|
|
f313fd00b1 | ||
|
|
270ece00f9 | ||
|
|
73673ea050 | ||
|
|
7535c416a1 | ||
|
|
d2d24a516c | ||
|
|
a24986d1bb | ||
|
|
2adbe1cdba | ||
|
|
5eddc89075 | ||
|
|
d0c6e5167a | ||
|
|
9723ccb5ae | ||
|
|
8baa72c007 | ||
|
|
b7de0086a8 | ||
|
|
63d92eab5c | ||
|
|
4084a24649 | ||
|
|
8d847962f3 | ||
|
|
698659f7c4 | ||
|
|
28947034ba | ||
|
|
6cd0163e2d | ||
|
|
c5b6ab3569 | ||
|
|
3189db9884 | ||
|
|
f2bacb6200 | ||
|
|
5e56fc78d2 | ||
|
|
60c38dbd38 | ||
|
|
032e1b0bbe | ||
|
|
782313a084 | ||
|
|
df2270a9c8 | ||
|
|
6f4a01f476 | ||
|
|
a1fd77f1f3 | ||
|
|
39e38c27ec | ||
|
|
09e6d637dd | ||
|
|
fee0b713c9 | ||
|
|
d492740475 | ||
|
|
211781be1c | ||
|
|
2fc900c02d | ||
|
|
0744eb5d03 | ||
|
|
e3661e9836 | ||
|
|
13aab390b0 | ||
|
|
c64dcea9b8 | ||
|
|
ecb076eec8 | ||
|
|
b51a22c2b6 | ||
|
|
50fb1c20fc | ||
|
|
abd6d46963 | ||
|
|
da338ef7b0 | ||
|
|
b5cee665b9 | ||
|
|
e3a7ea1516 | ||
|
|
68ad2efdf9 | ||
|
|
8acff3fc51 | ||
|
|
420c33787e | ||
|
|
93f3504009 | ||
|
|
7b9ff2497f | ||
|
|
f1ad5b8e03 | ||
|
|
393ad9073b | ||
|
|
ecc17e12e7 | ||
|
|
4357bd544f | ||
|
|
8c74a69625 | ||
|
|
61b971c0d1 | ||
|
|
b2776805f6 | ||
|
|
97e424c56b | ||
|
|
29ecceec63 | ||
|
|
18c2aa1f69 | ||
|
|
3a3c3941df | ||
|
|
712a09eaba | ||
|
|
6733de3f00 | ||
|
|
3c92a8d39e | ||
|
|
5671b4baa8 | ||
|
|
7f45ec6f18 | ||
|
|
26a20ac1d7 | ||
|
|
55ce67903b | ||
|
|
8827be45c3 | ||
|
|
804251888c | ||
|
|
c442a6b895 | ||
|
|
cd367702a8 | ||
|
|
a9e35f9b9b | ||
|
|
6b44eac9d1 | ||
|
|
d8c1f8ca19 | ||
|
|
b9dd1018ff | ||
|
|
d32b4e4998 | ||
|
|
722739a284 | ||
|
|
328bf41309 | ||
|
|
ee33c13f88 | ||
|
|
122cb44579 | ||
|
|
a54dda5095 | ||
|
|
87d273a3ff | ||
|
|
8012a59466 | ||
|
|
e50de00a34 | ||
|
|
0d5d0e2b1d | ||
|
|
20fb1b7e42 | ||
|
|
bdce05270a | ||
|
|
8f2699c927 | ||
|
|
7f4ad4387a | ||
|
|
0f08da3b10 | ||
|
|
15965b2f54 | ||
|
|
5171c3bf22 | ||
|
|
cc42501517 | ||
|
|
2c2039faa6 | ||
|
|
e9d9c3c858 | ||
|
|
b2f7e029be | ||
|
|
d6775677a2 | ||
|
|
4b43b6d01f | ||
|
|
bb80b724c8 | ||
|
|
6f13958974 | ||
|
|
c9b969f3fd | ||
|
|
fa44401f6e | ||
|
|
b927731bcf | ||
|
|
3f01c575fb | ||
|
|
4b8e9064d2 | ||
|
|
8e6848dc23 | ||
|
|
0da0c7deae | ||
|
|
87a7cb0d08 | ||
|
|
f75834dc70 | ||
|
|
131c9615b0 | ||
|
|
39d49bba6d | ||
|
|
5908ac8cd1 | ||
|
|
3d61f226ff | ||
|
|
526828ca87 | ||
|
|
918aa7582f | ||
|
|
ab12cc4017 | ||
|
|
bb2db66f81 | ||
|
|
1398427e65 | ||
|
|
d329acb0d7 | ||
|
|
f39db539e7 | ||
|
|
6b694352b1 | ||
|
|
6c356d3a73 | ||
|
|
7c6311eeb1 | ||
|
|
9a6e74f23c | ||
|
|
d6a96a4c6b | ||
|
|
90e1b75793 | ||
|
|
9d6488ac7b | ||
|
|
38d326294f | ||
|
|
2c8d353105 | ||
|
|
cb80db8bb6 | ||
|
|
fb02488cc2 | ||
|
|
bdb401cea8 | ||
|
|
cec8e1c963 | ||
|
|
4184f067f7 | ||
|
|
07764582bc | ||
|
|
cb5ffcc299 | ||
|
|
1c4b5eb4f5 | ||
|
|
6126dbef15 | ||
|
|
9a43e789a3 | ||
|
|
443b5f5c42 | ||
|
|
1e1cd602d6 | ||
|
|
e2a2d29b84 | ||
|
|
76533e7317 | ||
|
|
46a17faa73 | ||
|
|
234f70aae2 | ||
|
|
318bd3d9d3 | ||
|
|
b800ee03c2 | ||
|
|
d016312f86 | ||
|
|
cf5be1ea67 | ||
|
|
2ed447646d | ||
|
|
a180688c2e | ||
|
|
8a87142618 | ||
|
|
7b9dbe748e | ||
|
|
246462901e | ||
|
|
2309dd9c9d | ||
|
|
a36e377771 | ||
|
|
12b9fe46ef | ||
|
|
a27001e934 | ||
|
|
bca072eb23 | ||
|
|
3b2b3a194f | ||
|
|
3960d96377 | ||
|
|
b04b4b1aa3 | ||
|
|
11de025c42 | ||
|
|
401ee26e3e | ||
|
|
35ae4af61a | ||
|
|
6dee7bf2e2 | ||
|
|
d615d7ae3e | ||
|
|
9cb6df0bee | ||
|
|
13aff48429 | ||
|
|
c413ef2e48 | ||
|
|
b367cdc828 | ||
|
|
5c7efb6372 | ||
|
|
e3aacdbcdc | ||
|
|
91dd2f4a54 | ||
|
|
cf629ebd21 | ||
|
|
ce62f05c25 | ||
|
|
5150c85284 | ||
|
|
bff28f2642 | ||
|
|
70da538f78 | ||
|
|
a2827630b1 | ||
|
|
d527448d5b | ||
|
|
3cf62a9a2e | ||
|
|
e86ee3f5e8 | ||
|
|
6789a25986 | ||
|
|
825ec55d80 | ||
|
|
cf61ba1035 | ||
|
|
8fb56bad25 | ||
|
|
429d550eb5 | ||
|
|
c1781bd8b4 | ||
|
|
5c4a7ac43c | ||
|
|
4ea804b0d0 | ||
|
|
a546403f1c | ||
|
|
5947c38d30 | ||
|
|
863b543e28 | ||
|
|
d15fefd620 | ||
|
|
3873e3e3dd | ||
|
|
997be470d1 | ||
|
|
41fc7dd672 | ||
|
|
ffee882478 | ||
|
|
36783ef818 | ||
|
|
8f813cc6b6 | ||
|
|
7dfc99b08a | ||
|
|
f052decc10 | ||
|
|
f386c33a09 | ||
|
|
b457646087 | ||
|
|
77eaa45ee7 | ||
|
|
015bb01599 | ||
|
|
d14fc7dd5f | ||
|
|
88acdd0a4f | ||
|
|
660fd178b9 | ||
|
|
6c29b677cb | ||
|
|
09ef6a1d18 | ||
|
|
98c8eb7445 | ||
|
|
15fdea2cd1 | ||
|
|
97a3be2fc7 | ||
|
|
538674f68b | ||
|
|
c9a6a28af7 | ||
|
|
530340a01f | ||
|
|
6f104d56f4 | ||
|
|
5384766355 | ||
|
|
33ff264029 | ||
|
|
356c88bc1f | ||
|
|
9e66c34d99 | ||
|
|
6fcae817d4 | ||
|
|
144f1b9f6a | ||
|
|
e93b3d3912 | ||
|
|
b922219bb6 | ||
|
|
73adb17b98 | ||
|
|
2157d27cbe | ||
|
|
4b0c61fa16 | ||
|
|
e197993dbf | ||
|
|
f4670c5fb2 | ||
|
|
86b4440149 | ||
|
|
ce7ccf1730 | ||
|
|
4d7601a527 | ||
|
|
6be1784277 | ||
|
|
c177472a42 | ||
|
|
7f80b00860 | ||
|
|
fd74e6311b | ||
|
|
64b8991408 | ||
|
|
ea37dcfc3a | ||
|
|
6be74cad34 | ||
|
|
03556b02b5 | ||
|
|
a7f42d9d14 | ||
|
|
a83e75a4d3 | ||
|
|
afb5f2cb34 | ||
|
|
ff30d7d318 | ||
|
|
952fe5daa0 | ||
|
|
75647b121d | ||
|
|
36fb1a5d67 | ||
|
|
0b6f7b953e | ||
|
|
7da438efa9 | ||
|
|
f69cd6fe84 | ||
|
|
ffe1f27000 | ||
|
|
caaf65d63b | ||
|
|
e6b221da38 | ||
|
|
c813319260 | ||
|
|
11a2032b1f | ||
|
|
b49ba83115 | ||
|
|
19fa45a864 | ||
|
|
c60636e65d | ||
|
|
64876b97b3 | ||
|
|
6544352f17 | ||
|
|
7d363bc811 | ||
|
|
bf144300ba | ||
|
|
5d3155301e | ||
|
|
8eae98f9fb | ||
|
|
64730f9c10 | ||
|
|
4697af4d7b | ||
|
|
76f45d5ac0 | ||
|
|
347205c866 | ||
|
|
13ea1ffc8c | ||
|
|
928a9391d0 | ||
|
|
240651564a | ||
|
|
c2a68b6a6b | ||
|
|
5df19be765 | ||
|
|
df85bb2111 | ||
|
|
df1adc6c6a | ||
|
|
601b674f8d | ||
|
|
79100fe489 | ||
|
|
b0a8f48dae | ||
|
|
2a713fa2a4 | ||
|
|
abb2c8b8df | ||
|
|
b016726247 | ||
|
|
b019883b91 | ||
|
|
7b4bb82c75 | ||
|
|
03583e44d5 | ||
|
|
4bb8b7695c | ||
|
|
d375724f9e | ||
|
|
643155e4ec | ||
|
|
5b248ce379 | ||
|
|
41288cc957 | ||
|
|
e12dc083e7 | ||
|
|
5a0a632ae3 | ||
|
|
3d22970159 | ||
|
|
4d39b43f15 | ||
|
|
5489209a0d | ||
|
|
4845183691 | ||
|
|
e17d9f0123 | ||
|
|
30f4654d0f | ||
|
|
6b6dacea76 | ||
|
|
0594cba992 | ||
|
|
1cfcbd964b | ||
|
|
cffd32dda9 | ||
|
|
7e8071f33c | ||
|
|
926e21d258 | ||
|
|
8af08fe0fa | ||
|
|
0826769b62 | ||
|
|
f35457bdb0 | ||
|
|
6bc303f434 | ||
|
|
12050328a2 | ||
|
|
5ec5c53024 | ||
|
|
0388bcaf45 | ||
|
|
50faed905e | ||
|
|
b97d1e8edc | ||
|
|
699ce06906 | ||
|
|
28bf477422 | ||
|
|
10c206c37f | ||
|
|
506a5619cb | ||
|
|
56e4a8fa27 | ||
|
|
387e6f65ea | ||
|
|
6e94d7668e | ||
|
|
13be2daa16 | ||
|
|
5bdf0998e3 | ||
|
|
ce4f422335 | ||
|
|
fbf5bed567 | ||
|
|
b7dcf6324c | ||
|
|
fe25d084d9 | ||
|
|
cb329e9747 | ||
|
|
f5720fba05 | ||
|
|
0745ddf8cd | ||
|
|
4a6ce11692 | ||
|
|
bed330a7db | ||
|
|
b939caaf68 | ||
|
|
dae531dd26 | ||
|
|
84af9ba07f | ||
|
|
d32244a877 | ||
|
|
f2b5213e6e | ||
|
|
487ea74b51 | ||
|
|
124a1a6911 | ||
|
|
2e85998e72 | ||
|
|
83cefc54a1 | ||
|
|
fb42f359a1 | ||
|
|
0334db5ef9 | ||
|
|
305ef5e560 | ||
|
|
a4f3d1d5b4 | ||
|
|
16f72e287a | ||
|
|
de04086da7 | ||
|
|
557bd6a498 | ||
|
|
4b0704060b | ||
|
|
30debfc42b | ||
|
|
23568e9b97 | ||
|
|
2e0eb5033b | ||
|
|
260d15de65 | ||
|
|
aaaac02979 | ||
|
|
fea1f8f7ed | ||
|
|
b442122556 | ||
|
|
f054d9e209 | ||
|
|
0e84f92d32 | ||
|
|
6f02b27ff6 | ||
|
|
42e1f436e5 | ||
|
|
f684bfba27 | ||
|
|
feb93e3459 | ||
|
|
01dd4fb42c | ||
|
|
e91c510cbf | ||
|
|
afe0899dd8 | ||
|
|
91c1f97912 | ||
|
|
580ac33487 | ||
|
|
d5fa63428a | ||
|
|
7c29161b3b | ||
|
|
020bd77358 | ||
|
|
511fa074b4 | ||
|
|
01175b0fc8 | ||
|
|
793f1262e7 | ||
|
|
84fce9936e | ||
|
|
f06862057f | ||
|
|
75799fa4a2 | ||
|
|
7fdcc42626 | ||
|
|
c521227e4d | ||
|
|
646efa0b6e | ||
|
|
e460df11d2 | ||
|
|
7a1545ef1b | ||
|
|
ade64594f5 | ||
|
|
11f01c05bb | ||
|
|
73c4d5d62d | ||
|
|
278012c200 | ||
|
|
38d0a0b76e | ||
|
|
40f0032380 | ||
|
|
f564284d96 | ||
|
|
2a15bfb7e2 | ||
|
|
0722e819c3 | ||
|
|
5f49a5afd1 | ||
|
|
a3254586e5 | ||
|
|
04c4a57141 | ||
|
|
d7fd5cda70 | ||
|
|
9850e2da85 | ||
|
|
a0b7fab8da | ||
|
|
96fbb18677 | ||
|
|
9b10275f36 | ||
|
|
cb1000f32d | ||
|
|
c0c9bf2cae | ||
|
|
1b64db4792 | ||
|
|
7631e7f9a4 | ||
|
|
39f26f0050 | ||
|
|
2c67d72e4f | ||
|
|
006ead4074 | ||
|
|
ee57aa5fb0 | ||
|
|
aec5d229eb | ||
|
|
3ecc905ae8 | ||
|
|
e1bb325c03 | ||
|
|
037ae628a1 | ||
|
|
8af498aa8b | ||
|
|
3adddec261 | ||
|
|
4225f50f0c | ||
|
|
ef8b183c88 | ||
|
|
682a25a677 | ||
|
|
21c3a00c78 | ||
|
|
be3eeb0248 | ||
|
|
571869adbb | ||
|
|
a4401fb9f2 | ||
|
|
6625efb3a1 | ||
|
|
d920c03a71 | ||
|
|
3c32e12cdd | ||
|
|
c583974b74 | ||
|
|
295c1fded4 | ||
|
|
bcf73ffa3a | ||
|
|
85ded64073 | ||
|
|
01d1d358a6 | ||
|
|
0b4c744a00 | ||
|
|
42b868a9a3 | ||
|
|
9257d76dd9 | ||
|
|
98f01651f0 | ||
|
|
f851d2720e | ||
|
|
652188cc64 | ||
|
|
943da1be93 | ||
|
|
d7225a82c0 | ||
|
|
a25c9c0a8a | ||
|
|
e64fe01ed8 | ||
|
|
9e1d493ef5 | ||
|
|
8b1bd75348 | ||
|
|
1c33ed571a | ||
|
|
834c557a2d | ||
|
|
86a5cf8344 | ||
|
|
114f5cd821 | ||
|
|
d96f9ef46b | ||
|
|
0f90693439 | ||
|
|
fc45408d77 | ||
|
|
ffbb1c5e8f | ||
|
|
0b87316f2c | ||
|
|
395969ded9 | ||
|
|
856a161164 | ||
|
|
459f7a7f39 | ||
|
|
a2261ece1d | ||
|
|
da4008d6ab | ||
|
|
8a73fb4467 | ||
|
|
5300f24b10 | ||
|
|
4f0ef90eb6 | ||
|
|
f2b04aefe6 | ||
|
|
dc8a452c14 | ||
|
|
039c968cd8 | ||
|
|
521b9182a7 | ||
|
|
cf0b0d7c4f | ||
|
|
e0a2f29c68 | ||
|
|
eb452b21eb | ||
|
|
5f66778e45 | ||
|
|
03bf47d082 | ||
|
|
e2ed80369c | ||
|
|
16c2e2a958 | ||
|
|
012cfd179b | ||
|
|
211908f6de | ||
|
|
8a5b57d5de | ||
|
|
0c94dbbbfe | ||
|
|
f563d331b0 | ||
|
|
e11d78a0c8 | ||
|
|
600794dc8d | ||
|
|
43c5e96df1 | ||
|
|
285f490ebf | ||
|
|
0c2a1df6fd | ||
|
|
d484c77904 | ||
|
|
8848e49dab | ||
|
|
37fa7d19e9 | ||
|
|
f3f89188ee | ||
|
|
b95d95f440 | ||
|
|
46465da35a | ||
|
|
bbbce958f0 | ||
|
|
7f2b33ff36 | ||
|
|
7cc23c8caa | ||
|
|
2b62a32f55 | ||
|
|
48399d258d | ||
|
|
417126f22f | ||
|
|
9a2476155d | ||
|
|
bdbf4a6408 | ||
|
|
9969cb5874 | ||
|
|
652c903499 | ||
|
|
4475450603 | ||
|
|
f9158f4bcf | ||
|
|
246044776f | ||
|
|
25f33001ae | ||
|
|
c0a10dc003 | ||
|
|
a904779edd | ||
|
|
3e3979cf65 | ||
|
|
f6eec48671 | ||
|
|
de096bf1bc | ||
|
|
aac3b105d9 | ||
|
|
98e4852f43 | ||
|
|
f7ede8edb0 | ||
|
|
76dc90c563 | ||
|
|
24ab3d735b | ||
|
|
75348d5266 | ||
|
|
037742eacb | ||
|
|
31ac3b4bbb | ||
|
|
3afcd2f43c | ||
|
|
db71ab4744 | ||
|
|
b6fb4a1024 | ||
|
|
11da05c81e | ||
|
|
95dcd882db | ||
|
|
6b010d34d4 | ||
|
|
e4f0f7ace0 | ||
|
|
42b89e65cf | ||
|
|
131f03a0f6 | ||
|
|
d667d15ee9 | ||
|
|
f3cc7920bd | ||
|
|
790bbcd772 | ||
|
|
11a608ead6 | ||
|
|
785e087e95 | ||
|
|
0c1ad5e944 | ||
|
|
29f6a71881 | ||
|
|
04a05dd50b | ||
|
|
2e2ae7e7db | ||
|
|
23cfb9afd8 | ||
|
|
ee3d1e2dea | ||
|
|
ca2b3fded3 | ||
|
|
770660eefe | ||
|
|
7ee3a1b7dd | ||
|
|
7b0f9d5c81 | ||
|
|
c21247015b | ||
|
|
aa0c887504 | ||
|
|
4fd9a38860 | ||
|
|
fec186af27 | ||
|
|
6bca4de7b9 | ||
|
|
a0df248756 | ||
|
|
e420d1ebf0 | ||
|
|
93a0b55fc1 | ||
|
|
8507c62889 | ||
|
|
5aa9d85019 | ||
|
|
83a592837a | ||
|
|
c2b8389251 | ||
|
|
b2b1bf9c5b | ||
|
|
4099373b62 | ||
|
|
dc30039781 | ||
|
|
cb3c76a55e | ||
|
|
37c16f6725 | ||
|
|
626546b71f | ||
|
|
5abc5e86e4 | ||
|
|
cab87ec10e | ||
|
|
910f1b5cbd | ||
|
|
718bae37d9 | ||
|
|
4778372486 | ||
|
|
6d42461cd6 | ||
|
|
22d06eea8a | ||
|
|
6f0467eac4 | ||
|
|
5cce62efef | ||
|
|
746fb39d1c | ||
|
|
4636ffab67 | ||
|
|
23260de0d7 | ||
|
|
5959048cae | ||
|
|
95301a2a9f | ||
|
|
0175b4e5fc | ||
|
|
dee4cdf688 | ||
|
|
043780c85d | ||
|
|
de95204c72 | ||
|
|
e9ff5a7fd2 | ||
|
|
8c34993cef | ||
|
|
9afc83e633 | ||
|
|
9f017522f0 | ||
|
|
4bddc7f0ef | ||
|
|
b470a17913 | ||
|
|
00a2efbfbb | ||
|
|
54b1854bdf | ||
|
|
dbe03e6fd0 | ||
|
|
309c084222 | ||
|
|
51f2a5e428 | ||
|
|
5343a006ef | ||
|
|
2caf0e94b8 | ||
|
|
8c9eab3d71 | ||
|
|
8790567a50 | ||
|
|
7a75306222 | ||
|
|
a1e4bb2555 | ||
|
|
0a0fc03f70 | ||
|
|
24b30fb9cb | ||
|
|
6c40f9b2a5 | ||
|
|
6e59e71c7c | ||
|
|
95e10e43a8 | ||
|
|
88396d22a9 | ||
|
|
207b8efcc5 | ||
|
|
309cd9e417 | ||
|
|
69fd0d17ac | ||
|
|
02cf1d1375 | ||
|
|
faade64fb5 | ||
|
|
9deb301619 | ||
|
|
6c87f9d7ad | ||
|
|
105e8daff6 | ||
|
|
eca4df62b4 | ||
|
|
98d0369f6b | ||
|
|
046aa8e085 | ||
|
|
46f0faca0b | ||
|
|
5d9bdedb22 | ||
|
|
add112ff9a | ||
|
|
9bc28bec9e | ||
|
|
5b768c0e4f | ||
|
|
9d7bcfcbec | ||
|
|
f658054549 | ||
|
|
1919abfcea | ||
|
|
d058962498 | ||
|
|
0434986a00 | ||
|
|
6c6941d53c | ||
|
|
5bbfeaff35 | ||
|
|
32447b2e77 | ||
|
|
557e0c1d61 | ||
|
|
6ea1fb316a | ||
|
|
ee86eb6a0e | ||
|
|
70cc92f9a1 | ||
|
|
3317f1446b | ||
|
|
498ff60a73 | ||
|
|
de2bcebc64 | ||
|
|
916f039ed3 | ||
|
|
0bf79c7be8 | ||
|
|
8520a225d1 | ||
|
|
91a7374dc0 | ||
|
|
9917846559 | ||
|
|
7b26aa11be | ||
|
|
f0060c24c2 | ||
|
|
7c7c5d5f22 | ||
|
|
3afaabbc96 | ||
|
|
7bcae0fbe9 | ||
|
|
74a434acac | ||
|
|
ecabb8d55d | ||
|
|
e9e5a58154 | ||
|
|
14f1acea19 | ||
|
|
741200e217 | ||
|
|
5029510766 | ||
|
|
16b358b599 | ||
|
|
0248fcfc48 | ||
|
|
232b30ebdd | ||
|
|
7ade7b602b | ||
|
|
da7bf3d861 | ||
|
|
f8280ac203 | ||
|
|
aad177fc73 | ||
|
|
ed06002cfc | ||
|
|
063c8aeea4 | ||
|
|
efa9ca438e | ||
|
|
02080dd4c0 | ||
|
|
d67ad04e89 | ||
|
|
5ea83dccdd | ||
|
|
db9426279e | ||
|
|
f64e305f91 | ||
|
|
b125c63d7b | ||
|
|
a55a148a78 | ||
|
|
cc3d392909 | ||
|
|
124774b711 | ||
|
|
096381bb5c | ||
|
|
b93128d390 | ||
|
|
d4936a833f | ||
|
|
781fa723e4 | ||
|
|
2b8fc16dc0 | ||
|
|
96efa8624f | ||
|
|
d07a8765ed | ||
|
|
f513485016 | ||
|
|
e866951197 | ||
|
|
7bc623051c | ||
|
|
998b277216 | ||
|
|
dbcf6fe866 | ||
|
|
0bd75cec41 | ||
|
|
4e37c4c1d5 | ||
|
|
6f6b04e6a9 | ||
|
|
1410bd82cf | ||
|
|
6eecc8d8aa | ||
|
|
58b27e0261 | ||
|
|
4e6a00823f | ||
|
|
e599fd2e5a | ||
|
|
cee68f1b0d | ||
|
|
6358533179 | ||
|
|
117aa24a0a | ||
|
|
ff91bd0c15 | ||
|
|
647fa443fc | ||
|
|
5be3593a13 | ||
|
|
93dd13deaf | ||
|
|
d86fdba523 | ||
|
|
a53450f740 | ||
|
|
f7929ca621 | ||
|
|
dab44e62d5 | ||
|
|
dd81a4cdad | ||
|
|
0c2967f503 | ||
|
|
72647ec4e0 | ||
|
|
ee4f111f05 | ||
|
|
f671d05ba2 | ||
|
|
b395d0d5d0 | ||
|
|
536d06681f | ||
|
|
5b1320d108 | ||
|
|
bca1b3a16e | ||
|
|
87014f92f7 | ||
|
|
5d537211d0 | ||
|
|
02069a4f2c | ||
|
|
d9de2cc529 | ||
|
|
03c7cdd3c9 | ||
|
|
6274ef25fe | ||
|
|
76b0a7df3e | ||
|
|
5a50d33086 | ||
|
|
7fbcc3d9d6 | ||
|
|
362f488ff6 | ||
|
|
3e5bdf882a | ||
|
|
6674961963 | ||
|
|
fc3496e50b | ||
|
|
c613a50562 | ||
|
|
017697c7f9 | ||
|
|
3ace828927 | ||
|
|
9ab35f6796 | ||
|
|
b53f41f9cb | ||
|
|
50cde872fb | ||
|
|
e1d2e81578 | ||
|
|
131728a0f2 | ||
|
|
e174797e4f | ||
|
|
4361cbb283 | ||
|
|
1e24347c0e | ||
|
|
f1afe829ec | ||
|
|
28c312dc25 | ||
|
|
35bda326db | ||
|
|
fded7b243b | ||
|
|
fd7104a4e9 | ||
|
|
fc70ac9958 | ||
|
|
98d248db95 | ||
|
|
7c78a968ee | ||
|
|
6c95462282 | ||
|
|
7560b8d0ae | ||
|
|
10ac3f0399 | ||
|
|
e58134a824 | ||
|
|
e94d74c923 | ||
|
|
3b29d2b673 | ||
|
|
04bddab124 | ||
|
|
87b7439ba2 | ||
|
|
90d32887cf | ||
|
|
446bb38e6d | ||
|
|
cb0aa5e54f | ||
|
|
bdfaa43926 | ||
|
|
abd05f2061 | ||
|
|
aa111ad7cc | ||
|
|
26f30dcc0d | ||
|
|
fee7b3c8da | ||
|
|
241adadd02 | ||
|
|
10d84824d4 | ||
|
|
57f3fc8f73 | ||
|
|
f77b5daf0d | ||
|
|
e1242267d0 | ||
|
|
685e44d7f9 | ||
|
|
4374493eae | ||
|
|
5f24d34899 | ||
|
|
6dd2bc86cb | ||
|
|
aa8f3d4f00 | ||
|
|
0b0030a028 | ||
|
|
1c64a39256 | ||
|
|
e616eeab0d | ||
|
|
06d8056e23 | ||
|
|
07006d026a | ||
|
|
f7316d1107 | ||
|
|
f60d792145 | ||
|
|
d4b9d60ed7 | ||
|
|
74590f7f1a | ||
|
|
5c80b4336f | ||
|
|
f573f02840 | ||
|
|
807abc579c | ||
|
|
e75dc8eb10 | ||
|
|
792e173e35 | ||
|
|
6907997db3 | ||
|
|
759e50773e | ||
|
|
93aecb900f | ||
|
|
4e50e01151 | ||
|
|
3f0100ae2f | ||
|
|
61b9ee294a | ||
|
|
6c75e1898d | ||
|
|
edcf8cb43d | ||
|
|
4fb912da49 | ||
|
|
991dad1d6a | ||
|
|
4f7357c457 | ||
|
|
1b2255b5f9 | ||
|
|
0073d4926c | ||
|
|
0d8ea3ce76 | ||
|
|
ce0099e740 | ||
|
|
1c001275b1 | ||
|
|
5db4b9ba99 | ||
|
|
7bbb011ad9 | ||
|
|
3412677be3 | ||
|
|
f3fb6dd603 | ||
|
|
8531bdb71e | ||
|
|
81282ab548 | ||
|
|
c3d59e2581 | ||
|
|
f33ba1ae1c | ||
|
|
2b8657ceff | ||
|
|
818218cdf2 | ||
|
|
d98fd9e137 | ||
|
|
62578bd4c2 | ||
|
|
88d60e5a8d | ||
|
|
6fc6b2cb3d | ||
|
|
9f14cd4477 | ||
|
|
89b3519832 | ||
|
|
ea92045587 | ||
|
|
9e3f49b904 | ||
|
|
e642424b87 | ||
|
|
c85b9cc87c | ||
|
|
c77852cd40 | ||
|
|
51826a1bd2 | ||
|
|
3a63bc99d5 | ||
|
|
5de95f9ca6 | ||
|
|
20729b5ce7 | ||
|
|
93add4eae9 | ||
|
|
18f1415687 | ||
|
|
6223574859 | ||
|
|
ab9dfd1998 | ||
|
|
d989549dfd | ||
|
|
84d81e0cab | ||
|
|
34a39e0927 | ||
|
|
6c62653372 | ||
|
|
e61401013d | ||
|
|
860951085b | ||
|
|
8cb91578e2 | ||
|
|
95f3b763f4 | ||
|
|
989b406c69 | ||
|
|
4d52b6eb6b | ||
|
|
b11a1213c9 | ||
|
|
5bdc5b7cd8 | ||
|
|
275ae6082d | ||
|
|
3dd4da9687 | ||
|
|
af56d172d0 | ||
|
|
ff56e45316 | ||
|
|
3fe6fc7dad | ||
|
|
001d5a8037 | ||
|
|
d0c0768c59 | ||
|
|
096dfcda0d | ||
|
|
6e0816ac00 | ||
|
|
554cf592e1 | ||
|
|
6a2a6c5cf2 | ||
|
|
b9a34b842a | ||
|
|
a85da465a8 | ||
|
|
f17e987c05 | ||
|
|
2e569242c3 | ||
|
|
fd661ff020 | ||
|
|
a2b284a372 | ||
|
|
593fda1926 | ||
|
|
d199557aac | ||
|
|
0f7b5570b0 | ||
|
|
2b6e54a941 | ||
|
|
85e8d9d2e9 | ||
|
|
5477fb62f0 | ||
|
|
5318e559f4 | ||
|
|
f26b6e4fbb | ||
|
|
96cf326633 | ||
|
|
8f356d763d | ||
|
|
433f89f241 | ||
|
|
99dc346eae | ||
|
|
8a3d716185 | ||
|
|
ef04534e2c | ||
|
|
c6542e1a76 | ||
|
|
ee1946a4fd | ||
|
|
3d28c9b664 | ||
|
|
a589022332 | ||
|
|
cdb17c349c | ||
|
|
791497421a | ||
|
|
f02e3e3155 | ||
|
|
41cdfbb641 | ||
|
|
f42e7b4743 | ||
|
|
d64176f0c8 | ||
|
|
9086d8c9fa | ||
|
|
5ab2b44152 | ||
|
|
8902fad23b | ||
|
|
0fb7a234ca | ||
|
|
e966e22946 | ||
|
|
4106d2fb2c | ||
|
|
b7dfb3a83c | ||
|
|
e0dc045e0a | ||
|
|
efaf73f5f0 | ||
|
|
c5e4519148 | ||
|
|
fb07442887 | ||
|
|
07d2c0c05f | ||
|
|
7ec4daf204 | ||
|
|
e293a96693 | ||
|
|
f3e1eaab59 | ||
|
|
00290ef53b | ||
|
|
1c16cd3a3f | ||
|
|
fdc8a20b25 | ||
|
|
684111bde5 | ||
|
|
3ccad0a519 | ||
|
|
a5312d6c4e | ||
|
|
fde8bcb5b4 | ||
|
|
8dc675f09f | ||
|
|
45d047eefc | ||
|
|
2d679ae034 | ||
|
|
6b3ecf3297 | ||
|
|
9427d8991e | ||
|
|
222e09152e | ||
|
|
a4bc08e9a6 | ||
|
|
daa3b1c0f8 | ||
|
|
68ce99fb61 | ||
|
|
1a528db943 | ||
|
|
bc55792d84 | ||
|
|
02fdb1516a | ||
|
|
c365d5c80f | ||
|
|
6f45af2e8a | ||
|
|
0edf309245 | ||
|
|
fdddbf4d16 | ||
|
|
ca2ac6b5a9 | ||
|
|
d43e7fb70b | ||
|
|
1d47ceb7c2 | ||
|
|
07f2e6cf3a | ||
|
|
9644fc8ac0 | ||
|
|
dcbe749437 | ||
|
|
441b396fca | ||
|
|
ad72f16728 | ||
|
|
c672623d61 | ||
|
|
d3e52ea7c4 | ||
|
|
88e490e319 | ||
|
|
b1be5ef8ed | ||
|
|
a097baa4e0 | ||
|
|
1ac2bdc273 | ||
|
|
3cfc30395b | ||
|
|
70b8ba6686 | ||
|
|
641255091d | ||
|
|
22ba37f2c4 | ||
|
|
39c9011f1f | ||
|
|
c8bd5a00f5 | ||
|
|
637da2fa5b | ||
|
|
2df029ada8 | ||
|
|
50c42ef5f5 | ||
|
|
73e2b45557 | ||
|
|
0275b76f67 | ||
|
|
dae40b31b3 | ||
|
|
2c3adc5ade | ||
|
|
fa5cf38978 | ||
|
|
06676aa382 | ||
|
|
af85c3e014 | ||
|
|
9d7bac3588 | ||
|
|
43e59d411a | ||
|
|
54fe1e53de | ||
|
|
4f95c37098 | ||
|
|
4243880c4e | ||
|
|
7989df007a | ||
|
|
cb66638cb6 | ||
|
|
1e85057e60 | ||
|
|
33d541ce35 | ||
|
|
b6b33fa622 | ||
|
|
451cfee127 | ||
|
|
19b139f3cd | ||
|
|
c7541eeb0e | ||
|
|
704a031438 | ||
|
|
2caa3078b0 | ||
|
|
f159b49479 | ||
|
|
c76f1926a8 | ||
|
|
d3bb2a310f | ||
|
|
4414769791 | ||
|
|
9d2d18e377 | ||
|
|
d3a366371a | ||
|
|
21fb6f3068 | ||
|
|
66884b10c9 | ||
|
|
a518cf962e | ||
|
|
294c7383c6 | ||
|
|
4fd63ef2d1 | ||
|
|
fcd5af88d7 | ||
|
|
9f771be044 | ||
|
|
f196229534 | ||
|
|
a8a202b5ce | ||
|
|
7774c86111 | ||
|
|
9188b9cc01 | ||
|
|
5bd471bb6c | ||
|
|
118dfe405e | ||
|
|
86b1a21157 | ||
|
|
ab005bebf0 | ||
|
|
6c10e12d73 | ||
|
|
2b5ee53e24 | ||
|
|
74509036f1 | ||
|
|
4069ca6a1e | ||
|
|
8603873e5a | ||
|
|
2d788bf5d5 | ||
|
|
f994b739a8 | ||
|
|
296ed731c9 | ||
|
|
b0ad873274 | ||
|
|
8d7bfcdabb | ||
|
|
726c1f5c79 | ||
|
|
096a09a928 | ||
|
|
a0f4047e1c | ||
|
|
01057407d0 | ||
|
|
d887123196 | ||
|
|
b7fc5813ca | ||
|
|
1427d8abe5 | ||
|
|
11df9a9121 | ||
|
|
6217280a5f | ||
|
|
e7548982b2 | ||
|
|
d83efa9813 | ||
|
|
5e442b9f48 | ||
|
|
7803ad2c1e | ||
|
|
82622a9b35 | ||
|
|
87a3d54b83 | ||
|
|
d1efd4371d | ||
|
|
2d6c2c72b7 | ||
|
|
e602512597 | ||
|
|
400fc1bffc | ||
|
|
ce4c7cd220 | ||
|
|
07114cbbb5 | ||
|
|
5f258fe40c | ||
|
|
a72ab2a9df | ||
|
|
622421a752 | ||
|
|
8a3478b49e | ||
|
|
3a7e1a270e | ||
|
|
185f59fa7d | ||
|
|
b6a5f9279b | ||
|
|
a7f2f51039 | ||
|
|
5846994ec2 | ||
|
|
f0407ceae5 | ||
|
|
7c5887c7e4 | ||
|
|
45a4975cbb | ||
|
|
38acffde86 | ||
|
|
4b00a98b75 | ||
|
|
56a0595dfa | ||
|
|
2b1a27afd7 | ||
|
|
59ea639191 | ||
|
|
79cafe9024 | ||
|
|
805166642e | ||
|
|
50af8e2343 | ||
|
|
d07e4bdd1d | ||
|
|
ebeea7e8f8 | ||
|
|
7c9416ae50 | ||
|
|
f9942bc7d3 | ||
|
|
c4b18502f6 | ||
|
|
47d2af2c0a | ||
|
|
d88f45969d | ||
|
|
e423b4c99b | ||
|
|
f17abb0a2d | ||
|
|
8a8f04eb25 | ||
|
|
9b57af76d8 | ||
|
|
1f92e97260 | ||
|
|
504f0f07da | ||
|
|
d9fc3dc646 | ||
|
|
46895a3c83 | ||
|
|
b6bec97ed4 | ||
|
|
53520f8283 | ||
|
|
77aab7e570 | ||
|
|
6a689b444d | ||
|
|
138842a6fd | ||
|
|
b1939bd375 | ||
|
|
d90c780699 | ||
|
|
f3b65a9e79 | ||
|
|
476f1858ff | ||
|
|
b8c96fe78c | ||
|
|
1753012a4f | ||
|
|
7317d59483 | ||
|
|
6ab120d29d | ||
|
|
a14af6607c | ||
|
|
94517b1b6c | ||
|
|
190468454f | ||
|
|
764aa2ce3a | ||
|
|
d83858d492 | ||
|
|
a0f53ad1e0 | ||
|
|
fd1e210e25 | ||
|
|
72193a7909 | ||
|
|
1d7816d4db | ||
|
|
435c2b25e3 | ||
|
|
2bfe1283c9 | ||
|
|
c98c33db77 | ||
|
|
fd99f80cf1 | ||
|
|
95634ef122 | ||
|
|
a1a32a0d0b | ||
|
|
bee3e086ec | ||
|
|
6cafb200ec | ||
|
|
bb8476841d | ||
|
|
c32c82dbb0 | ||
|
|
bab8a488bd | ||
|
|
3025780b9b | ||
|
|
5700719586 | ||
|
|
e333f2ba00 | ||
|
|
cdc0cbfd7e | ||
|
|
4c5f403aa4 | ||
|
|
199982b6e8 | ||
|
|
c7ded86e4a | ||
|
|
808dc584a8 | ||
|
|
7382e16798 | ||
|
|
ebbc0064fc | ||
|
|
9b6024b169 | ||
|
|
b6e026e129 | ||
|
|
fc58c2fcd5 | ||
|
|
47b1d568eb | ||
|
|
f1726858a7 | ||
|
|
76f130e221 | ||
|
|
67ee2b419e | ||
|
|
a58d17f4cc | ||
|
|
b5fc2e2f6e | ||
|
|
6b5a3f50a6 | ||
|
|
cc10a74831 | ||
|
|
1afe337213 | ||
|
|
50a42e705c | ||
|
|
e7183e900d | ||
|
|
3f39c6ff4e | ||
|
|
fcfea2b96b | ||
|
|
4d8ba42a6e | ||
|
|
551e689c4d | ||
|
|
abc79dda97 | ||
|
|
c788beaecc | ||
|
|
0dd31ce941 | ||
|
|
3d85725fde | ||
|
|
4004402c3e | ||
|
|
1ab30229b7 | ||
|
|
a7e03c64d5 | ||
|
|
2113acc375 | ||
|
|
3a2dc247f2 | ||
|
|
990d774aaa | ||
|
|
29709ec444 | ||
|
|
fa5f34b65b | ||
|
|
1733ebb6f7 | ||
|
|
79498f9118 | ||
|
|
c03546d9e6 | ||
|
|
44b09470e8 | ||
|
|
f7a6960e8a | ||
|
|
a04b543f2b | ||
|
|
0a43c7ebd6 | ||
|
|
e19f9950f9 | ||
|
|
0a887b9330 | ||
|
|
353782e38e | ||
|
|
3450017713 | ||
|
|
9eed34aee2 | ||
|
|
82c1d7860c | ||
|
|
2bbd6a9d9b | ||
|
|
f5c330a189 | ||
|
|
b47a0d795a | ||
|
|
4c881d448b | ||
|
|
0b41be7e57 | ||
|
|
c34c1eec6b | ||
|
|
16febba7bd | ||
|
|
a8a038d816 | ||
|
|
e1c603e1b8 | ||
|
|
e214a3eae7 | ||
|
|
b8b7666105 | ||
|
|
27d432c7c5 | ||
|
|
d6f34ba1e1 | ||
|
|
7ed9b185a2 | ||
|
|
455542dea7 | ||
|
|
765ee5ed61 | ||
|
|
13d9843f7c | ||
|
|
ffd840ebf6 | ||
|
|
f17d1b1212 | ||
|
|
af17532417 | ||
|
|
843c830c3d | ||
|
|
5912f5be6a | ||
|
|
7867d44bea | ||
|
|
98ba47b4a9 | ||
|
|
1a864dffd9 | ||
|
|
d9710690e6 | ||
|
|
33c2481ab8 | ||
|
|
34e05d8999 | ||
|
|
d94df01000 | ||
|
|
c7f32b8573 | ||
|
|
7eba5d7def | ||
|
|
bbeb30172b | ||
|
|
5757901cad | ||
|
|
db373c1465 | ||
|
|
c96c83103f | ||
|
|
20e8cb8618 | ||
|
|
74c34b7270 | ||
|
|
5460337f8b | ||
|
|
8555726045 | ||
|
|
10cfdb1609 | ||
|
|
2ffc4e0122 | ||
|
|
a94f019f62 | ||
|
|
a73d8dd53b | ||
|
|
26d11ed149 | ||
|
|
2cb42979a8 | ||
|
|
148ad44b94 | ||
|
|
e01642979e | ||
|
|
fec2bdc290 | ||
|
|
3b547e9c5a | ||
|
|
4fff45e9fc | ||
|
|
60993cfb7c | ||
|
|
43efe7f8d8 | ||
|
|
461da38856 | ||
|
|
16e6c8b098 | ||
|
|
aa36617cd7 | ||
|
|
09e16af753 | ||
|
|
b58053ae25 | ||
|
|
d34ca29c74 | ||
|
|
d4b0a857a0 | ||
|
|
039013d6ac | ||
|
|
2f1cc6502e | ||
|
|
dd7bc3ad4b | ||
|
|
a4821bfaeb | ||
|
|
3c709904db | ||
|
|
d5fd0ced5f | ||
|
|
b737a91be4 | ||
|
|
ab7e3e6087 | ||
|
|
7dfa1b686e | ||
|
|
e1bebac6bc | ||
|
|
12e468a804 | ||
|
|
f1e3392084 | ||
|
|
20807c9031 | ||
|
|
cc6f1a1ba0 | ||
|
|
49eb4ed7c0 | ||
|
|
13e1b11ad9 | ||
|
|
70f9d41b24 | ||
|
|
7b52151c05 | ||
|
|
43176273f3 | ||
|
|
29e2ba10b9 | ||
|
|
5d04f6fc8d | ||
|
|
2bf0fd70b0 | ||
|
|
aed532b1e1 | ||
|
|
6e68938295 | ||
|
|
943b7f932c | ||
|
|
c1c9b3ac9d | ||
|
|
2f3c279705 | ||
|
|
2ecc74a483 | ||
|
|
c8079b3a7f | ||
|
|
26dd901d0f | ||
|
|
f764502c7a | ||
|
|
ce0397d09e | ||
|
|
d077a8243c | ||
|
|
6b9fd8fcdd | ||
|
|
8f42d1f059 | ||
|
|
b5d0281461 | ||
|
|
c7b1321147 | ||
|
|
1b1b987435 | ||
|
|
ec77b5ed5e | ||
|
|
57ead1a3bf | ||
|
|
e9270a961d | ||
|
|
ba617de004 | ||
|
|
91d97a0b1a | ||
|
|
4de98d3662 | ||
|
|
4ec8e65591 | ||
|
|
8a8a4c2bd8 | ||
|
|
d19a628897 | ||
|
|
9a91323187 | ||
|
|
282068b309 | ||
|
|
4c6a87d9d8 | ||
|
|
c0ec425dc7 | ||
|
|
b6a4d8ebb8 | ||
|
|
e53283cf44 | ||
|
|
ea28095073 | ||
|
|
a5b4306213 | ||
|
|
471c416ab4 | ||
|
|
96bb9f09bd | ||
|
|
cdb24f7613 | ||
|
|
2d499c6bbc | ||
|
|
315aec6333 | ||
|
|
d1c0cd9f6f | ||
|
|
3e60a05ae0 | ||
|
|
3fbd7982d1 | ||
|
|
aaf73abee5 | ||
|
|
7522dbfc24 | ||
|
|
9eaba0a755 | ||
|
|
adc82c809c | ||
|
|
b7d2b0ff40 | ||
|
|
18b69b1710 | ||
|
|
9371b32b8f | ||
|
|
c5629a5fa2 | ||
|
|
738a5883b4 | ||
|
|
11415c896b | ||
|
|
22e44057fb | ||
|
|
5d747d910d | ||
|
|
02d0576e96 | ||
|
|
a042ff567b | ||
|
|
608759c776 | ||
|
|
378cacf83f | ||
|
|
45943b5539 | ||
|
|
0f4a6e077c | ||
|
|
8b2ae445b5 | ||
|
|
50ddc20910 | ||
|
|
4f0bd7c846 | ||
|
|
ca241d950a | ||
|
|
7b0fb58bea | ||
|
|
824dca69cf | ||
|
|
74d5d3104e | ||
|
|
4b9f13c0f4 | ||
|
|
b02d9a99da | ||
|
|
969499f462 | ||
|
|
5276736d37 | ||
|
|
b0a1de5953 | ||
|
|
c465c85e93 | ||
|
|
ee1333caf3 | ||
|
|
5b8826a506 | ||
|
|
f63c34bb04 | ||
|
|
76e5c5e841 | ||
|
|
9151f5fb62 | ||
|
|
4207b52d20 | ||
|
|
16bfe80387 | ||
|
|
0636c493a0 | ||
|
|
852418ee23 | ||
|
|
eb4974fa34 | ||
|
|
56d7b1edfb | ||
|
|
3eedfe890b | ||
|
|
331dc0619f | ||
|
|
55db39cd71 | ||
|
|
5604b25cb2 | ||
|
|
788247e353 | ||
|
|
3fe4b1af49 | ||
|
|
7789451766 | ||
|
|
eb2b1ea4ce | ||
|
|
fd3a18daf1 | ||
|
|
ef77b71a16 | ||
|
|
644f8b5484 | ||
|
|
a83254e1ae | ||
|
|
1036799e11 | ||
|
|
63b9dbf422 | ||
|
|
942e2a9187 | ||
|
|
1da832e30c | ||
|
|
45b25bf5e1 | ||
|
|
467b35abcf | ||
|
|
6801ae388e | ||
|
|
2dfa5c9aeb | ||
|
|
08647195a6 | ||
|
|
ac5c971d7b | ||
|
|
764056f986 | ||
|
|
1164474d05 | ||
|
|
9181a635d3 | ||
|
|
c5e152b82c | ||
|
|
e6ab05e32f | ||
|
|
bd9e8e9fd9 | ||
|
|
90f0004983 | ||
|
|
9c0c45f5a9 | ||
|
|
b2ddb0be44 | ||
|
|
88919ae68e | ||
|
|
b9ca46bb20 | ||
|
|
3e7f99a66a | ||
|
|
86148edec9 | ||
|
|
cce1c37496 | ||
|
|
29418ef4a3 | ||
|
|
43779c891e | ||
|
|
c4c483248b | ||
|
|
64de5703d0 | ||
|
|
19b5e9b80c | ||
|
|
3b43fe35be | ||
|
|
28d8f6de54 | ||
|
|
628c10478a | ||
|
|
8becc718f6 | ||
|
|
2b8773cbf5 | ||
|
|
86c4d30dc5 | ||
|
|
a2ef85e4cd | ||
|
|
98fb62cff4 | ||
|
|
90cf763c07 | ||
|
|
c02aeece32 | ||
|
|
334ba984cd | ||
|
|
dd9ffb7027 | ||
|
|
e7424052a5 | ||
|
|
49f8901541 | ||
|
|
3cb43ae2ea | ||
|
|
c1c57e314a | ||
|
|
727c9e81b8 | ||
|
|
630d03ce9c | ||
|
|
f6609baab2 | ||
|
|
d0db787758 | ||
|
|
92f4ffa0f5 | ||
|
|
7ebfb1f134 | ||
|
|
085096295d | ||
|
|
d6bb021295 | ||
|
|
5f88eb5597 | ||
|
|
2f08d97a2d | ||
|
|
4b7cb00fc6 | ||
|
|
07626029a8 | ||
|
|
3b43518888 | ||
|
|
8255e53e1b | ||
|
|
e7fdf5730f | ||
|
|
4210dd496b | ||
|
|
51fd856a4b | ||
|
|
ccbe5fb215 | ||
|
|
89f79bde10 | ||
|
|
b67718fb63 | ||
|
|
0b6beef55a | ||
|
|
2246606178 | ||
|
|
1fb2132418 | ||
|
|
523e12de93 | ||
|
|
3d856a5353 | ||
|
|
202d2881cf | ||
|
|
3912444abe | ||
|
|
a9f734fc60 | ||
|
|
ffaa1c17ff | ||
|
|
9b0c069a1c | ||
|
|
73aad46b22 | ||
|
|
144323ec02 | ||
|
|
1c6278ce49 | ||
|
|
e36df287e1 | ||
|
|
c66bbb7f4e | ||
|
|
938bf86849 | ||
|
|
91dc3d35b0 | ||
|
|
a912d6c647 | ||
|
|
bea61d4903 | ||
|
|
e7f221888d | ||
|
|
50c896f159 | ||
|
|
0cb9269d97 | ||
|
|
26a9e0efc5 | ||
|
|
07854ef9e5 | ||
|
|
100b494f6b | ||
|
|
e39391915d | ||
|
|
b79fcd0e65 | ||
|
|
e5b51395bc | ||
|
|
4e1292012b | ||
|
|
6ee8312080 | ||
|
|
7e05310f96 | ||
|
|
8592add469 | ||
|
|
08a26b7387 | ||
|
|
d8e67f7ae4 | ||
|
|
58c39e596e | ||
|
|
14aa53e53c | ||
|
|
628aba76db | ||
|
|
22069ef959 | ||
|
|
8f4bf3dae8 | ||
|
|
cba9a5a61e | ||
|
|
f91e0dc434 | ||
|
|
0f92f7fc4c | ||
|
|
03b5422555 | ||
|
|
b8c5a900fa | ||
|
|
bf1b6ec703 | ||
|
|
a5c755d3d6 | ||
|
|
0f2a4e302d | ||
|
|
e10cbfb7d6 | ||
|
|
9b19bf8908 | ||
|
|
40796f3bd3 | ||
|
|
673e217c46 | ||
|
|
e76903361a | ||
|
|
c8d80e268c | ||
|
|
70e50d858a | ||
|
|
d6dc3036f8 | ||
|
|
57181e614f | ||
|
|
7525f5fb11 | ||
|
|
decdbf1b2b | ||
|
|
6d81b9cd59 | ||
|
|
3d72bc7afb | ||
|
|
3b4140d834 | ||
|
|
3b3509cbcd | ||
|
|
566521658c | ||
|
|
0e6945b15d | ||
|
|
05b6754afd | ||
|
|
2d60a14d66 | ||
|
|
80d75441b7 | ||
|
|
94fd53116f | ||
|
|
614e10afb8 | ||
|
|
6c31b0c53a | ||
|
|
d16df23b3b | ||
|
|
6e1aa04b46 | ||
|
|
f8efcc7b38 | ||
|
|
fdcbbf8e7b | ||
|
|
404973babe | ||
|
|
84bdd9abaf | ||
|
|
413ca96773 | ||
|
|
c11069265f | ||
|
|
ad0eb8d096 | ||
|
|
d0d42b6eec | ||
|
|
4c41ac12a7 | ||
|
|
075d7057d7 | ||
|
|
447d6cdfcd | ||
|
|
fb37f21c31 | ||
|
|
763580f91e | ||
|
|
394855383b | ||
|
|
1cd9316bc3 | ||
|
|
d32d141529 | ||
|
|
de920ac150 | ||
|
|
866b1e0113 | ||
|
|
dbba56a09c | ||
|
|
1cf395a4cc | ||
|
|
8dde360020 | ||
|
|
f1ce7219af | ||
|
|
94af7ce215 | ||
|
|
18dedac1c5 | ||
|
|
3d0bf48be2 | ||
|
|
73a675a800 | ||
|
|
202ea3bea9 | ||
|
|
766e2ead0b | ||
|
|
cc2f524f35 | ||
|
|
85b6de49bd | ||
|
|
5efb530785 | ||
|
|
9c105875b1 | ||
|
|
a12517132e | ||
|
|
6fa4fb6a6f | ||
|
|
4a1b980d48 | ||
|
|
be09cc83f5 | ||
|
|
4403f312bb | ||
|
|
b67b6f807a | ||
|
|
fbf8524aab | ||
|
|
88a8394db3 | ||
|
|
2b1bb04dbb | ||
|
|
95640e4164 | ||
|
|
914c1f0e5f | ||
|
|
4d033e5122 | ||
|
|
3e4615c942 | ||
|
|
0a131611fd | ||
|
|
2cef8ad8b9 | ||
|
|
f0a567a171 | ||
|
|
f266dcba73 | ||
|
|
0051ec2742 | ||
|
|
6e6997fef4 | ||
|
|
5f16afcb71 | ||
|
|
0cd43754bc | ||
|
|
75e66d5509 | ||
|
|
2e4ed0601e | ||
|
|
4cc46beb1b | ||
|
|
70d559d6f6 | ||
|
|
3aa2e27526 | ||
|
|
c20fe8ff94 | ||
|
|
4bb171cd6c | ||
|
|
4ebd2ab15f | ||
|
|
01502af789 | ||
|
|
f9888a9534 | ||
|
|
4cd851aa31 | ||
|
|
4513164f40 | ||
|
|
0a6eb1ba2d | ||
|
|
f8573595f9 | ||
|
|
d44a590f41 | ||
|
|
fff193d244 | ||
|
|
ec5c79fd62 | ||
|
|
514f048e06 | ||
|
|
3b4100a657 | ||
|
|
c8b57fb8cd | ||
|
|
a742565d56 | ||
|
|
abfa76c71d | ||
|
|
90106f134c | ||
|
|
09d51006f1 | ||
|
|
72ce1ac22a | ||
|
|
4102b030c0 | ||
|
|
37d9e2b8eb | ||
|
|
008064559d | ||
|
|
5ac3296195 | ||
|
|
68fb20bc48 | ||
|
|
bc361ee747 | ||
|
|
66cae3acf4 | ||
|
|
c704cf32ea | ||
|
|
6f5e0aa144 | ||
|
|
c10531426f | ||
|
|
188b998d8f | ||
|
|
93b4939cc0 | ||
|
|
fe60560451 | ||
|
|
3ab7370d47 | ||
|
|
aac4a15c56 | ||
|
|
510c5c99d3 | ||
|
|
81674a6871 | ||
|
|
0c99895c13 | ||
|
|
a0d52ad5e1 | ||
|
|
462e6717f8 | ||
|
|
2ef83d5085 | ||
|
|
1501e29ca3 | ||
|
|
0b4554e895 | ||
|
|
10acff9bbf | ||
|
|
61e8a2bb86 | ||
|
|
712e4a1f9c | ||
|
|
7ada7d2c31 | ||
|
|
ae42a84e4b | ||
|
|
e637fbe374 | ||
|
|
7028dfb41f | ||
|
|
f00e8e7dd8 | ||
|
|
1cb0471c2f | ||
|
|
bed6017e12 | ||
|
|
420fd5dc9b | ||
|
|
789641007e | ||
|
|
8bbdf49b38 | ||
|
|
b22eeda7e1 | ||
|
|
05d701196c | ||
|
|
2bb7e1367e | ||
|
|
a5b8f4ee6c | ||
|
|
2db3f2ce6d | ||
|
|
c272eb1bfe | ||
|
|
7dcea00188 | ||
|
|
437ae82578 | ||
|
|
f8ac797fe4 | ||
|
|
897b14d502 | ||
|
|
7d3cef3a83 | ||
|
|
59ab565798 | ||
|
|
5d81ea82e7 | ||
|
|
095c783529 | ||
|
|
8af23535d8 | ||
|
|
ee1e59e993 | ||
|
|
7f81b5e1f3 | ||
|
|
d2548f0ead | ||
|
|
d1524dd4d9 | ||
|
|
f768c7dc19 | ||
|
|
d3d6a508ad | ||
|
|
0ca25232b1 | ||
|
|
cdabb773ed | ||
|
|
f6b277bf9f | ||
|
|
eb32de8935 | ||
|
|
771379ad5d | ||
|
|
1d76501744 | ||
|
|
ce8bf01bfa | ||
|
|
819e0b9f8e | ||
|
|
cfac39da5f | ||
|
|
e68b1f4c03 | ||
|
|
65a79f0574 | ||
|
|
3be08c1ef3 | ||
|
|
7b5e5dca23 | ||
|
|
c951f60b55 | ||
|
|
d51c0e6f39 | ||
|
|
d3753ddf33 | ||
|
|
0800800e9f | ||
|
|
19c692298d | ||
|
|
8e74140a0d | ||
|
|
074b50fcbb | ||
|
|
e6a5d8f3a7 | ||
|
|
126fdd1ce9 | ||
|
|
ed25f647dd | ||
|
|
69e9ac9648 | ||
|
|
3f96670794 | ||
|
|
9fe40a263d | ||
|
|
9cddbe3923 | ||
|
|
547ad7675a | ||
|
|
125be24d40 | ||
|
|
c7827a4bc4 | ||
|
|
1f2a1da1bb | ||
|
|
943d97c763 | ||
|
|
03ff090163 | ||
|
|
75720b97f8 | ||
|
|
e483a91743 | ||
|
|
9b29aed3b1 | ||
|
|
86b6d45114 | ||
|
|
f627d7b6ef | ||
|
|
57ef5f7e6e | ||
|
|
92598321eb | ||
|
|
4ef4c0ee7a | ||
|
|
43fd4e06ff | ||
|
|
ac2b2b0d5d | ||
|
|
4f07b63746 | ||
|
|
c858934817 | ||
|
|
936694fa64 | ||
|
|
691e8ba282 | ||
|
|
45fb892a1b | ||
|
|
6ad75a1578 | ||
|
|
462db2da85 | ||
|
|
9e3e4dacbf | ||
|
|
7f78c81fae | ||
|
|
aaa32c0534 | ||
|
|
62d4bf4435 | ||
|
|
425ce08589 | ||
|
|
a860e58ad4 | ||
|
|
77719dc8bb | ||
|
|
d43ab4e793 | ||
|
|
dfd95cccff | ||
|
|
59e39a7c40 | ||
|
|
7c19a20cfe | ||
|
|
480ed3e7a5 | ||
|
|
24527fa7aa | ||
|
|
b396d8f6ab | ||
|
|
cf37ff7f5b | ||
|
|
bf31653f59 | ||
|
|
29cee80072 | ||
|
|
ed45ebc15c | ||
|
|
768275cbe8 | ||
|
|
22fd395267 | ||
|
|
f9af8b1823 | ||
|
|
1fd1677516 | ||
|
|
7f6f286243 | ||
|
|
53e4547ea0 | ||
|
|
8ed260d579 | ||
|
|
d8adc4657f | ||
|
|
06480e4164 | ||
|
|
a9346002c3 | ||
|
|
ae57d7178a | ||
|
|
edc9f2268e | ||
|
|
c5366cba8b | ||
|
|
1f76e0892e | ||
|
|
92f048d335 | ||
|
|
8d11e2cf9c | ||
|
|
a2c664f93b | ||
|
|
3c34a443f3 | ||
|
|
e136c17ff5 | ||
|
|
3e11089624 | ||
|
|
f20fa8500a | ||
|
|
dae1efdf77 | ||
|
|
79724e5ed6 | ||
|
|
db23406e3f | ||
|
|
2437dc792f | ||
|
|
f1a1456c48 | ||
|
|
578fc302f0 | ||
|
|
0ceb4d1ef9 | ||
|
|
2344872b3c | ||
|
|
6e1d17a771 | ||
|
|
12981c8853 | ||
|
|
cf7b675108 | ||
|
|
5417fe24f0 | ||
|
|
cf1488e2bb | ||
|
|
9cdbaf37b3 | ||
|
|
96b565743e | ||
|
|
dcca3610cb | ||
|
|
3bd18b1f53 | ||
|
|
744ea55733 | ||
|
|
1b0040e195 | ||
|
|
87d3d47419 | ||
|
|
75f83de788 | ||
|
|
0fe06658db | ||
|
|
0977c45d3a | ||
|
|
a109fbf221 | ||
|
|
2a8a8d421b | ||
|
|
f4854de58f | ||
|
|
62f4257bcd | ||
|
|
40cec9b101 | ||
|
|
a26451296c | ||
|
|
dfede2ffc3 | ||
|
|
32d7bc7370 | ||
|
|
4973077a20 | ||
|
|
e36a828ed0 | ||
|
|
e8ac912600 | ||
|
|
71fdf2f829 | ||
|
|
8885f2dceb | ||
|
|
9db1581b83 | ||
|
|
fc19c259f8 | ||
|
|
52fea44ca0 | ||
|
|
d37b9e8fc8 | ||
|
|
173fdf2fbb | ||
|
|
dadbdf8ecb | ||
|
|
a5e97854ee | ||
|
|
c43e37f76f | ||
|
|
332a9f1f0a | ||
|
|
5fadbd78f2 | ||
|
|
ee00e4a853 | ||
|
|
585787bb51 | ||
|
|
db10f0a088 | ||
|
|
783d6e3d52 | ||
|
|
b8b6ece4ad | ||
|
|
d01b0817d4 | ||
|
|
ca3a23f04c | ||
|
|
7982c7d9e3 | ||
|
|
464481beb2 | ||
|
|
e035fa2639 | ||
|
|
2dacca93ed | ||
|
|
6981bfe333 | ||
|
|
6d6eb1a5c5 | ||
|
|
3f7dc57048 | ||
|
|
0d8709d1ab | ||
|
|
cecb79e2f0 | ||
|
|
372d126996 | ||
|
|
233f5f6849 | ||
|
|
a807f20224 | ||
|
|
6adc4c7b4b | ||
|
|
b51430fa5a | ||
|
|
a954003c76 | ||
|
|
16be0690a5 | ||
|
|
fa112138ed | ||
|
|
93ffe47acd | ||
|
|
cedd92b914 | ||
|
|
d8bf9ad55c | ||
|
|
d103946ed9 | ||
|
|
83166325ce | ||
|
|
4f6f334beb | ||
|
|
ab96e1b3b9 | ||
|
|
ec3a1c1f8f | ||
|
|
f03d54d35b | ||
|
|
a956b9b23e | ||
|
|
1f23a1e088 | ||
|
|
fbf218714f | ||
|
|
a67703442c | ||
|
|
1bac31ffa9 | ||
|
|
bc58a4ca43 | ||
|
|
374041d3a4 | ||
|
|
dcb04f213b | ||
|
|
aae3d3d78c | ||
|
|
dc2c11dee0 | ||
|
|
f2b4fd8406 | ||
|
|
276cc39b41 | ||
|
|
7cd9a7329e | ||
|
|
53e0225bf1 | ||
|
|
ec741c5fd7 | ||
|
|
96799b0040 | ||
|
|
75b263e97e | ||
|
|
0bec87e2cb | ||
|
|
9b2f950dcd | ||
|
|
489ecc5d42 | ||
|
|
6dd266519d | ||
|
|
beea372687 | ||
|
|
e96ec02814 | ||
|
|
240d4a9ebe | ||
|
|
74ba5c2480 | ||
|
|
54ad6831c0 | ||
|
|
b3ac00301d | ||
|
|
29120a7b07 | ||
|
|
ad54b19310 | ||
|
|
509935aca5 | ||
|
|
44f9ef934c | ||
|
|
27e7239297 | ||
|
|
7e0cc9db3a | ||
|
|
3368c7d64b | ||
|
|
70ce6f910e | ||
|
|
cb5d1585d7 | ||
|
|
b5fc65388b | ||
|
|
dcdd184401 | ||
|
|
83e18d7b02 | ||
|
|
d76f616206 | ||
|
|
b8982574c7 | ||
|
|
d3e30943bb | ||
|
|
a88aab0af5 | ||
|
|
4301cf996b | ||
|
|
5cf1a7cac5 | ||
|
|
84ad3df5c4 | ||
|
|
11f81e3619 | ||
|
|
d7c944f8f1 | ||
|
|
034abbca03 | ||
|
|
179328d98d | ||
|
|
04b0eb0baf | ||
|
|
034437b6a1 | ||
|
|
ed8223f20e | ||
|
|
a04421075c | ||
|
|
239509b460 | ||
|
|
034a7a7170 | ||
|
|
30761541dd | ||
|
|
79fd004d9e | ||
|
|
7fc6df5b42 | ||
|
|
916ce9f185 | ||
|
|
42cd3cd72a | ||
|
|
51058a6fcd | ||
|
|
a9277273e6 | ||
|
|
bff4590fcd | ||
|
|
827981fe67 | ||
|
|
685f1bc182 | ||
|
|
4d939cfce9 | ||
|
|
8fe086b809 | ||
|
|
c07c056347 | ||
|
|
146b442cc8 | ||
|
|
60f3eed59f | ||
|
|
55319e5146 | ||
|
|
48966a79ba | ||
|
|
61d5c39f00 | ||
|
|
de574430ac | ||
|
|
4802aecff8 | ||
|
|
d8fb18e771 | ||
|
|
eec2114d61 | ||
|
|
65fe2b987d | ||
|
|
cce67ee39e | ||
|
|
44e418e8ed | ||
|
|
fdf67edb4f | ||
|
|
99759d128b | ||
|
|
b35dd72017 | ||
|
|
5a4055e23b | ||
|
|
4d946bdce2 | ||
|
|
e2c4c4e2ba | ||
|
|
d8129622ce | ||
|
|
a10c34dea8 | ||
|
|
4e4a7e5a6c | ||
|
|
6ed925064d | ||
|
|
26614d12a1 | ||
|
|
79d7528d24 | ||
|
|
88831f6c44 | ||
|
|
101401600b | ||
|
|
928d1cbe4e | ||
|
|
4929cc1911 | ||
|
|
1c23f29d9e | ||
|
|
a037ab9b2a | ||
|
|
d8f11cdd6d | ||
|
|
bf8c5331c4 | ||
|
|
f828a46405 | ||
|
|
a2e4807b0a | ||
|
|
57377b17f3 | ||
|
|
b12c69608f | ||
|
|
f5239a10b2 | ||
|
|
2410991813 | ||
|
|
6e0ed1ab59 | ||
|
|
1ac35bdc83 | ||
|
|
ff2f193237 | ||
|
|
987b6f19ab | ||
|
|
83057cb187 | ||
|
|
35f1da6f6d | ||
|
|
e0a8653c20 | ||
|
|
d724b4ca83 | ||
|
|
2639ebbe41 | ||
|
|
94cb07404e | ||
|
|
238bd90bc3 | ||
|
|
6b2b357e5e | ||
|
|
28d960d701 | ||
|
|
aad13b0ccf | ||
|
|
008ab901af | ||
|
|
4051665fec | ||
|
|
f9ed8f46c3 | ||
|
|
9ecf7c4fe5 | ||
|
|
030cd8bec6 | ||
|
|
7440b239b7 | ||
|
|
9901118304 | ||
|
|
5ca5f7c46a | ||
|
|
49804569c0 | ||
|
|
274806fc17 | ||
|
|
9fc46744ce | ||
|
|
b847ba2c04 | ||
|
|
b9ee22223a | ||
|
|
80b59cb417 | ||
|
|
f5a417e93b | ||
|
|
e7869352b5 | ||
|
|
514b4b3045 | ||
|
|
5a9e99fb22 | ||
|
|
d893917454 | ||
|
|
3ff4c6dee4 | ||
|
|
ac8f1b1cb2 | ||
|
|
94a45b526a | ||
|
|
e9a82745cd | ||
|
|
3f59822eec | ||
|
|
1f11342d51 | ||
|
|
5c6793b6fe | ||
|
|
03909a8473 | ||
|
|
f60bb0579c | ||
|
|
7e35f1312a | ||
|
|
0d7e5d4449 | ||
|
|
6e35194d9c | ||
|
|
9c16ebe5dc | ||
|
|
da8c021bfa | ||
|
|
8becae8e3c | ||
|
|
cfac08f7ce | ||
|
|
76a3883301 | ||
|
|
5482059c8a | ||
|
|
bb5388541d | ||
|
|
d82f2ccafe | ||
|
|
d054c14716 | ||
|
|
541003e05e | ||
|
|
8c61b4b02c | ||
|
|
c176330285 | ||
|
|
d7f8d8b02b | ||
|
|
7ede88263a | ||
|
|
47c1c98b34 | ||
|
|
8a43b47335 | ||
|
|
cb12572b18 | ||
|
|
a458c9489d | ||
|
|
0d435d55d1 | ||
|
|
731161ad5c | ||
|
|
422e56eea1 | ||
|
|
897927bfdf | ||
|
|
6bc5240db9 | ||
|
|
e3bd0634b0 | ||
|
|
1ea4bc42b0 | ||
|
|
e20267c626 | ||
|
|
8ab4c733af | ||
|
|
de315025f3 | ||
|
|
331bac16ae | ||
|
|
2c7651e44e | ||
|
|
3bee69bbdb | ||
|
|
92663b8b13 | ||
|
|
b865ccf51d | ||
|
|
f3964cd922 | ||
|
|
26598efcf3 | ||
|
|
6197177ce0 | ||
|
|
26ec9b8fb7 | ||
|
|
412da2af5b | ||
|
|
1db4f303a8 | ||
|
|
4708741f82 | ||
|
|
b43ec15426 | ||
|
|
d83388d6f7 | ||
|
|
7514c8f433 | ||
|
|
fecde264fc | ||
|
|
7956389305 | ||
|
|
cf97d62be3 | ||
|
|
1295582194 | ||
|
|
bc9c479a78 | ||
|
|
c7c597e96c | ||
|
|
3ebf6736f3 | ||
|
|
d41d59867d | ||
|
|
423954354d | ||
|
|
5b7f8030e5 | ||
|
|
87f4a03160 | ||
|
|
1364839214 | ||
|
|
c8bebc6867 | ||
|
|
63ce1849e7 | ||
|
|
1239b9ea12 | ||
|
|
e04fddca5a | ||
|
|
e2fec37605 | ||
|
|
83c24e0e2e | ||
|
|
0fb24ddf1b | ||
|
|
7e301e24fd | ||
|
|
373f90224a | ||
|
|
8f757023c3 | ||
|
|
9feabd3c31 | ||
|
|
af12a38d50 | ||
|
|
b4eca79724 | ||
|
|
b62d7835b7 | ||
|
|
e35a4a6ac1 | ||
|
|
880f660f23 | ||
|
|
3394dfcbcd | ||
|
|
7164441459 | ||
|
|
c81cf3d2b3 | ||
|
|
1178a85204 | ||
|
|
1c485313e4 | ||
|
|
2ccf5036a4 | ||
|
|
2aa82363b2 | ||
|
|
b773be076b | ||
|
|
b05ca7db8d | ||
|
|
5fa49e7ab9 | ||
|
|
5591410077 | ||
|
|
4d0e2d026c | ||
|
|
6ed9a7523a | ||
|
|
816c24f0d0 | ||
|
|
0c11526b8c | ||
|
|
0733be5a5b | ||
|
|
edf44b84d0 | ||
|
|
e7f8c6aed4 | ||
|
|
359f6c3e15 | ||
|
|
26732b87fc | ||
|
|
441d2010f4 | ||
|
|
938975f241 | ||
|
|
ec076102e0 | ||
|
|
4bf42a1327 | ||
|
|
91c681feba | ||
|
|
a9b13dbb4f | ||
|
|
423d1aa96a | ||
|
|
6a483e7b37 | ||
|
|
98c33352f4 | ||
|
|
70785f343b | ||
|
|
41539409fb | ||
|
|
f6d14cd92d | ||
|
|
c078a679a5 | ||
|
|
8fd4ad4b37 | ||
|
|
5b8f0b353a | ||
|
|
39ab6a040a | ||
|
|
921da06a38 | ||
|
|
8f5e2da181 | ||
|
|
26e509e4e5 | ||
|
|
73622e3f0e | ||
|
|
d4b3e0fec4 | ||
|
|
7922e15c72 | ||
|
|
52ac8db808 | ||
|
|
0db7083de8 | ||
|
|
94f65de505 | ||
|
|
f46a73300e | ||
|
|
747adf2887 | ||
|
|
c42c031a23 | ||
|
|
a9cef63a4c | ||
|
|
ecd0eb3f28 | ||
|
|
edb6444dff | ||
|
|
38e7cc0acc | ||
|
|
e43eb19ad2 | ||
|
|
94d8ada147 | ||
|
|
1cac4d41f7 | ||
|
|
c664b1237d | ||
|
|
13a6628962 | ||
|
|
23fbc824d5 | ||
|
|
9a8eb8efa7 | ||
|
|
32c1891d81 | ||
|
|
72f4cd8fb0 | ||
|
|
64f587034b | ||
|
|
3cc7765b35 | ||
|
|
b83dcb3b77 | ||
|
|
84af03fe84 | ||
|
|
7d5c84509a | ||
|
|
84d92986d3 | ||
|
|
f22edac533 | ||
|
|
9cf379a6df | ||
|
|
36db4b6f3a | ||
|
|
45c9fda0e4 | ||
|
|
a7a311b191 | ||
|
|
d90cbe94ea | ||
|
|
4dede745c7 | ||
|
|
b19e12158f | ||
|
|
622e90655b | ||
|
|
b0b5e3cbda | ||
|
|
7f5825119f | ||
|
|
a62043722f | ||
|
|
8ec1af9069 | ||
|
|
8799f15a33 | ||
|
|
0037c691c8 | ||
|
|
024e8bce75 | ||
|
|
34056fc8a9 | ||
|
|
0847a949e7 | ||
|
|
2e6d6f1861 | ||
|
|
37955620a4 | ||
|
|
3e24314858 | ||
|
|
ea2f646036 | ||
|
|
200b6cd6a3 | ||
|
|
a1336d2e13 | ||
|
|
81b6580256 | ||
|
|
c8f7c638e6 | ||
|
|
32ea138180 | ||
|
|
fea96c1b77 | ||
|
|
3901458b59 | ||
|
|
a8f1612822 | ||
|
|
6a5bbc8adb | ||
|
|
9cd783f35a | ||
|
|
5eda51dce5 | ||
|
|
e71a3d4662 | ||
|
|
c73e04d697 | ||
|
|
2b9315ea3f | ||
|
|
f56fc21bb9 | ||
|
|
4a9e586e58 | ||
|
|
48b7d52c5a | ||
|
|
8b9062e462 | ||
|
|
cbf6573160 | ||
|
|
393bc25640 | ||
|
|
76adbbbd05 | ||
|
|
e7e4009f77 | ||
|
|
23fddc3f39 | ||
|
|
102daccd39 | ||
|
|
fc95ce7467 | ||
|
|
7ff85a99c5 | ||
|
|
45102c2e8f | ||
|
|
8af9c215b1 | ||
|
|
bf8a6795c3 | ||
|
|
9675dcb7b7 | ||
|
|
b69dbae446 | ||
|
|
8dda0a5139 | ||
|
|
fd898a77ed | ||
|
|
0011851def | ||
|
|
cd94367b7d | ||
|
|
06d985ae03 | ||
|
|
54ae7eb268 | ||
|
|
e2e0b754af | ||
|
|
faa459e4e6 | ||
|
|
24ff6bbc8e | ||
|
|
df71a0b184 | ||
|
|
5fe880ccf2 | ||
|
|
e2a9e7266a | ||
|
|
d45085b76c | ||
|
|
baca34298e | ||
|
|
fc7a85c741 | ||
|
|
a85bea83eb | ||
|
|
aeacef8abc | ||
|
|
795b33b8b2 | ||
|
|
a1cd72d364 | ||
|
|
ec1507bd2f | ||
|
|
72964bc21f | ||
|
|
c3d95c77b6 | ||
|
|
1f8bab8c9b | ||
|
|
b4751b9705 | ||
|
|
f82fdaa03c | ||
|
|
f8016df255 | ||
|
|
0a0df16088 | ||
|
|
ec0f12b02d | ||
|
|
f9a6bcaa46 | ||
|
|
dec3deaf50 | ||
|
|
45129f5a51 | ||
|
|
e3b2feba38 | ||
|
|
b64aba6675 | ||
|
|
4268bedd3e | ||
|
|
418489936b | ||
|
|
b6b2fe52a2 | ||
|
|
ae628b5555 | ||
|
|
624c061f7a | ||
|
|
acf1a064aa | ||
|
|
24e1478ef3 | ||
|
|
c44dd5ae1e | ||
|
|
f3097b7091 | ||
|
|
cd7c85e9a9 | ||
|
|
bea0a817ba | ||
|
|
420d46277f | ||
|
|
7c2b96be19 | ||
|
|
982b48f145 | ||
|
|
ba48d07d2d | ||
|
|
07a95072a6 | ||
|
|
ffd5bb2458 | ||
|
|
b693e94e3b | ||
|
|
6c27b9e70e | ||
|
|
724701e650 | ||
|
|
8e4a6f47e3 | ||
|
|
e83bcb9cff | ||
|
|
1db79d3560 | ||
|
|
5d96b71283 | ||
|
|
6c70954493 | ||
|
|
5a75099232 | ||
|
|
ef8da5f8e4 | ||
|
|
4786399cc8 | ||
|
|
e2d4ee925a | ||
|
|
ac6584f3ac | ||
|
|
b49c0c3a92 | ||
|
|
76fea07b1f | ||
|
|
64e63aa41b | ||
|
|
68ccd8fa32 | ||
|
|
4d8828f324 | ||
|
|
0e10c60983 | ||
|
|
a3df2108fc | ||
|
|
de03eae234 | ||
|
|
fc4b8a0e8c | ||
|
|
654d629ec6 | ||
|
|
3e1c5fe37a | ||
|
|
35a9f01a2c | ||
|
|
4647ac609b | ||
|
|
fffedda3ad | ||
|
|
b669151a0a | ||
|
|
4c5171dcd4 | ||
|
|
1f7e76fb40 | ||
|
|
cb252668b3 | ||
|
|
d9d992ef13 | ||
|
|
6de7fdbe69 | ||
|
|
3de5672d0d | ||
|
|
ef3d3e87b6 | ||
|
|
8be9bcb95c | ||
|
|
d810e34dac | ||
|
|
3ae3cd344e | ||
|
|
3e7bbd82f3 | ||
|
|
f633ff4d50 | ||
|
|
613b16498a |
@@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
env: {
|
||||
browser: true,
|
||||
es2021: true,
|
||||
|
||||
BIN
.github/AgentListView.png
vendored
Normal file
BIN
.github/AgentListView.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1022 KiB |
BIN
.github/Hero2.png
vendored
Normal file
BIN
.github/Hero2.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 990 KiB |
BIN
.github/KB.png
vendored
Normal file
BIN
.github/KB.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.0 MiB |
BIN
.github/Search2.png
vendored
Normal file
BIN
.github/Search2.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.1 MiB |
29
.github/helpers/install.sh
vendored
29
.github/helpers/install.sh
vendored
@@ -6,11 +6,10 @@ cd ~ || ex
|
||||
|
||||
sudo apt update
|
||||
sudo apt remove mysql-server mysql-client
|
||||
sudo apt install libcups2-dev redis-server mariadb-client-10.6
|
||||
sudo apt install libcups2-dev redis-server mariadb-client libmariadb-dev
|
||||
|
||||
pip install frappe-bench
|
||||
|
||||
git clone "https://github.com/frappe/frappe" --branch "develop" --depth 1
|
||||
git clone "https://github.com/frappe/frappe" --branch "develop" --depth 1
|
||||
bench init --skip-assets --frappe-path ~/frappe --python "$(which python)" frappe-bench
|
||||
|
||||
mkdir ~/frappe-bench/sites/test_site
|
||||
@@ -19,23 +18,20 @@ cp -r "${GITHUB_WORKSPACE}/.github/helpers/site_config_mariadb.json" ~/frappe-be
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE USER 'test_frappe'@'localhost' IDENTIFIED BY 'test_frappe'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "CREATE DATABASE test_frappe"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "GRANT ALL PRIVILEGES ON \`test_frappe\`.* TO 'test_frappe'@'localhost'"
|
||||
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "FLUSH PRIVILEGES"
|
||||
|
||||
install_whktml() {
|
||||
if [ "$(lsb_release -rs)" = "22.04" ]; then
|
||||
wget -O /tmp/wkhtmltox.deb https://github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.jammy_amd64.deb
|
||||
sudo apt install /tmp/wkhtmltox.deb
|
||||
else
|
||||
echo "Please update this script to support wkhtmltopdf for $(lsb_release -ds)"
|
||||
exit 1
|
||||
fi
|
||||
wget -O /tmp/wkhtmltox.tar.xz https://github.com/frappe/wkhtmltopdf/raw/master/wkhtmltox-0.12.3_linux-generic-amd64.tar.xz
|
||||
tar -xf /tmp/wkhtmltox.tar.xz -C /tmp
|
||||
sudo mv /tmp/wkhtmltox/bin/wkhtmltopdf /usr/local/bin/wkhtmltopdf
|
||||
sudo chmod o+x /usr/local/bin/wkhtmltopdf
|
||||
}
|
||||
install_whktml &
|
||||
wkpid=$!
|
||||
|
||||
|
||||
cd ~/frappe-bench || exit
|
||||
|
||||
@@ -44,11 +40,16 @@ sed -i 's/schedule:/# schedule:/g' Procfile
|
||||
sed -i 's/socketio:/# socketio:/g' Procfile
|
||||
sed -i 's/redis_socketio:/# redis_socketio:/g' Procfile
|
||||
|
||||
bench get-app erpnext --branch "develop"
|
||||
bench get-app telephony
|
||||
bench get-app helpdesk "${GITHUB_WORKSPACE}"
|
||||
bench setup requirements --dev
|
||||
|
||||
wait $wkpid
|
||||
|
||||
bench start &> bench_run_logs.txt &
|
||||
bench start &>> ~/frappe-bench/bench_start.log &
|
||||
CI=Yes bench build --app frappe &
|
||||
bench --site test_site reinstall --yes
|
||||
|
||||
bench --verbose --site test_site install-app erpnext
|
||||
bench --verbose --site test_site install-app telephony
|
||||
bench --verbose --site test_site install-app helpdesk
|
||||
|
||||
41
.github/helpers/update_pot_file.sh
vendored
Normal file
41
.github/helpers/update_pot_file.sh
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
cd ~ || exit
|
||||
|
||||
echo "Setting Up Bench..."
|
||||
|
||||
pip install frappe-bench
|
||||
bench -v init frappe-bench --skip-assets --skip-redis-config-generation --python "$(which python)" --frappe-branch develop
|
||||
|
||||
cd ./frappe-bench || exit
|
||||
|
||||
echo "Get Helpdesk..."
|
||||
bench get-app --skip-assets helpdesk "${GITHUB_WORKSPACE}"
|
||||
|
||||
echo "Generating POT file..."
|
||||
bench generate-pot-file --app helpdesk
|
||||
|
||||
cd ./apps/helpdesk || exit
|
||||
|
||||
echo "Configuring git user..."
|
||||
git config user.email "developers@erpnext.com"
|
||||
git config user.name "frappe-pr-bot"
|
||||
|
||||
echo "Setting the correct git remote..."
|
||||
# Here, the git remote is a local file path by default. Let's change it to the upstream repo.
|
||||
git remote set-url upstream https://github.com/frappe/helpdesk.git
|
||||
|
||||
echo "Creating a new branch..."
|
||||
isodate=$(date -u +"%Y-%m-%d")
|
||||
branch_name="pot_${BASE_BRANCH}_${isodate}"
|
||||
git checkout -b "${branch_name}"
|
||||
|
||||
echo "Commiting changes..."
|
||||
git add helpdesk/locale/main.pot
|
||||
git commit -m "chore: update POT file"
|
||||
|
||||
gh auth setup-git
|
||||
git push -u upstream "${branch_name}"
|
||||
|
||||
echo "Creating a PR..."
|
||||
gh pr create --fill --base "${BASE_BRANCH}" --head "${branch_name}" -R frappe/helpdesk
|
||||
15
.github/release.yml
vendored
15
.github/release.yml
vendored
@@ -1,15 +0,0 @@
|
||||
changelog:
|
||||
exclude:
|
||||
authors:
|
||||
- octocat
|
||||
categories:
|
||||
- title: Breaking Changes 🛠
|
||||
labels:
|
||||
- breaking-change
|
||||
- title: Bug Fixes 🐛
|
||||
labels:
|
||||
- bug-fix
|
||||
- title: Exciting New Features 🎉
|
||||
labels:
|
||||
- enhancement
|
||||
- feature
|
||||
15
.github/workflows/assets.yml
vendored
Normal file
15
.github/workflows/assets.yml
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
name: Pre-build assets
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [develop, main]
|
||||
|
||||
jobs:
|
||||
assets:
|
||||
name: Pre-build assets
|
||||
uses: frappe/pilot/.github/workflows/app-assets.yml@develop
|
||||
with:
|
||||
# main supports Frappe v15 and v16; Pilot benches run v16 or later.
|
||||
frappe-branch: ${{ github.ref_name == 'main' && 'version-16' || 'develop' }}
|
||||
permissions:
|
||||
contents: write
|
||||
68
.github/workflows/build.yml
vendored
Normal file
68
.github/workflows/build.yml
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
name: Build Container Image
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
permissions:
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout Entire Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v2
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Set Branch
|
||||
run: |
|
||||
echo '[{"url": "https://github.com/frappe/telephony","branch": "develop"},{"url": "https://github.com/frappe/helpdesk","branch": "main"}]' > apps.json
|
||||
echo "FRAPPE_BRANCH=version-15" >> $GITHUB_ENV
|
||||
|
||||
- name: Set Image Tag
|
||||
run: |
|
||||
echo "IMAGE_TAG=stable" >> $GITHUB_ENV
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
repository: frappe/frappe_docker
|
||||
path: builds
|
||||
|
||||
- name: Build
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
load: true
|
||||
context: builds
|
||||
file: builds/images/layered/Containerfile
|
||||
tags: >
|
||||
ghcr.io/${{ github.repository }}:${{ github.ref_name }},
|
||||
ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }}
|
||||
build-args: |
|
||||
"FRAPPE_BRANCH=${{ env.FRAPPE_BRANCH }}"
|
||||
secret-files: |
|
||||
apps_json=apps.json
|
||||
|
||||
- name: Verify apps are installed
|
||||
run: |
|
||||
apps=$(docker run --rm --entrypoint ls ghcr.io/${{ github.repository }}:${{ env.IMAGE_TAG }} apps)
|
||||
echo "$apps"
|
||||
grep -qx helpdesk <<< "$apps" && grep -qx telephony <<< "$apps"
|
||||
|
||||
- name: Push
|
||||
run: docker push --all-tags ghcr.io/${{ github.repository }}
|
||||
40
.github/workflows/generate-pot-file.yml
vendored
Normal file
40
.github/workflows/generate-pot-file.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
name: Regenerate POT file (translatable strings)
|
||||
on:
|
||||
schedule:
|
||||
# 9:30 UTC => 4 PM IST Sunday
|
||||
- cron: "30 10 * * 0"
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
regenerate-pot-file:
|
||||
name: Regenerate POT file
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
branch: ["develop", "main-hotfix"]
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ matrix.branch }}
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Run script to update POT file
|
||||
run: |
|
||||
bash ${GITHUB_WORKSPACE}/.github/helpers/update_pot_file.sh
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
BASE_BRANCH: ${{ matrix.branch }}
|
||||
7
.github/workflows/lint.yml
vendored
7
.github/workflows/lint.yml
vendored
@@ -4,6 +4,7 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- main-hotfix
|
||||
- develop
|
||||
|
||||
jobs:
|
||||
@@ -16,7 +17,7 @@ jobs:
|
||||
fetch-depth: 200
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
check-latest: true
|
||||
- name: Check commit titles
|
||||
run: |
|
||||
@@ -34,10 +35,10 @@ jobs:
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: '3.10'
|
||||
python-version: '3.14'
|
||||
|
||||
- name: Install and Run Pre-commit
|
||||
uses: pre-commit/action@v2.0.3
|
||||
uses: pre-commit/action@v3.0.1
|
||||
|
||||
- name: Download Semgrep rules
|
||||
run: git clone --depth 1 https://github.com/frappe/semgrep-rules.git frappe-semgrep-rules
|
||||
|
||||
32
.github/workflows/on_release.yml
vendored
Normal file
32
.github/workflows/on_release.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
name: Generate Semantic Release
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
release:
|
||||
name: Release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Entire Repository
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
persist-credentials: false
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
- name: Setup dependencies
|
||||
run: |
|
||||
npm install @semantic-release/git @semantic-release/exec --no-save
|
||||
- name: Create Release
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
GIT_AUTHOR_NAME: "Frappe PR Bot"
|
||||
GIT_AUTHOR_EMAIL: "developers@frappe.io"
|
||||
GIT_COMMITTER_NAME: "Frappe PR Bot"
|
||||
GIT_COMMITTER_EMAIL: "developers@frappe.io"
|
||||
run: npx semantic-release
|
||||
40
.github/workflows/release.yml
vendored
Normal file
40
.github/workflows/release.yml
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
# This action:
|
||||
#
|
||||
# 1. Generates release notes using github API.
|
||||
# 2. Strips unnecessary info like chore/style etc from notes.
|
||||
# 3. Updates release info.
|
||||
|
||||
name: 'Release Notes'
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
tag_name:
|
||||
description: 'Tag of release like v1.0.0'
|
||||
required: true
|
||||
type: string
|
||||
release:
|
||||
types: [released]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
regen-notes:
|
||||
name: 'Regenerate release notes'
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Update notes
|
||||
run: |
|
||||
NEW_NOTES=$(gh api --method POST -H "Accept: application/vnd.github+json" /repos/frappe/helpdesk/releases/generate-notes -f tag_name=$RELEASE_TAG \
|
||||
| jq -r '.body' \
|
||||
| sed -E '/^\* (chore|ci|test|docs|style)/d' \
|
||||
| sed -E 's/by @mergify //'
|
||||
)
|
||||
RELEASE_ID=$(gh api -H "Accept: application/vnd.github+json" /repos/frappe/helpdesk/releases/tags/$RELEASE_TAG | jq -r '.id')
|
||||
gh api --method PATCH -H "Accept: application/vnd.github+json" /repos/frappe/helpdesk/releases/$RELEASE_ID -f body="$NEW_NOTES"
|
||||
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.RELEASE_TOKEN }}
|
||||
RELEASE_TAG: ${{ github.event.inputs.tag_name || github.event.release.tag_name }}
|
||||
71
.github/workflows/server-tests.yml
vendored
71
.github/workflows/server-tests.yml
vendored
@@ -4,6 +4,8 @@ on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
- main-hotfix
|
||||
- develop
|
||||
|
||||
paths-ignore:
|
||||
- '**.js'
|
||||
@@ -11,53 +13,48 @@ on:
|
||||
- '**.md'
|
||||
- '**.html'
|
||||
- '**.csv'
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
user:
|
||||
description: 'Frappe Framework repository user (add your username for forks)'
|
||||
required: true
|
||||
default: 'frappe'
|
||||
type: string
|
||||
branch:
|
||||
description: 'Frappe Framework branch'
|
||||
default: 'develop'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
concurrency:
|
||||
group: server-mariadb-develop-${{ github.event_name }}-${{ github.event.number || github.event_name == 'workflow_dispatch' && github.run_id || '' }}
|
||||
group: develop-helpdesk-${{ github.event.number }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
tests:
|
||||
name: Python Unit Tests
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
services:
|
||||
mysql:
|
||||
image: mariadb:10.6
|
||||
env:
|
||||
MARIADB_ROOT_PASSWORD: 'root'
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mariadb-admin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v2
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: '3.11'
|
||||
python-version: '3.14'
|
||||
|
||||
- name: Check for valid Python & Merge Conflicts
|
||||
if: github.event.pull_request.base.ref == 'develop'
|
||||
run: |
|
||||
python -m compileall -f "${GITHUB_WORKSPACE}"
|
||||
if grep -lr --exclude-dir=node_modules "^<<<<<<< " "${GITHUB_WORKSPACE}"
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
then echo "Found merge conflicts"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 18
|
||||
node-version: 24
|
||||
check-latest: true
|
||||
|
||||
- name: Install Yarn
|
||||
@@ -67,7 +64,7 @@ jobs:
|
||||
run: echo "127.0.0.1 test_site" | sudo tee -a /etc/hosts
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/*requirements.txt', '**/pyproject.toml') }}
|
||||
@@ -76,7 +73,7 @@ jobs:
|
||||
${{ runner.os }}-
|
||||
|
||||
- name: Cache node modules
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
env:
|
||||
cache-name: cache-node-modules
|
||||
with:
|
||||
@@ -91,7 +88,7 @@ jobs:
|
||||
id: yarn-cache-dir-path
|
||||
run: echo "::set-output name=dir::$(yarn cache dir)"
|
||||
|
||||
- uses: actions/cache@v2
|
||||
- uses: actions/cache@v4
|
||||
id: yarn-cache
|
||||
with:
|
||||
path: ${{ steps.yarn-cache-dir-path.outputs.dir }}
|
||||
@@ -99,13 +96,6 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
|
||||
- name: Setup MariaDB
|
||||
uses: getong/mariadb-action@v1.1
|
||||
with:
|
||||
collation server: 'utf8mb4_unicode_ci'
|
||||
mariadb version: '10.6'
|
||||
mysql root password: 'root'
|
||||
|
||||
- name: Install
|
||||
run: bash ${GITHUB_WORKSPACE}/.github/helpers/install.sh
|
||||
env:
|
||||
@@ -118,29 +108,28 @@ jobs:
|
||||
env:
|
||||
TYPE: server
|
||||
CI_BUILD_ID: ${{ github.run_id }}
|
||||
ORCHESTRATOR_URL: http://test-orchestrator.frappe.io
|
||||
|
||||
|
||||
- name: Upload coverage data
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: coverage
|
||||
name: coverage-${{ matrix.container }}
|
||||
path: /home/runner/frappe-bench/sites/coverage.xml
|
||||
|
||||
coverage:
|
||||
name: Coverage
|
||||
needs: test
|
||||
name: Coverage Wrap Up
|
||||
needs: tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download artifacts
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
|
||||
- name: Upload coverage data
|
||||
uses: codecov/codecov-action@v2
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
name: MariaDB
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
fail_ci_if_error: true
|
||||
verbose: true
|
||||
verbose: true
|
||||
187
.github/workflows/ui-tests.yml
vendored
Normal file
187
.github/workflows/ui-tests.yml
vendored
Normal file
@@ -0,0 +1,187 @@
|
||||
name: UI Tests
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- "desk/**"
|
||||
- "e2e/**"
|
||||
- "playwright.config.ts"
|
||||
- "package.json"
|
||||
- "yarn.lock"
|
||||
- ".github/workflows/ui-tests.yml"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ui-tests-helpdesk-${{ github.event.number || github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
FRAPPE_BRANCH: develop
|
||||
SITE: helpdesk.test
|
||||
|
||||
jobs:
|
||||
ui-tests:
|
||||
name: Playwright E2E Tests (${{ matrix.shard }}/2)
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 60
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
shard: [1, 2]
|
||||
|
||||
services:
|
||||
redis-cache:
|
||||
image: redis/redis-stack-server:latest
|
||||
ports:
|
||||
- 13000:6379
|
||||
redis-queue:
|
||||
image: redis:alpine
|
||||
ports:
|
||||
- 11000:6379
|
||||
mariadb:
|
||||
image: mariadb:10.6
|
||||
env:
|
||||
MARIADB_ROOT_PASSWORD: root
|
||||
ports:
|
||||
- 3306:3306
|
||||
options: --health-cmd="mariadb-admin ping" --health-interval=5s --health-timeout=2s --health-retries=3
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.14"
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
check-latest: true
|
||||
|
||||
- name: Cache pip
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pip
|
||||
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}
|
||||
restore-keys: ${{ runner.os }}-pip-
|
||||
|
||||
- name: Cache yarn
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/yarn
|
||||
key: ${{ runner.os }}-yarn-ui-${{ hashFiles('**/yarn.lock') }}
|
||||
restore-keys: ${{ runner.os }}-yarn-ui-
|
||||
|
||||
- name: Cache Playwright browsers
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/ms-playwright
|
||||
key: ${{ runner.os }}-playwright-${{ hashFiles('yarn.lock') }}
|
||||
|
||||
- name: Install MariaDB Client
|
||||
run: |
|
||||
sudo apt update
|
||||
sudo apt install -y mariadb-client
|
||||
|
||||
- name: Setup Bench
|
||||
run: |
|
||||
pip install frappe-bench
|
||||
bench init --skip-redis-config-generation --skip-assets --frappe-branch "$FRAPPE_BRANCH" --python "$(which python)" ~/frappe-bench
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL character_set_server = 'utf8mb4'"
|
||||
mariadb --host 127.0.0.1 --port 3306 -u root -proot -e "SET GLOBAL collation_server = 'utf8mb4_unicode_ci'"
|
||||
|
||||
- name: Install Helpdesk
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
bench get-app telephony
|
||||
bench get-app helpdesk $GITHUB_WORKSPACE
|
||||
bench setup requirements --dev
|
||||
bench new-site --db-root-password root --admin-password admin --install-app helpdesk $SITE
|
||||
bench use $SITE
|
||||
bench --site $SITE set-config host_name "http://localhost:8000"
|
||||
bench build --apps frappe,helpdesk
|
||||
env:
|
||||
CI: "Yes"
|
||||
|
||||
- name: Start Frappe Server
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
sed -i 's/^watch:/# watch:/g' Procfile
|
||||
sed -i 's/^schedule:/# schedule:/g' Procfile
|
||||
bench start &> bench_start.log &
|
||||
timeout 120 bash -c "until curl -s http://localhost:8000 > /dev/null; do sleep 2; done"
|
||||
|
||||
- name: Install Playwright
|
||||
run: |
|
||||
yarn install --frozen-lockfile --ignore-scripts
|
||||
npx playwright install --with-deps chromium
|
||||
|
||||
- name: Run Playwright Tests
|
||||
run: npx playwright test --shard=${{ matrix.shard }}/2
|
||||
env:
|
||||
# localhost is a secure context, which crypto.randomUUID in frappe/ui needs.
|
||||
BASE_URL: http://localhost:8000
|
||||
ADMIN_PASSWORD: admin
|
||||
|
||||
- name: Upload Blob Report
|
||||
uses: actions/upload-artifact@v4
|
||||
if: always()
|
||||
with:
|
||||
name: blob-report-${{ matrix.shard }}
|
||||
path: blob-report/
|
||||
retention-days: 1
|
||||
|
||||
- name: Upload Test Results
|
||||
uses: actions/upload-artifact@v4
|
||||
if: failure()
|
||||
with:
|
||||
name: test-results-${{ matrix.shard }}
|
||||
path: test-results/
|
||||
retention-days: 7
|
||||
|
||||
- name: Show Bench Logs on Failure
|
||||
if: failure()
|
||||
working-directory: /home/runner/frappe-bench
|
||||
run: |
|
||||
cat bench_start.log || true
|
||||
cat logs/*.log || true
|
||||
|
||||
merge-reports:
|
||||
name: Merge Playwright Reports
|
||||
needs: ui-tests
|
||||
if: always()
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Clone
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 24
|
||||
|
||||
- name: Install Playwright
|
||||
run: yarn install --frozen-lockfile --ignore-scripts
|
||||
|
||||
- name: Download Blob Reports
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
path: all-blob-reports
|
||||
pattern: blob-report-*
|
||||
merge-multiple: true
|
||||
|
||||
- name: Merge Into HTML Report
|
||||
run: npx playwright merge-reports --reporter html ./all-blob-reports
|
||||
|
||||
- name: Upload Playwright Report
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: playwright-report
|
||||
path: playwright-report/
|
||||
retention-days: 7
|
||||
13
.gitignore
vendored
13
.gitignore
vendored
@@ -8,6 +8,7 @@ __pycache__/
|
||||
*.log
|
||||
tags
|
||||
node_modules
|
||||
.vscode
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
@@ -28,9 +29,21 @@ share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
.playwright-mcp
|
||||
.claude-flow
|
||||
.claude
|
||||
.claude-worktrees
|
||||
CLAUDE.md
|
||||
|
||||
|
||||
helpdesk/docs/current
|
||||
helpdesk/public/desk
|
||||
helpdesk/public/frontend
|
||||
helpdesk/public/node_modules
|
||||
helpdesk/www/helpdesk/index.html
|
||||
desk/components.d.ts
|
||||
desk/stats.html
|
||||
# Playwright
|
||||
e2e/.auth
|
||||
playwright-report
|
||||
test-results
|
||||
|
||||
42
.mergify.yml
Normal file
42
.mergify.yml
Normal file
@@ -0,0 +1,42 @@
|
||||
pull_request_rules:
|
||||
- name: Auto-close PRs on stable branch
|
||||
conditions:
|
||||
- and:
|
||||
- author != RitvikSardana
|
||||
- author != frappe-pr-bot
|
||||
- author != mergify[bot]
|
||||
- author != aerodeval
|
||||
- or:
|
||||
- base = main
|
||||
actions:
|
||||
close:
|
||||
comment:
|
||||
message: |
|
||||
@{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on develop branch.
|
||||
- name: backport to develop
|
||||
conditions:
|
||||
- label = "backport develop"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- develop
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
- name: backport to main-hotfix
|
||||
conditions:
|
||||
- label = "backport main-hotfix"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- main-hotfix
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
- name: backport to main
|
||||
conditions:
|
||||
- label = "backport main"
|
||||
actions:
|
||||
backport:
|
||||
branches:
|
||||
- main
|
||||
assignees:
|
||||
- "{{ author }}"
|
||||
@@ -1,22 +1,22 @@
|
||||
exclude: "node_modules|.git"
|
||||
default_stages: [commit]
|
||||
default_stages: [pre-commit]
|
||||
fail_fast: false
|
||||
|
||||
repos:
|
||||
- repo: https://github.com/psf/black
|
||||
rev: 22.6.0
|
||||
rev: 25.11.0
|
||||
hooks:
|
||||
- id: black
|
||||
types_or: [python, pyi]
|
||||
|
||||
- repo: https://github.com/PyCQA/flake8
|
||||
rev: 5.0.4
|
||||
rev: 7.3.0
|
||||
hooks:
|
||||
- id: flake8
|
||||
additional_dependencies:
|
||||
- flake8-bugbear
|
||||
- flake8-comprehensions
|
||||
- flake8-simplify
|
||||
- flake8-simplify==0.30.0
|
||||
args: ['--config', '.github/helpers/.flake8_strict']
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-prettier
|
||||
|
||||
21
.releaserc
Normal file
21
.releaserc
Normal file
@@ -0,0 +1,21 @@
|
||||
{
|
||||
"branches": ["main"],
|
||||
"plugins": [
|
||||
"@semantic-release/commit-analyzer", {
|
||||
"preset": "angular"
|
||||
},
|
||||
"@semantic-release/release-notes-generator",
|
||||
[
|
||||
"@semantic-release/exec", {
|
||||
"prepareCmd": 'sed -ir "s/[0-9]*\.[0-9]*\.[0-9]*/${nextRelease.version}/" helpdesk/__init__.py'
|
||||
}
|
||||
],
|
||||
[
|
||||
"@semantic-release/git", {
|
||||
"assets": ["helpdesk/__init__.py"],
|
||||
"message": "chore(release): Bumped to Version ${nextRelease.version}"
|
||||
}
|
||||
],
|
||||
"@semantic-release/github"
|
||||
]
|
||||
}
|
||||
471
AGENTS.md
Normal file
471
AGENTS.md
Normal file
@@ -0,0 +1,471 @@
|
||||
# Copilot Instructions for Frappe Helpdesk
|
||||
|
||||
## Skills
|
||||
|
||||
For Frappe development tasks, reference the frappe-dev skill:
|
||||
- **Location**: `~/.agents/skills/frappe-dev/`
|
||||
- **Usage**: When working on DocType, controllers, whitelisted APIs, background jobs, permissions, or frontend tasks, read the relevant skill reference files:
|
||||
- `doctype.md` — Creating/modifying DocTypes and fields
|
||||
- `controllers.md` — Document lifecycle and server logic
|
||||
- `api.md` — REST endpoints with `@frappe.whitelist()`
|
||||
- `database.md` — `frappe.db`, queries, raw SQL
|
||||
- `background-jobs.md` — `frappe.enqueue`, scheduled jobs
|
||||
- `permissions.md` — Roles, DocType permissions
|
||||
- `frontend-desk.md`, `frontend-vue.md`, `frontend-portal.md` — Frontend references
|
||||
|
||||
## Project Overview
|
||||
|
||||
Frappe Helpdesk is an open-source ticket management tool built on the [Frappe Framework](https://github.com/frappe/frappe) (Python backend) and [Frappe UI](https://github.com/frappe/frappe-ui) (Vue.js frontend). It provides agent/customer portals, SLAs, assignment rules, a knowledge base, and saved replies.
|
||||
|
||||
## Tech Stack & Architecture
|
||||
|
||||
- **Backend**: Frappe Framework with Python
|
||||
- **Frontend**: Vue 3 + TypeScript SPA with Vite dev server
|
||||
- **Database**: MariaDB with structured doctypes
|
||||
- **Real-time**: WebSockets via Socket.IO for live updates
|
||||
- **UI Library**: frappe-ui for consistent design components
|
||||
- **Styling**: Tailwind CSS with semantic design tokens
|
||||
|
||||
## Architecture
|
||||
|
||||
- **Backend (Python):** Located in `helpdesk/`.
|
||||
- API endpoints: `helpdesk/api/`
|
||||
- Business logic: `helpdesk/utils.py`, `helpdesk/search.py`, etc.
|
||||
- Extensibility: `helpdesk/extends/`, `helpdesk/overrides/`
|
||||
- **Frontend (Vue.js):** Located in `desk/`.
|
||||
- Main entry: `desk/src/main.js`, `desk/src/App.vue`
|
||||
- Components: `desk/src/components/`
|
||||
- State: `desk/src/stores/`
|
||||
- Routing: `desk/src/router/`
|
||||
- Styles: Tailwind via `desk/index.css`, config in `desk/tailwind.config.js`
|
||||
|
||||
# Frontend: Vue 3 Development Standards
|
||||
|
||||
## Frontend Project Context
|
||||
|
||||
- `desk/src/` contains the main Vue 3 frontend source code
|
||||
- Vue 3.x with Composition API as default approach
|
||||
- TypeScript for type safety and better development experience
|
||||
- Single File Components (`.vue`) with `<script setup lang="ts">` syntax preferred
|
||||
- Vite as the build tool for fast development and optimized builds
|
||||
- Pinia for state management (unlike gameplan which avoids state libraries)
|
||||
- frappe-ui for UI components and data fetching utilities
|
||||
|
||||
## Development Standards
|
||||
|
||||
### Architecture & Component Design
|
||||
|
||||
- Favor the Composition API (`setup` functions and composables) over the Options API
|
||||
- Organize components and composables by feature or domain for scalability
|
||||
- Separate UI-focused components (presentational) from logic-focused components (containers)
|
||||
- Use PascalCase for component names and file names
|
||||
- Keep components small and focused on one concern
|
||||
- Use `<script setup lang="ts">` syntax for brevity and performance
|
||||
- Favor slots and scoped slots for flexible composition
|
||||
|
||||
### TypeScript Integration
|
||||
|
||||
- TypeScript is enabled but not in strict mode (as per actual tsconfig.json)
|
||||
- Use `<script setup lang="ts">` with `defineProps` and `defineEmits`
|
||||
- Leverage `PropType<T>` for typed props and default values
|
||||
- Use interfaces or type aliases for complex prop and state shapes
|
||||
- Define types for event handlers, refs, and `useRoute`/`useRouter` hooks
|
||||
|
||||
### Styling Guidelines
|
||||
|
||||
- Always prefer Tailwind CSS for styling
|
||||
- Use utility classes for layout and spacing
|
||||
- Use semantic class names wherever possible:
|
||||
- Background colors: `bg-surface-white`, `bg-surface-gray-1` through `bg-surface-gray-9`, `bg-surface-black`
|
||||
- Text colors: `text-ink-white`, `text-ink-gray-1` through `text-ink-gray-9`, `text-ink-black`
|
||||
- Fill colors: `fill-ink-*`
|
||||
- Placeholder colors: `placeholder-ink-*`
|
||||
- Border colors: `border-outline-white`, `border-outline-gray-1` through `border-outline-gray-5`, `border-outline-black`
|
||||
- Font sizes: `text-xs`, `text-sm`, `text-base`, `text-lg`, `text-xl`, `text-2xl`, `text-3xl`
|
||||
- Multiline text: `text-p-xs`, `text-p-sm`, `text-p-base`, `text-p-lg`, `text-p-xl`, `text-p-2xl`
|
||||
- Always use gray shades for everything, never use color shades even for primary states
|
||||
- Implement mobile-first, responsive design with CSS Grid and Flexbox
|
||||
- Ensure styles are accessible (contrast, focus states)
|
||||
|
||||
### Data Fetching with frappe-ui
|
||||
|
||||
- Use `createResource`, `createListResource`, and `createDocumentResource` from frappe-ui for data fetching
|
||||
- Handle loading, error, and success states explicitly
|
||||
- These are the older but stable composables used throughout the project
|
||||
|
||||
When working with a list of documents:
|
||||
|
||||
```ts
|
||||
const tickets = createListResource({
|
||||
doctype: "HD Ticket",
|
||||
filters: { status: "Open" },
|
||||
fields: ["name", "subject", "modified"],
|
||||
limit: 20,
|
||||
auto: true,
|
||||
});
|
||||
|
||||
// Access data
|
||||
tickets.data; // Array of ticket objects
|
||||
tickets.loading; // Boolean loading state
|
||||
tickets.error; // Error object if any
|
||||
|
||||
// Operations
|
||||
tickets.reload(); // Refresh the list
|
||||
tickets.update({ name: "<id>", subject: "Updated Subject" }); // Update item
|
||||
tickets.insert({ subject: "New Ticket" }); // Add new item
|
||||
tickets.delete("<id>"); // Delete item
|
||||
```
|
||||
|
||||
When working with a single document:
|
||||
|
||||
```ts
|
||||
const ticket = createDocumentResource({
|
||||
doctype: "HD Ticket",
|
||||
name: "<ticket-id>",
|
||||
auto: true,
|
||||
});
|
||||
|
||||
// Access data
|
||||
ticket.doc; // Document object
|
||||
ticket.loading; // Boolean loading state
|
||||
ticket.error; // Error object if any
|
||||
|
||||
// Operations
|
||||
ticket.get(); // Fetch/refresh document
|
||||
ticket.setValue("status", "Resolved"); // Update field
|
||||
ticket.save(); // Save changes
|
||||
ticket.delete(); // Delete document
|
||||
```
|
||||
|
||||
For API calls:
|
||||
|
||||
```ts
|
||||
const apiCall = createResource({
|
||||
url: "helpdesk.api.ticket.assign_ticket_to_agent",
|
||||
onSuccess(data) {
|
||||
// Handle success
|
||||
},
|
||||
onError(error) {
|
||||
// Handle error
|
||||
},
|
||||
});
|
||||
|
||||
// Make the call
|
||||
apiCall.submit({ ticket_id: "<id>", agent_id: "<agent>" });
|
||||
```
|
||||
|
||||
### Icons
|
||||
|
||||
- **Primary icon system**: Lucide icons via unplugin-icons for consistency and modern design
|
||||
- **Secondary**: FeatherIcon component from frappe-ui (legacy usage only)
|
||||
- **Rule**: Never introduce `FeatherIcon` in new code. New components must use Lucide
|
||||
icons (`<LucideInfo />`, `<LucidePlus />`, …) — no exceptions, including small
|
||||
helper icons like tooltip/info glyphs.
|
||||
- Use Lucide icons for all new components. They are globally auto-registered
|
||||
(see `desk/components.d.ts`), so no import is needed when used as a template tag:
|
||||
```vue
|
||||
<template>
|
||||
<LucidePlus class="size-4" />
|
||||
</template>
|
||||
```
|
||||
- For script usage, import Lucide icons like this:
|
||||
```ts
|
||||
import LucidePlus from "~icons/lucide/plus";
|
||||
import LucideTicket from "~icons/lucide/ticket";
|
||||
```
|
||||
- Only use FeatherIcon for maintaining existing components:
|
||||
```vue
|
||||
<template>
|
||||
<FeatherIcon name="plus" class="h-4 w-4" />
|
||||
</template>
|
||||
```
|
||||
|
||||
### State Management
|
||||
|
||||
- Use Pinia stores for complex shared state
|
||||
- For simple local state, use `ref` and `reactive` within `setup`
|
||||
- Use `computed` for derived state
|
||||
- Keep state normalized for complex structures
|
||||
|
||||
### Performance & Accessibility
|
||||
|
||||
- Apply `v-once` and `v-memo` for static or infrequently changing elements
|
||||
- Avoid unnecessary watchers; prefer `computed` where possible
|
||||
- Use semantic HTML elements and ARIA attributes
|
||||
- Manage focus for modals and dynamic content
|
||||
- Ensure keyboard navigation for interactive components
|
||||
|
||||
# Backend: Frappe Framework Development Standards
|
||||
|
||||
## Backend Project Context
|
||||
|
||||
- Frappe Framework provides full-stack capabilities with ORM, permissions, and background jobs
|
||||
- MariaDB database with structured DocTypes for business entities
|
||||
- Redis for background workers and caching
|
||||
- Socket.IO for real-time updates
|
||||
|
||||
## Critical Development Workflows
|
||||
|
||||
**Local Development Setup**:
|
||||
|
||||
- Backend runs via `bench start` from frappe-bench directory
|
||||
- Python web server: Assume server is already started on port 8000
|
||||
- Frontend dev server: `cd desk && yarn dev` (typically runs on port 8080)
|
||||
- Site-specific commands: `bench --site helpdesk.test <command>`
|
||||
|
||||
**Data Query Patterns**:
|
||||
|
||||
- Always prefer `frappe.get_list()` over `frappe.get_all()` for new code. It handles perms out of the box and is more flexible.
|
||||
- `frappe.get_all()` is fine for child tables (e.g. `Has Role`, `HD Customer Member`), which have no permissions of their own.
|
||||
- When `frappe.get_all()` is used on a parent DocType, make sure the caller may see the result some other way, for example a `frappe.has_permission(...)` check first, or `@agent_only` / `@agent_manager_only` (`helpdesk/utils.py`) on the endpoint.
|
||||
- Use `frappe.qb.get_query(..., ignore_permissions=False)` when permission checks are needed
|
||||
- Example query patterns from helpdesk context
|
||||
|
||||
**Debugging Workflow**:
|
||||
|
||||
- Create debug files like `./helpdesk/debug.py` with `def execute():` function
|
||||
- Run with `bench --site helpdesk.test execute helpdesk.debug.execute`
|
||||
- Use `print()` statements for console output during debugging
|
||||
|
||||
## DocType Architecture Patterns
|
||||
|
||||
- Follow Frappe's DocType conventions for business entities
|
||||
- Implement custom permission logic in `has_permission` hooks
|
||||
- Use proper field types and validation in DocType definitions
|
||||
- Leverage DocType methods for business logic encapsulation
|
||||
|
||||
## Controller Code Structure
|
||||
|
||||
All controller logic must follow this structure strictly:
|
||||
|
||||
**Rule: Lifecycle hooks call methods. Methods are defined below on the class.**
|
||||
|
||||
```python
|
||||
class HDFoo(Document):
|
||||
# 1. Lifecycle hooks at the top — each hook calls methods, no inline logic
|
||||
def after_insert(self):
|
||||
self.do_a()
|
||||
self.do_b()
|
||||
|
||||
def on_update(self):
|
||||
self.do_a()
|
||||
|
||||
# 2. Methods below — one responsibility each
|
||||
def do_a(self):
|
||||
pass
|
||||
|
||||
def do_b(self):
|
||||
pass
|
||||
|
||||
|
||||
```
|
||||
|
||||
**Rules:**
|
||||
|
||||
- Lifecycle hooks (`after_insert`, `on_update`, `before_save`, `on_trash`, `after_rename`, etc.) contain **no inline logic** — they only call `self.method()`.
|
||||
- All logic lives in methods on the class, not in module-level helper functions.
|
||||
- Methods that mutate a related document (e.g. an Assignment Rule) receive that doc as an argument and mutate it in memory. The **caller** is responsible for the final `doc.save()` — this keeps saves to a minimum (one save per hook).
|
||||
- Never fetch the same document twice in one hook. Fetch once, pass the doc through the call chain.
|
||||
- `@staticmethod` is allowed for pure transformations (e.g. building a condition string) that don't touch `self` or any Frappe doc.
|
||||
- If there is an issue in framework/ui or frappe-ui or frappe framework, dont do a workaround. Instead, raise a blocker in the spec and wait for a fix. Do not implement workarounds that will be removed later. If possible, raise a PR to fix the issue in the framework instead of implementing a workaround in helpdesk.
|
||||
|
||||
**Save discipline:**
|
||||
|
||||
- Mutate all fields on a document before calling `.save()` once.
|
||||
- Never call `.save()` inside a helper method — save in the hook or the method that owns the full mutation.
|
||||
- Exception: if a method truly owns a complete document lifecycle (e.g. `create_assignment_rule` creates and fully initialises a new doc), it may save internally.
|
||||
Take inspiration from "helpdesk.doctype.hd_team.hd_team.HDTeam" for examples of this pattern in practice.
|
||||
|
||||
## Conventions & Patterns
|
||||
|
||||
- **API Design:** Python modules in `helpdesk/api/` follow RESTful patterns. Extend via `helpdesk/extends/`.
|
||||
- **Frontend:** Vue 3 + Vite with TypeScript. Use Pinia for state management. Components auto-imported via `desk/components.d.ts`.
|
||||
- **Testing:** Follow Frappe's conventions for backend tests.
|
||||
- **Localization:** Add translations in `helpdesk/locale/`.
|
||||
- **Custom Logic:** Use `helpdesk/overrides/` for customizations.
|
||||
|
||||
## Utilities and Composables
|
||||
|
||||
- @vueuse/core is available for common Vue utilities
|
||||
- Prefer vueuse composables over custom implementations where applicable
|
||||
- Common composables: `useLocalStorage`, `useDebounce`, `useElementSize`
|
||||
- Always use frappe-ui's data fetching composables (`createResource`, `createListResource`, `createDocumentResource`), never `useFetch`
|
||||
|
||||
## Error Handling & Forms
|
||||
|
||||
- Use global error handlers for uncaught errors
|
||||
- Wrap risky logic in `try/catch` with user-friendly messages
|
||||
- Build forms with controlled `v-model` bindings
|
||||
- Validate on blur or input with debouncing for performance
|
||||
- Ensure accessible labeling and error announcements
|
||||
|
||||
## Integration Points
|
||||
|
||||
- **Frappe Framework:** All backend logic integrates with Frappe ORM, permissions, and hooks (`helpdesk/hooks.py`).
|
||||
- **Frappe UI:** Frontend uses Frappe UI for consistent design components and data fetching.
|
||||
- **Real-time Updates:** WebSockets via Socket.IO for live ticket updates.
|
||||
- **Crowdin:** Translation sync via `crowdin.yml`.
|
||||
|
||||
## Examples
|
||||
|
||||
### Adding a New API Endpoint
|
||||
|
||||
1. Create a Python file in `helpdesk/api/`
|
||||
2. Add `@frappe.whitelist()` decorator to functions
|
||||
3. Register in `helpdesk/hooks.py` if needed
|
||||
4. Use `frappe.qb.get_query()` for database queries
|
||||
|
||||
### Adding a Frontend Component
|
||||
|
||||
1. Create Vue component in `desk/src/components/` or `desk/src/pages/`
|
||||
2. Use `<script setup lang="ts">` syntax
|
||||
3. Follow Tailwind semantic class conventions
|
||||
4. Use frappe-ui composables for data fetching
|
||||
5. Add route in `desk/src/router/` if it's a page component
|
||||
|
||||
### Styling Example
|
||||
|
||||
```vue
|
||||
<template>
|
||||
<div class="bg-surface-white border border-outline-gray-2 rounded-lg p-4">
|
||||
<h2 class="text-lg text-ink-gray-9 font-semibold mb-2">Ticket Details</h2>
|
||||
<p class="text-p-sm text-ink-gray-7">{{ ticket.doc.subject }}</p>
|
||||
<LucideTicket class="size-4 text-ink-gray-6" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { createDocumentResource } from "frappe-ui";
|
||||
import LucideTicket from "~icons/lucide/ticket";
|
||||
|
||||
const ticket = createDocumentResource({
|
||||
doctype: "HD Ticket",
|
||||
name: props.ticketId,
|
||||
auto: true,
|
||||
});
|
||||
</script>
|
||||
```
|
||||
|
||||
## Key Files & Directories
|
||||
|
||||
### Backend
|
||||
|
||||
- `helpdesk/api/` — Backend API endpoints with @frappe.whitelist() decorators
|
||||
- `helpdesk/utils.py` — Shared backend utilities and helper functions
|
||||
- `helpdesk/hooks.py` — Frappe hooks
|
||||
- `helpdesk/overrides/` — Custom logic and extensions
|
||||
|
||||
### Frontend
|
||||
|
||||
- `desk/src/` — Main Vue 3 frontend source code
|
||||
- `desk/src/components/` — Reusable Vue components
|
||||
- `desk/src/pages/` — Page-level components and routes
|
||||
- `desk/src/stores/` — Pinia stores for state management
|
||||
- `desk/tailwind.config.js` — Tailwind CSS configuration with semantic tokens
|
||||
- `desk/components.d.ts` — Auto-generated component type definitions
|
||||
|
||||
### Development
|
||||
|
||||
- `docker/` — Docker setup for containerized development
|
||||
|
||||
## Code Quality & Standards
|
||||
|
||||
- Follow Vue's official style guide and best practices
|
||||
- Use ESLint with Vue 3 recommended rules and Prettier for consistency
|
||||
- Write meaningful commit messages and maintain clean git history
|
||||
- Document complex logic with JSDoc/TSDoc comments
|
||||
- Keep a comment to 2 lines at most. If it needs more to explain, simplify the code instead
|
||||
- Keep dependencies updated and audit for security vulnerabilities
|
||||
|
||||
## References
|
||||
|
||||
- [README.md](../README.md) — Full setup and feature list
|
||||
- [Frappe Docs](https://frappeframework.com/docs/) — Framework documentation
|
||||
- [Frappe Helpdesk Docs](https://docs.frappe.io/helpdesk) — Project-specific docs
|
||||
- [Vue 3 Style Guide](https://vuejs.org/style-guide/) — Vue.js best practices
|
||||
- [Tailwind CSS](https://tailwindcss.com/docs) — Utility-first CSS framework
|
||||
|
||||
---
|
||||
|
||||
## Agent Working Rules
|
||||
|
||||
These rules apply to all agents working in this codebase. Follow them without exception.
|
||||
|
||||
### 1. Site Data — Read Before You Write
|
||||
|
||||
When a Frappe site is referenced in the conversation (e.g. `erp-hd.localhost`, `hd-tests`),
|
||||
treat it as the **source of truth for current data state**.
|
||||
|
||||
- Before assuming anything about existing records, custom fields, settings, or DocType state —
|
||||
query the site first using the bench venv Python or `bench execute`.
|
||||
- **Never write data to a site unless the user explicitly asks you to.**
|
||||
Querying is always safe. Mutations (insert, update, delete, migrate, patch) require explicit
|
||||
user instruction.
|
||||
- If you need to verify a fix worked, re-query the site — do not assume success from code
|
||||
inspection alone.
|
||||
|
||||
```python
|
||||
# Safe pattern for querying a site
|
||||
import sys, os
|
||||
sys.path.insert(0, 'apps/frappe')
|
||||
os.chdir('sites')
|
||||
import frappe
|
||||
frappe.init(site='<site-name>', sites_path='.')
|
||||
frappe.connect()
|
||||
|
||||
# ... read-only queries here ...
|
||||
|
||||
frappe.destroy()
|
||||
```
|
||||
|
||||
Run via: `cd /path/to/frappe-bench && env/bin/python /tmp/your_script.py`
|
||||
|
||||
---
|
||||
|
||||
### 2. Spec-Driven Development — Keep the Spec Current
|
||||
|
||||
When a feature has a spec document (e.g. `docs/erpnext-customer-sync.md`), the spec is the
|
||||
**living source of truth** for that feature. It must be kept in sync with the actual
|
||||
implementation at all times.
|
||||
|
||||
**Rules:**
|
||||
|
||||
- **Update the spec in the same session as the code change.** Never defer spec updates to a
|
||||
later session.
|
||||
- **The spec reflects what is implemented, not what was originally planned.** If a decision
|
||||
changes mid-build (e.g. removing a scheduler job, changing how a field is set), update the
|
||||
spec immediately after the code change.
|
||||
- **Removed features must be removed from the spec.** Do not leave stale sections, blockers, or
|
||||
file manifest entries for things that no longer exist.
|
||||
- **New features must be added to the spec.** If a new API, component, or behaviour is
|
||||
introduced, add a corresponding section.
|
||||
- **Decisions and their rationale belong in the spec.** If something was done a specific way to
|
||||
avoid a bug or framework limitation (e.g. not setting `customer_group` to avoid the group-node
|
||||
error), document that in the relevant Blocker section.
|
||||
- When in doubt about whether a spec update is needed — update it.
|
||||
|
||||
---
|
||||
|
||||
### 3. Test Utilities — Always Use `helpdesk/test_utils.py`
|
||||
|
||||
All backend test helpers must live in `helpdesk/test_utils.py` and be imported from there.
|
||||
Never define helper functions (factories, enable/disable toggles, fixture builders) directly
|
||||
inside individual test files.
|
||||
|
||||
**Rules:**
|
||||
|
||||
- **Before writing a helper in a test file**, check `helpdesk/test_utils.py` first — it may
|
||||
already exist.
|
||||
- **If a helper doesn't exist**, add it to `helpdesk/test_utils.py` and import it in the test
|
||||
file. Do not leave it inline.
|
||||
- **If you write helpers inline during development**, move them to `test_utils.py` before
|
||||
finishing the task.
|
||||
- Helper functions in `test_utils.py` must have a docstring explaining what they create or do. Only if the function is completely self-explanatory (e.g. `enable_erpnext_sync`) can the docstring be omitted.
|
||||
- Naming conventions:
|
||||
- Factories: `make_<doctype>(...)` — e.g. `make_hd_customer`, `make_ticket`, `make_team`
|
||||
- Toggle helpers: `enable_<feature>()` / `disable_<feature>()` — e.g. `enable_erpnext_sync`
|
||||
- Query helpers: descriptive verb — e.g. `get_latest_ticket_communication`
|
||||
|
||||
**For updates, merge new conventions here. If anything is unclear or missing, ask for clarification.**
|
||||
|
||||
**In the end your code will be reviewed by Codex, but following these rules will help ensure a smooth review process and a high-quality codebase.**
|
||||
244
README.md
244
README.md
@@ -1,63 +1,217 @@
|
||||
<div align="center" markdown="1">
|
||||
<a href="https://frappedesk.com/">
|
||||
<img src=".github/hd-logo.svg" height="128" alt="Frappe Helpdesk Logo">
|
||||
</a>
|
||||
<h2>Frappe Helpdesk</h2>
|
||||
<p align="center">
|
||||
<p>Modern, Streamlined, Customer Service Software</p>
|
||||
</p>
|
||||
|
||||
[frappedesk.com](https://frappedesk.com)
|
||||
|
||||
<div align="center" style="max-height: 40px;">
|
||||
<a href="https://frappecloud.com/helpdesk/signup">
|
||||
<img src=".github/try-on-f-cloud-button.svg" height="50">
|
||||
</a>
|
||||
</div>
|
||||
<img src=".github/hd-logo.svg" alt="Frappe Helpdesk logo" width="80"/>
|
||||
<h1>Frappe Helpdesk</h1>
|
||||
|
||||
**Customer Service, Made Simple and Effective**
|
||||
|
||||

|
||||
[](https://codecov.io/github/frappe/helpdesk)
|
||||
|
||||
<a href="https://trendshift.io/repositories/12764" target="_blank"><img src="https://trendshift.io/api/badge/repositories/12764" alt="teableio%2Fteable | Trendshift" style="width: 250px; height: 55px;" width="250" height="55"/></a>
|
||||
</div>
|
||||
|
||||
---
|
||||
</div>
|
||||
|
||||
Frappe Helpdesk offers an easy setup, clean user interface, and automation tools to resolve customer issues efficiently. It is based on Frappe Framework. It lets you streamline your company's support and helps you to efficiently manage your customer queries. It can help you to,
|
||||
|
||||
- Create tickets from email or help center
|
||||
- Empower customers with a comprehensive knowledge base and self-service portal
|
||||
- Automate redundant tasks like agent assignment and set up triggers to notify agents and customers based on certain events
|
||||
<div align="center">
|
||||
<img src="./.github/Hero2.png" alt="Hero Image" width="100%" />
|
||||
</div>
|
||||
<br />
|
||||
<div align="center">
|
||||
<a href="https://frappe.io/helpdesk">Website</a>
|
||||
-
|
||||
<a href="https://docs.frappe.io/helpdesk">Documentation</a>
|
||||
</div>
|
||||
|
||||

|
||||
## Frappe Helpdesk
|
||||
Frappe Helpdesk is an 100% open-source Ticket Management tool which helps you streamline your company's support, offers an easy setup, clean user interface, and automation tools to resolve customer queries efficiently.
|
||||
|
||||
## Installation
|
||||
|
||||
1. Install and setup bench by following [this guide](https://frappeframework.com/docs/user/en/installation)
|
||||
2. In the bench directory, run `bench start` and keep it running
|
||||
3. Open another terminal in bench directory, and run these commands
|
||||
|
||||
```
|
||||
bench get-app helpdesk
|
||||
bench new-site helpdesk.test
|
||||
bench --site helpdesk.test install-app helpdesk
|
||||
bench --site helpdesk.test add-to-hosts
|
||||
```
|
||||
### Motivation
|
||||
Managing issues from our customers was a big challenge for us. We were using the ERPNext support module which was not very good in UI and the UX was also not good. We wanted to have a tool that can be easily integrated with our existing system and can be customized as per our needs. So we decided to build Frappe Helpdesk.
|
||||
|
||||
You can now access Helpdesk at `http://helpdesk.test`
|
||||
5. You can also run a development server by following theses steps, in Helpdesk
|
||||
directory (`apps/helpdesk`)
|
||||
### Key Features
|
||||
|
||||
```
|
||||
yarn
|
||||
yarn dev
|
||||
```
|
||||
- **Agent and Customer Portal Views**: Dual portals for agents and customers to simplify issue submission and management.
|
||||
|
||||
Development server will be now available at `http://localhost:8080`
|
||||
- **Customizable SLAs**: Discover how you can set and track SLAs for better response times.
|
||||
|
||||
## Contributions and Community
|
||||
- **Assignment Rules**: Custom auto-assignment of tickets based on priority, issue type, or workload.
|
||||
|
||||
There are many ways you can contribute even if you don't code:
|
||||
- **Knowledge Base**: Learn how to create and manage help articles to empower users and reduce tickets.
|
||||
|
||||
1. You can start by giving a star to this repository!
|
||||
2. If you find any issues, even if it is a typo, you can [raise an issue](https://github.com/frappe/desk/issues/new) to inform us.
|
||||
3. Join our [Telegram group](https://t.me/frappedesk) and share your thoughts.
|
||||
- **Saved Replies**: Pre-written replies for common queries to ensure quick and consistent communication.
|
||||
|
||||
## License
|
||||
<details open>
|
||||
<summary >View Screenshots</summary>
|
||||
<h3></h3>
|
||||
|
||||
[GNU Affero General Public License v3.0](/licence.md)
|
||||
<div align="center">
|
||||
<sub>
|
||||
Agent List View
|
||||
</sub>
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
|
||||
<div align="center">
|
||||
<sub>
|
||||
Upload articles and let your customer solve their queries through the Knowledge Base.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||

|
||||
|
||||
<div align="center">
|
||||
<sub>
|
||||
With advanced search, your customers will be recommended relevant articles regarding their issue.
|
||||
</sub>
|
||||
</div>
|
||||
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
</details>
|
||||
<br>
|
||||
|
||||
|
||||
### Under the Hood
|
||||
|
||||
- [**Frappe Framework**](https://github.com/frappe/frappe): A full-stack web application framework written in Python and Javascript.
|
||||
|
||||
- [**Frappe UI**](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface.
|
||||
|
||||
|
||||
## Production Setup
|
||||
|
||||
### Managed Hosting
|
||||
|
||||
You can try [Frappe Cloud](https://frappecloud.com), a simple, user-friendly and sophisticated [open-source](https://github.com/frappe/press) platform to host Frappe applications with peace of mind.
|
||||
|
||||
It takes care of installation, setup, upgrades, monitoring, maintenance and support of your Frappe deployments. It is a fully featured developer platform with an ability to manage and control multiple Frappe deployments.
|
||||
|
||||
<div>
|
||||
<a href="https://frappecloud.com/helpdesk/signup" target="_blank">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/try-on-fc-white.png">
|
||||
<img src="https://frappe.io/files/try-on-fc-black.png" alt="Try on Frappe Cloud" height="28" />
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
### Self Hosting
|
||||
|
||||
Follow these steps to set up Frappe Helpdesk in production:
|
||||
|
||||
**Step 1**: Download the easy install script
|
||||
|
||||
```bash
|
||||
wget https://frappe.io/easy-install.py
|
||||
```
|
||||
|
||||
**Step 2**: Run the deployment command
|
||||
|
||||
```bash
|
||||
python3 ./easy-install.py deploy \
|
||||
--project=helpdesk_prod_setup \
|
||||
--email=your_email.example.com \
|
||||
--image=ghcr.io/frappe/helpdesk \
|
||||
--version=stable \
|
||||
--app=helpdesk \
|
||||
--sitename subdomain.domain.tld
|
||||
```
|
||||
|
||||
Replace the following parameters with your values:
|
||||
- `your_email.example.com`: Your email address
|
||||
- `subdomain.domain.tld`: Your domain name where Helpdesk will be hosted
|
||||
|
||||
The script will set up a production-ready instance of Frappe Helpdesk with all the necessary configurations in about 5 minutes.
|
||||
|
||||
## Development Setup
|
||||
|
||||
### Docker
|
||||
|
||||
You need Docker, docker-compose and git setup on your machine. Refer [Docker documentation](https://docs.docker.com/). After that, follow below steps:
|
||||
|
||||
**Step 1**: Setup folder and download the required files
|
||||
|
||||
mkdir frappe-helpdesk
|
||||
cd frappe-helpdesk
|
||||
|
||||
# Download the docker-compose file
|
||||
wget -O docker-compose.yml https://raw.githubusercontent.com/frappe/helpdesk/develop/docker/docker-compose.yml
|
||||
|
||||
# Download the setup script
|
||||
wget -O init.sh https://raw.githubusercontent.com/frappe/helpdesk/develop/docker/init.sh
|
||||
|
||||
**Step 2**: Run the container and daemonize it
|
||||
|
||||
docker compose up -d
|
||||
|
||||
**Step 3**: The site [http://helpdesk.localhost:8000/helpdesk](http://helpdesk.localhost:8000/helpdesk) should now be available. The default credentials are:
|
||||
- Username: Administrator
|
||||
- Password: admin
|
||||
|
||||
### Local
|
||||
|
||||
To setup the repository locally follow the steps mentioned below:
|
||||
|
||||
1. Install bench and setup a `frappe-bench` directory by following the [Installation Steps](https://frappeframework.com/docs/user/en/installation)
|
||||
1. Start the server by running `bench start`
|
||||
1. In a separate terminal window, create a new site by running `bench new-site helpdesk.test`
|
||||
1. Map your site to localhost with the command `bench --site helpdesk.test add-to-hosts`
|
||||
1. Get the Telephony app. Run `bench get-app https://github.com/frappe/telephony`
|
||||
1. Get the Helpdesk app. Run `bench get-app https://github.com/frappe/helpdesk`
|
||||
1. Run `bench --site helpdesk.test install-app helpdesk`.
|
||||
1. Run `bench build --app helpdesk`
|
||||
1. Now open the URL `http://helpdesk.test:8000/helpdesk` in your browser, you should see the app running
|
||||
|
||||
|
||||
**For Frontend Development**
|
||||
1. Open a new terminal session and cd into `frappe-bench/apps/helpdesk/desk`, and run the following commands:
|
||||
```
|
||||
yarn install
|
||||
yarn dev or yarn dev --host helpdesk.test
|
||||
```
|
||||
1. Now, you can access the site on vite dev server at `http://helpdesk.test:8080`
|
||||
|
||||
**Note:** You'll find all the code related to Helpdesk's frontend inside `frappe-bench/apps/helpdesk/desk`
|
||||
|
||||
|
||||
## Compatibility matrix
|
||||
|
||||
| Helpdesk Branch | Compatible Frappe Framework Version |
|
||||
|-----------------|-------------------------------------|
|
||||
| main | version-15 |
|
||||
| main | version-16 |
|
||||
| develop | develop branch |
|
||||
|
||||
|
||||
## Learn and connect
|
||||
|
||||
- [Telegram Public Group](https://t.me/frappedesk)
|
||||
- [Discuss Forum](https://discuss.frappe.io/c/frappehelpdesk/69)
|
||||
- [Documentation](https://docs.frappe.io/helpdesk)
|
||||
|
||||
## Contributing
|
||||
|
||||
1. [Issue Guidelines](https://github.com/frappe/erpnext/wiki/Issue-Guidelines)
|
||||
1. [Report Security Vulnerabilities](https://frappe.io/security)
|
||||
1. [Pull Request Requirements](https://github.com/frappe/erpnext/wiki/Contribution-Guidelines)
|
||||
2. [Translations](https://crowdin.com/project/frappe)
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<div align="center">
|
||||
<a href="https://frappe.io" target="_blank">
|
||||
<picture>
|
||||
<source media="(prefers-color-scheme: dark)" srcset="https://frappe.io/files/Frappe-white.png">
|
||||
<img src="https://frappe.io/files/Frappe-black.png" alt="Frappe Technologies" height="28"/>
|
||||
</picture>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
parserPreset: "conventional-changelog-conventionalcommits",
|
||||
rules: {
|
||||
"subject-empty": [2, "never"],
|
||||
8
crowdin.yml
Normal file
8
crowdin.yml
Normal file
@@ -0,0 +1,8 @@
|
||||
files:
|
||||
- source: /helpdesk/locale/main.pot
|
||||
translation: /helpdesk/locale/%two_letters_code%.po
|
||||
pull_request_title: "chore: sync translations from crowdin"
|
||||
pull_request_labels:
|
||||
- translation
|
||||
commit_message: "chore: %language% translations"
|
||||
append_commit_message: false
|
||||
14
desk/auto-imports.d.ts
vendored
Normal file
14
desk/auto-imports.d.ts
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
// @ts-nocheck
|
||||
// noinspection JSUnusedGlobalSymbols
|
||||
// Generated by unplugin-auto-import
|
||||
// biome-ignore lint: disable
|
||||
export {}
|
||||
declare global {
|
||||
const LucideAlignJustify: typeof import('~icons/lucide/align-justify')['default']
|
||||
const LucideCornerUpLeft: typeof import('~icons/lucide/corner-up-left')['default']
|
||||
const LucideFileSearch: typeof import('~icons/lucide/file-search')['default']
|
||||
const LucideMessageCircle: typeof import('~icons/lucide/message-circle')['default']
|
||||
const LucideTag: typeof import('~icons/lucide/tag')['default']
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<html lang="{{ boot.lang or 'en' }}" dir="{{ boot.dir or 'ltr' }}">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="/favicon.svg" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Helpdesk</title>
|
||||
<meta name="mobile-web-app-capable" content="yes" />
|
||||
@@ -206,15 +205,7 @@
|
||||
<div id="popovers"></div>
|
||||
<script type="module" src="/src/main.js"></script>
|
||||
<script>
|
||||
window.csrf_token = "{{ csrf_token }}";
|
||||
window.frappe_version = "{{ frappe_version }}";
|
||||
window.helpdesk_version = "{{ helpdesk_version }}";
|
||||
window.site_name = "{{ site_name }}";
|
||||
window.favicon = "{{ favicon }}";
|
||||
|
||||
document.querySelectorAll("link[rel='icon']").forEach((link) => {
|
||||
link.href = window.favicon;
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import * as LucideIcons from "lucide-static";
|
||||
|
||||
const icons = {};
|
||||
for (const icon in LucideIcons) {
|
||||
let iconSvg = LucideIcons[icon];
|
||||
if (icon == "default") {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set stroke-width to 1.5
|
||||
if (iconSvg && iconSvg.includes("stroke-width")) {
|
||||
iconSvg = iconSvg.replace(/stroke-width="2"/g, 'stroke-width="1.5"');
|
||||
}
|
||||
icons[icon] = iconSvg;
|
||||
|
||||
const dashKeys = camelToDash(icon);
|
||||
for (const dashKey of dashKeys) {
|
||||
if (dashKey !== icon) {
|
||||
icons[dashKey] = iconSvg;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default icons;
|
||||
|
||||
function camelToDash(key) {
|
||||
// barChart2 -> bar-chart-2
|
||||
const withNumber = key.replace(/[A-Z0-9]/g, (m) => "-" + m.toLowerCase());
|
||||
// barChart2 -> bar-chart2
|
||||
const withoutNumber = key.replace(/[A-Z]/g, (m) => "-" + m.toLowerCase());
|
||||
|
||||
if (withNumber !== withoutNumber) {
|
||||
// both are required because unplugin icon resolver doesn't put a dash before numbers
|
||||
return [withNumber, withoutNumber];
|
||||
}
|
||||
return [withNumber];
|
||||
}
|
||||
@@ -1,53 +1,61 @@
|
||||
{
|
||||
"name": "helpdesk-ui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"preview": "vite preview",
|
||||
"build": "vite build --base=/assets/helpdesk/desk/ && yarn copy-html-entry",
|
||||
"serve": "vite preview",
|
||||
"copy-html-entry": "cp ../helpdesk/public/desk/index.html ../helpdesk/www/helpdesk/index.html"
|
||||
},
|
||||
"dependencies": {
|
||||
"@headlessui/vue": "^1.7.22",
|
||||
"@iconify-json/lucide": "^1.1.99",
|
||||
"@iconify-json/ph": "^1.1.5",
|
||||
"@iconify/tools": "^2.2.6",
|
||||
"@iconify/vue": "^4.1.1",
|
||||
"@tailwindcss/line-clamp": "^0.4.4",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@tiptap/core": "^2.2.4",
|
||||
"@vee-validate/zod": "^4.8.2",
|
||||
"@vitejs/plugin-vue": "^4.0.0",
|
||||
"@vueuse/core": "^10.0.2",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"dayjs": "^1.11.7",
|
||||
"echarts": "^5.4.1",
|
||||
"frappe-ui": "^0.1.53",
|
||||
"lodash": "^4.17.21",
|
||||
"lucide-static": "^0.276.0",
|
||||
"mime": "^3.0.0",
|
||||
"mitt": "^3.0.1",
|
||||
"pinia": "^2.0.33",
|
||||
"pluralize": "^8.0.0",
|
||||
"sanitize-html": "^2.10.0",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"tailwindcss": "^3.2.7",
|
||||
"unplugin-icons": "^0.16.1",
|
||||
"unplugin-vue-components": "^0.25.2",
|
||||
"vee-validate": "^4.8.2",
|
||||
"vite": "^4.4.9",
|
||||
"vue": "^3.4.12",
|
||||
"vue-echarts": "^6.5.4",
|
||||
"vue-router": "^4.2.2",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"resolutions": {
|
||||
"cheerio": "1.0.0-rc.12"
|
||||
},
|
||||
"devDependencies": {
|
||||
"vite-plugin-pwa": "^0.20.5"
|
||||
}
|
||||
"name": "helpdesk-ui",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite preview",
|
||||
"postinstall": "patch-package"
|
||||
},
|
||||
"dependencies": {
|
||||
"@framework/ui": "link:../../frappe/ui",
|
||||
"@headlessui/vue": "^1.7.22",
|
||||
"@tailwindcss/typography": "^0.5.9",
|
||||
"@tiptap/core": "^3.26.0",
|
||||
"@tiptap/extension-table": "^3.26.0",
|
||||
"@tiptap/extension-text-align": "^3.26.0",
|
||||
"@tiptap/extension-text-style": "^3.26.0",
|
||||
"@tiptap/pm": "^3.26.0",
|
||||
"@tiptap/starter-kit": "^3.26.0",
|
||||
"@twilio/voice-sdk": "^2.15.0",
|
||||
"@vee-validate/zod": "^4.8.2",
|
||||
"@vitejs/plugin-vue": "^4.6.2",
|
||||
"@vueuse/core": "^14.1.0",
|
||||
"@vueuse/integrations": "^14.1.0",
|
||||
"dayjs": "^1.11.7",
|
||||
"echarts": "^6.1.0",
|
||||
"grid-layout-plus": "^1.1.0",
|
||||
"frappe-ui": "1.0.0-rc.1",
|
||||
"mime": "^3.0.0",
|
||||
"pinia": "^2.0.33",
|
||||
"sanitize-html": "^2.10.0",
|
||||
"socket.io-client": "^4.7.2",
|
||||
"tailwindcss-rtl": "^0.9.0",
|
||||
"vue": "^3.5.14",
|
||||
"vue-router": "^4.2.2",
|
||||
"vuedraggable": "^4.1.0",
|
||||
"zod": "^3.21.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitejs/plugin-vue-jsx": "^3.1.0",
|
||||
"autoprefixer": "^10.4.13",
|
||||
"patch-package": "^8.0.1",
|
||||
"postcss": "^8.4.5",
|
||||
"postinstall-postinstall": "^2.1.0",
|
||||
"prettier": "2.8.4",
|
||||
"tailwindcss": "^3.4.15",
|
||||
"typescript": "^5.0.2",
|
||||
"unplugin-icons": "^22.1.0",
|
||||
"vite": "^5.4.21",
|
||||
"vite-plugin-pwa": "0.17.5"
|
||||
},
|
||||
"resolutions": {
|
||||
"cheerio": "1.0.0-rc.12",
|
||||
"prosemirror-model": "1.25.9",
|
||||
"prosemirror-state": "1.4.4",
|
||||
"prosemirror-view": "1.41.9",
|
||||
"prosemirror-transform": "1.12.0"
|
||||
}
|
||||
}
|
||||
|
||||
70
desk/patches/frappe-ui+1.0.0-rc.1.patch
Normal file
70
desk/patches/frappe-ui+1.0.0-rc.1.patch
Normal file
@@ -0,0 +1,70 @@
|
||||
diff --git a/node_modules/frappe-ui/src/molecules/editor/extensions/shared/suggestion-renderer.ts b/node_modules/frappe-ui/src/molecules/editor/extensions/shared/suggestion-renderer.ts
|
||||
index 91c8dc4..2883b93 100644
|
||||
--- a/node_modules/frappe-ui/src/molecules/editor/extensions/shared/suggestion-renderer.ts
|
||||
+++ b/node_modules/frappe-ui/src/molecules/editor/extensions/shared/suggestion-renderer.ts
|
||||
@@ -5,6 +5,7 @@ import type {
|
||||
} from '@tiptap/suggestion'
|
||||
import type { Component } from 'vue'
|
||||
import {
|
||||
+ autoUpdate,
|
||||
computePosition,
|
||||
flip,
|
||||
offset,
|
||||
@@ -40,6 +41,9 @@ export function createSuggestionRenderer(
|
||||
let isActive = false
|
||||
// Monotonic token; a stale onUpdate from a superseded query bails.
|
||||
let renderToken = 0
|
||||
+ // Monotonic token; a stale computePosition settling later bails.
|
||||
+ let positionToken = 0
|
||||
+ let cleanupAutoUpdate: (() => void) | null = null
|
||||
|
||||
function getListExpose(): SuggestionListExpose | null {
|
||||
const ref = renderer?.ref as SuggestionListExpose | null | undefined
|
||||
@@ -52,6 +56,7 @@ export function createSuggestionRenderer(
|
||||
const rect = getReferenceClientRect()
|
||||
if (!rect) return
|
||||
const reference = { getBoundingClientRect: () => rect }
|
||||
+ const token = ++positionToken
|
||||
void computePosition(reference, floatingEl, {
|
||||
placement: floatingOptions?.placement ?? 'bottom-start',
|
||||
middleware: [
|
||||
@@ -60,7 +65,7 @@ export function createSuggestionRenderer(
|
||||
shift({ padding: 8 }),
|
||||
],
|
||||
}).then(({ x, y }) => {
|
||||
- if (!floatingEl) return
|
||||
+ if (!floatingEl || token !== positionToken) return
|
||||
Object.assign(floatingEl.style, {
|
||||
position: 'absolute',
|
||||
left: `${x}px`,
|
||||
@@ -93,7 +98,19 @@ export function createSuggestionRenderer(
|
||||
floatingEl.style.position = 'absolute'
|
||||
document.body.appendChild(floatingEl)
|
||||
getReferenceClientRect = props.clientRect as () => DOMRect | null
|
||||
- updatePosition()
|
||||
+
|
||||
+ // Positions once, then keeps the popup on the caret through scroll, window
|
||||
+ // resize and its own height changes (`flip()` measures a height that async
|
||||
+ // rows and late fonts change after the fact).
|
||||
+ cleanupAutoUpdate = autoUpdate(
|
||||
+ {
|
||||
+ getBoundingClientRect: () =>
|
||||
+ getReferenceClientRect?.() ?? new DOMRect(),
|
||||
+ contextElement: props.editor?.view?.dom as HTMLElement | undefined,
|
||||
+ },
|
||||
+ floatingEl,
|
||||
+ updatePosition,
|
||||
+ )
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -139,6 +156,9 @@ export function createSuggestionRenderer(
|
||||
onExit() {
|
||||
isActive = false
|
||||
renderToken++
|
||||
+ positionToken++
|
||||
+ cleanupAutoUpdate?.()
|
||||
+ cleanupAutoUpdate = null
|
||||
floatingEl?.remove()
|
||||
renderer?.destroy()
|
||||
floatingEl = null
|
||||
@@ -1,4 +1,4 @@
|
||||
module.exports = {
|
||||
export default {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
|
||||
BIN
desk/public/ticketActivity.png
Normal file
BIN
desk/public/ticketActivity.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 210 KiB |
BIN
desk/public/timers.png
Normal file
BIN
desk/public/timers.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 67 KiB |
BIN
desk/public/videos/commentVideo.mp4
Normal file
BIN
desk/public/videos/commentVideo.mp4
Normal file
Binary file not shown.
BIN
desk/public/videos/createInviteContact.mp4
Normal file
BIN
desk/public/videos/createInviteContact.mp4
Normal file
Binary file not shown.
BIN
desk/public/videos/mailVideo.mp4
Normal file
BIN
desk/public/videos/mailVideo.mp4
Normal file
Binary file not shown.
BIN
desk/public/videos/sidebarVideo.mp4
Normal file
BIN
desk/public/videos/sidebarVideo.mp4
Normal file
Binary file not shown.
@@ -1,39 +1,45 @@
|
||||
<template>
|
||||
<RouterView class="antialiased" />
|
||||
<Toasts />
|
||||
<KeymapDialog />
|
||||
<FrappeUIProvider>
|
||||
<router-view />
|
||||
</FrappeUIProvider>
|
||||
<Dialogs />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { provide, ref, onMounted, onUnmounted } from "vue";
|
||||
import { Toasts } from "frappe-ui";
|
||||
import { createToast } from "@/utils";
|
||||
import { Dialogs } from "@/components/dialogs";
|
||||
import { useConfigStore } from "@/stores/config";
|
||||
import KeymapDialog from "@/pages/KeymapDialog.vue";
|
||||
import { stopSession } from "@/telemetry";
|
||||
import { init as initTelemetry } from "@/telemetry";
|
||||
useConfigStore();
|
||||
import { useFavicon } from "@vueuse/core";
|
||||
import { FrappeUIProvider, setConfig, toast, useColorScheme } from "frappe-ui";
|
||||
import { storeToRefs } from "pinia";
|
||||
import { h, onMounted } from "vue";
|
||||
import Wifi from "~icons/lucide/wifi";
|
||||
import WifiOff from "~icons/lucide/wifi-off";
|
||||
import { __ } from "./translation";
|
||||
import { isCustomerPortal } from "./utils";
|
||||
|
||||
onMounted(async () => {
|
||||
const configStore = useConfigStore();
|
||||
const { favicon } = storeToRefs(configStore);
|
||||
|
||||
useFavicon(favicon);
|
||||
|
||||
if (!localStorage.getItem("theme")) {
|
||||
localStorage.setItem("theme", "light");
|
||||
}
|
||||
useColorScheme();
|
||||
|
||||
onMounted(() => {
|
||||
window.addEventListener("online", () => {
|
||||
createToast({
|
||||
title: "You are now online",
|
||||
icon: "wifi",
|
||||
iconClasses: "stroke-green-600",
|
||||
toast(__("You are now online."), {
|
||||
icon: () => h(Wifi, { class: "text-ink-base" }),
|
||||
});
|
||||
});
|
||||
|
||||
window.addEventListener("offline", () => {
|
||||
createToast({
|
||||
title: "You are now offline",
|
||||
icon: "wifi-off",
|
||||
iconClasses: "stroke-red-600",
|
||||
toast(__("You are now offline."), {
|
||||
icon: () => h(WifiOff, { class: "text-ink-base" }),
|
||||
});
|
||||
});
|
||||
await initTelemetry();
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
stopSession();
|
||||
!isCustomerPortal.value && setConfig("localTimezone", window.timezone?.user);
|
||||
setConfig("systemTimezone", window.timezone?.system || null);
|
||||
});
|
||||
</script>
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -1,152 +0,0 @@
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-Thin.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Thin.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 100;
|
||||
font-display: swap;
|
||||
src: url("Inter-ThinItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ThinItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLight.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraLight.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 200;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraLightItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraLightItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-Light.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Light.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 300;
|
||||
font-display: swap;
|
||||
src: url("Inter-LightItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-LightItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Regular.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Regular.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url("Inter-Italic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Italic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-Medium.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Medium.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 500;
|
||||
font-display: swap;
|
||||
src: url("Inter-MediumItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-MediumItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-SemiBold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 600;
|
||||
font-display: swap;
|
||||
src: url("Inter-SemiBoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-SemiBoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-Bold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Bold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 700;
|
||||
font-display: swap;
|
||||
src: url("Inter-BoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-BoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBold.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraBold.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 800;
|
||||
font-display: swap;
|
||||
src: url("Inter-ExtraBoldItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-ExtraBoldItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: normal;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-Black.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-Black.woff?v=3.12") format("woff");
|
||||
}
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
font-style: italic;
|
||||
font-weight: 900;
|
||||
font-display: swap;
|
||||
src: url("Inter-BlackItalic.woff2?v=3.12") format("woff2"),
|
||||
url("Inter-BlackItalic.woff?v=3.12") format("woff");
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
<template>
|
||||
<Popover placement="right-start" class="flex w-full">
|
||||
<template #target="{ togglePopover }">
|
||||
<button
|
||||
:class="[
|
||||
'group w-full flex h-7 items-center justify-between rounded px-2 text-base text-gray-800 hover:bg-gray-100',
|
||||
]"
|
||||
@click.prevent="togglePopover()"
|
||||
>
|
||||
<div class="flex gap-2">
|
||||
<AppsIcon />
|
||||
<span class="whitespace-nowrap">Apps</span>
|
||||
</div>
|
||||
<ChevronRight class="h-4 w-4 stroke-1.5" />
|
||||
</button>
|
||||
</template>
|
||||
<template #body>
|
||||
<div
|
||||
class="grid grid-cols-3 justify-between mx-3 p-2 rounded-lg border border-gray-100 bg-white shadow-xl"
|
||||
>
|
||||
<div v-for="app in apps.data" key="name">
|
||||
<a
|
||||
:href="app.route"
|
||||
class="flex flex-col gap-1.5 rounded justify-center items-center py-2 px-3 hover:bg-gray-100"
|
||||
>
|
||||
<img class="size-8" :src="app.logo" />
|
||||
<div class="text-sm" @click="app.onClick">
|
||||
{{ app.title }}
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</template>
|
||||
<script setup>
|
||||
import { Popover, createResource } from "frappe-ui";
|
||||
import AppsIcon from "./icons/AppsIcon.vue";
|
||||
import ChevronRight from "~icons/lucide/chevron-right";
|
||||
|
||||
const apps = createResource({
|
||||
url: "frappe.apps.get_apps",
|
||||
cache: "apps",
|
||||
auto: true,
|
||||
transform: (data) => {
|
||||
let _apps = [
|
||||
{
|
||||
name: "frappe",
|
||||
logo: "/assets/helpdesk/desk/desk.png",
|
||||
title: "Desk",
|
||||
route: "/app",
|
||||
},
|
||||
];
|
||||
data.map((app) => {
|
||||
if (app.name === "helpdesk") return;
|
||||
_apps.push({
|
||||
name: app.name,
|
||||
logo: app.logo,
|
||||
title: app.title,
|
||||
route: app.route,
|
||||
});
|
||||
});
|
||||
return _apps;
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,128 +0,0 @@
|
||||
<template>
|
||||
<Dialog
|
||||
v-model="show"
|
||||
:options="{
|
||||
title: 'Assign To',
|
||||
size: 'xl',
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<SearchComplete
|
||||
class="form-control"
|
||||
doctype="HD Agent"
|
||||
:custom-filters="customFilters"
|
||||
:reset-input="true"
|
||||
@change="
|
||||
(option) => {
|
||||
addAssignee(option.value);
|
||||
}
|
||||
"
|
||||
>
|
||||
<template #item-prefix="{ option }">
|
||||
<UserAvatar class="mr-2" :name="option.value" size="sm" />
|
||||
</template>
|
||||
<template #item-label="{ option }">
|
||||
<Tooltip :text="option.value">
|
||||
{{ getUser(option.value).full_name }}
|
||||
</Tooltip>
|
||||
</template>
|
||||
</SearchComplete>
|
||||
<div class="mt-3 flex flex-wrap items-center gap-2">
|
||||
<Tooltip
|
||||
v-for="currentAssignee in assignees"
|
||||
:key="currentAssignee.name"
|
||||
:text="currentAssignee.name"
|
||||
>
|
||||
<Button
|
||||
:label="getUser(currentAssignee.name).full_name"
|
||||
theme="gray"
|
||||
variant="outline"
|
||||
>
|
||||
<template #prefix>
|
||||
<UserAvatar :name="currentAssignee.name" size="sm" />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<FeatherIcon
|
||||
class="h-3.5"
|
||||
name="x"
|
||||
@click.stop="removeCurrentAssignee(currentAssignee.name)"
|
||||
/>
|
||||
</template>
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<ErrorMessage v-if="error" class="mt-2" :message="error" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref, computed } from "vue";
|
||||
import { createResource } from "frappe-ui";
|
||||
import { UserAvatar, SearchComplete } from "@/components";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const props = defineProps({
|
||||
assignees: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
doctype: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
docname: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const show = defineModel();
|
||||
|
||||
const emit = defineEmits(["update"]);
|
||||
|
||||
const { getUser } = useUserStore();
|
||||
|
||||
const error = ref("");
|
||||
|
||||
const addAssignee = (value) => {
|
||||
error.value = "";
|
||||
createResource({
|
||||
url: "frappe.desk.form.assign_to.add",
|
||||
auto: true,
|
||||
params: {
|
||||
doctype: props.doctype,
|
||||
name: props.docname,
|
||||
assign_to: [value],
|
||||
},
|
||||
onSuccess: () => {
|
||||
emit("update");
|
||||
},
|
||||
});
|
||||
emit("update");
|
||||
};
|
||||
|
||||
const removeCurrentAssignee = (value) => {
|
||||
createResource({
|
||||
url: "frappe.desk.form.assign_to.remove",
|
||||
auto: true,
|
||||
params: {
|
||||
doctype: props.doctype,
|
||||
name: props.docname,
|
||||
assign_to: value,
|
||||
},
|
||||
onSuccess: () => {
|
||||
emit("update");
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const customFilters = computed(() => {
|
||||
const filters = {};
|
||||
filters["is_active"] = ["=", 1];
|
||||
if (Boolean(props.assignees?.length)) {
|
||||
filters["name"] = ["not in", [...props.assignees.map((a) => a.name)]];
|
||||
}
|
||||
return filters;
|
||||
});
|
||||
</script>
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<span>
|
||||
<a :href="isShowable ? null : url" target="_blank">
|
||||
<a :href="preview ? undefined : url" target="_blank">
|
||||
<Button
|
||||
:label="label"
|
||||
theme="gray"
|
||||
@@ -8,72 +8,113 @@
|
||||
@click="toggleDialog()"
|
||||
>
|
||||
<template #prefix>
|
||||
<component :is="getIcon()" class="h-4 w-4" />
|
||||
<component :is="icon" class="h-4 w-4" />
|
||||
</template>
|
||||
<template #suffix>
|
||||
<slot name="suffix" />
|
||||
</template>
|
||||
</Button>
|
||||
</a>
|
||||
<Dialog
|
||||
v-model="showDialog"
|
||||
:options="{
|
||||
title: label,
|
||||
size: '4xl',
|
||||
}"
|
||||
>
|
||||
<template #body-content>
|
||||
<Dialog v-model:open="showDialog" :title="label" size="4xl">
|
||||
<template #default>
|
||||
<div
|
||||
v-if="isText"
|
||||
v-if="preview === 'text'"
|
||||
class="prose prose-sm max-w-none whitespace-pre-wrap"
|
||||
>
|
||||
{{ content }}
|
||||
</div>
|
||||
<img v-if="isImage" :src="url" class="m-auto rounded border" />
|
||||
<img
|
||||
v-if="preview === 'image'"
|
||||
:src="url"
|
||||
class="m-auto rounded-4 border"
|
||||
/>
|
||||
<video
|
||||
v-if="preview === 'video'"
|
||||
:src="url"
|
||||
controls
|
||||
class="m-auto max-h-[70vh] rounded-4 border"
|
||||
/>
|
||||
</template>
|
||||
</Dialog>
|
||||
</span>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { Button, Dialog } from "frappe-ui";
|
||||
import { getType as getMime } from "mime";
|
||||
import LucideFileType from "~icons/lucide/file-type";
|
||||
import LucideFileImage from "~icons/lucide/file-image";
|
||||
import LucideFileText from "~icons/lucide/file-text";
|
||||
import LucideFileSpreadsheet from "~icons/lucide/file-spreadsheet";
|
||||
import { markRaw, ref, type Component } from "vue";
|
||||
import LucideFile from "~icons/lucide/file";
|
||||
import LucideFileImage from "~icons/lucide/file-image";
|
||||
import LucideFileSpreadsheet from "~icons/lucide/file-spreadsheet";
|
||||
import LucideFileText from "~icons/lucide/file-text";
|
||||
import LucideFileType from "~icons/lucide/file-type";
|
||||
import LucideFileVideo from "~icons/lucide/file-video";
|
||||
|
||||
interface P {
|
||||
label: string;
|
||||
url?: string;
|
||||
url?: string | null;
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<P>(), {
|
||||
url: null,
|
||||
});
|
||||
|
||||
const showDialog = ref(false);
|
||||
const mimeType = getMime(props.label) || "";
|
||||
const isImage = mimeType.startsWith("image/");
|
||||
const isPdf = mimeType === "application/pdf";
|
||||
const isSpreadsheet = mimeType.includes("spreadsheet");
|
||||
const isText = mimeType === "text/plain";
|
||||
const isShowable = props.url && (isText || isImage);
|
||||
const content = ref("");
|
||||
type AttachmentKind =
|
||||
| "image"
|
||||
| "video"
|
||||
| "pdf"
|
||||
| "spreadsheet"
|
||||
| "text"
|
||||
| "file";
|
||||
|
||||
function getIcon() {
|
||||
if (isText) return LucideFileType;
|
||||
else if (isImage) return LucideFileImage;
|
||||
else if (isPdf) return LucideFileText;
|
||||
else if (isSpreadsheet) return LucideFileSpreadsheet;
|
||||
else return LucideFile;
|
||||
const ICONS: Record<AttachmentKind, Component> = {
|
||||
image: markRaw(LucideFileImage),
|
||||
video: markRaw(LucideFileVideo),
|
||||
pdf: markRaw(LucideFileText),
|
||||
spreadsheet: markRaw(LucideFileSpreadsheet),
|
||||
text: markRaw(LucideFileType),
|
||||
file: markRaw(LucideFile),
|
||||
};
|
||||
|
||||
// browsers render only some image/video mimes (.dwg is image/vnd.dwg, .avi is
|
||||
// video/x-msvideo) — anything absent here becomes a download link like pdf
|
||||
type Preview = "image" | "video" | "text";
|
||||
|
||||
const PREVIEWS: Record<string, Preview> = {
|
||||
"image/png": "image",
|
||||
"image/jpeg": "image",
|
||||
"image/gif": "image",
|
||||
"image/webp": "image",
|
||||
"image/svg+xml": "image",
|
||||
"image/avif": "image",
|
||||
"image/bmp": "image",
|
||||
"image/apng": "image",
|
||||
"image/vnd.microsoft.icon": "image",
|
||||
"video/mp4": "video",
|
||||
"video/webm": "video",
|
||||
"video/ogg": "video",
|
||||
"video/x-m4v": "video",
|
||||
"text/plain": "text",
|
||||
};
|
||||
|
||||
function getKind(mime: string): AttachmentKind {
|
||||
if (mime.startsWith("image/")) return "image";
|
||||
if (mime.startsWith("video/")) return "video";
|
||||
if (mime === "application/pdf") return "pdf";
|
||||
if (mime.includes("spreadsheet")) return "spreadsheet";
|
||||
if (mime === "text/plain") return "text";
|
||||
return "file";
|
||||
}
|
||||
|
||||
const showDialog = ref(false);
|
||||
const mimeType = getMime(props.label) || "";
|
||||
const icon = ICONS[getKind(mimeType)];
|
||||
const preview = props.url ? PREVIEWS[mimeType] : undefined;
|
||||
const content = ref("");
|
||||
|
||||
function toggleDialog() {
|
||||
if (!isShowable) return;
|
||||
if (isText) {
|
||||
if (!preview) return;
|
||||
if (preview === "text") {
|
||||
fetch(props.url).then((res) => res.text().then((t) => (content.value = t)));
|
||||
}
|
||||
showDialog.value = !showDialog.value;
|
||||
|
||||
33
desk/src/components/AttachmentList.vue
Normal file
33
desk/src/components/AttachmentList.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<AttachmentItem
|
||||
v-for="attachment in attachments"
|
||||
:key="attachment.file_url"
|
||||
:label="attachment.file_name"
|
||||
:url="attachment.file_url"
|
||||
>
|
||||
<template #suffix>
|
||||
<LucideX
|
||||
class="size-3.5 cursor-pointer text-ink-gray-6 transition-colors hover:text-ink-gray-9"
|
||||
@click.stop.prevent="emit('remove', attachment)"
|
||||
/>
|
||||
</template>
|
||||
</AttachmentItem>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AttachmentItem } from "@/components";
|
||||
import LucideX from "~icons/lucide/x";
|
||||
|
||||
interface Attachment {
|
||||
file_url: string;
|
||||
file_name: string;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<{ attachments?: Attachment[] }>(), {
|
||||
attachments: () => [],
|
||||
});
|
||||
|
||||
const emit = defineEmits<{ remove: [attachment: Attachment] }>();
|
||||
</script>
|
||||
@@ -1,280 +0,0 @@
|
||||
<template>
|
||||
<Combobox v-slot="{ open: isComboboxOpen }" v-model="selectedValue" nullable>
|
||||
<Popover v-model:show="showOptions" class="w-full">
|
||||
<template #target="{ open: openPopover, togglePopover }">
|
||||
<slot name="target" v-bind="{ open: openPopover, togglePopover }">
|
||||
<div class="w-full">
|
||||
<button
|
||||
class="flex w-full items-center justify-between focus:outline-none"
|
||||
:class="inputClasses"
|
||||
@click="() => togglePopover()"
|
||||
>
|
||||
<div class="flex items-center">
|
||||
<slot name="prefix" />
|
||||
<span
|
||||
v-if="selectedValue"
|
||||
class="overflow-hidden text-ellipsis whitespace-nowrap text-base leading-5"
|
||||
>
|
||||
{{ displayValue(selectedValue) }}
|
||||
</span>
|
||||
<span v-else class="text-base leading-5 text-gray-500">
|
||||
{{ placeholder || "" }}
|
||||
</span>
|
||||
</div>
|
||||
<FeatherIcon
|
||||
name="chevron-down"
|
||||
class="h-4 w-4 text-gray-600"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</button>
|
||||
</div>
|
||||
</slot>
|
||||
</template>
|
||||
<template #body="{ isOpen }">
|
||||
<div v-show="isOpen">
|
||||
<div class="mt-1 rounded-lg bg-white py-1 text-base shadow-2xl">
|
||||
<div class="relative px-1.5 pt-0.5">
|
||||
<ComboboxInput
|
||||
ref="search"
|
||||
class="form-input w-full"
|
||||
type="text"
|
||||
:value="query"
|
||||
autocomplete="off"
|
||||
placeholder="Search"
|
||||
@change="
|
||||
(e) => {
|
||||
query = e.target.value;
|
||||
}
|
||||
"
|
||||
/>
|
||||
<button
|
||||
class="absolute right-1.5 inline-flex h-7 w-7 items-center justify-center"
|
||||
@click="selectedValue = null"
|
||||
>
|
||||
<FeatherIcon name="x" class="w-4" />
|
||||
</button>
|
||||
</div>
|
||||
<ComboboxOptions
|
||||
class="my-1 max-h-[12rem] overflow-y-auto px-1.5"
|
||||
static
|
||||
>
|
||||
<div
|
||||
v-for="group in groups"
|
||||
v-show="group.items.length > 0"
|
||||
:key="group.key"
|
||||
class="mt-1.5"
|
||||
>
|
||||
<div
|
||||
v-if="group.group && !group.hideLabel"
|
||||
class="px-2.5 py-1.5 text-sm font-medium text-gray-500"
|
||||
>
|
||||
{{ group.group }}
|
||||
</div>
|
||||
<ComboboxOption
|
||||
v-for="option in group.items"
|
||||
:key="option.value"
|
||||
v-slot="{ active, selected }"
|
||||
as="template"
|
||||
:value="option"
|
||||
>
|
||||
<li
|
||||
:class="[
|
||||
'flex items-center rounded px-2.5 py-1.5 text-base',
|
||||
{ 'bg-gray-100': active },
|
||||
]"
|
||||
>
|
||||
<slot
|
||||
name="item-prefix"
|
||||
v-bind="{ active, selected, option }"
|
||||
/>
|
||||
<slot
|
||||
name="item-label"
|
||||
v-bind="{ active, selected, option }"
|
||||
>
|
||||
{{ option.label }}
|
||||
</slot>
|
||||
</li>
|
||||
</ComboboxOption>
|
||||
</div>
|
||||
<li
|
||||
v-if="groups.length == 0"
|
||||
class="mt-1.5 rounded-md px-2.5 py-1.5 text-base text-gray-600"
|
||||
>
|
||||
No results found
|
||||
</li>
|
||||
</ComboboxOptions>
|
||||
<div v-if="slots.footer" class="border-t p-1.5 pb-0.5">
|
||||
<slot
|
||||
name="footer"
|
||||
v-bind="{ value: search?.el._value, close }"
|
||||
></slot>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
</Combobox>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import {
|
||||
Combobox,
|
||||
ComboboxInput,
|
||||
ComboboxOptions,
|
||||
ComboboxOption,
|
||||
} from "@headlessui/vue";
|
||||
import { Popover, Button, FeatherIcon } from "frappe-ui";
|
||||
import { ref, computed, useAttrs, useSlots, watch, nextTick } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
modelValue: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
options: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
},
|
||||
size: {
|
||||
type: String,
|
||||
default: "md",
|
||||
},
|
||||
variant: {
|
||||
type: String,
|
||||
default: "subtle",
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
filterable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
const emit = defineEmits(["update:modelValue", "update:query", "change"]);
|
||||
|
||||
const query = ref("");
|
||||
const showOptions = ref(false);
|
||||
const search = ref(null);
|
||||
|
||||
const attrs = useAttrs();
|
||||
const slots = useSlots();
|
||||
|
||||
const valuePropPassed = computed(() => "value" in attrs);
|
||||
|
||||
const selectedValue = computed({
|
||||
get() {
|
||||
return valuePropPassed.value ? attrs.value : props.modelValue;
|
||||
},
|
||||
set(val) {
|
||||
query.value = "";
|
||||
if (val) {
|
||||
showOptions.value = false;
|
||||
}
|
||||
emit(valuePropPassed.value ? "change" : "update:modelValue", val);
|
||||
},
|
||||
});
|
||||
|
||||
function close() {
|
||||
showOptions.value = false;
|
||||
}
|
||||
|
||||
const groups = computed(() => {
|
||||
if (!props.options || props.options.length == 0) return [];
|
||||
|
||||
let groups = props.options[0]?.group
|
||||
? props.options
|
||||
: [{ group: "", items: props.options }];
|
||||
|
||||
return groups
|
||||
.map((group, i) => {
|
||||
return {
|
||||
key: i,
|
||||
group: group.group,
|
||||
hideLabel: group.hideLabel || false,
|
||||
items: props.filterable ? filterOptions(group.items) : group.items,
|
||||
};
|
||||
})
|
||||
.filter((group) => group.items.length > 0);
|
||||
});
|
||||
|
||||
function filterOptions(options) {
|
||||
if (!query.value) {
|
||||
return options;
|
||||
}
|
||||
return options.filter((option) => {
|
||||
let searchTexts = [option.label, option.value];
|
||||
return searchTexts.some((text) =>
|
||||
(text || "").toString().toLowerCase().includes(query.value.toLowerCase())
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
function displayValue(option) {
|
||||
if (typeof option === "string") {
|
||||
let allOptions = groups.value.flatMap((group) => group.items);
|
||||
let selectedOption = allOptions.find((o) => o.value === option);
|
||||
return selectedOption?.label || option;
|
||||
}
|
||||
return option?.label;
|
||||
}
|
||||
|
||||
watch(query, (q) => {
|
||||
emit("update:query", q);
|
||||
});
|
||||
|
||||
watch(showOptions, (val) => {
|
||||
if (val) {
|
||||
nextTick(() => {
|
||||
search.value.el.focus();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const textColor = computed(() => {
|
||||
return props.disabled ? "text-gray-600" : "text-gray-800";
|
||||
});
|
||||
|
||||
const inputClasses = computed(() => {
|
||||
let sizeClasses = {
|
||||
sm: "text-base rounded h-7",
|
||||
md: "text-base rounded h-8",
|
||||
lg: "text-lg rounded-md h-10",
|
||||
xl: "text-xl rounded-md h-10",
|
||||
}[props.size];
|
||||
|
||||
let paddingClasses = {
|
||||
sm: "py-1.5 px-2",
|
||||
md: "py-1.5 px-2.5",
|
||||
lg: "py-1.5 px-3",
|
||||
xl: "py-1.5 px-3",
|
||||
}[props.size];
|
||||
|
||||
let variant = props.disabled ? "disabled" : props.variant;
|
||||
let variantClasses = {
|
||||
subtle:
|
||||
"border border-gray-100 bg-gray-100 placeholder-gray-500 hover:border-gray-200 hover:bg-gray-200 focus:bg-white focus:border-gray-500 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-gray-400",
|
||||
outline:
|
||||
"border border-gray-300 bg-white placeholder-gray-500 hover:border-gray-400 hover:shadow-sm focus:bg-white focus:border-gray-500 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-gray-400",
|
||||
disabled: [
|
||||
"border bg-gray-50 placeholder-gray-400",
|
||||
props.variant === "outline" ? "border-gray-300" : "border-transparent",
|
||||
],
|
||||
}[variant];
|
||||
|
||||
return [
|
||||
sizeClasses,
|
||||
paddingClasses,
|
||||
variantClasses,
|
||||
textColor.value,
|
||||
"transition-colors w-full",
|
||||
];
|
||||
});
|
||||
|
||||
defineExpose({ query });
|
||||
</script>
|
||||
32
desk/src/components/AvailabilityMenu.vue
Normal file
32
desk/src/components/AvailabilityMenu.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<Select
|
||||
:model-value="agentStatusStore.myStatus"
|
||||
:options="dropdownOptions"
|
||||
:placeholder="__('Set status')"
|
||||
variant="subtle"
|
||||
@update:model-value="agentStatusStore.setMyStatus"
|
||||
>
|
||||
<template #item-prefix="{ item }">
|
||||
<div
|
||||
class="size-2 rounded-full flex-shrink-0"
|
||||
:class="agentStatusStore.statusColor(item.value)"
|
||||
/>
|
||||
</template>
|
||||
</Select>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { useAgentStatusStore } from "@/stores/agentStatus";
|
||||
import { __ } from "@/translation";
|
||||
import { Select } from "frappe-ui";
|
||||
import { computed } from "vue";
|
||||
|
||||
const agentStatusStore = useAgentStatusStore();
|
||||
|
||||
const dropdownOptions = computed(() =>
|
||||
agentStatusStore.statusOptions.map((statusOption: string) => ({
|
||||
label: __(statusOption),
|
||||
value: statusOption,
|
||||
}))
|
||||
);
|
||||
</script>
|
||||
26
desk/src/components/BackButton.vue
Normal file
26
desk/src/components/BackButton.vue
Normal file
@@ -0,0 +1,26 @@
|
||||
<template>
|
||||
<Button
|
||||
variant="ghost"
|
||||
icon-left="lucide-chevron-left"
|
||||
:label="label"
|
||||
:size="size"
|
||||
class="!justify-start truncate font-medium text-ink-gray-8 hover:bg-transparent hover:opacity-70 focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 active:bg-transparent active:outline-none active:ring-0 rtl:flex-row-reverse ps-1"
|
||||
@click="$emit('back')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Button } from "frappe-ui";
|
||||
|
||||
interface P {
|
||||
label: string;
|
||||
size?: string;
|
||||
}
|
||||
|
||||
interface E {
|
||||
(event: "back"): void;
|
||||
}
|
||||
|
||||
withDefaults(defineProps<P>(), { size: "md" });
|
||||
defineEmits<E>();
|
||||
</script>
|
||||
283
desk/src/components/BarChartCard.vue
Normal file
283
desk/src/components/BarChartCard.vue
Normal file
@@ -0,0 +1,283 @@
|
||||
<template>
|
||||
<div class="w-full h-full overflow-hidden">
|
||||
<CardBase
|
||||
:title="title"
|
||||
:text="chartData.text"
|
||||
:percentageChange="chartData.percentageChange"
|
||||
:chartConfig="hasData ? chartConfig : placeholderChartConfig"
|
||||
:currentDuration="currentDuration"
|
||||
:orientation="orientation"
|
||||
:timelineFilter="timelineFilter"
|
||||
@changeDuration="changeDuration"
|
||||
>
|
||||
<template v-if="$slots.text" #text>
|
||||
<slot name="text" v-bind="{ text: chartData.text }" />
|
||||
</template>
|
||||
</CardBase>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { __ } from "@/translation";
|
||||
import { buildPercentageChange } from "@/utils";
|
||||
import { EChartsOption } from "echarts";
|
||||
import { createResource } from "frappe-ui";
|
||||
import { computed, onMounted, ref, type PropType } from "vue";
|
||||
import CardBase from "./ChartCardBase.vue";
|
||||
|
||||
interface BarChartData {
|
||||
percentage_change?: number;
|
||||
total?: number;
|
||||
average?: number;
|
||||
data: { date: string; count: number }[] | Record<number, number>;
|
||||
total_reviews?: number;
|
||||
}
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
apiUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
data: {
|
||||
type: Object as PropType<BarChartData>,
|
||||
required: true,
|
||||
},
|
||||
barColor: {
|
||||
type: String,
|
||||
default: "#3BBDE5",
|
||||
},
|
||||
dt: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
dn: {
|
||||
type: String,
|
||||
required: false,
|
||||
},
|
||||
orientation: {
|
||||
type: String as PropType<"vertical" | "horizontal">,
|
||||
default: "vertical",
|
||||
},
|
||||
measure: {
|
||||
type: String as PropType<"total" | "average">,
|
||||
default: "total",
|
||||
},
|
||||
negativeIsBetter: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
timelineFilter: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
// the untranslated key: it is lowercased straight into the API period
|
||||
const currentDuration = ref("Last month");
|
||||
|
||||
const chartData = computed(() => {
|
||||
const isDataFetched = resource.fetched;
|
||||
const _data: BarChartData = isDataFetched ? resource.data : props.data;
|
||||
|
||||
// Star-distribution shape: data is { 1: n, 2: n, ... }
|
||||
if (!props.timelineFilter && _data?.data && !Array.isArray(_data.data)) {
|
||||
const distribution = _data.data as Record<number, number>;
|
||||
const values = [1, 2, 3, 4, 5].map((s) => distribution[s] ?? 0);
|
||||
return {
|
||||
labels: ["1", "2", "3", "4", "5"],
|
||||
counts: values,
|
||||
percentageChange: buildPercentageChange(0, props.negativeIsBetter),
|
||||
text: _data?.average ?? 0,
|
||||
isStarDistribution: true,
|
||||
};
|
||||
}
|
||||
|
||||
// Time-series shape: data is [{ date, count }, ...]
|
||||
const timeData = Array.isArray(_data?.data)
|
||||
? (_data.data as { date: string; count: number }[])
|
||||
: [];
|
||||
const labels = timeData.map((item) => item.date);
|
||||
const counts = timeData.map((item) => item.count);
|
||||
const _percentageChange = _data?.percentage_change || 0;
|
||||
const percentageChange = buildPercentageChange(
|
||||
_percentageChange,
|
||||
props.negativeIsBetter
|
||||
);
|
||||
|
||||
return {
|
||||
labels,
|
||||
counts,
|
||||
percentageChange,
|
||||
text: props.measure === "average" ? _data?.average ?? 0 : _data?.total ?? 0,
|
||||
isStarDistribution: false,
|
||||
};
|
||||
});
|
||||
|
||||
const hasData = computed(() => {
|
||||
const counts = chartData.value.counts as number[];
|
||||
return counts.length > 0 && counts.some((c) => c > 0);
|
||||
});
|
||||
|
||||
const chartConfig = computed<EChartsOption>(() => {
|
||||
const color = props.barColor;
|
||||
|
||||
if (chartData.value.isStarDistribution) {
|
||||
const values = chartData.value.counts as number[];
|
||||
// rank by value descending: index 0 = highest, 4 = lowest
|
||||
const opacities = [1, 0.7, 0.5, 0.3, 0.2];
|
||||
const baseColor = props.barColor; // #E79913
|
||||
|
||||
// unique sorted counts descending (for tie-aware rank lookup)
|
||||
const uniqueSorted = [...new Set(values)].sort((a, b) => b - a);
|
||||
|
||||
const opacityByIndex: number[] = values.map((v) => {
|
||||
const rank = uniqueSorted.indexOf(v); // same count → same rank
|
||||
return opacities[Math.min(rank, opacities.length - 1)];
|
||||
});
|
||||
|
||||
// helper: hex + opacity → rgba
|
||||
const hexToRgba = (hex: string, alpha: number) => {
|
||||
const r = parseInt(hex.slice(1, 3), 16);
|
||||
const g = parseInt(hex.slice(3, 5), 16);
|
||||
const b = parseInt(hex.slice(5, 7), 16);
|
||||
return `rgba(${r},${g},${b},${alpha})`;
|
||||
};
|
||||
|
||||
return {
|
||||
grid: { left: 4, right: 4, top: 16, bottom: 20, containLabel: false },
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: ["1", "2", "3", "4", "5"],
|
||||
axisLine: { show: true, lineStyle: { color: "#ededed" } },
|
||||
axisTick: { show: false },
|
||||
axisLabel: { color: "#6b7280", fontSize: 11 },
|
||||
},
|
||||
yAxis: { type: "value", show: false, min: 0 },
|
||||
series: [
|
||||
{
|
||||
type: "bar",
|
||||
data: values.map((value, i) => ({
|
||||
value: value === 0 ? 0 : value,
|
||||
itemStyle: {
|
||||
color: hexToRgba(baseColor, opacityByIndex[i]),
|
||||
borderRadius: [4, 4, 0, 0],
|
||||
},
|
||||
label: {
|
||||
show: true,
|
||||
position: "top" as const,
|
||||
formatter: value > 0 ? String(value) : "",
|
||||
color: "#6b7280",
|
||||
fontSize: 11,
|
||||
},
|
||||
})),
|
||||
barWidth: 16,
|
||||
emphasis: { disabled: true },
|
||||
},
|
||||
],
|
||||
tooltip: { show: false },
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
xAxis: {
|
||||
type: "category",
|
||||
data: chartData.value.labels,
|
||||
show: false,
|
||||
boundaryGap: true,
|
||||
},
|
||||
yAxis: {
|
||||
type: "value",
|
||||
show: false,
|
||||
},
|
||||
series: [
|
||||
{
|
||||
data: (chartData.value.counts as number[]).map((value) => ({
|
||||
value,
|
||||
itemStyle: {
|
||||
color: value === 0 ? "#e5e7eb" : color,
|
||||
borderRadius: [3, 3, 0, 0],
|
||||
},
|
||||
})),
|
||||
type: "bar",
|
||||
barMaxWidth: 12,
|
||||
barMinHeight: 4,
|
||||
emphasis: { disabled: true },
|
||||
label: { show: false },
|
||||
},
|
||||
],
|
||||
grid: {
|
||||
left: 2,
|
||||
right: 2,
|
||||
top: 2,
|
||||
bottom: 2,
|
||||
},
|
||||
tooltip: {
|
||||
show: true,
|
||||
trigger: "axis",
|
||||
appendToBody: true,
|
||||
position: (point: number[]) => [point[0] + 12, point[1] - 50],
|
||||
axisPointer: { type: "none" },
|
||||
formatter: (params: any) => {
|
||||
const p = Array.isArray(params) ? params[0] : params;
|
||||
if (!p.value) return "";
|
||||
return `<span style="font-size:12px;color:#6b7280">${p.name}: <b style="color:#374151">${p.value}</b></span>`;
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
const placeholderChartConfig = computed<EChartsOption>(() => {
|
||||
const placeholderValues = Array.from(
|
||||
{ length: 7 },
|
||||
() => Math.floor(Math.random() * 8) + 3
|
||||
);
|
||||
return {
|
||||
xAxis: { type: "category", show: false, boundaryGap: true },
|
||||
yAxis: { type: "value", show: false },
|
||||
series: [
|
||||
{
|
||||
data: placeholderValues.map((value) => ({
|
||||
value,
|
||||
itemStyle: { color: "#f1f1f1", borderRadius: [3, 3, 0, 0] },
|
||||
})),
|
||||
type: "bar",
|
||||
barMaxWidth: 12,
|
||||
emphasis: { disabled: true },
|
||||
},
|
||||
],
|
||||
grid: { left: 2, right: 2, top: 2, bottom: 2 },
|
||||
tooltip: { show: false },
|
||||
animation: false,
|
||||
};
|
||||
});
|
||||
|
||||
const resource = createResource({
|
||||
url: props.apiUrl || "",
|
||||
type: "GET",
|
||||
makeParams: () => {
|
||||
const params: Record<string, any> = {
|
||||
period: currentDuration.value.toLowerCase(),
|
||||
};
|
||||
if (props.dt && props.dn) {
|
||||
params.dt = props.dt;
|
||||
params.dn = props.dn;
|
||||
}
|
||||
return params;
|
||||
},
|
||||
});
|
||||
|
||||
const changeDuration = (period: string) => {
|
||||
currentDuration.value = period;
|
||||
if (props.apiUrl) resource.submit();
|
||||
};
|
||||
|
||||
onMounted(() => {
|
||||
if (props.timelineFilter && props.apiUrl && !props.data?.data) {
|
||||
resource.submit();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -1,10 +1,14 @@
|
||||
<template>
|
||||
<Avatar v-if="config.brandLogo" size="xl" :image="config.brandLogo" />
|
||||
<HDLogo v-else class="h-8 w-8 shrink-0 rounded" />
|
||||
<img
|
||||
v-if="config.brandLogo"
|
||||
:src="config.brandLogo"
|
||||
alt="Brand Logo"
|
||||
class="h-8 w-8 shrink-0 object-cover"
|
||||
/>
|
||||
<HDLogo v-else class="h-8 w-8 shrink-0 rounded-4" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { Avatar } from "frappe-ui";
|
||||
import HDLogo from "@/assets/logos/HDLogo.vue";
|
||||
|
||||
import { useConfigStore } from "@/stores/config";
|
||||
|
||||
118
desk/src/components/CallArea.vue
Normal file
118
desk/src/components/CallArea.vue
Normal file
@@ -0,0 +1,118 @@
|
||||
<template>
|
||||
<div class="w-full">
|
||||
<div class="mb-1 flex items-center justify-stretch gap-2 py-1 text-base">
|
||||
<div class="inline-flex items-center flex-wrap gap-1 text-ink-gray-5">
|
||||
<Avatar
|
||||
:image="activity?._caller?.image"
|
||||
:label="activity?._caller?.label"
|
||||
size="md"
|
||||
/>
|
||||
<span class="font-medium text-ink-gray-8 ms-1">
|
||||
{{ activity?._caller?.label }}
|
||||
</span>
|
||||
<span>{{
|
||||
activity.call_type == "Incoming"
|
||||
? __("has reached out")
|
||||
: __("has made a call")
|
||||
}}</span>
|
||||
</div>
|
||||
<div class="ms-auto whitespace-nowrap">
|
||||
<Tooltip :text="dateFormat(activity.creation, 'MMM D, dddd')">
|
||||
<div class="text-sm text-ink-gray-5">
|
||||
{{ __(timeAgo(activity.creation)) }}
|
||||
</div>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
@click="showCallLogDetailModal = true"
|
||||
class="flex flex-col gap-2 cursor-pointer border-transparent shadow rounded-5 bg-surface-elevation-1 px-3 py-2.5 text-ink-gray-9"
|
||||
>
|
||||
<div class="flex items-center justify-between">
|
||||
<div class="inline-flex gap-2 items-center text-base-medium">
|
||||
<div>
|
||||
{{
|
||||
activity.call_type == "Incoming"
|
||||
? __("Inbound Call")
|
||||
: __("Outbound Call")
|
||||
}}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<MultipleAvatar
|
||||
:avatars="[
|
||||
{
|
||||
name: activity._caller.label,
|
||||
label: activity._caller.label,
|
||||
image: activity._caller.image,
|
||||
},
|
||||
{
|
||||
name: activity._receiver.label,
|
||||
label: activity._receiver.label,
|
||||
image: activity._receiver.image,
|
||||
},
|
||||
]"
|
||||
size="sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex items-center flex-wrap gap-2">
|
||||
<Badge :label="dateFormat(activity.creation, 'MMM D, dddd')">
|
||||
<template #prefix>
|
||||
<CalendarIcon class="size-3" />
|
||||
</template>
|
||||
</Badge>
|
||||
<Badge v-if="activity.status == 'Completed'" :label="activity.duration">
|
||||
<template #prefix>
|
||||
<DurationIcon class="size-3" />
|
||||
</template>
|
||||
</Badge>
|
||||
<Badge
|
||||
v-if="activity.recording_url"
|
||||
:label="__('Listen')"
|
||||
class="cursor-pointer"
|
||||
>
|
||||
<template #prefix>
|
||||
<PlayIcon class="size-3" />
|
||||
</template>
|
||||
</Badge>
|
||||
<Badge
|
||||
:label="statusLabelMap[activity.status]"
|
||||
:theme="statusColorMap[activity.status]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<CallLogDetailModal
|
||||
v-model="showCallLogDetailModal"
|
||||
v-model:callLogModal="showCallLogModal"
|
||||
:callLogId="props.activity.name"
|
||||
:hideTicket="true"
|
||||
/>
|
||||
<CallLogModal
|
||||
v-model="showCallLogModal"
|
||||
:callLogId="props.activity.name"
|
||||
@afterInsert="refreshTicket()"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { dateFormat, timeAgo } from "@/utils";
|
||||
import { Avatar, Badge, Tooltip } from "frappe-ui";
|
||||
import { inject, ref } from "vue";
|
||||
import MultipleAvatar from "./MultipleAvatar.vue";
|
||||
import CalendarIcon from "./icons/CalendarIcon.vue";
|
||||
import DurationIcon from "./icons/DurationIcon.vue";
|
||||
import PlayIcon from "./icons/PlayIcon.vue";
|
||||
import { statusColorMap, statusLabelMap } from "@/pages/call-logs/utils";
|
||||
import CallLogDetailModal from "@/pages/call-logs/CallLogDetailModal.vue";
|
||||
import CallLogModal from "@/pages/call-logs/CallLogModal.vue";
|
||||
|
||||
const props = defineProps({
|
||||
activity: Object,
|
||||
});
|
||||
|
||||
const showCallLogDetailModal = ref(false);
|
||||
const showCallLogModal = ref(false);
|
||||
|
||||
const refreshTicket = inject<() => void>("refreshTicket");
|
||||
</script>
|
||||
@@ -1,89 +0,0 @@
|
||||
<template>
|
||||
<Dialog v-model="show" :options="{ title: 'Canned Responses', size: '4xl' }">
|
||||
<template #body-content>
|
||||
<TextInput
|
||||
ref="searchInput"
|
||||
v-model="search"
|
||||
type="text"
|
||||
:placeholder="'Site Down'"
|
||||
>
|
||||
<template #prefix>
|
||||
<FeatherIcon name="search" class="h-4 w-4 text-gray-500" />
|
||||
</template>
|
||||
</TextInput>
|
||||
<div
|
||||
v-if="filteredTemplates.length"
|
||||
class="mt-2 grid max-h-[560px] grid-cols-1 md:grid-cols-3 gap-2 overflow-y-auto"
|
||||
>
|
||||
<div
|
||||
v-for="template in filteredTemplates"
|
||||
:key="template.name"
|
||||
class="flex h-56 cursor-pointer flex-col gap-2 rounded-lg border p-3 hover:bg-gray-100"
|
||||
@click="emit('apply', template)"
|
||||
>
|
||||
<div class="border-b pb-2 text-base font-semibold">
|
||||
{{ template.title }}
|
||||
</div>
|
||||
<TextEditor
|
||||
v-if="template.message"
|
||||
:content="template.message"
|
||||
:editable="false"
|
||||
editor-class="!prose-sm max-w-none !text-sm text-gray-600 focus:outline-none"
|
||||
class="flex-1 overflow-hidden"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else class="mt-2">
|
||||
<div class="flex h-56 flex-col items-center justify-center">
|
||||
<div class="text-lg text-gray-500">
|
||||
{{ "No templates found" }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { TextEditor, createListResource } from "frappe-ui";
|
||||
import { ref, computed, nextTick, watch, onMounted } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
doctype: {
|
||||
type: String,
|
||||
default: "",
|
||||
},
|
||||
});
|
||||
|
||||
const show = defineModel();
|
||||
const searchInput = ref("");
|
||||
|
||||
const emit = defineEmits(["apply"]);
|
||||
|
||||
const search = ref("");
|
||||
|
||||
const templates = createListResource({
|
||||
type: "list",
|
||||
doctype: "HD Canned Response",
|
||||
cache: ["cannedResponses", props.doctype],
|
||||
fields: ["title", "message", "modified"],
|
||||
orderBy: "modified desc",
|
||||
pageLength: 99999,
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (templates.data == null) {
|
||||
templates.fetch();
|
||||
}
|
||||
});
|
||||
|
||||
const filteredTemplates = computed(() => {
|
||||
return (
|
||||
templates.data?.filter((template) => {
|
||||
return template.title.toLowerCase().includes(search.value.toLowerCase());
|
||||
}) ?? []
|
||||
);
|
||||
});
|
||||
|
||||
watch(show, (value) => value && nextTick(() => searchInput.value?.el?.focus()));
|
||||
</script>
|
||||
173
desk/src/components/ChartCardBase.vue
Normal file
173
desk/src/components/ChartCardBase.vue
Normal file
@@ -0,0 +1,173 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-col w-full h-full rounded-5 p-4"
|
||||
:class="[orientation == 'horizontal' && 'pt-3']"
|
||||
>
|
||||
<slot name="title">
|
||||
<div class="text-ink-gray-5 text-base mb-2">
|
||||
{{ title }}
|
||||
</div>
|
||||
</slot>
|
||||
<div
|
||||
class="flex flex-col gap-2 h-full w-full"
|
||||
v-if="orientation === 'vertical'"
|
||||
>
|
||||
<div class="flex items-end w-full gap-2">
|
||||
<slot name="text">
|
||||
<div
|
||||
class="text-2xl-medium text-center text-ink-gray-8 whitespace-nowrap"
|
||||
>
|
||||
{{ text }}
|
||||
</div>
|
||||
</slot>
|
||||
<div v-if="timelineFilter" class="flex items-center text-sm gap-1">
|
||||
<div class="flex items-center gap-1" :class="percentageChange.color">
|
||||
<span
|
||||
v-if="percentageChange.icon"
|
||||
:class="percentageChange.icon"
|
||||
class="size-4"
|
||||
/>
|
||||
<div>{{ percentageChange.value }}%</div>
|
||||
</div>
|
||||
<Dropdown :options="durationOptions">
|
||||
<div
|
||||
class="flex items-center gap-0.5 text-ink-gray-5 hover:text-ink-gray-6 cursor-pointer shrink-0"
|
||||
>
|
||||
<div class="flex gap-1">
|
||||
<span>vs</span>
|
||||
<span>{{ __(currentDuration).toLowerCase() }}</span>
|
||||
</div>
|
||||
<LucideChevronDown class="size-4" />
|
||||
</div>
|
||||
<template #item-label="{ item }">
|
||||
<div
|
||||
class="data-[disabled]:cursor-not-allowed group flex w-full items-center rounded-4 px-2 text-base focus:outline-none focus:bg-surface-gray-3 data-[highlighted]:bg-surface-gray-3 data-[state=open]:bg-surface-gray-3 whitespace-nowrap text-ink-gray-7 cursor-pointer justify-between"
|
||||
>
|
||||
<span>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #item-suffix="{ item }">
|
||||
<LucideCheck
|
||||
v-if="item.label == __(currentDuration)"
|
||||
class="size-4"
|
||||
/>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<slot name="chart">
|
||||
<div v-if="chartConfig" class="w-full h-full">
|
||||
<ECharts :options="chartConfig" class="w-full h-full" />
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div class="flex flex-col gap-2 h-full w-full" v-else>
|
||||
<div class="flex items-end w-full gap-2 justify-between flex-1">
|
||||
<slot name="text">
|
||||
<span
|
||||
class="text-2xl-medium text-center text-ink-gray-8 whitespace-nowrap"
|
||||
>
|
||||
{{ text }}
|
||||
</span>
|
||||
</slot>
|
||||
<slot name="chart">
|
||||
<div v-if="chartConfig" class="h-full max-w-[50%] w-[50%]">
|
||||
<ECharts :options="chartConfig" class="w-full h-full" />
|
||||
</div>
|
||||
</slot>
|
||||
</div>
|
||||
<div v-if="timelineFilter" class="flex items-center text-sm gap-1">
|
||||
<div class="flex items-center gap-1" :class="percentageChange.color">
|
||||
<span
|
||||
v-if="percentageChange.icon"
|
||||
:class="percentageChange.icon"
|
||||
class="size-4"
|
||||
/>
|
||||
<div>{{ percentageChange.value }}%</div>
|
||||
</div>
|
||||
<Dropdown :options="durationOptions">
|
||||
<div
|
||||
class="flex items-center gap-0.5 text-ink-gray-5 hover:text-ink-gray-6 cursor-pointer shrink-0"
|
||||
>
|
||||
vs {{ __(currentDuration).toLowerCase() }}
|
||||
<LucideChevronDown class="size-4" />
|
||||
</div>
|
||||
<template #item-label="{ item }">
|
||||
<div
|
||||
class="data-[disabled]:cursor-not-allowed group flex w-full items-center rounded-4 px-2 text-base focus:outline-none focus:bg-surface-gray-3 data-[highlighted]:bg-surface-gray-3 data-[state=open]:bg-surface-gray-3 whitespace-nowrap text-ink-gray-7 cursor-pointer justify-between"
|
||||
>
|
||||
<span>
|
||||
{{ item.label }}
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
<template #item-suffix="{ item }">
|
||||
<LucideCheck
|
||||
v-if="item.label == __(currentDuration)"
|
||||
class="size-4"
|
||||
/>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import LucideCheck from "~icons/lucide/check";
|
||||
import LucideChevronDown from "~icons/lucide/chevron-down";
|
||||
import { __ } from "@/translation";
|
||||
import { EChartsOption } from "echarts";
|
||||
import { Dropdown } from "frappe-ui";
|
||||
import { ECharts } from "frappe-ui/experimental";
|
||||
import { computed, type PropType } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
text: {
|
||||
type: [Number, String] as PropType<number | string>,
|
||||
default: "",
|
||||
},
|
||||
percentageChange: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
chartConfig: {
|
||||
type: Object as PropType<EChartsOption>,
|
||||
required: true,
|
||||
},
|
||||
currentDuration: {
|
||||
type: String,
|
||||
default: __("Last month"),
|
||||
},
|
||||
orientation: {
|
||||
type: String as PropType<"vertical" | "horizontal">,
|
||||
default: "vertical",
|
||||
},
|
||||
timelineFilter: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
});
|
||||
|
||||
const chartConfig = computed<EChartsOption>(() => props.chartConfig);
|
||||
|
||||
const currentDuration = computed(() => props.currentDuration);
|
||||
|
||||
const emit = defineEmits(["changeDuration"]);
|
||||
|
||||
// the emitted value is the untranslated key: it travels to the API as the
|
||||
// period, so only the label goes through __()
|
||||
const DURATIONS = ["Last week", "Last month", "Last 3 months"];
|
||||
|
||||
const durationOptions = DURATIONS.map((duration) => ({
|
||||
label: __(duration),
|
||||
onClick: () => {
|
||||
if (currentDuration.value !== duration) emit("changeDuration", duration);
|
||||
},
|
||||
}));
|
||||
</script>
|
||||
@@ -1,212 +0,0 @@
|
||||
<template>
|
||||
<NestedPopover>
|
||||
<template #target>
|
||||
<Button label="Columns">
|
||||
<template v-if="hideLabel">
|
||||
<ColumnsIcon class="h-4" />
|
||||
</template>
|
||||
<template v-if="!hideLabel" #prefix>
|
||||
<ColumnsIcon class="h-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
<template #body>
|
||||
<div
|
||||
class="my-2 rounded-lg border border-gray-100 bg-white p-1.5 shadow-xl"
|
||||
>
|
||||
<div v-if="!edit">
|
||||
<Draggable
|
||||
:list="columns"
|
||||
item-key="key"
|
||||
class="list-group"
|
||||
@end="update"
|
||||
>
|
||||
<template #item="{ element }">
|
||||
<div
|
||||
class="flex cursor-grab items-center justify-between gap-6 rounded px-2 py-1.5 text-base text-gray-800 hover:bg-gray-100"
|
||||
>
|
||||
<div class="flex items-center gap-2">
|
||||
<DragIcon class="h-3.5" />
|
||||
<div>{{ element.label }}</div>
|
||||
</div>
|
||||
<div class="flex cursor-pointer items-center gap-1">
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="!h-5 w-5 !p-1"
|
||||
@click="editColumn(element)"
|
||||
>
|
||||
<EditIcon class="h-3.5" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="!h-5 w-5 !p-1"
|
||||
@click="removeColumn(element)"
|
||||
>
|
||||
<FeatherIcon name="x" class="h-3.5" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Draggable>
|
||||
<div class="mt-1.5 flex flex-col gap-1 border-t pt-1.5">
|
||||
<Autocomplete
|
||||
value=""
|
||||
:options="fields"
|
||||
@change="(e) => addColumn(e)"
|
||||
>
|
||||
<template #target="{ togglePopover }">
|
||||
<Button
|
||||
class="w-full !justify-start !text-gray-600"
|
||||
variant="ghost"
|
||||
label="Add Column"
|
||||
@click="togglePopover()"
|
||||
>
|
||||
<template #prefix>
|
||||
<FeatherIcon name="plus" class="h-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
</Autocomplete>
|
||||
<Button
|
||||
class="w-full !justify-start !text-gray-600"
|
||||
variant="ghost"
|
||||
label="Reset to Default"
|
||||
@click="resetToDefault(close)"
|
||||
>
|
||||
<template #prefix>
|
||||
<ReloadIcon class="h-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<div
|
||||
class="flex flex-col items-center justify-between gap-2 rounded px-2 py-1.5 text-base text-gray-800"
|
||||
>
|
||||
<div class="flex flex-col items-center gap-3">
|
||||
<FormControl
|
||||
v-model="column.label"
|
||||
type="text"
|
||||
size="md"
|
||||
label="Label"
|
||||
class="w-full"
|
||||
placeholder="Column Label"
|
||||
/>
|
||||
<FormControl
|
||||
v-model="column.width"
|
||||
type="text"
|
||||
size="md"
|
||||
label="Width"
|
||||
class="w-full"
|
||||
placeholder="Column Width"
|
||||
description="Width can be in number, pixel or rem (eg. 3, 30px, 10rem)"
|
||||
:debounce="500"
|
||||
/>
|
||||
</div>
|
||||
<div class="flex w-full gap-2 border-t pt-2">
|
||||
<Button
|
||||
variant="subtle"
|
||||
label="Cancel"
|
||||
class="w-full flex-1"
|
||||
@click="cancelUpdate"
|
||||
/>
|
||||
<Button
|
||||
variant="solid"
|
||||
label="Update"
|
||||
class="w-full flex-1"
|
||||
@click="update"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</NestedPopover>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import ColumnsIcon from "@/components/icons/ColumnsIcon.vue";
|
||||
import EditIcon from "@/components/icons/EditIcon.vue";
|
||||
import NestedPopover from "@/components/NestedPopover.vue";
|
||||
import { Autocomplete } from "@/components";
|
||||
import Draggable from "vuedraggable";
|
||||
|
||||
let emit = defineEmits(["event:column"]);
|
||||
let edit = ref(false);
|
||||
const column = ref({
|
||||
old: {},
|
||||
label: "",
|
||||
key: "",
|
||||
width: "10rem",
|
||||
});
|
||||
|
||||
let props = defineProps({
|
||||
fields: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
columns: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
hideLabel: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isCustomerPortal: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
});
|
||||
|
||||
function resetToDefault(close) {
|
||||
let columnEvent = {
|
||||
event: "reset",
|
||||
};
|
||||
emit("event:column", columnEvent);
|
||||
close();
|
||||
}
|
||||
|
||||
function editColumn(c) {
|
||||
edit.value = true;
|
||||
column.value = c;
|
||||
column.value.old = { ...c };
|
||||
}
|
||||
|
||||
function cancelUpdate() {
|
||||
edit.value = false;
|
||||
column.value.label = column.value.old.label;
|
||||
column.value.width = column.value.old.width;
|
||||
delete column.value.old;
|
||||
}
|
||||
|
||||
function addColumn(c) {
|
||||
let columnEvent = {
|
||||
event: "add",
|
||||
data: {
|
||||
label: c.label,
|
||||
type: c.type,
|
||||
key: c.value,
|
||||
width: "10rem",
|
||||
},
|
||||
};
|
||||
emit("event:column", columnEvent);
|
||||
}
|
||||
|
||||
function update() {
|
||||
edit.value = false;
|
||||
let columnEvent = {
|
||||
event: "update",
|
||||
};
|
||||
emit("event:column", columnEvent);
|
||||
}
|
||||
|
||||
function removeColumn(c) {
|
||||
let columnEvent = {
|
||||
event: "remove",
|
||||
data: c,
|
||||
};
|
||||
emit("event:column", columnEvent);
|
||||
}
|
||||
</script>
|
||||
@@ -1,97 +0,0 @@
|
||||
<template>
|
||||
<div class="flex-col text-base">
|
||||
<div class="mb-1 ml-0.5 flex items-center justify-between">
|
||||
<div class="text-gray-600 flex items-center gap-2">
|
||||
<Avatar
|
||||
size="sm"
|
||||
:label="commenter"
|
||||
:image="getUser(commentedBy).user_image"
|
||||
/>
|
||||
<p>
|
||||
<span class="font-medium text-gray-800">
|
||||
{{ commenter }}
|
||||
</span>
|
||||
<span> added a</span>
|
||||
<span class="max-w-xs truncate font-medium text-gray-800">
|
||||
comment
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center">
|
||||
<Tooltip :text="dateFormat(creation, dateTooltipFormat)">
|
||||
<span class="pl-0.5 text-sm text-gray-600">
|
||||
{{ timeAgo(creation) }}
|
||||
</span>
|
||||
</Tooltip>
|
||||
<div v-if="authStore.userId === commentedBy">
|
||||
<Dropdown
|
||||
:options="[{ label: 'Delete', onClick: () => (showDialog = true) }]"
|
||||
>
|
||||
<Button
|
||||
icon="more-horizontal"
|
||||
class="text-gray-600"
|
||||
variant="ghost"
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="prose-f grow cursor-pointer rounded bg-gray-50 px-4 py-3 text-base leading-6 transition-all duration-300 ease-in-out"
|
||||
v-html="content"
|
||||
/>
|
||||
</div>
|
||||
<Dialog
|
||||
v-model="showDialog"
|
||||
:options="{
|
||||
title: 'Delete Comment',
|
||||
message: 'Are you sure you want to confirm this action?',
|
||||
actions: [
|
||||
{ label: 'Cancel', onClick: () => (showDialog = false) },
|
||||
{
|
||||
label: 'Delete',
|
||||
onClick: () => deleteComment.submit(),
|
||||
variant: 'solid',
|
||||
},
|
||||
],
|
||||
}"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { Dropdown, createResource, Dialog, Avatar } from "frappe-ui";
|
||||
import { dateFormat, timeAgo, dateTooltipFormat, createToast } from "@/utils";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
|
||||
const authStore = useAuthStore();
|
||||
const props = defineProps({
|
||||
activity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
const { getUser } = useUserStore();
|
||||
|
||||
const { name, creation, content, commenter, commentedBy } = props.activity;
|
||||
|
||||
const emit = defineEmits(["update"]);
|
||||
const showDialog = ref(false);
|
||||
|
||||
const deleteComment = createResource({
|
||||
url: "frappe.client.delete",
|
||||
makeParams: () => ({
|
||||
doctype: "HD Ticket Comment",
|
||||
name: name,
|
||||
}),
|
||||
onSuccess() {
|
||||
emit("update");
|
||||
createToast({
|
||||
title: "Comment deleted",
|
||||
icon: "check",
|
||||
iconClasses: "text-green-500",
|
||||
});
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,115 +1,156 @@
|
||||
<template>
|
||||
<TextEditor
|
||||
v-if="agentsList.data"
|
||||
ref="textEditor"
|
||||
:editor-class="[
|
||||
'prose-sm max-w-none',
|
||||
editable &&
|
||||
'min-h-[7rem] mx-10 max-h-[50vh] overflow-y-auto border-t py-3',
|
||||
]"
|
||||
:content="newComment"
|
||||
:starterkit-options="{ heading: { levels: [2, 3, 4, 5, 6] } }"
|
||||
:placeholder="placeholder"
|
||||
<Editor
|
||||
ref="editorRef"
|
||||
v-model="newComment"
|
||||
:extensions="extensions"
|
||||
:editable="editable"
|
||||
:mentions="agents"
|
||||
@change="editable ? (newComment = $event) : null"
|
||||
:placeholder="placeholder"
|
||||
:upload-function="
|
||||
(file: any, options: any) =>
|
||||
track(uploadFunction(file, doctype, ticketId, true, options))
|
||||
"
|
||||
>
|
||||
<template #bottom>
|
||||
<div v-if="editable" class="flex flex-col gap-2">
|
||||
<div class="flex flex-wrap gap-2 px-10">
|
||||
<AttachmentItem
|
||||
v-for="a in attachments"
|
||||
:key="a.file_url"
|
||||
:label="a.file_name"
|
||||
>
|
||||
<template #suffix>
|
||||
<FeatherIcon
|
||||
class="h-3.5"
|
||||
name="x"
|
||||
@click.stop="removeAttachment(a)"
|
||||
/>
|
||||
</template>
|
||||
</AttachmentItem>
|
||||
</div>
|
||||
<div
|
||||
class="flex justify-between gap-2 overflow-hidden border-t px-10 py-2.5"
|
||||
>
|
||||
<div class="flex items-center overflow-x-auto">
|
||||
<TextEditorFixedMenu
|
||||
class="-ml-1"
|
||||
:buttons="textEditorMenuButtons"
|
||||
/>
|
||||
<FileUploader
|
||||
:upload-args="{
|
||||
doctype: doctype,
|
||||
docname: modelValue.name,
|
||||
private: true,
|
||||
}"
|
||||
@success="(f) => attachments.push(f)"
|
||||
>
|
||||
<template #default="{ openFileSelector }">
|
||||
<Button
|
||||
theme="gray"
|
||||
variant="ghost"
|
||||
@click="openFileSelector()"
|
||||
<template #default="{ isEmpty }">
|
||||
<!-- Scroll here so selected nodes aren't clipped. -->
|
||||
<div :class="editable && 'max-h-[44vh] overflow-y-auto'">
|
||||
<EditorContent
|
||||
:class="[
|
||||
'prose-sm max-w-none',
|
||||
editable && 'min-h-[7rem] mx-5 border-t py-3',
|
||||
getFontFamily(newComment),
|
||||
]"
|
||||
/>
|
||||
</div>
|
||||
<!-- Attachments -->
|
||||
<AttachmentList
|
||||
class="my-2 ms-5"
|
||||
:attachments="attachments"
|
||||
@remove="removeAttachment"
|
||||
/>
|
||||
<div v-if="editable" class="flex flex-col gap-2 border-t">
|
||||
<div class="px-4">
|
||||
<!-- Fixed Menu -->
|
||||
<div class="flex justify-between gap-2 overflow-hidden py-2.5">
|
||||
<div class="flex min-w-0 flex-1 items-center overflow-x-auto">
|
||||
<div class="inline-flex items-center gap-1.5 p-1">
|
||||
<FileUploader
|
||||
:doctype="doctype"
|
||||
:docname="ticketId"
|
||||
private
|
||||
@success="(f) => attachments.push(f)"
|
||||
>
|
||||
<template #icon>
|
||||
<AttachmentIcon class="h-4" />
|
||||
<template #default="{ openFileSelector, uploading }">
|
||||
{{ void (loading = uploading) }}
|
||||
<button
|
||||
class="flex rounded-4 p-1 text-ink-gray-8 transition-colors focus-within:ring-0 hover:bg-surface-gray-3"
|
||||
@click="openFileSelector()"
|
||||
:disabled="uploading"
|
||||
>
|
||||
<LoadingIndicator v-if="uploading" class="h-4 w-4" />
|
||||
<AttachmentIcon
|
||||
v-else
|
||||
class="h-4 w-4"
|
||||
style="stroke-width: 1.5 !important"
|
||||
/>
|
||||
</button>
|
||||
</template>
|
||||
</Button>
|
||||
</template>
|
||||
</FileUploader>
|
||||
</div>
|
||||
<div class="mt-2 flex items-center justify-end space-x-2 sm:mt-0">
|
||||
<Button
|
||||
label="Discard"
|
||||
@click="
|
||||
() => {
|
||||
newComment = '';
|
||||
emit('discard');
|
||||
}
|
||||
"
|
||||
/>
|
||||
<Button
|
||||
variant="solid"
|
||||
label="Submit"
|
||||
:disabled="commentEmpty"
|
||||
:loading="loading"
|
||||
@click="
|
||||
() => {
|
||||
loading = true;
|
||||
submitComment();
|
||||
newComment = '';
|
||||
}
|
||||
"
|
||||
/>
|
||||
</FileUploader>
|
||||
<div class="h-4 w-[2px] border-s ml-1" />
|
||||
</div>
|
||||
<EditorFixedMenu :items="fullToolbar" />
|
||||
<EditorTableMenu />
|
||||
</div>
|
||||
<div class="flex shrink-0 items-center justify-end gap-x-2">
|
||||
<Button
|
||||
label="Discard"
|
||||
@click="
|
||||
() => {
|
||||
newComment = '';
|
||||
attachments = [];
|
||||
dropUnused(null);
|
||||
emit('discard');
|
||||
}
|
||||
"
|
||||
/>
|
||||
<!-- A disabled button fires no pointer events, so the span
|
||||
carries the hover for the tooltip -->
|
||||
<Tooltip
|
||||
:text="isUploading ? __('Please wait, media is uploading') : ''"
|
||||
>
|
||||
<span class="inline-flex">
|
||||
<Button
|
||||
variant="solid"
|
||||
:label="label"
|
||||
:disabled="isDisabled"
|
||||
:loading="loading"
|
||||
@click="submitComment()"
|
||||
/>
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</TextEditor>
|
||||
</Editor>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import { computed, ref } from "vue";
|
||||
import {
|
||||
TextEditorFixedMenu,
|
||||
TextEditor,
|
||||
FileUploader,
|
||||
LoadingIndicator,
|
||||
Tooltip,
|
||||
createResource,
|
||||
dayjs,
|
||||
toast,
|
||||
} from "frappe-ui";
|
||||
import {
|
||||
Editor,
|
||||
EditorContent,
|
||||
EditorFixedMenu,
|
||||
EditorTableMenu,
|
||||
} from "frappe-ui/editor";
|
||||
import { addPendingActivity } from "@framework/ui/ActivityTimeline";
|
||||
import { useOnboarding } from "@framework/ui";
|
||||
import { computed, onBeforeUnmount, onMounted, ref, watch } from "vue";
|
||||
|
||||
import { AttachmentList } from "@/components/";
|
||||
import { buildEditorExtensions, fullToolbar } from "@/components/editor/config";
|
||||
import { AttachmentIcon } from "@/components/icons/";
|
||||
import { AttachmentItem } from "@/components/";
|
||||
import { useTyping } from "@/composables/realtime";
|
||||
import { useUploadTracker } from "@/composables/useUploadTracker";
|
||||
import { useAgentStore } from "@/stores/agent";
|
||||
import { useAuthStore } from "@/stores/auth";
|
||||
import { useUserStore } from "@/stores/user";
|
||||
import { __ } from "@/translation";
|
||||
import { capture } from "@/telemetry";
|
||||
import {
|
||||
getFontFamily,
|
||||
isContentEmpty,
|
||||
removeAttachmentFromServer,
|
||||
uploadFunction,
|
||||
} from "@/utils";
|
||||
import { useStorage } from "@vueuse/core";
|
||||
import { storeToRefs } from "pinia";
|
||||
|
||||
const { agents: agentsList } = useAgentStore();
|
||||
const { updateOnboardingStep } = useOnboarding("helpdesk") ?? {};
|
||||
const { agents: agentsList, dropdown } = storeToRefs(useAgentStore());
|
||||
const authStore = useAuthStore();
|
||||
const { isManager } = authStore;
|
||||
const { getUser } = useUserStore();
|
||||
|
||||
const props = defineProps({
|
||||
ticketId: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
label: {
|
||||
type: String,
|
||||
default: "Comment",
|
||||
},
|
||||
editable: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
@@ -120,83 +161,124 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
const doc = defineModel();
|
||||
const emit = defineEmits(["submit", "discard", "sending", "restore"]);
|
||||
|
||||
const newComment = useStorage("commentBoxContent" + props.ticketId, null);
|
||||
|
||||
// Mentions as a reactive getter so the `@` list stays in sync as agents load.
|
||||
const extensions = buildEditorExtensions({
|
||||
mentions: () => dropdown.value ?? [],
|
||||
});
|
||||
|
||||
// Initialize typing composable
|
||||
const { onUserType, cleanup } = useTyping(props.ticketId);
|
||||
|
||||
const attachments = ref([]);
|
||||
const emit = defineEmits(["submit", "discard"]);
|
||||
const newComment = useStorage("commentBoxContent", "");
|
||||
const commentEmpty = computed(() => {
|
||||
return !newComment.value || newComment.value === "<p></p>";
|
||||
const { isUploading, track, dropUnused } = useUploadTracker();
|
||||
const isDisabled = computed(() => {
|
||||
return isContentEmpty(newComment.value) || loading.value || isUploading.value;
|
||||
});
|
||||
const loading = ref(false);
|
||||
|
||||
const agents = computed(() => {
|
||||
return (
|
||||
agentsList.data?.map((agent) => ({
|
||||
label: agent.agent_name.trimEnd(),
|
||||
value: agent.name,
|
||||
})) || []
|
||||
);
|
||||
});
|
||||
|
||||
function removeAttachment(attachment) {
|
||||
attachments.value = attachments.value.filter((a) => a !== attachment);
|
||||
removeAttachmentFromServer(attachment.name);
|
||||
}
|
||||
|
||||
async function submitComment() {
|
||||
if (isContentEmpty(newComment.value)) {
|
||||
return false;
|
||||
}
|
||||
// The keyboard shortcut reaches here without passing the disabled button
|
||||
if (isUploading.value || loading.value) return false;
|
||||
|
||||
const content = newComment.value;
|
||||
const sentAttachments = attachments.value;
|
||||
const pendingRow = addPendingActivity(props.doctype, props.ticketId, {
|
||||
type: "comment",
|
||||
timestamp: dayjs().format("YYYY-MM-DD HH:mm:ss"),
|
||||
author: {
|
||||
email: getUser(authStore.userId).email,
|
||||
// the users list may still be a stub with a guessed name and no avatar
|
||||
fullname: authStore.userName,
|
||||
image: authStore.userImage,
|
||||
},
|
||||
data: { name: "", content, attachments: sentAttachments },
|
||||
});
|
||||
|
||||
// drop before clearing, or an unmount mid-send deletes what the comment carries
|
||||
dropUnused(content);
|
||||
newComment.value = null;
|
||||
attachments.value = [];
|
||||
loading.value = true;
|
||||
emit("sending");
|
||||
|
||||
const comment = createResource({
|
||||
url: "run_doc_method",
|
||||
makeParams: () => ({
|
||||
dt: props.doctype,
|
||||
dn: doc.value.name,
|
||||
dn: props.ticketId,
|
||||
method: "new_comment",
|
||||
args: {
|
||||
content: newComment.value,
|
||||
},
|
||||
args: { content, attachments: sentAttachments },
|
||||
}),
|
||||
onSuccess: () => {
|
||||
onSuccess: (res: { message?: string } | string) => {
|
||||
// run_doc_method answers with the whole body, since it always carries `docs`
|
||||
const name = typeof res === "string" ? res : res?.message;
|
||||
// the real row replaces the pending one the moment it arrives; unkeyed,
|
||||
// it would outlive it
|
||||
name ? pendingRow.resolve(`comment:${name}`) : pendingRow.drop();
|
||||
capture("comment_added");
|
||||
if (isManager) {
|
||||
updateOnboardingStep?.("comment_on_ticket");
|
||||
}
|
||||
emit("submit");
|
||||
loading.value = false;
|
||||
},
|
||||
onError: () => {
|
||||
toast.error(__("Could not add the comment"));
|
||||
pendingRow.drop();
|
||||
newComment.value = content;
|
||||
attachments.value = sentAttachments;
|
||||
loading.value = false;
|
||||
emit("restore");
|
||||
},
|
||||
});
|
||||
|
||||
comment.submit();
|
||||
}
|
||||
|
||||
const textEditorMenuButtons = [
|
||||
"Paragraph",
|
||||
["Heading 2", "Heading 3", "Heading 4", "Heading 5", "Heading 6"],
|
||||
"Separator",
|
||||
"Bold",
|
||||
"Italic",
|
||||
"Separator",
|
||||
"Bullet List",
|
||||
"Numbered List",
|
||||
"Separator",
|
||||
"Align Left",
|
||||
"Align Center",
|
||||
"Align Right",
|
||||
"FontColor",
|
||||
"Separator",
|
||||
"Image",
|
||||
"Video",
|
||||
"Link",
|
||||
"Blockquote",
|
||||
"Code",
|
||||
"Horizontal Rule",
|
||||
[
|
||||
"InsertTable",
|
||||
"AddColumnBefore",
|
||||
"AddColumnAfter",
|
||||
"DeleteColumn",
|
||||
"AddRowBefore",
|
||||
"AddRowAfter",
|
||||
"DeleteRow",
|
||||
"MergeCells",
|
||||
"SplitCell",
|
||||
"ToggleHeaderColumn",
|
||||
"ToggleHeaderRow",
|
||||
"ToggleHeaderCell",
|
||||
"DeleteTable",
|
||||
],
|
||||
];
|
||||
const editorRef = ref(null);
|
||||
const editor = computed(() => editorRef.value?.editor);
|
||||
|
||||
// Watch for changes in comment content to trigger typing events
|
||||
watch(newComment, (newValue, oldValue) => {
|
||||
if (newValue !== oldValue && newValue) {
|
||||
onUserType();
|
||||
}
|
||||
});
|
||||
|
||||
onMounted(() => {
|
||||
if (
|
||||
agentsList.value.loading ||
|
||||
agentsList.value.data?.length ||
|
||||
agentsList.value.list.promise
|
||||
) {
|
||||
return;
|
||||
}
|
||||
agentsList.value.fetch();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
cleanup();
|
||||
// the saved draft still references what it shows, so only what it dropped goes
|
||||
dropUnused(newComment.value);
|
||||
if (isContentEmpty(newComment.value)) {
|
||||
localStorage.removeItem("commentBoxContent" + props.ticketId);
|
||||
}
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
submitComment,
|
||||
editor,
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<template>
|
||||
<div class="flex flex-col comm-area">
|
||||
<div class="comm-area" resizable="true">
|
||||
<div
|
||||
class="flex justify-between gap-3 border-t px-4 lg:px-10 py-4 md:py-2.5"
|
||||
class="flex justify-between gap-3 border-t px-6 md:px-5 py-4 md:py-2.5"
|
||||
>
|
||||
<div class="flex gap-1.5">
|
||||
<div class="flex gap-1.5 items-center">
|
||||
<Button
|
||||
ref="sendEmailRef"
|
||||
variant="ghost"
|
||||
label="Reply"
|
||||
:class="[showEmailBox ? '!bg-gray-300 hover:!bg-gray-200' : '']"
|
||||
:class="[
|
||||
showEmailBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
|
||||
]"
|
||||
@click="toggleEmailBox()"
|
||||
>
|
||||
<template #prefix>
|
||||
@@ -18,78 +20,122 @@
|
||||
<Button
|
||||
variant="ghost"
|
||||
label="Comment"
|
||||
:class="[showCommentBox ? '!bg-gray-300 hover:!bg-gray-200' : '']"
|
||||
:class="[
|
||||
showCommentBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
|
||||
]"
|
||||
@click="toggleCommentBox()"
|
||||
>
|
||||
<template #prefix>
|
||||
<CommentIcon class="h-4" />
|
||||
</template>
|
||||
</Button>
|
||||
<TypingIndicator :ticketId="ticketId" />
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="showCommentBox">
|
||||
<CommentTextEditor
|
||||
v-model="doc"
|
||||
v-model:attachments="attachments"
|
||||
:editable="showCommentBox"
|
||||
:doctype="doctype"
|
||||
placeholder="Add a comment..."
|
||||
@submit="
|
||||
() => {
|
||||
showCommentBox = false;
|
||||
emit('update');
|
||||
}
|
||||
"
|
||||
@discard="
|
||||
() => {
|
||||
showCommentBox = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
v-show="showEmailBox"
|
||||
class="flex gap-1.5"
|
||||
@keydown.ctrl.enter.capture.stop="submitEmail"
|
||||
@keydown.meta.enter.capture.stop="submitEmail"
|
||||
>
|
||||
<EmailEditor
|
||||
ref="emailEditorRef"
|
||||
v-model="doc"
|
||||
v-model:content="content"
|
||||
v-model:attachments="attachments"
|
||||
:to-emails="toEmails"
|
||||
:cc-emails="ccEmails"
|
||||
:bcc-emails="bccEmails"
|
||||
@submit="
|
||||
() => {
|
||||
showEmailBox = false;
|
||||
emit('update');
|
||||
}
|
||||
"
|
||||
@discard="
|
||||
() => {
|
||||
showEmailBox = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
<Transition name="slide">
|
||||
<div
|
||||
v-show="showEmailBox"
|
||||
ref="emailBoxRef"
|
||||
@keydown.ctrl.enter.capture.stop="submitEmail"
|
||||
@keydown.meta.enter.capture.stop="submitEmail"
|
||||
@keydown.esc.capture.stop="showEmailBox = false"
|
||||
>
|
||||
<div class="overflow-hidden">
|
||||
<EmailEditor
|
||||
ref="emailEditorRef"
|
||||
:label="
|
||||
isMobileView ? 'Send' : isMac ? 'Send (⌘ + ⏎)' : 'Send (Ctrl + ⏎)'
|
||||
"
|
||||
placeholder="Hi John, we are looking into this issue."
|
||||
:ticketId="ticketId"
|
||||
:to-emails="toEmails"
|
||||
:cc-emails="ccEmails"
|
||||
:bcc-emails="bccEmails"
|
||||
@sending="
|
||||
() => {
|
||||
showEmailBox = false;
|
||||
}
|
||||
"
|
||||
@submit="() => emit('update')"
|
||||
@restore="
|
||||
() => {
|
||||
showEmailBox = true;
|
||||
}
|
||||
"
|
||||
@discard="
|
||||
() => {
|
||||
showEmailBox = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
<Transition name="slide">
|
||||
<div
|
||||
v-show="showCommentBox"
|
||||
ref="commentBoxRef"
|
||||
@keydown.ctrl.enter.capture.stop="submitComment"
|
||||
@keydown.meta.enter.capture.stop="submitComment"
|
||||
@keydown.esc.capture.stop="showCommentBox = false"
|
||||
>
|
||||
<div class="overflow-hidden">
|
||||
<CommentTextEditor
|
||||
ref="commentTextEditorRef"
|
||||
:label="
|
||||
isMobileView
|
||||
? 'Comment'
|
||||
: isMac
|
||||
? 'Comment (⌘ + ⏎)'
|
||||
: 'Comment (Ctrl + ⏎)'
|
||||
"
|
||||
:ticketId="ticketId"
|
||||
:editable="showCommentBox"
|
||||
:doctype="doctype"
|
||||
placeholder="@John could you please look into this?"
|
||||
@sending="
|
||||
() => {
|
||||
showCommentBox = false;
|
||||
}
|
||||
"
|
||||
@submit="() => emit('update')"
|
||||
@restore="
|
||||
() => {
|
||||
showCommentBox = true;
|
||||
}
|
||||
"
|
||||
@discard="
|
||||
() => {
|
||||
showCommentBox = false;
|
||||
}
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Transition>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { ref } from "vue";
|
||||
import { CommentTextEditor, EmailEditor, TypingIndicator } from "@/components";
|
||||
import { CommentIcon, EmailIcon } from "@/components/icons/";
|
||||
import { useDevice } from "@/composables";
|
||||
import { useScreenSize } from "@/composables/screen";
|
||||
import { useShortcut } from "@/composables/shortcuts";
|
||||
import { showCommentBox, showEmailBox } from "@/pages/ticket/modalStates";
|
||||
import { onClickOutside } from "@vueuse/core";
|
||||
import { ref, watch } from "vue";
|
||||
|
||||
import { EmailEditor, CommentTextEditor } from "@/components";
|
||||
import { EmailIcon, CommentIcon } from "@/components/icons/";
|
||||
|
||||
const content = defineModel("content");
|
||||
const showEmailBox = ref(false);
|
||||
const showCommentBox = ref(false);
|
||||
const doc = defineModel();
|
||||
const attachments = ref([]);
|
||||
const emit = defineEmits(["update"]);
|
||||
const content = defineModel("content");
|
||||
const { isMac } = useDevice();
|
||||
const { isMobileView } = useScreenSize();
|
||||
let doc = defineModel();
|
||||
// let doc = inject(TicketSymbol)?.value.doc
|
||||
const emailEditorRef = ref(null);
|
||||
const commentTextEditorRef = ref(null);
|
||||
const emailBoxRef = ref(null);
|
||||
const commentBoxRef = ref(null);
|
||||
|
||||
function toggleEmailBox() {
|
||||
if (showCommentBox.value) {
|
||||
@@ -105,13 +151,31 @@ function toggleCommentBox() {
|
||||
showCommentBox.value = !showCommentBox.value;
|
||||
}
|
||||
|
||||
// the editors emit `submit` once the write lands; reloading here too would
|
||||
// fetch twice, and the guards' `false` never reaches this side anyway
|
||||
function submitEmail() {
|
||||
emailEditorRef.value.submitMail();
|
||||
}
|
||||
|
||||
function submitComment() {
|
||||
commentTextEditorRef.value.submitComment();
|
||||
}
|
||||
|
||||
function splitIfString(str: string | string[]) {
|
||||
if (typeof str === "string") {
|
||||
return str.split(",");
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
function replyToEmail(data: object) {
|
||||
showEmailBox.value = true;
|
||||
|
||||
emailEditorRef.value.addToReply(
|
||||
data.content,
|
||||
data.to?.split(","),
|
||||
data.cc?.split(","),
|
||||
data.bcc?.split(",")
|
||||
splitIfString(data.to),
|
||||
splitIfString(data.cc),
|
||||
splitIfString(data.bcc)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -120,6 +184,10 @@ const props = defineProps({
|
||||
type: String,
|
||||
default: "HD Ticket",
|
||||
},
|
||||
ticketId: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
toEmails: {
|
||||
type: Array,
|
||||
default: () => [],
|
||||
@@ -134,12 +202,82 @@ const props = defineProps({
|
||||
},
|
||||
});
|
||||
|
||||
watch(
|
||||
() => showEmailBox.value,
|
||||
(value) => {
|
||||
if (value) {
|
||||
emailEditorRef.value?.editor?.commands?.focus("start");
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
watch(
|
||||
() => showCommentBox.value,
|
||||
(value) => {
|
||||
if (value) {
|
||||
commentTextEditorRef.value?.editor?.commands?.focus();
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
useShortcut("r", () => {
|
||||
toggleEmailBox();
|
||||
});
|
||||
useShortcut("c", () => {
|
||||
toggleCommentBox();
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
replyToEmail,
|
||||
toggleEmailBox,
|
||||
toggleCommentBox,
|
||||
editor: emailEditorRef,
|
||||
});
|
||||
|
||||
const IGNORED_SELECTORS = [
|
||||
".tippy-box",
|
||||
".tippy-content",
|
||||
".PopoverContent",
|
||||
'[role="dialog"]',
|
||||
'[role="presentation"]',
|
||||
'[role="menu"]',
|
||||
".dialog-overlay",
|
||||
// Grammarly suggestions appear outside the box, allow them to stop collapsing.
|
||||
"grammarly-extension",
|
||||
"grammarly-popups",
|
||||
"[data-grammarly-part]",
|
||||
];
|
||||
|
||||
// `ignore` is only consulted on pointerdown, which dialogs stop, so the click
|
||||
// through has to be checked too. Without this a dialog button closes the box.
|
||||
function isIgnored(event: Event): boolean {
|
||||
const target = event.target as HTMLElement | null;
|
||||
return Boolean(target?.closest?.(IGNORED_SELECTORS.join(", ")));
|
||||
}
|
||||
|
||||
onClickOutside(
|
||||
emailBoxRef,
|
||||
(event) => {
|
||||
if (showEmailBox.value && !isIgnored(event)) {
|
||||
showEmailBox.value = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
ignore: IGNORED_SELECTORS,
|
||||
}
|
||||
);
|
||||
|
||||
onClickOutside(
|
||||
commentBoxRef,
|
||||
(event) => {
|
||||
if (showCommentBox.value && !isIgnored(event)) {
|
||||
showCommentBox.value = false;
|
||||
}
|
||||
},
|
||||
{
|
||||
ignore: IGNORED_SELECTORS,
|
||||
}
|
||||
);
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -148,4 +286,18 @@ defineExpose({
|
||||
width: 100vw;
|
||||
}
|
||||
}
|
||||
|
||||
.slide-enter-active,
|
||||
.slide-leave-active {
|
||||
display: grid;
|
||||
transition: grid-template-rows 0.25s ease;
|
||||
}
|
||||
.slide-enter-from,
|
||||
.slide-leave-to {
|
||||
grid-template-rows: 0fr;
|
||||
}
|
||||
.slide-enter-to,
|
||||
.slide-leave-from {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
</style>
|
||||
|
||||
206
desk/src/components/CompactEditor.vue
Normal file
206
desk/src/components/CompactEditor.vue
Normal file
@@ -0,0 +1,206 @@
|
||||
<template>
|
||||
<div class="flex flex-col">
|
||||
<Editor
|
||||
ref="editorRef"
|
||||
v-model="internalContent"
|
||||
:extensions="extensions"
|
||||
v-bind="uploadFn ? { uploadFunction: uploadFn } : {}"
|
||||
:placeholder="placeholder"
|
||||
>
|
||||
<template #default>
|
||||
<EditorBubbleMenu :items="commentToolbar" />
|
||||
<div
|
||||
class="flex items-center overflow-x-auto rounded-t-4 border border-b-0 border-outline-gray-1 bg-surface-gray-1 px-1 py-1"
|
||||
>
|
||||
<div
|
||||
v-if="showAttachments"
|
||||
class="inline-flex items-center gap-1.5 pe-1"
|
||||
>
|
||||
<FileUploader private @success="addAttachment">
|
||||
<template #default="{ openFileSelector, uploading }">
|
||||
{{ syncUploadingState(uploading) }}
|
||||
<button
|
||||
class="flex rounded-4 p-1 text-ink-gray-8 transition-colors hover:bg-surface-gray-3 disabled:opacity-40"
|
||||
:disabled="uploading"
|
||||
@click="openFileSelector()"
|
||||
>
|
||||
<LoadingIndicator v-if="uploading" class="h-4 w-4" />
|
||||
<AttachmentIcon
|
||||
v-else
|
||||
class="h-4 w-4"
|
||||
style="stroke-width: 1.5 !important"
|
||||
/>
|
||||
</button>
|
||||
</template>
|
||||
</FileUploader>
|
||||
<div class="h-4 w-[2px] border-s ml-1" />
|
||||
</div>
|
||||
<EditorFixedMenu :items="fullToolbar" />
|
||||
<EditorTableMenu />
|
||||
</div>
|
||||
<EditorContent :class="editorClass" />
|
||||
</template>
|
||||
</Editor>
|
||||
<AttachmentList
|
||||
v-if="showAttachments && attachments?.length"
|
||||
class="mt-2"
|
||||
:attachments="attachments ?? []"
|
||||
@remove="removeAttachment"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { AttachmentList } from "@/components";
|
||||
import {
|
||||
buildEditorExtensions,
|
||||
commentToolbar,
|
||||
fullToolbar,
|
||||
} from "@/components/editor/config";
|
||||
import { AttachmentIcon } from "@/components/icons";
|
||||
import { getUserEmailInfo } from "@/composables/useUserEmailInfo";
|
||||
import { isContentEmpty } from "@/utils";
|
||||
import { FileUploader, LoadingIndicator, type UploadedFile } from "frappe-ui";
|
||||
import {
|
||||
Editor,
|
||||
EditorBubbleMenu,
|
||||
EditorContent,
|
||||
EditorFixedMenu,
|
||||
EditorTableMenu,
|
||||
} from "frappe-ui/editor";
|
||||
import { computed, nextTick, onMounted, ref, watch } from "vue";
|
||||
|
||||
type UploadFunction = (file: File) => Promise<UploadedFile>;
|
||||
|
||||
const props = withDefaults(
|
||||
defineProps<{
|
||||
placeholder?: string;
|
||||
minHeight?: string;
|
||||
maxHeight?: string;
|
||||
extensions?: any[];
|
||||
showSignature?: boolean;
|
||||
showAttachments?: boolean;
|
||||
uploadFn?: UploadFunction;
|
||||
}>(),
|
||||
{
|
||||
placeholder: "",
|
||||
minHeight: "min-h-[180px]",
|
||||
maxHeight: "max-h-80",
|
||||
extensions: () => [],
|
||||
showSignature: false,
|
||||
showAttachments: false,
|
||||
}
|
||||
);
|
||||
|
||||
const internalContent = defineModel<string>({ default: "" });
|
||||
|
||||
const editorRef = ref<any>(null);
|
||||
const attachments = defineModel<UploadedFile[] | null>("attachments", {
|
||||
default: () => [],
|
||||
});
|
||||
const isUploading = ref(false);
|
||||
|
||||
const extensions = buildEditorExtensions({ extra: props.extensions });
|
||||
|
||||
const contentClass = [
|
||||
"!prose-sm max-w-full overflow-auto py-1.5 px-3",
|
||||
"rounded-b-4 border border-outline-gray-1 bg-surface-base",
|
||||
"placeholder-ink-gray-4 text-ink-gray-8 -mt-0.5",
|
||||
];
|
||||
|
||||
const editorClass = computed(() => [
|
||||
...contentClass,
|
||||
props.minHeight,
|
||||
props.maxHeight,
|
||||
]);
|
||||
|
||||
const userResource = getUserEmailInfo();
|
||||
|
||||
function getDefaultContent(signature: string): string {
|
||||
return `<p></p><p></p>${signature}`;
|
||||
}
|
||||
|
||||
function applySignature(signature: string) {
|
||||
if (!isContentEmpty(internalContent.value)) return;
|
||||
const commands = editorRef.value?.editor?.commands;
|
||||
if (commands) {
|
||||
commands.setContent(signature);
|
||||
setTimeout(() => {
|
||||
editorRef.value?.editor?.commands?.focus("start");
|
||||
}, 0);
|
||||
} else {
|
||||
internalContent.value = signature;
|
||||
}
|
||||
}
|
||||
|
||||
function addAttachment(file: UploadedFile) {
|
||||
attachments.value = [...(attachments.value ?? []), file];
|
||||
}
|
||||
|
||||
function removeAttachment(attachment: UploadedFile) {
|
||||
attachments.value = (attachments.value ?? []).filter((a) => a !== attachment);
|
||||
}
|
||||
|
||||
// FileUploader exposes `uploading` only via slot scope, so mirror it into a
|
||||
// ref that the parent can read through the exposed `isUploading`.
|
||||
function syncUploadingState(uploading: boolean): string {
|
||||
isUploading.value = uploading;
|
||||
return "";
|
||||
}
|
||||
|
||||
function getContent(): string {
|
||||
return editorRef.value?.editor?.getHTML() ?? "";
|
||||
}
|
||||
|
||||
function isEmpty(): boolean {
|
||||
return !editorRef.value?.editor?.state?.doc?.textContent?.trim()?.length;
|
||||
}
|
||||
|
||||
function reset() {
|
||||
const commands = editorRef.value?.editor?.commands;
|
||||
if (!commands) {
|
||||
internalContent.value = "";
|
||||
return;
|
||||
}
|
||||
const data = userResource?.data as { email_signature?: string } | null;
|
||||
const sig = data?.email_signature
|
||||
? getDefaultContent(data.email_signature)
|
||||
: "";
|
||||
commands.setContent(sig || "<p></p>");
|
||||
internalContent.value = sig;
|
||||
attachments.value = null;
|
||||
setTimeout(() => {
|
||||
editorRef.value?.editor?.commands?.focus("start");
|
||||
}, 0);
|
||||
}
|
||||
|
||||
if (props.showSignature) {
|
||||
// Late arrival: resource resolves after mount
|
||||
watch(
|
||||
() => userResource.data,
|
||||
(data: { email_signature?: string } | null) => {
|
||||
if (!data?.email_signature) return;
|
||||
applySignature(getDefaultContent(data.email_signature));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
if (!props.showSignature) return;
|
||||
|
||||
nextTick(() => {
|
||||
const data = userResource.data as { email_signature?: string } | null;
|
||||
if (data?.email_signature) {
|
||||
applySignature(getDefaultContent(data.email_signature));
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
defineExpose({
|
||||
getContent,
|
||||
isEmpty,
|
||||
reset,
|
||||
editorRef,
|
||||
isUploading,
|
||||
});
|
||||
</script>
|
||||
104
desk/src/components/ConfirmDialog.vue
Normal file
104
desk/src/components/ConfirmDialog.vue
Normal file
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<Dialog v-model:open="isOpen" :title="title" @close="closeDialog">
|
||||
<template #default>
|
||||
<div class="space-y-4">
|
||||
<p
|
||||
class="text-p-base text-ink-gray-8"
|
||||
v-if="message"
|
||||
v-html="message"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
<Button
|
||||
class="w-full"
|
||||
label="Confirm"
|
||||
variant="solid"
|
||||
:loading="isLoading"
|
||||
@click="onConfirm"
|
||||
/>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
<script>
|
||||
import { Button, Dialog } from "frappe-ui";
|
||||
|
||||
export default {
|
||||
name: "ConfirmDialog",
|
||||
props: {
|
||||
title: {
|
||||
type: String,
|
||||
},
|
||||
message: {
|
||||
type: String,
|
||||
},
|
||||
// Optional v-model; when absent, visibility falls back to the internal
|
||||
// state (open on mount), preserving the `v-if` + `show()`/`hide()` mode.
|
||||
modelValue: {
|
||||
type: Boolean,
|
||||
default: undefined,
|
||||
},
|
||||
onConfirm: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
onCancel: {
|
||||
type: Function,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
emits: ["update:modelValue"],
|
||||
expose: ["show", "hide"],
|
||||
components: {
|
||||
Dialog,
|
||||
Button,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showDialog: true,
|
||||
isLoading: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
isOpen: {
|
||||
get() {
|
||||
return this.modelValue !== undefined
|
||||
? this.modelValue
|
||||
: this.showDialog;
|
||||
},
|
||||
set(value) {
|
||||
this.showDialog = value;
|
||||
this.$emit("update:modelValue", value);
|
||||
},
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
async handleConfirmation() {
|
||||
if (this.isLoading) return;
|
||||
this.isLoading = true;
|
||||
try {
|
||||
if (this.onConfirm) {
|
||||
await this.onConfirm({
|
||||
hideDialog: this.hide,
|
||||
});
|
||||
}
|
||||
this.hide();
|
||||
} catch (error) {
|
||||
console.error("Error in confirmation:", error);
|
||||
} finally {
|
||||
this.isLoading = false;
|
||||
}
|
||||
},
|
||||
show() {
|
||||
this.isOpen = true;
|
||||
},
|
||||
closeDialog() {
|
||||
this.hide();
|
||||
this.onCancel?.();
|
||||
},
|
||||
hide() {
|
||||
this.isOpen = false;
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
@@ -1,26 +1,24 @@
|
||||
<template>
|
||||
<div v-if="normalActions.length">
|
||||
<div v-if="normalActions.length" class="flex gap-2">
|
||||
<!-- onClick rides along in `action`; binding it twice would run it twice -->
|
||||
<Button
|
||||
v-for="action in normalActions"
|
||||
:key="action.label"
|
||||
:label="action.label"
|
||||
@click="action.onClick()"
|
||||
v-bind="action"
|
||||
>
|
||||
<template v-if="action.icon" #prefix>
|
||||
<FeatherIcon :name="action.icon" class="h-4 w-4" />
|
||||
<Icon :icon="action.icon" class="h-4 w-4" />
|
||||
</template>
|
||||
</Button>
|
||||
</div>
|
||||
<Dropdown v-if="groupedActions.length" :options="groupedActions">
|
||||
<Button icon="more-horizontal" />
|
||||
</Dropdown>
|
||||
<div v-if="groupedWithLabelActions.length">
|
||||
<div v-for="g in groupedWithLabelActions" :key="g.label">
|
||||
<Dropdown v-slot="{ open }" :options="g.action">
|
||||
<Button :label="g.label">
|
||||
<template #suffix>
|
||||
<FeatherIcon
|
||||
:name="open ? 'chevron-up' : 'chevron-down'"
|
||||
<component
|
||||
:is="open ? LucideChevronUp : LucideChevronDown"
|
||||
class="h-4"
|
||||
/>
|
||||
</template>
|
||||
@@ -28,11 +26,17 @@
|
||||
</Dropdown>
|
||||
</div>
|
||||
</div>
|
||||
<Dropdown v-if="groupedActions.length" :options="groupedActions">
|
||||
<Button icon="lucide-more-horizontal" variant="ghost" />
|
||||
</Dropdown>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { computed, h } from "vue";
|
||||
import LucideChevronUp from "~icons/lucide/chevron-up";
|
||||
import LucideChevronDown from "~icons/lucide/chevron-down";
|
||||
import Icon from "@/components/Icon.vue";
|
||||
import { Dropdown } from "frappe-ui";
|
||||
import { computed } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
actions: {
|
||||
|
||||
89
desk/src/components/DeleteWithTicketsDialog.vue
Normal file
89
desk/src/components/DeleteWithTicketsDialog.vue
Normal file
@@ -0,0 +1,89 @@
|
||||
<template>
|
||||
<Dialog v-model:open="open" :title="dialogTitle" size="md">
|
||||
<template #default>
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="text-p-base text-ink-gray-7">{{ message }}</p>
|
||||
<Checkbox
|
||||
v-if="count"
|
||||
size="sm"
|
||||
v-model="deleteLinkedTickets"
|
||||
:label="__('Delete {0} ticket(s)', [count])"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<template #actions>
|
||||
<div class="flex justify-end">
|
||||
<Button
|
||||
variant="solid"
|
||||
theme="red"
|
||||
icon-left="lucide-trash-2"
|
||||
:label="__('Delete')"
|
||||
:loading="isDeleting"
|
||||
@click="confirmDelete"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
</Dialog>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { __ } from "@/translation";
|
||||
import { Button, Checkbox, createResource, Dialog } from "frappe-ui";
|
||||
import { computed, ref, watch } from "vue";
|
||||
|
||||
const props = defineProps<{
|
||||
/** Name of the record being deleted. */
|
||||
name: string;
|
||||
/** HD Ticket link field that ties tickets to this record. */
|
||||
linkField: "customer" | "contact";
|
||||
/** Confirmation copy shown above the checkbox. */
|
||||
message: string;
|
||||
title?: string;
|
||||
/** Async delete handler; the button stays in a loading state until it settles. */
|
||||
onDelete: (payload: { deleteLinkedTickets: boolean }) => Promise<void> | void;
|
||||
}>();
|
||||
|
||||
const open = defineModel<boolean>({ default: false });
|
||||
|
||||
const resource = createResource({
|
||||
url: "frappe.client.get_count",
|
||||
params: {
|
||||
doctype: "HD Ticket",
|
||||
filters: { [props.linkField]: props.name },
|
||||
},
|
||||
auto: true,
|
||||
});
|
||||
|
||||
const count = computed<number>(() => {
|
||||
if (resource.loading) return 0;
|
||||
return resource.data ?? 0;
|
||||
});
|
||||
|
||||
const deleteLinkedTickets = ref(false);
|
||||
const isDeleting = ref(false);
|
||||
|
||||
const dialogTitle = computed(() => props.title ?? __("Delete"));
|
||||
|
||||
async function confirmDelete() {
|
||||
if (isDeleting.value) return;
|
||||
isDeleting.value = true;
|
||||
try {
|
||||
await props.onDelete({ deleteLinkedTickets: deleteLinkedTickets.value });
|
||||
open.value = false;
|
||||
} catch {
|
||||
// Keep the dialog open on failure; the handler surfaces the error.
|
||||
} finally {
|
||||
isDeleting.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
watch(
|
||||
open,
|
||||
(isOpen) => {
|
||||
if (isOpen) {
|
||||
resource.reload();
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
</script>
|
||||
49
desk/src/components/DiscardButton.vue
Normal file
49
desk/src/components/DiscardButton.vue
Normal file
@@ -0,0 +1,49 @@
|
||||
<template>
|
||||
<Button :label="label" @click="handleDiscard" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { globalStore } from "@/stores/globalStore";
|
||||
const { $dialog } = globalStore();
|
||||
const emit = defineEmits<{
|
||||
(event: "discard"): void;
|
||||
}>();
|
||||
|
||||
const {
|
||||
label = "Discard",
|
||||
hideDialog = false,
|
||||
title = "Discard?",
|
||||
message = "Are you sure you want to discard this?",
|
||||
} = defineProps<{
|
||||
label?: string;
|
||||
hideDialog?: boolean;
|
||||
title?: string;
|
||||
message?: string;
|
||||
}>();
|
||||
|
||||
function handleDiscard() {
|
||||
if (hideDialog) {
|
||||
emit("discard");
|
||||
return;
|
||||
}
|
||||
$dialog({
|
||||
title: title,
|
||||
message: message,
|
||||
onConfirm: ({ hideDialog }: { hideDialog: Function }) => {
|
||||
hideDialog();
|
||||
},
|
||||
actions: [
|
||||
{
|
||||
label: "Delete",
|
||||
theme: "red",
|
||||
iconLeft: "lucide-trash-2",
|
||||
variant: "solid",
|
||||
onClick({ close }: { close: () => void }) {
|
||||
emit("discard");
|
||||
close();
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
</script>
|
||||
19
desk/src/components/DocumentationButton.vue
Normal file
19
desk/src/components/DocumentationButton.vue
Normal file
@@ -0,0 +1,19 @@
|
||||
<template>
|
||||
<Tooltip text="View documentation">
|
||||
<a :href="url" target="_blank">
|
||||
<lucide-circle-question-mark
|
||||
class="h-4 w-4 text-ink-gray-6"
|
||||
:class="color"
|
||||
/>
|
||||
</a>
|
||||
</Tooltip>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
defineProps<{
|
||||
url: string;
|
||||
color?: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
@@ -1,172 +0,0 @@
|
||||
<template>
|
||||
<div
|
||||
class="grow cursor-pointer border-transparent bg-white rounded-md shadow text-base leading-6 transition-all duration-300 ease-in-out"
|
||||
>
|
||||
<div class="mb-1 flex items-center justify-between gap-2">
|
||||
<!-- email design for mobile -->
|
||||
<div v-if="isMobileView" class="flex items-center gap-2">
|
||||
<div class="leading-tight">
|
||||
<span>{{ sender.full_name || "No name found" }}</span>
|
||||
<span
|
||||
class="sm:flex hidden text-sm text-gray-600"
|
||||
v-if="sender.name"
|
||||
>{{ "<" + sender.name + ">" }}</span
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
<!-- email design for desktop -->
|
||||
<div v-else class="flex items-center gap-2">
|
||||
<span>{{ sender.full_name || "No name found" }}</span>
|
||||
<span class="sm:flex hidden text-sm text-gray-600" v-if="sender.name">{{
|
||||
"<" + sender.name + ">"
|
||||
}}</span>
|
||||
</div>
|
||||
|
||||
<div class="flex gap-0.5 items-center">
|
||||
<Tooltip :text="dateFormat(creation, dateTooltipFormat)">
|
||||
<div class="text-sm text-gray-600">
|
||||
{{ timeAgo(creation) }}
|
||||
</div>
|
||||
</Tooltip>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="text-gray-700"
|
||||
@click="
|
||||
emit('reply', {
|
||||
content: content,
|
||||
to: to ?? sender.name,
|
||||
})
|
||||
"
|
||||
>
|
||||
<ReplyIcon class="h-4 w-4" />
|
||||
</Button>
|
||||
<Button
|
||||
variant="ghost"
|
||||
class="text-gray-700"
|
||||
@click="
|
||||
emit('reply', {
|
||||
content: content,
|
||||
to: to ?? sender.name,
|
||||
cc: cc,
|
||||
bcc: bcc,
|
||||
})
|
||||
"
|
||||
>
|
||||
<ReplyAllIcon class="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="text-sm leading-5 text-gray-600">
|
||||
{{ subject }}
|
||||
</div> -->
|
||||
<div class="mb-3 text-sm leading-5 text-gray-600">
|
||||
<span v-if="to" class="text-2xs mr-1 font-bold text-gray-500">TO:</span>
|
||||
<span v-if="to"> {{ to }} </span>
|
||||
<span v-if="cc">, </span>
|
||||
<span v-if="cc" class="text-2xs mr-1 font-bold text-gray-500"> CC: </span>
|
||||
<span v-if="cc">{{ cc }}</span>
|
||||
<span v-if="bcc">, </span>
|
||||
<span v-if="bcc" class="text-2xs mr-1 font-bold text-gray-500">
|
||||
BCC:
|
||||
</span>
|
||||
<span v-if="bcc">{{ bcc }}</span>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="email-content prose-f max-h-[500px] overflow-y-auto"
|
||||
v-html="content"
|
||||
/> -->
|
||||
<EmailContent :content="content" :emailBox="emailBox" />
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<AttachmentItem
|
||||
v-for="a in attachments"
|
||||
:key="a.file_url"
|
||||
:label="a.file_name"
|
||||
:url="a.file_url"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { UserAvatar, AttachmentItem } from "@/components";
|
||||
import { dateFormat, timeAgo, dateTooltipFormat } from "@/utils";
|
||||
import { ReplyIcon, ReplyAllIcon } from "./icons";
|
||||
import { useScreenSize } from "@/composables/screen";
|
||||
import { inject } from "vue";
|
||||
|
||||
const props = defineProps({
|
||||
activity: {
|
||||
type: Object,
|
||||
required: true,
|
||||
},
|
||||
});
|
||||
|
||||
const { sender, to, cc, bcc, creation, subject, attachments, content } =
|
||||
props.activity;
|
||||
|
||||
const emit = defineEmits(["reply"]);
|
||||
|
||||
let emailBox = inject("communicationArea");
|
||||
const { isMobileView } = useScreenSize();
|
||||
|
||||
// TODO: Implement reply functionality using this way instead of emit drillup
|
||||
// function reply(email, reply_all = false) {
|
||||
// emailBox.toggleEmailBox();
|
||||
// let editor = emailBox.editor;
|
||||
// let message = email.content;
|
||||
// let recipients = sender.name;
|
||||
// editor.toEmails = [email.sender];
|
||||
// editor.cc = editor.bcc = false;
|
||||
// editor.ccEmails = [];
|
||||
// editor.bccEmails = [];
|
||||
// console.log(recipients);
|
||||
|
||||
// if (!email.subject.startsWith("Re:")) {
|
||||
// editor.subject = `Re: ${email.subject}`;
|
||||
// } else {
|
||||
// editor.subject = email.subject;
|
||||
// }
|
||||
|
||||
// if (reply_all) {
|
||||
// let cc = email.cc?.split(",").map((r) => r.trim());
|
||||
// let bcc = email.bcc?.split(",").map((r) => r.trim());
|
||||
|
||||
// if (cc?.length) {
|
||||
// recipients = recipients.filter((r) => !cc?.includes(r));
|
||||
// cc.push(...recipients);
|
||||
// } else {
|
||||
// cc = recipients;
|
||||
// }
|
||||
|
||||
// editor.cc = cc ? true : false;
|
||||
// editor.bcc = bcc ? true : false;
|
||||
|
||||
// editor.ccEmails = cc;
|
||||
// editor.bccEmails = bcc;
|
||||
// }
|
||||
|
||||
// let repliedMessage = `<blockquote>${message}</blockquote>`;
|
||||
|
||||
// editor.editor
|
||||
// .chain()
|
||||
// .clearContent()
|
||||
// .insertContent("<p>.</p>")
|
||||
// .updateAttributes("paragraph", { class: "reply-to-content" })
|
||||
// .insertContent(repliedMessage)
|
||||
// .focus("all")
|
||||
// .insertContentAt(0, { type: "paragraph" })
|
||||
// .focus("start")
|
||||
// .run();
|
||||
// }
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.email-content {
|
||||
max-width: 100%;
|
||||
}
|
||||
.email-content > * {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
flex-wrap: nowrap;
|
||||
}
|
||||
</style>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user