Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ab183acac3 | ||
|
|
d9b967a74d | ||
|
|
4180224fd9 | ||
|
|
aa34da61fe | ||
|
|
058b95f4eb | ||
|
|
4115d62bac | ||
|
|
3d72c82bca | ||
|
|
4bed5059c2 | ||
|
|
ac57df409e | ||
|
|
e242e2b137 | ||
|
|
94cb33a0ce | ||
|
|
a2894bf0cb | ||
|
|
a56d47c768 | ||
|
|
3214800741 | ||
|
|
c11c3f9a88 | ||
|
|
81d120ac50 | ||
|
|
50b25572f1 | ||
|
|
39ac19db20 | ||
|
|
5dbbaae6fd | ||
|
|
423480903f | ||
|
|
f00395a6b6 | ||
|
|
391c0606d1 | ||
|
|
a27aaca918 | ||
|
|
03e5d84e0e | ||
|
|
8f21c86737 | ||
|
|
25dc779a73 | ||
|
|
4396d7cfd5 | ||
|
|
4700ed52da | ||
|
|
115d2c5fe9 | ||
|
|
afd5d1d0c0 | ||
|
|
a647768368 | ||
|
|
a9eddbbe9d | ||
|
|
80b23e5cc1 | ||
|
|
8cb4945617 | ||
|
|
f384e3d066 | ||
|
|
3977f2187a | ||
|
|
4ab1a04814 | ||
|
|
2e17f2b4b9 | ||
|
|
4b3270e82a | ||
|
|
de27be0911 | ||
|
|
34000ad159 | ||
|
|
bbcb236a46 | ||
|
|
d29f0eb5b6 | ||
|
|
b480c82f86 | ||
|
|
3105548c98 | ||
|
|
118635facb | ||
|
|
4746b7c361 | ||
|
|
801d0aacf0 | ||
|
|
82236484bc | ||
|
|
9a7cd8ae69 | ||
|
|
c330a47aac | ||
|
|
9293de541b | ||
|
|
01bd94d2b3 | ||
|
|
5913a4af1b | ||
|
|
72e5cb00b3 | ||
|
|
1d866093f1 | ||
|
|
0252591564 | ||
|
|
9ec1904119 | ||
|
|
f46243d943 | ||
|
|
dbcab96eea | ||
|
|
059191702b | ||
|
|
4f6cc96466 | ||
|
|
b98df8ef87 | ||
|
|
d09e448fbd | ||
|
|
fa00b797ee | ||
|
|
508ce6088e | ||
|
|
4d71848360 | ||
|
|
4ebad9efc1 | ||
|
|
4e8ee8eb86 | ||
|
|
ecc3558987 | ||
|
|
986ab29676 | ||
|
|
4679db6ec4 | ||
|
|
35a7925a21 | ||
|
|
5ab449eb7e | ||
|
|
5ba1d6f880 | ||
|
|
734c56a6b6 | ||
|
|
103d03d4c8 | ||
|
|
55b121e0d3 | ||
|
|
0e1c510948 | ||
|
|
b79ee281ec | ||
|
|
758b829a3c | ||
|
|
adc7846aff | ||
|
|
2e955cff54 | ||
|
|
aeeea2281c | ||
|
|
fa3af68836 | ||
|
|
1abdd5177d | ||
|
|
d62d890183 | ||
|
|
62a8602b2b | ||
|
|
1698b5cafb | ||
|
|
108d01ee35 | ||
|
|
e55b50bc5a | ||
|
|
4649553c5e | ||
|
|
1ea99a5dc8 | ||
|
|
ff8d899266 | ||
|
|
2e6064ce5c | ||
|
|
c7f260d030 | ||
|
|
f7e85ac86c | ||
|
|
5f647fd2ab | ||
|
|
6007fe263e | ||
|
|
26921a9c36 | ||
|
|
94a3c1dc21 | ||
|
|
5f0cb23f52 | ||
|
|
b1910d4300 | ||
|
|
163e4c8060 | ||
|
|
87e848beae | ||
|
|
febc020cd3 | ||
|
|
1733162df8 | ||
|
|
ee118d26b6 | ||
|
|
1dfe406ff9 | ||
|
|
5549c49326 | ||
|
|
754a91dbdc | ||
|
|
e3b90fb579 | ||
|
|
4bfe017b08 | ||
|
|
5e68362352 | ||
|
|
0497d38c1d | ||
|
|
1a1d6da451 | ||
|
|
763dc9c8e0 | ||
|
|
89c68d1987 | ||
|
|
70803f31d4 | ||
|
|
db2497424d | ||
|
|
0d3805d10a | ||
|
|
7b8b132062 | ||
|
|
d171f4088f | ||
|
|
e8e733184e | ||
|
|
e793e71163 | ||
|
|
46e47e3fc9 | ||
|
|
d4b3dc7472 | ||
|
|
df47dcc3f3 | ||
|
|
bfc16fc544 | ||
|
|
991e1baffd | ||
|
|
cd54ced1b2 | ||
|
|
f88c3755e0 | ||
|
|
0592b0c56a | ||
|
|
a0b72d0287 | ||
|
|
7a419c1563 | ||
|
|
ea42a3763f | ||
|
|
0f6a60fa69 | ||
|
|
a58b27e9b0 | ||
|
|
cfdeaf2f5d | ||
|
|
b64cd358ed | ||
|
|
12034ab619 | ||
|
|
ad482d5cfb | ||
|
|
885de88d35 | ||
|
|
223fb78bd8 | ||
|
|
077e78d37c | ||
|
|
e49d3923d0 | ||
|
|
65795a673e | ||
|
|
e39e0c9a85 | ||
|
|
f35b042324 | ||
|
|
9c8d5c2613 | ||
|
|
03bfd9a2b5 | ||
|
|
07aa1fd276 | ||
|
|
5aca681b36 | ||
|
|
94f466102e | ||
|
|
08866ae20b | ||
|
|
f73bdcdfb6 | ||
|
|
6410012384 | ||
|
|
93a24aaef8 | ||
|
|
688a31877b | ||
|
|
e9b9f204a5 | ||
|
|
dfee3a7a7c | ||
|
|
d03e2170dd | ||
|
|
d0cdc33c19 | ||
|
|
b7e1521e0d | ||
|
|
ed12cfe160 | ||
|
|
5578949bf5 | ||
|
|
5603d159b3 | ||
|
|
9e2093d6ae | ||
|
|
b7137e617e | ||
|
|
2c33f71ba7 | ||
|
|
56c2c24638 | ||
|
|
a8453657c9 | ||
|
|
55ff74de95 | ||
|
|
e2f7b1ec05 | ||
|
|
1cd2d28a3b | ||
|
|
c7808c5c03 | ||
|
|
3ed9f07015 | ||
|
|
676d2c46a1 | ||
|
|
b5f1a6b08b | ||
|
|
d9616b6d94 | ||
|
|
4812cb6412 | ||
|
|
9e60a23845 | ||
|
|
6cca39af1b | ||
|
|
7ffbe2ab5e | ||
|
|
28850e5510 | ||
|
|
d62bed1536 | ||
|
|
b19cf01a3a | ||
|
|
39dece1e25 | ||
|
|
61ae62a83a | ||
|
|
775f0d9fe6 | ||
|
|
53a925cf7f | ||
|
|
6bf33a5578 | ||
|
|
7f3c4acf62 | ||
|
|
8481c791d7 | ||
|
|
9dd0fb88d6 | ||
|
|
9b004d75c7 | ||
|
|
86c7fbd717 | ||
|
|
6bd7f40511 | ||
|
|
a82257f0b1 | ||
|
|
ee26f32a20 | ||
|
|
7df3d52635 | ||
|
|
f9ba17177e | ||
|
|
ab4941390b | ||
|
|
11d044ede9 | ||
|
|
3c406d955e | ||
|
|
ea37dd5e1d | ||
|
|
fd7225d861 | ||
|
|
e0bd22e674 | ||
|
|
89332cefc5 | ||
|
|
5172f64b72 | ||
|
|
6cb4b9fe4a | ||
|
|
c978f55c56 | ||
|
|
4a205fcfcb | ||
|
|
2e1e703e35 | ||
|
|
a75c162483 | ||
|
|
f6c0700633 | ||
|
|
dece7ddf13 | ||
|
|
d06bcd9dcc | ||
|
|
ee7d82c006 | ||
|
|
b777f7f2af | ||
|
|
fe87b9928c | ||
|
|
fb36709047 | ||
|
|
73aaccb6dd | ||
|
|
1fe0059402 | ||
|
|
0c12c45080 | ||
|
|
a6c48329ef | ||
|
|
a3cd1b89ff | ||
|
|
7a08f42edb | ||
|
|
e8722b56e3 | ||
|
|
052948f6eb | ||
|
|
cd03395e05 | ||
|
|
61caf18fd4 | ||
|
|
015f4d671d | ||
|
|
c13e828c79 | ||
|
|
7a6abaac44 | ||
|
|
58dffd0a33 | ||
|
|
fe0232a4e8 | ||
|
|
8dff6c2e2a | ||
|
|
3a6e2813a6 | ||
|
|
8005640b77 | ||
|
|
bc929fb7e0 | ||
|
|
019874b6af | ||
|
|
a7977a8fc7 | ||
|
|
62f6cc7198 | ||
|
|
ad331ee122 | ||
|
|
387f0600ce | ||
|
|
0801e33f97 | ||
|
|
f576d2f356 | ||
|
|
051f7b2769 | ||
|
|
1f207c493d | ||
|
|
03f565bf95 | ||
|
|
36e29a405e | ||
|
|
2ec53b27d1 | ||
|
|
152a0b50f2 | ||
|
|
c09758fb91 | ||
|
|
2b2884d996 | ||
|
|
4537971300 | ||
|
|
0b43e8b42a | ||
|
|
bf94161f30 | ||
|
|
573426899a | ||
|
|
3816227837 | ||
|
|
fe5e311673 | ||
|
|
bec0b7ec56 | ||
|
|
9d2a9ee70b | ||
|
|
baf652a569 | ||
|
|
9f340bcecd | ||
|
|
cc0a866166 | ||
|
|
d39b62503f | ||
|
|
e9b9af4616 | ||
|
|
7d88ef7ab2 | ||
|
|
5a49bd6f8c | ||
|
|
a255fc8524 | ||
|
|
d1b5c42d42 | ||
|
|
d957768a39 | ||
|
|
999630aed5 | ||
|
|
cf7efccde5 | ||
|
|
7b82a80fb4 | ||
|
|
cfe500794c | ||
|
|
a2d298f493 | ||
|
|
4687a866f5 | ||
|
|
ff08aff131 | ||
|
|
5510c2a37d | ||
|
|
608a084b94 | ||
|
|
9e47abdaa3 | ||
|
|
4d7bd455c9 | ||
|
|
05a72f7c62 | ||
|
|
4e23429cb8 | ||
|
|
b67d3e91af | ||
|
|
636487502d | ||
|
|
3207f457d4 | ||
|
|
af0cb1d6e7 | ||
|
|
06c16b79e3 | ||
|
|
09617e17d9 | ||
|
|
94f50dd6b6 | ||
|
|
d667554686 | ||
|
|
cbf3bcfe1c | ||
|
|
3d82323eaa | ||
|
|
83cd5e7494 | ||
|
|
e1e5554b88 | ||
|
|
6193a0b64e | ||
|
|
d1c8917cd2 | ||
|
|
7e17db4feb | ||
|
|
c214510087 | ||
|
|
9bac5aa58e | ||
|
|
9dbb10c59b | ||
|
|
d5325cc830 | ||
|
|
1539da75ed | ||
|
|
f786afc4b9 | ||
|
|
37ae4d5302 | ||
|
|
37b0543ed6 | ||
|
|
69fc2cd8f8 | ||
|
|
5e03507eba | ||
|
|
01fea212ec | ||
|
|
81ff3ec5b1 | ||
|
|
393464f2d8 | ||
|
|
17867159ea | ||
|
|
7b064ce448 | ||
|
|
bf403cacf8 | ||
|
|
a08bc8bb81 | ||
|
|
554e01a172 | ||
|
|
ed4260dd38 | ||
|
|
9e56cd5ea3 | ||
|
|
8db8766a48 | ||
|
|
222fca3ad7 | ||
|
|
efc50aec07 | ||
|
|
21aebe845f | ||
|
|
345e2357c8 | ||
|
|
8250cbcf6e | ||
|
|
d0040754ea | ||
|
|
22501749da | ||
|
|
c30bc77eea | ||
|
|
f74bac4f6b | ||
|
|
f54036225d | ||
|
|
f1b680119f | ||
|
|
9ffdb83004 | ||
|
|
7080a0ce7d | ||
|
|
de4f1aa8c4 | ||
|
|
fa6182b979 | ||
|
|
a457e337ac | ||
|
|
ba2c280d56 | ||
|
|
c8ed4947e1 | ||
|
|
5b700a30d9 | ||
|
|
d62f9a716e | ||
|
|
949f22acf0 | ||
|
|
358c411255 | ||
|
|
cfec612704 | ||
|
|
1741808e53 | ||
|
|
fd41e8ba45 | ||
|
|
01285ba10d | ||
|
|
0180196d7e | ||
|
|
167d9d34eb | ||
|
|
ab288f1593 | ||
|
|
5813ad95cf | ||
|
|
6801c960b1 | ||
|
|
76d1148a98 | ||
|
|
f63ed78f5b | ||
|
|
0ef248574c | ||
|
|
415fac8a25 | ||
|
|
6cbb77b591 | ||
|
|
65ea8edea7 | ||
|
|
c87fbfd3f8 | ||
|
|
faad739f97 | ||
|
|
38bcb8a724 | ||
|
|
82237f2e79 | ||
|
|
fd363c69cc | ||
|
|
e7769ce467 | ||
|
|
76273300e7 | ||
|
|
cb6d74d7d9 | ||
|
|
cfe78471aa | ||
|
|
e79e0cfb66 | ||
|
|
a74bc81ff8 | ||
|
|
b10b7a713e | ||
|
|
c9a2120c54 | ||
|
|
4e2d337620 | ||
|
|
ec33cdcb29 | ||
|
|
4cfddf1d8d | ||
|
|
3f9b86d8e7 | ||
|
|
f4fdb94a3f | ||
|
|
02856877a6 | ||
|
|
0a5f9307d2 | ||
|
|
579968143c | ||
|
|
aa454a5542 | ||
|
|
ce563085b5 | ||
|
|
6f99b22dc6 | ||
|
|
b08f228191 | ||
|
|
55252300c6 | ||
|
|
f99934b994 | ||
|
|
cd16fa43a0 | ||
|
|
ae9d82430a | ||
|
|
d75ca0c8f0 | ||
|
|
66a4b1c2df | ||
|
|
6fe39d99ac | ||
|
|
388c249212 | ||
|
|
af583145ed | ||
|
|
9c8b7b324f | ||
|
|
a3f5ef1a54 | ||
|
|
305658da3a | ||
|
|
2b24ebf539 | ||
|
|
13d5015fc3 | ||
|
|
13cf1a687e | ||
|
|
d2f434879c | ||
|
|
c3ffaa7ce2 | ||
|
|
2955c167c2 | ||
|
|
81d1bf6d27 | ||
|
|
46ce345203 | ||
|
|
363e69f01c | ||
|
|
9b0875169b | ||
|
|
e616247254 | ||
|
|
cc5f22df79 | ||
|
|
3448467953 | ||
|
|
74dbb96d85 | ||
|
|
d2cfe76a28 | ||
|
|
045e9db7b8 | ||
|
|
460b1d3a66 | ||
|
|
a463f2a855 | ||
|
|
8b3399b8f6 | ||
|
|
ef59d6dcb9 | ||
|
|
1b429b3f99 | ||
|
|
5098f7dee1 | ||
|
|
c509aaf246 | ||
|
|
d7333dec84 | ||
|
|
9d97494cfc | ||
|
|
acf9e7caea | ||
|
|
f6d000b26a | ||
|
|
ba5b35d0cc | ||
|
|
1eae8222c4 | ||
|
|
9b5a519bc7 | ||
|
|
b8a209249e | ||
|
|
ecc1b69f5c | ||
|
|
6253bc6c14 | ||
|
|
7768a4c1ba | ||
|
|
cd1bc7a695 | ||
|
|
42f45f9a83 | ||
|
|
d081eb0a2e | ||
|
|
504533991b | ||
|
|
44a5976b85 | ||
|
|
ac65b93b43 | ||
|
|
e9d27c521e | ||
|
|
dc86ae21de | ||
|
|
befb0f18b6 | ||
|
|
b796a6cbf4 | ||
|
|
9336a55a50 | ||
|
|
26749442fd | ||
|
|
7223d6e750 | ||
|
|
41a8e79e0e | ||
|
|
ec8a78537f | ||
|
|
4eb7597aa9 | ||
|
|
3d13fa3a26 | ||
|
|
655fe8afd3 | ||
|
|
855c66976e | ||
|
|
185cf163b2 | ||
|
|
45b7365025 | ||
|
|
ed5f64ccd6 | ||
|
|
3fc80e1145 | ||
|
|
05e3fc31b4 | ||
|
|
d5e1c4bfa5 | ||
|
|
a7c3317ed6 | ||
|
|
7db08082bc | ||
|
|
32836d42c9 | ||
|
|
789c4b480a | ||
|
|
abe291837a | ||
|
|
81ac0fdba9 | ||
|
|
d19cc972e0 | ||
|
|
8f6c3550e3 | ||
|
|
40681ccda4 | ||
|
|
4f76e1e1eb | ||
|
|
5cd9f89b21 | ||
|
|
b24685e38d | ||
|
|
5d7aa373fd | ||
|
|
e79b7fad0a | ||
|
|
e05541da88 | ||
|
|
0ccbfcfc9e | ||
|
|
8e6a570d47 | ||
|
|
129a884a4e | ||
|
|
2d278f303a | ||
|
|
dd67bd4b5e | ||
|
|
17239fe052 | ||
|
|
389908be7c | ||
|
|
33cf589c05 | ||
|
|
d961355016 | ||
|
|
9a72cf7ac2 | ||
|
|
53027559cd | ||
|
|
2e5545491b | ||
|
|
f9b0da65f1 | ||
|
|
4c734ee70f | ||
|
|
7173e293ef | ||
|
|
19ff17b3a5 | ||
|
|
d2b84c7773 | ||
|
|
623d6c09c4 | ||
|
|
8ae80138a0 | ||
|
|
cca041e21a | ||
|
|
b333061de7 | ||
|
|
abf4322b6c | ||
|
|
4e1a73fa27 | ||
|
|
214c86cc22 | ||
|
|
e0192f570e | ||
|
|
f5b5ab6331 | ||
|
|
d1c83b28f3 | ||
|
|
aa12b3f162 | ||
|
|
754087b5cf | ||
|
|
e656e36a92 | ||
|
|
0bf138281e | ||
|
|
fe62e12ab4 | ||
|
|
3c64c504c8 | ||
|
|
479472c1d8 | ||
|
|
c10c10c4a9 | ||
|
|
d8c515c858 | ||
|
|
168a308f5f | ||
|
|
fe40c5fd37 | ||
|
|
c430e36357 | ||
|
|
007bf743a6 | ||
|
|
774f57f3f6 | ||
|
|
044a64b964 | ||
|
|
f6bdb4d694 | ||
|
|
6a6b76e084 | ||
|
|
9357ce8a26 | ||
|
|
0aab2b3085 | ||
|
|
3edafd6c67 | ||
|
|
850ded2e17 | ||
|
|
67a58daaf3 | ||
|
|
9fdafd2008 | ||
|
|
66c37ccd3e | ||
|
|
fd3139201a | ||
|
|
abfedf573b | ||
|
|
a1f9536657 | ||
|
|
dec0563e3c | ||
|
|
9a4136399f | ||
|
|
20b0177105 | ||
|
|
e0957f70e6 | ||
|
|
125c4684bd | ||
|
|
991d4909e1 | ||
|
|
f81fd8084f | ||
|
|
231137617f | ||
|
|
f6b4c0ab25 | ||
|
|
30f2de151b | ||
|
|
20fe8bc09b | ||
|
|
2e715444ed | ||
|
|
1b13beb106 | ||
|
|
88213911fd | ||
|
|
50f3957011 | ||
|
|
bf18792d77 | ||
|
|
ca39fce578 | ||
|
|
f0df8dcdc7 | ||
|
|
7d594705fb | ||
|
|
fe5e124f93 | ||
|
|
41b1c55988 | ||
|
|
cfcbf640d6 | ||
|
|
d344c39d49 | ||
|
|
22d07d7a65 | ||
|
|
44fc7c0771 | ||
|
|
7ec671bb9f | ||
|
|
df35683043 | ||
|
|
03bfd8a734 | ||
|
|
409245e374 | ||
|
|
5870d38e8e | ||
|
|
c105e348d8 | ||
|
|
ccd0f89ae0 | ||
|
|
bdd28444bb | ||
|
|
c96468d76d | ||
|
|
943cd25592 | ||
|
|
7f4d3ff3ec | ||
|
|
5d2daa4a80 | ||
|
|
6372bb82c4 | ||
|
|
03a7da0795 | ||
|
|
bc1165ef3e | ||
|
|
47f34f6d12 | ||
|
|
d887e553ce | ||
|
|
13b5bb6407 | ||
|
|
5863df3323 | ||
|
|
b0cf69c160 | ||
|
|
60b2787c55 | ||
|
|
4d1e4f011f | ||
|
|
ec607596d1 | ||
|
|
7e4b791c29 | ||
|
|
55d8d26b34 | ||
|
|
3f5175778d | ||
|
|
7e80db36cf | ||
|
|
6828a1e07a | ||
|
|
2a51a17ddc | ||
|
|
ce11933dda | ||
|
|
b9f87bf310 | ||
|
|
28eeee3a28 | ||
|
|
e17e8d4154 | ||
|
|
dee7020a5a | ||
|
|
79f4e2ad6d | ||
|
|
25f1256724 | ||
|
|
4d49265b25 | ||
|
|
3d0e91f80e | ||
|
|
533857c961 | ||
|
|
83bc176ebf | ||
|
|
910f0cecbe | ||
|
|
10f0c49007 | ||
|
|
ba2911a645 | ||
|
|
07860bd4de | ||
|
|
42bd03e333 | ||
|
|
97f525fdbc | ||
|
|
1050e04c10 | ||
|
|
1534b22315 | ||
|
|
bcec728c2e | ||
|
|
6f503ca818 | ||
|
|
1b927a9d3a | ||
|
|
045b8a84a2 | ||
|
|
1624fc82f7 | ||
|
|
42d8773e36 | ||
|
|
15dff73b94 | ||
|
|
ec1d8f275f | ||
|
|
68391a943b | ||
|
|
9c48cc9ec0 | ||
|
|
41c06c1374 | ||
|
|
2c6841210c | ||
|
|
eba8fb4c9c | ||
|
|
95522ebcd9 | ||
|
|
8bf13f43e8 | ||
|
|
ca8f2a70a4 | ||
|
|
f6e9f5a5e8 | ||
|
|
be6d1044a0 | ||
|
|
52938b2f1c | ||
|
|
116372e11e | ||
|
|
14cdb5bdf1 | ||
|
|
de28bf8569 | ||
|
|
419615bed4 | ||
|
|
3ee9b13b3b | ||
|
|
0725ce3fb1 | ||
|
|
eb7623e218 | ||
|
|
19acd7861d | ||
|
|
282f0f91fe | ||
|
|
b51094d5cd | ||
|
|
b9a4b0b51d | ||
|
|
1a49d25c90 | ||
|
|
f57ed2990f | ||
|
|
87412ceb55 | ||
|
|
87cb4598f7 | ||
|
|
b35b9d8aa2 | ||
|
|
6646d48ccb | ||
|
|
23ee93ca3d | ||
|
|
0911511d0c | ||
|
|
b7562a7085 | ||
|
|
16a793e672 | ||
|
|
6e4407ed9c | ||
|
|
05cd1247ab | ||
|
|
af240450d6 | ||
|
|
ba24c4e40c | ||
|
|
2cbd7d83f9 | ||
|
|
892008563b | ||
|
|
c7a40784e7 | ||
|
|
c5e0832e00 | ||
|
|
eb4219504d | ||
|
|
a5e5b44330 | ||
|
|
ee6852f8ea | ||
|
|
2575552e11 | ||
|
|
a77cf56fbd | ||
|
|
07dfe33ed8 | ||
|
|
c8b21b2e17 | ||
|
|
0be1c00fcc | ||
|
|
20edac091a | ||
|
|
311c0d23a4 | ||
|
|
032099cfbe | ||
|
|
cd97cca7b8 | ||
|
|
3f0fddf448 | ||
|
|
f1e103b082 | ||
|
|
afe00d02cd | ||
|
|
e21c078521 | ||
|
|
5eb3784527 | ||
|
|
0ff1e63a5d | ||
|
|
b11ae567c9 | ||
|
|
e41256f935 | ||
|
|
b00db983c8 | ||
|
|
3e4a8bca36 | ||
|
|
54b4682258 | ||
|
|
bda49ed609 | ||
|
|
39be9aa58d | ||
|
|
f245b6b7fa | ||
|
|
ad87f9ff4e | ||
|
|
40abff4c1e | ||
|
|
51ad89c3af | ||
|
|
768412ba7c | ||
|
|
670b964e6b | ||
|
|
f6c377eb9f | ||
|
|
6d063a4f64 | ||
|
|
207be3a363 | ||
|
|
e1ffe943c8 | ||
|
|
431d884e83 | ||
|
|
983714cd72 | ||
|
|
e6629779f7 | ||
|
|
f1587753cb | ||
|
|
a6d4f445fb | ||
|
|
8f34cdc279 | ||
|
|
71cbac358b | ||
|
|
3b2b108744 | ||
|
|
100e2d4696 | ||
|
|
d42c4fb4f6 | ||
|
|
ed3e20dce5 | ||
|
|
82b0bd9ddb | ||
|
|
ab6ec59bfb | ||
|
|
b144fab042 | ||
|
|
b1d1c7c45a | ||
|
|
2353f654de | ||
|
|
6e0ae161ad | ||
|
|
f1660e3b9f | ||
|
|
336a22555f | ||
|
|
06b548f12e | ||
|
|
e4de42d487 | ||
|
|
1617577378 | ||
|
|
2add82efc5 | ||
|
|
06cacd7a5a | ||
|
|
2d4f29cb5a | ||
|
|
0b26250b46 | ||
|
|
09677d0bfa | ||
|
|
aa4bdf7efb | ||
|
|
5755ece33e | ||
|
|
2e93a975c4 | ||
|
|
c4df69a05b | ||
|
|
a562ee4ba1 | ||
|
|
781b384fe9 | ||
|
|
b6cc6c440d | ||
|
|
20da91b774 | ||
|
|
e530077fc5 | ||
|
|
444fff47dc | ||
|
|
1aa8f502ae | ||
|
|
2a25318ba8 | ||
|
|
39a8524354 | ||
|
|
573ca73b45 | ||
|
|
07d1a864d8 | ||
|
|
ffcd380523 | ||
|
|
55534b8b2e | ||
|
|
ca23934bde | ||
|
|
8a622ec7c3 | ||
|
|
39519d1cc9 | ||
|
|
dcbf92b5b1 | ||
|
|
7f6d500cbe | ||
|
|
cb1e91fee8 | ||
|
|
96494bacf5 | ||
|
|
99f68f36b0 | ||
|
|
61e682470c | ||
|
|
415e94d187 | ||
|
|
6b22f96313 | ||
|
|
8c3322f9a9 | ||
|
|
f935cf391e | ||
|
|
fb44df9815 | ||
|
|
e127895cf3 | ||
|
|
1f85b25549 | ||
|
|
df9851e2b7 | ||
|
|
232bc746f4 | ||
|
|
ea448cd6c3 | ||
|
|
a7d12ddcaa | ||
|
|
420e9b23d2 | ||
|
|
cd49018306 | ||
|
|
ddbf4f18ff | ||
|
|
24104991b4 | ||
|
|
d9d451a206 | ||
|
|
1f07050979 | ||
|
|
399ddd2dab | ||
|
|
2876ce633c | ||
|
|
333b9c811d | ||
|
|
1df3d56f7c | ||
|
|
d2a7a82870 | ||
|
|
5e49006b6f | ||
|
|
f73ea218ee |
No files matched your search
@@ -1,12 +1,16 @@
|
||||
FROM ubuntu:rolling
|
||||
FROM quay.io/wekan/ubuntu:groovy-20201125.2
|
||||
LABEL maintainer="sgr"
|
||||
|
||||
# 2020-12-03:
|
||||
# - Above Ubuntu base image copied from Docker Hub ubuntu:groovy-20201125.2
|
||||
# to Quay to avoid Docker Hub rate limits.
|
||||
|
||||
ENV BUILD_DEPS="gnupg gosu bsdtar wget curl bzip2 g++ build-essential python git ca-certificates iproute2"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ENV \
|
||||
DEBUG=false \
|
||||
NODE_VERSION=12.17.0 \
|
||||
NODE_VERSION=v12.20.1 \
|
||||
METEOR_RELEASE=1.10.2 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
@@ -21,10 +25,13 @@ ENV \
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE=3 \
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60 \
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15 \
|
||||
RICHER_CARD_COMMENT_EDITOR=true \
|
||||
RICHER_CARD_COMMENT_EDITOR=false \
|
||||
CARD_OPENED_WEBHOOK_ENABLED=false \
|
||||
ATTACHMENTS_STORE_PATH="" \
|
||||
MAX_IMAGE_PIXEL="" \
|
||||
IMAGE_COMPRESS_RATIO="" \
|
||||
BIGEVENTS_PATTERN="" \
|
||||
NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE="" \
|
||||
BIGEVENTS_PATTERN=NONE \
|
||||
NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="" \
|
||||
NOTIFY_DUE_AT_HOUR_OF_DAY="" \
|
||||
EMAIL_NOTIFICATION_TIMEOUT=30000 \
|
||||
@@ -36,6 +43,8 @@ ENV \
|
||||
TRUSTED_URL="" \
|
||||
WEBHOOKS_ATTRIBUTES="" \
|
||||
OAUTH2_ENABLED=false \
|
||||
OAUTH2_CA_CERT="" \
|
||||
OAUTH2_ADFS_ENABLED=false \
|
||||
OAUTH2_LOGIN_STYLE=redirect \
|
||||
OAUTH2_CLIENT_ID="" \
|
||||
OAUTH2_SECRET="" \
|
||||
@@ -108,7 +117,23 @@ ENV \
|
||||
CORS="" \
|
||||
CORS_ALLOW_HEADERS="" \
|
||||
CORS_EXPOSE_HEADERS="" \
|
||||
DEFAULT_AUTHENTICATION_METHOD=""
|
||||
DEFAULT_AUTHENTICATION_METHOD="" \
|
||||
PASSWORD_LOGIN_ENABLED=true \
|
||||
CAS_ENABLED=false \
|
||||
CAS_BASE_URL="" \
|
||||
CAS_LOGIN_URL="" \
|
||||
CAS_VALIDATE_URL="" \
|
||||
SAML_ENABLED=false \
|
||||
SAML_PROVIDER="" \
|
||||
SAML_ENTRYPOINT="" \
|
||||
SAML_ISSUER="" \
|
||||
SAML_CERT="" \
|
||||
SAML_IDPSLO_REDIRECTURL="" \
|
||||
SAML_PRIVATE_KEYFILE="" \
|
||||
SAML_PUBLIC_CERTFILE="" \
|
||||
SAML_IDENTIFIER_FORMAT="" \
|
||||
SAML_LOCAL_PROFILE_MATCH_ATTRIBUTE="" \
|
||||
SAML_ATTRIBUTES=""
|
||||
|
||||
# Install OS
|
||||
RUN set -o xtrace \
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@
|
||||
"no-spaced-func": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"operator-linebreak": 2,
|
||||
"quotes": [2, "single"],
|
||||
"quotes": [2, "single", { "avoidEscape": true }],
|
||||
"semi-spacing": 2,
|
||||
"space-unary-ops": 2,
|
||||
"arrow-spacing": 2,
|
||||
|
||||
@@ -81,7 +81,7 @@ parts:
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.17.0
|
||||
node-engine: 12.20.1
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
|
||||
Executable
+198
@@ -0,0 +1,198 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Note: If you use other locale than en_US.UTF-8 , you need to additionally install en_US.UTF-8"
|
||||
echo " with 'sudo dpkg-reconfigure locales' , so that MongoDB works correctly."
|
||||
echo " You can still use any other locale as your main locale."
|
||||
|
||||
#Below script installs newest node 8.x for Debian/Ubuntu/Mint.
|
||||
#NODE_VERSION=12.18.2
|
||||
#X64NODE="https://nodejs.org/dist/v${NODE_VERSION}/node-v${NODE_VERSION}-linux-x64.tar.gz"
|
||||
|
||||
function pause(){
|
||||
read -p "$*"
|
||||
}
|
||||
|
||||
function cprec(){
|
||||
if [[ -d "$1" ]]; then
|
||||
if [[ ! -d "$2" ]]; then
|
||||
sudo mkdir -p "$2"
|
||||
fi
|
||||
|
||||
for i in $(ls -A "$1"); do
|
||||
cprec "$1/$i" "$2/$i"
|
||||
done
|
||||
else
|
||||
sudo cp "$1" "$2"
|
||||
fi
|
||||
}
|
||||
|
||||
# sudo npm doesn't work right, so this is a workaround
|
||||
function npm_call(){
|
||||
TMPDIR="/tmp/tmp_npm_prefix"
|
||||
if [[ -d "$TMPDIR" ]]; then
|
||||
rm -rf $TMPDIR
|
||||
fi
|
||||
mkdir $TMPDIR
|
||||
NPM_PREFIX="$(npm config get prefix)"
|
||||
npm config set prefix $TMPDIR
|
||||
npm "$@"
|
||||
npm config set prefix "$NPM_PREFIX"
|
||||
|
||||
echo "Moving files to $NPM_PREFIX"
|
||||
for i in $(ls -A $TMPDIR); do
|
||||
cprec "$TMPDIR/$i" "$NPM_PREFIX/$i"
|
||||
done
|
||||
rm -rf $TMPDIR
|
||||
}
|
||||
|
||||
#function wekan_repo_check(){
|
||||
## UNCOMMENTING, IT'S NOT REQUIRED THAT /HOME/USERNAME IS /HOME/WEKAN
|
||||
# git_remotes="$(git remote show 2>/dev/null)"
|
||||
# res=""
|
||||
# for i in $git_remotes; do
|
||||
# res="$(git remote get-url $i | sed 's/.*wekan\/wekan.*/wekan\/wekan/')"
|
||||
# if [[ "$res" == "wekan/wekan" ]]; then
|
||||
# break
|
||||
# fi
|
||||
# done
|
||||
#
|
||||
# if [[ "$res" != "wekan/wekan" ]]; then
|
||||
# echo "$PWD is not a wekan repository"
|
||||
# exit;
|
||||
# fi
|
||||
#}
|
||||
|
||||
echo
|
||||
PS3='Please enter your choice: '
|
||||
options=("Install Wekan dependencies" "Build Wekan" "Run Meteor for dev on http://localhost:4000" "Run Meteor for dev on http://CURRENT-IP-ADDRESS:4000" "Run Meteor for dev on http://CUSTOM-IP-ADDRESS:PORT" "Quit")
|
||||
|
||||
select opt in "${options[@]}"
|
||||
do
|
||||
case $opt in
|
||||
"Install Wekan dependencies")
|
||||
|
||||
if [[ "$OSTYPE" == "linux-gnu" ]]; then
|
||||
echo "Linux";
|
||||
# Debian, Ubuntu, Mint
|
||||
sudo apt-get install -y build-essential gcc g++ make git curl wget
|
||||
# npm nodejs
|
||||
#sudo npm -g install npm
|
||||
curl -0 -L https://npmjs.org/install.sh | sudo sh
|
||||
sudo chown -R $(id -u):$(id -g) $HOME/.npm
|
||||
sudo npm -g install n
|
||||
sudo n 12.18.2
|
||||
#curl -sL https://deb.nodesource.com/setup_8.x | sudo -E bash -
|
||||
#sudo apt-get install -y nodejs
|
||||
elif [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
echo "macOS";
|
||||
pause '1) Install XCode 2) Install Node 8.x from https://nodejs.org/en/ 3) Press [Enter] key to continue.'
|
||||
elif [[ "$OSTYPE" == "cygwin" ]]; then
|
||||
# POSIX compatibility layer and Linux environment emulation for Windows
|
||||
echo "TODO: Add Cygwin";
|
||||
exit;
|
||||
elif [[ "$OSTYPE" == "msys" ]]; then
|
||||
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
|
||||
echo "TODO: Add msys on Windows";
|
||||
exit;
|
||||
elif [[ "$OSTYPE" == "win32" ]]; then
|
||||
# I'm not sure this can happen.
|
||||
echo "TODO: Add Windows";
|
||||
exit;
|
||||
elif [[ "$OSTYPE" == "freebsd"* ]]; then
|
||||
echo "TODO: Add FreeBSD";
|
||||
exit;
|
||||
else
|
||||
echo "Unknown"
|
||||
echo ${OSTYPE}
|
||||
exit;
|
||||
fi
|
||||
|
||||
## Latest npm with Meteor 1.8.x
|
||||
npm_call -g install npm
|
||||
npm_call -g install node-gyp
|
||||
# Latest fibers for Meteor 1.8.x
|
||||
sudo mkdir -p /usr/local/lib/node_modules/fibers/.node-gyp
|
||||
npm_call -g install fibers
|
||||
# Install Meteor, if it's not yet installed
|
||||
curl https://install.meteor.com | bash
|
||||
sudo chown -R $(id -u):$(id -g) $HOME/.npm $HOME/.meteor
|
||||
break
|
||||
;;
|
||||
|
||||
"Build Wekan")
|
||||
echo "Building Wekan."
|
||||
#wekan_repo_check
|
||||
# REPOS BELOW ARE INCLUDED TO WEKAN REPO
|
||||
#rm -rf packages/kadira-flow-router packages/meteor-useraccounts-core packages/meteor-accounts-cas packages/wekan-ldap packages/wekan-ldap packages/wekan-scrfollbar packages/meteor-accounts-oidc packages/markdown
|
||||
#mkdir packages
|
||||
#cd packages
|
||||
#git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router
|
||||
#git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core
|
||||
#git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git
|
||||
#git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git
|
||||
#git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git
|
||||
#git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git
|
||||
#git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git
|
||||
#mv meteor-accounts-oidc/packages/switch_accounts-oidc wekan_accounts-oidc
|
||||
#mv meteor-accounts-oidc/packages/switch_oidc wekan_oidc
|
||||
#rm -rf meteor-accounts-oidc
|
||||
#if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
# echo "sed at macOS";
|
||||
# sed -i '' 's/api\.versionsFrom/\/\/api.versionsFrom/' ~/repos/wekan/packages/meteor-useraccounts-core/package.js
|
||||
#else
|
||||
# echo "sed at ${OSTYPE}"
|
||||
# sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' ~/repos/wekan/packages/meteor-useraccounts-core/package.js
|
||||
#fi
|
||||
#cd ..
|
||||
sudo chown -R $(id -u):$(id -g) $HOME/.npm $HOME/.meteor
|
||||
rm -rf node_modules .meteor/local
|
||||
npm install
|
||||
rm -rf .build
|
||||
meteor build .build --directory
|
||||
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
|
||||
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
|
||||
rm -rf .build/bundle/programs/web.browser.legacy
|
||||
#Removed binary version of bcrypt because of security vulnerability that is not fixed yet.
|
||||
#https://github.com/wekan/wekan/commit/4b2010213907c61b0e0482ab55abb06f6a668eac
|
||||
#https://github.com/wekan/wekan/commit/7eeabf14be3c63fae2226e561ef8a0c1390c8d3c
|
||||
#cd ~/repos/wekan/.build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt
|
||||
#rm -rf node_modules/bcrypt
|
||||
#meteor npm install bcrypt
|
||||
cd .build/bundle/programs/server
|
||||
rm -rf node_modules
|
||||
npm install
|
||||
#meteor npm install bcrypt
|
||||
cd ../../../..
|
||||
echo Done.
|
||||
break
|
||||
;;
|
||||
|
||||
"Run Meteor for dev on http://localhost:4000")
|
||||
WITH_API=true RICHER_CARD_COMMENT_EDITOR=false ROOT_URL=http://localhost:4000 meteor run --exclude-archs web.browser.legacy,web.cordova --port 4000
|
||||
break
|
||||
;;
|
||||
|
||||
"Run Meteor for dev on http://CURRENT-IP-ADDRESS:4000")
|
||||
IPADDRESS=$(ip a | grep 'noprefixroute' | grep 'inet ' | cut -d: -f2 | awk '{ print $2}' | cut -d '/' -f 1)
|
||||
echo "Your IP address is $IPADDRESS"
|
||||
WITH_API=true RICHER_CARD_COMMENT_EDITOR=false ROOT_URL=http://$IPADDRESS:4000 meteor run --exclude-archs web.browser.legacy,web.cordova --port 4000
|
||||
break
|
||||
;;
|
||||
|
||||
"Run Meteor for dev on http://CUSTOM-IP-ADDRESS:PORT")
|
||||
ip address
|
||||
echo "From above list, what is your IP address?"
|
||||
read IPADDRESS
|
||||
echo "On what port you would like to run Wekan?"
|
||||
read PORT
|
||||
echo "ROOT_URL=http://$IPADDRESS:$PORT"
|
||||
WITH_API=true RICHER_CARD_COMMENT_EDITOR=false ROOT_URL=http://$IPADDRESS:$PORT meteor run --exclude-archs web.browser.legacy,web.cordova --port $PORT
|
||||
break
|
||||
;;
|
||||
|
||||
"Quit")
|
||||
break
|
||||
;;
|
||||
*) echo invalid option;;
|
||||
esac
|
||||
done
|
||||
@@ -83,7 +83,7 @@ parts:
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.17.0
|
||||
node-engine: 12.20.1
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
name: "CodeQL"
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [master]
|
||||
pull_request:
|
||||
# The branches below must be a subset of the branches above
|
||||
branches: [master]
|
||||
schedule:
|
||||
- cron: '0 16 * * 3'
|
||||
|
||||
jobs:
|
||||
analyze:
|
||||
name: Analyze
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Override automatic language detection by changing the below list
|
||||
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||
language: ['javascript', 'python']
|
||||
# Learn more...
|
||||
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# We must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head.
|
||||
fetch-depth: 2
|
||||
|
||||
# If this run was triggered by a pull request event, then checkout
|
||||
# the head of the pull request instead of the merge commit.
|
||||
- run: git checkout HEAD^2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
|
||||
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||
# and modify them (or add more) to build your code if your project
|
||||
# uses a compiled language
|
||||
|
||||
#- run: |
|
||||
# make bootstrap
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
@@ -5,6 +5,7 @@
|
||||
tmp/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.gitmodules
|
||||
.vscode/
|
||||
.idea/
|
||||
.build/*
|
||||
|
||||
+58
-11
@@ -6,8 +6,8 @@
|
||||
meteor-base@1.4.0
|
||||
|
||||
# Build system
|
||||
ecmascript@0.14.3
|
||||
standard-minifier-css@1.6.0
|
||||
ecmascript@0.14.4
|
||||
standard-minifier-css@1.7.1
|
||||
standard-minifier-js@2.6.0
|
||||
mquandalle:jade
|
||||
coffeescript@2.4.1!
|
||||
@@ -23,7 +23,7 @@ dburles:collection-helpers
|
||||
idmontie:migrations
|
||||
matb33:collection-hooks
|
||||
matteodem:easy-search
|
||||
mongo@1.10.0
|
||||
mongo@1.10.1
|
||||
mquandalle:collection-mutations
|
||||
|
||||
# Account system
|
||||
@@ -70,21 +70,17 @@ rajit:bootstrap3-datepicker
|
||||
shell-server@0.5.0
|
||||
simple:rest-accounts-password
|
||||
useraccounts:core
|
||||
email@1.2.3
|
||||
email@2.0.0
|
||||
horka:swipebox
|
||||
dynamic-import@0.5.2
|
||||
staringatlights:fast-render
|
||||
dynamic-import@0.5.5
|
||||
|
||||
accounts-password@1.6.0
|
||||
accounts-password@1.6.3
|
||||
cfs:gridfs
|
||||
rzymek:fullcalendar
|
||||
momentjs:moment@2.22.2
|
||||
browser-policy-framing@1.1.0
|
||||
mquandalle:moment
|
||||
msavin:usercache
|
||||
wekan-scrollbar
|
||||
mquandalle:perfect-scrollbar
|
||||
mdg:meteor-apm-agent@3.2.0-rc.0!
|
||||
# Keep stylus in 1.1.0, because building v2 takes extra 52 minutes.
|
||||
coagmano:stylus@1.1.0!
|
||||
lucasantoniassi:accounts-lockout
|
||||
@@ -97,4 +93,55 @@ konecty:mongo-counter
|
||||
percolate:synced-cron
|
||||
easylogic:summernote
|
||||
cfs:filesystem
|
||||
ostrio:cookies
|
||||
tmeasday:check-npm-versions
|
||||
steffo:meteor-accounts-saml
|
||||
rajit:bootstrap3-datepicker-fi
|
||||
rajit:bootstrap3-datepicker-ar
|
||||
rajit:bootstrap3-datepicker-bg
|
||||
rajit:bootstrap3-datepicker-br
|
||||
rajit:bootstrap3-datepicker-ca
|
||||
rajit:bootstrap3-datepicker-cs
|
||||
rajit:bootstrap3-datepicker-da
|
||||
rajit:bootstrap3-datepicker-de
|
||||
rajit:bootstrap3-datepicker-el
|
||||
rajit:bootstrap3-datepicker-en-gb
|
||||
rajit:bootstrap3-datepicker-eo
|
||||
rajit:bootstrap3-datepicker-es
|
||||
rajit:bootstrap3-datepicker-eu
|
||||
rajit:bootstrap3-datepicker-fa
|
||||
rajit:bootstrap3-datepicker-fr
|
||||
rajit:bootstrap3-datepicker-gl
|
||||
rajit:bootstrap3-datepicker-he
|
||||
rajit:bootstrap3-datepicker-hi
|
||||
rajit:bootstrap3-datepicker-hu
|
||||
rajit:bootstrap3-datepicker-hy
|
||||
rajit:bootstrap3-datepicker-id
|
||||
rajit:bootstrap3-datepicker-it
|
||||
rajit:bootstrap3-datepicker-ja
|
||||
rajit:bootstrap3-datepicker-ka
|
||||
rajit:bootstrap3-datepicker-km
|
||||
rajit:bootstrap3-datepicker-ko
|
||||
rajit:bootstrap3-datepicker-lv
|
||||
rajit:bootstrap3-datepicker-mk
|
||||
rajit:bootstrap3-datepicker-mn
|
||||
rajit:bootstrap3-datepicker-nb
|
||||
rajit:bootstrap3-datepicker-nl
|
||||
rajit:bootstrap3-datepicker-oc
|
||||
rajit:bootstrap3-datepicker-pl
|
||||
rajit:bootstrap3-datepicker-pt-br
|
||||
rajit:bootstrap3-datepicker-pt
|
||||
rajit:bootstrap3-datepicker-ro
|
||||
rajit:bootstrap3-datepicker-ru
|
||||
rajit:bootstrap3-datepicker-sl
|
||||
rajit:bootstrap3-datepicker-sr
|
||||
rajit:bootstrap3-datepicker-sv
|
||||
rajit:bootstrap3-datepicker-sw
|
||||
rajit:bootstrap3-datepicker-ta
|
||||
rajit:bootstrap3-datepicker-th
|
||||
rajit:bootstrap3-datepicker-tr
|
||||
rajit:bootstrap3-datepicker-uk
|
||||
rajit:bootstrap3-datepicker-vi
|
||||
rajit:bootstrap3-datepicker-zh-cn
|
||||
rajit:bootstrap3-datepicker-zh-tw
|
||||
staringatlights:fast-render
|
||||
spacebars
|
||||
+1
-1
@@ -1 +1 @@
|
||||
METEOR@1.10.2
|
||||
METEOR@1.12.1
|
||||
+74
-28
@@ -1,7 +1,7 @@
|
||||
3stack:presence@1.1.2
|
||||
accounts-base@1.6.0
|
||||
accounts-base@1.7.1
|
||||
accounts-oauth@1.2.0
|
||||
accounts-password@1.6.0
|
||||
accounts-password@1.6.3
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
@@ -11,13 +11,13 @@ allow-deny@1.1.0
|
||||
arillo:flow-router-helpers@0.5.2
|
||||
audit-argument-checks@1.0.7
|
||||
autoupdate@1.6.0
|
||||
babel-compiler@7.5.3
|
||||
babel-compiler@7.5.5
|
||||
babel-runtime@1.5.0
|
||||
base64@1.0.12
|
||||
binary-heap@1.0.11
|
||||
blaze@2.3.4
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.7.0
|
||||
boilerplate-generator@1.7.1
|
||||
browser-policy-common@1.0.11
|
||||
browser-policy-framing@1.1.0
|
||||
caching-compiler@1.2.2
|
||||
@@ -51,18 +51,18 @@ dburles:collection-helpers@1.1.0
|
||||
ddp@1.4.0
|
||||
ddp-client@2.3.3
|
||||
ddp-common@1.4.0
|
||||
ddp-rate-limiter@1.0.7
|
||||
ddp-server@2.3.1
|
||||
ddp-rate-limiter@1.0.9
|
||||
ddp-server@2.3.2
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.1
|
||||
dynamic-import@0.5.2
|
||||
dynamic-import@0.5.5
|
||||
easylogic:summernote@0.8.8
|
||||
ecmascript@0.14.3
|
||||
ecmascript@0.14.4
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.10.0
|
||||
ecmascript-runtime-server@0.9.0
|
||||
ecmascript-runtime-client@0.11.0
|
||||
ecmascript-runtime-server@0.10.0
|
||||
ejson@1.1.1
|
||||
email@1.2.3
|
||||
email@2.0.0
|
||||
es5-shim@4.8.0
|
||||
fastclick@1.0.13
|
||||
fetch@0.1.1
|
||||
@@ -91,7 +91,6 @@ logging@1.1.20
|
||||
lucasantoniassi:accounts-lockout@1.0.0
|
||||
matb33:collection-hooks@0.9.1
|
||||
matteodem:easy-search@1.6.4
|
||||
mdg:meteor-apm-agent@3.2.5
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.9.3
|
||||
meteor-base@1.4.0
|
||||
@@ -101,17 +100,17 @@ meteorhacks:collection-utils@1.2.0
|
||||
meteorhacks:picker@1.0.3
|
||||
meteorhacks:subs-manager@1.6.4
|
||||
meteorspark:util@0.2.0
|
||||
minifier-css@1.5.0
|
||||
minifier-css@1.5.3
|
||||
minifier-js@2.6.0
|
||||
minifiers@1.1.8-faster-rebuild.0
|
||||
minimongo@1.6.0
|
||||
minimongo@1.6.1
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.5
|
||||
modules@0.15.0
|
||||
modules-runtime@0.12.0
|
||||
momentjs:moment@2.26.0
|
||||
mongo@1.10.0
|
||||
mongo-decimal@0.1.1
|
||||
momentjs:moment@2.29.1
|
||||
mongo@1.10.1
|
||||
mongo-decimal@0.1.2
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.7
|
||||
mongo-livedata@1.0.12
|
||||
@@ -124,16 +123,14 @@ mquandalle:jquery-textcomplete@0.8.0_1
|
||||
mquandalle:jquery-ui-drag-drop-sort@0.2.0
|
||||
mquandalle:moment@1.0.1
|
||||
mquandalle:mousetrap-bindglobal@0.0.1
|
||||
mquandalle:perfect-scrollbar@0.6.5_2
|
||||
msavin:usercache@1.8.0
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@3.7.1
|
||||
oauth@1.3.0
|
||||
npm-mongo@3.8.1
|
||||
oauth@1.3.2
|
||||
oauth2@1.3.0
|
||||
observe-sequence@1.0.16
|
||||
ongoworks:speakingurl@1.1.0
|
||||
ordered-dict@1.1.0
|
||||
ostrio:cookies@2.6.0
|
||||
peerlibrary:assert@0.3.0
|
||||
peerlibrary:base-component@0.16.0
|
||||
peerlibrary:blaze-components@0.15.1
|
||||
@@ -144,11 +141,59 @@ promise@0.11.2
|
||||
raix:eventemitter@0.1.3
|
||||
raix:handlebar-helpers@0.2.5
|
||||
rajit:bootstrap3-datepicker@1.7.1_1
|
||||
rajit:bootstrap3-datepicker-ar@1.7.1
|
||||
rajit:bootstrap3-datepicker-bg@1.7.1
|
||||
rajit:bootstrap3-datepicker-br@1.7.1
|
||||
rajit:bootstrap3-datepicker-ca@1.7.1
|
||||
rajit:bootstrap3-datepicker-cs@1.7.1
|
||||
rajit:bootstrap3-datepicker-da@1.7.1
|
||||
rajit:bootstrap3-datepicker-de@1.7.1
|
||||
rajit:bootstrap3-datepicker-el@1.7.1
|
||||
rajit:bootstrap3-datepicker-en-gb@1.7.1
|
||||
rajit:bootstrap3-datepicker-eo@1.7.1
|
||||
rajit:bootstrap3-datepicker-es@1.7.1
|
||||
rajit:bootstrap3-datepicker-eu@1.7.1
|
||||
rajit:bootstrap3-datepicker-fa@1.7.1
|
||||
rajit:bootstrap3-datepicker-fi@1.7.1
|
||||
rajit:bootstrap3-datepicker-fr@1.7.1
|
||||
rajit:bootstrap3-datepicker-gl@1.7.1
|
||||
rajit:bootstrap3-datepicker-he@1.7.1
|
||||
rajit:bootstrap3-datepicker-hi@1.7.1
|
||||
rajit:bootstrap3-datepicker-hu@1.7.1
|
||||
rajit:bootstrap3-datepicker-hy@1.7.1
|
||||
rajit:bootstrap3-datepicker-id@1.7.1
|
||||
rajit:bootstrap3-datepicker-it@1.7.1
|
||||
rajit:bootstrap3-datepicker-ja@1.7.1
|
||||
rajit:bootstrap3-datepicker-ka@1.7.1
|
||||
rajit:bootstrap3-datepicker-km@1.7.1
|
||||
rajit:bootstrap3-datepicker-ko@1.7.1
|
||||
rajit:bootstrap3-datepicker-lv@1.7.1
|
||||
rajit:bootstrap3-datepicker-mk@1.7.1
|
||||
rajit:bootstrap3-datepicker-mn@1.7.1
|
||||
rajit:bootstrap3-datepicker-nb@1.7.1
|
||||
rajit:bootstrap3-datepicker-nl@1.7.1
|
||||
rajit:bootstrap3-datepicker-oc@1.7.1
|
||||
rajit:bootstrap3-datepicker-pl@1.7.1
|
||||
rajit:bootstrap3-datepicker-pt@1.7.1
|
||||
rajit:bootstrap3-datepicker-pt-br@1.7.1
|
||||
rajit:bootstrap3-datepicker-ro@1.7.1
|
||||
rajit:bootstrap3-datepicker-ru@1.7.1
|
||||
rajit:bootstrap3-datepicker-sl@1.7.1
|
||||
rajit:bootstrap3-datepicker-sr@1.7.1
|
||||
rajit:bootstrap3-datepicker-sv@1.7.1
|
||||
rajit:bootstrap3-datepicker-sw@1.7.1
|
||||
rajit:bootstrap3-datepicker-ta@1.7.1
|
||||
rajit:bootstrap3-datepicker-th@1.7.1
|
||||
rajit:bootstrap3-datepicker-tr@1.7.1
|
||||
rajit:bootstrap3-datepicker-uk@1.7.1
|
||||
rajit:bootstrap3-datepicker-vi@1.7.1
|
||||
rajit:bootstrap3-datepicker-zh-cn@1.7.1
|
||||
rajit:bootstrap3-datepicker-zh-tw@1.7.1
|
||||
random@1.2.0
|
||||
rate-limit@1.0.9
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.3.0
|
||||
reload@1.3.1
|
||||
retry@1.1.0
|
||||
routepolicy@1.1.0
|
||||
rzymek:fullcalendar@3.8.0
|
||||
@@ -162,26 +207,28 @@ simple:json-routes@2.1.0
|
||||
simple:rest-accounts-password@1.1.2
|
||||
simple:rest-bearer-token-parser@1.0.1
|
||||
simple:rest-json-error-handler@1.0.1
|
||||
socket-stream-client@0.3.0
|
||||
socket-stream-client@0.3.1
|
||||
softwarerero:accounts-t9n@1.3.11
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.3
|
||||
srp@1.1.0
|
||||
standard-minifier-css@1.6.0
|
||||
standard-minifier-css@1.7.1
|
||||
standard-minifier-js@2.6.0
|
||||
staringatlights:fast-render@3.2.0
|
||||
staringatlights:fast-render@3.3.0
|
||||
staringatlights:inject-data@2.3.0
|
||||
steffo:meteor-accounts-saml@0.0.18
|
||||
tap:i18n@1.8.2
|
||||
templates:tabs@2.3.0
|
||||
templating@1.3.2
|
||||
templating-compiler@1.3.3
|
||||
templating-runtime@1.3.2
|
||||
templating-tools@1.1.2
|
||||
tmeasday:check-npm-versions@0.3.2
|
||||
tracker@1.2.0
|
||||
twbs:bootstrap@3.3.6
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.3.0
|
||||
url@1.3.1
|
||||
useraccounts:core@1.14.2
|
||||
useraccounts:flow-routing@1.14.2
|
||||
useraccounts:unstyled@1.14.2
|
||||
@@ -191,8 +238,7 @@ webapp-hashing@1.0.9
|
||||
wekan-accounts-cas@0.1.0
|
||||
wekan-accounts-oidc@1.0.10
|
||||
wekan-ldap@0.0.2
|
||||
wekan-markdown@1.0.7
|
||||
wekan-markdown@1.0.9
|
||||
wekan-oidc@1.0.12
|
||||
wekan-scrollbar@3.1.3
|
||||
yasaricli:slugify@0.0.7
|
||||
zimme:active-route@2.3.2
|
||||
+1
-1
@@ -3,7 +3,7 @@ sudo: required
|
||||
|
||||
env:
|
||||
TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
|
||||
TRAVIS_NODE_VERSION: 12.17.0
|
||||
TRAVIS_NODE_VERSION: 12.20.1
|
||||
TRAVIS_NPM_VERSION: latest
|
||||
|
||||
before_install:
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ host = https://www.transifex.com
|
||||
# tap:i18n requires us to use `-` separator in the language identifiers whereas
|
||||
# Transifex uses a `_` separator, without an option to customize it on one side
|
||||
# or the other, so we need to do a Manual mapping.
|
||||
lang_map = bg_BG:bg, en_GB:en-GB, es_AR:es-AR, es_CL:es-CL, el_GR:el, fi_FI:fi, hu_HU:hu, id_ID:id, mn_MN:mn, no:nb, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, sl_SI:sl, zh_CN:zh-CN, zh_TW:zh-TW, zh_HK:zh-HK
|
||||
lang_map = bg_BG:bg, en_GB:en-GB, es_AR:es-AR, es_CL:es-CL, es_PE:es-PE, es_MX:es-MX, es_TX:es-TX, es_PY:es-PY, el_GR:el, fi_FI:fi, hu_HU:hu, id_ID:id, mn_MN:mn, no:nb, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, sl_SI:sl, zh_CN:zh-CN, zh_TW:zh-TW, zh_HK:zh-HK
|
||||
|
||||
[wekan.application]
|
||||
file_filter = i18n/<lang>.i18n.json
|
||||
|
||||
+1159
File diff suppressed because it is too large.
Load diff
+25
-5
@@ -1,6 +1,10 @@
|
||||
FROM ubuntu:rolling
|
||||
FROM quay.io/wekan/ubuntu:groovy-20201125.2
|
||||
LABEL maintainer="wekan"
|
||||
|
||||
# 2020-12-03:
|
||||
# - Above Ubuntu base image copied from Docker Hub ubuntu:groovy-20201125.2
|
||||
# to Quay to avoid Docker Hub rate limits.
|
||||
|
||||
# Set the environment variables (defaults where required)
|
||||
# DOES NOT WORK: paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
|
||||
# ENV BUILD_DEPS="paxctl"
|
||||
@@ -8,7 +12,7 @@ ARG DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-essential git ca-certificates python3" \
|
||||
DEBUG=false \
|
||||
NODE_VERSION=v12.17.0 \
|
||||
NODE_VERSION=v12.20.1 \
|
||||
METEOR_RELEASE=1.10.2 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
@@ -41,6 +45,8 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
TRUSTED_URL="" \
|
||||
WEBHOOKS_ATTRIBUTES="" \
|
||||
OAUTH2_ENABLED=false \
|
||||
OAUTH2_CA_CERT="" \
|
||||
OAUTH2_ADFS_ENABLED=false \
|
||||
OAUTH2_LOGIN_STYLE=redirect \
|
||||
OAUTH2_CLIENT_ID="" \
|
||||
OAUTH2_SECRET="" \
|
||||
@@ -114,9 +120,23 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
CORS_ALLOW_HEADERS="" \
|
||||
CORS_EXPOSE_HEADERS="" \
|
||||
DEFAULT_AUTHENTICATION_METHOD="" \
|
||||
SCROLLINERTIA="0" \
|
||||
SCROLLAMOUNT="auto" \
|
||||
PASSWORD_LOGIN_ENABLED=true
|
||||
PASSWORD_LOGIN_ENABLED=true \
|
||||
CAS_ENABLED=false \
|
||||
CAS_BASE_URL="" \
|
||||
CAS_LOGIN_URL="" \
|
||||
CAS_VALIDATE_URL="" \
|
||||
SAML_ENABLED=false \
|
||||
SAML_PROVIDER="" \
|
||||
SAML_ENTRYPOINT="" \
|
||||
SAML_ISSUER="" \
|
||||
SAML_CERT="" \
|
||||
SAML_IDPSLO_REDIRECTURL="" \
|
||||
SAML_PRIVATE_KEYFILE="" \
|
||||
SAML_PUBLIC_CERTFILE="" \
|
||||
SAML_IDENTIFIER_FORMAT="" \
|
||||
SAML_LOCAL_PROFILE_MATCH_ATTRIBUTE="" \
|
||||
SAML_ATTRIBUTES="" \
|
||||
ORACLE_OIM_ENABLED=false
|
||||
|
||||
# Copy the app to the image
|
||||
COPY ${SRC_PATH} /home/wekan/app
|
||||
|
||||
+2
-2
@@ -4,7 +4,7 @@ FROM amd64/alpine:3.7 AS builder
|
||||
ENV QEMU_VERSION=v4.2.0-6 \
|
||||
QEMU_ARCHITECTURE=aarch64 \
|
||||
NODE_ARCHITECTURE=linux-arm64 \
|
||||
NODE_VERSION=v12.17.0 \
|
||||
NODE_VERSION=v12.20.1 \
|
||||
WEKAN_VERSION=3.96 \
|
||||
WEKAN_ARCHITECTURE=arm64
|
||||
|
||||
@@ -40,7 +40,7 @@ LABEL maintainer="wekan"
|
||||
# Set the environment variables (defaults where required)
|
||||
ENV QEMU_ARCHITECTURE=aarch64 \
|
||||
NODE_ARCHITECTURE=linux-arm64 \
|
||||
NODE_VERSION=v12.17.0 \
|
||||
NODE_VERSION=v12.20.1 \
|
||||
NODE_ENV=production \
|
||||
NPM_VERSION=latest \
|
||||
WITH_API=true \
|
||||
|
||||
@@ -52,7 +52,7 @@ that by providing one-click installation on various platforms.
|
||||
|
||||
- Wekan is used in [most countries of the world](https://snapcraft.io/wekan).
|
||||
- Wekan largest user has 13k users using Wekan in their company.
|
||||
- Wekan has been [translated](https://transifex.com/wekan/wekan) to about 50 languages.
|
||||
- Wekan has been [translated](https://transifex.com/wekan/wekan) to about 60 languages.
|
||||
- [Features][features]: Wekan has real-time user interface.
|
||||
- [Platforms][platforms]: Wekan supports many platforms.
|
||||
Wekan is critical part of new platforms Wekan is currently being integrated to.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v4.10.0"
|
||||
appVersion: "v4.78.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -0,0 +1,251 @@
|
||||
#! /usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
# vi:ts=4:et
|
||||
|
||||
# Wekan API Python CLI, originally from here, where is more details:
|
||||
# https://github.com/wekan/wekan/wiki/New-card-with-Python3-and-REST-API
|
||||
|
||||
try:
|
||||
# python 3
|
||||
from urllib.parse import urlencode
|
||||
except ImportError:
|
||||
# python 2
|
||||
from urllib import urlencode
|
||||
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
|
||||
arguments = len(sys.argv) - 1
|
||||
|
||||
if arguments == 0:
|
||||
print("=== Wekan API Python CLI: Shows IDs for addcard ===")
|
||||
print("AUTHORID is USERID that writes card.")
|
||||
print("If *nix: chmod +x api.py => ./api.py users")
|
||||
print("Syntax:")
|
||||
print(" python3 api.py users # All users")
|
||||
print(" python3 api.py boards USERID # Boards of USERID")
|
||||
print(" python3 api.py board BOARDID # Info of BOARDID")
|
||||
print(" python3 api.py swimlanes BOARDID # Swimlanes of BOARDID")
|
||||
print(" python3 api.py lists BOARDID # Lists of BOARDID")
|
||||
print(" python3 api.py createlist BOARDID LISTTITLE # Create list")
|
||||
print(" python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION")
|
||||
print(" python3 api.py listattachments BOARDID # List attachments")
|
||||
# TODO:
|
||||
# print(" python3 api.py attachmentdownload BOARDID ATTACHMENTID # One attachment as file")
|
||||
# print(" python3 api.py attachmentsdownload BOARDID # All attachments as files")
|
||||
exit
|
||||
|
||||
# ------- SETTINGS START -------------
|
||||
|
||||
# Username is your Wekan username or email address.
|
||||
# OIDC/OAuth2 etc uses email address as username.
|
||||
|
||||
username = 'testtest'
|
||||
|
||||
password = 'testtest'
|
||||
|
||||
wekanurl = 'http://localhost:4000/'
|
||||
|
||||
# ------- SETTINGS END -------------
|
||||
|
||||
"""
|
||||
EXAMPLE:
|
||||
|
||||
python3 api.py
|
||||
|
||||
OR:
|
||||
chmod +x api.py
|
||||
./api.py
|
||||
|
||||
=== Wekan API Python CLI: Shows IDs for addcard ===
|
||||
AUTHORID is USERID that writes card.
|
||||
Syntax:
|
||||
python3 api.py users # All users
|
||||
python3 api.py boards USERID # Boards of USERID
|
||||
python3 api.py board BOARDID # Info of BOARDID
|
||||
python3 api.py swimlanes BOARDID # Swimlanes of BOARDID
|
||||
python3 api.py lists BOARDID # Lists of BOARDID
|
||||
python3 api.py createlist BOARDID LISTTITLE # Create list
|
||||
python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION
|
||||
python3 api.py listattachments BOARDID # List attachments
|
||||
python3 api.py attachmentjson BOARDID ATTACHMENTID # One attachment as JSON base64
|
||||
python3 api.py attachmentbinary BOARDID ATTACHMENTID # One attachment as binary file
|
||||
|
||||
=== USERS ===
|
||||
|
||||
python3 api.py users
|
||||
|
||||
=> abcd1234
|
||||
|
||||
=== BOARDS ===
|
||||
|
||||
python3 api.py boards abcd1234
|
||||
|
||||
|
||||
=== SWIMLANES ===
|
||||
|
||||
python3 api.py swimlanes dYZ
|
||||
|
||||
[{"_id":"Jiv","title":"Default"}
|
||||
]
|
||||
|
||||
=== LISTS ===
|
||||
|
||||
python3 api.py lists dYZ
|
||||
|
||||
[]
|
||||
|
||||
There is no lists, so create a list:
|
||||
|
||||
=== CREATE LIST ===
|
||||
|
||||
python3 api.py createlist dYZ 'Test'
|
||||
|
||||
{"_id":"7Kp"}
|
||||
|
||||
# python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION
|
||||
|
||||
python3 api.py addcard ppg dYZ Jiv 7Kp 'Test card' 'Test description'
|
||||
|
||||
=== LIST ATTACHMENTS WITH DOWNLOAD URLs ====
|
||||
|
||||
python3 api.py listattachments BOARDID
|
||||
|
||||
"""
|
||||
|
||||
# ------- API URL GENERATION START -----------
|
||||
|
||||
loginurl = 'users/login'
|
||||
wekanloginurl = wekanurl + loginurl
|
||||
apiboards = 'api/boards/'
|
||||
apiattachments = 'api/attachments/'
|
||||
apiusers = 'api/users'
|
||||
e = 'export'
|
||||
s = '/'
|
||||
l = 'lists'
|
||||
sw = 'swimlane'
|
||||
sws = 'swimlanes'
|
||||
cs = 'cards'
|
||||
bs = 'boards'
|
||||
atl = 'attachmentslist'
|
||||
at = 'attachment'
|
||||
ats = 'attachments'
|
||||
users = wekanurl + apiusers
|
||||
|
||||
# ------- API URL GENERATION END -----------
|
||||
|
||||
# ------- LOGIN TOKEN START -----------
|
||||
|
||||
data = {"username": username, "password": password}
|
||||
body = requests.post(wekanloginurl, data=data)
|
||||
d = body.json()
|
||||
apikey = d['token']
|
||||
|
||||
# ------- LOGIN TOKEN END -----------
|
||||
|
||||
if arguments == 7:
|
||||
|
||||
if sys.argv[1] == 'addcard':
|
||||
# ------- WRITE TO CARD START -----------
|
||||
authorid = sys.argv[2]
|
||||
boardid = sys.argv[3]
|
||||
swimlaneid = sys.argv[4]
|
||||
listid = sys.argv[5]
|
||||
cardtitle = sys.argv[6]
|
||||
carddescription = sys.argv[7]
|
||||
cardtolist = wekanurl + apiboards + boardid + s + l + s + listid + s + cs
|
||||
# Write to card
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
post_data = {'authorId': '{}'.format(authorid), 'title': '{}'.format(cardtitle), 'description': '{}'.format(carddescription), 'swimlaneId': '{}'.format(swimlaneid)}
|
||||
body = requests.post(cardtolist, data=post_data, headers=headers)
|
||||
print(body.text)
|
||||
# ------- WRITE TO CARD END -----------
|
||||
|
||||
if arguments == 3:
|
||||
|
||||
if sys.argv[1] == 'createlist':
|
||||
|
||||
# ------- CREATE LIST START -----------
|
||||
boardid = sys.argv[2]
|
||||
listtitle = sys.argv[3]
|
||||
list = wekanurl + apiboards + boardid + s + l
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
post_data = {'title': '{}'.format(listtitle)}
|
||||
body = requests.post(list, data=post_data, headers=headers)
|
||||
print("=== CREATE LIST ===\n")
|
||||
print(body.text)
|
||||
# ------- CREATE LIST END -----------
|
||||
|
||||
if arguments == 2:
|
||||
|
||||
# ------- BOARDS LIST START -----------
|
||||
userid = sys.argv[2]
|
||||
boards = users + s + userid + s + bs
|
||||
if sys.argv[1] == 'boards':
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
#post_data = {'userId': '{}'.format(userid)}
|
||||
body = requests.get(boards, headers=headers)
|
||||
print("=== BOARDS ===\n")
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- BOARDS LIST END -----------
|
||||
if sys.argv[1] == 'board':
|
||||
|
||||
# ------- BOARD INFO START -----------
|
||||
boardid = sys.argv[2]
|
||||
board = wekanurl + apiboards + boardid
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
body = requests.get(board, headers=headers)
|
||||
print("=== BOARD ===\n")
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- BOARD INFO END -----------
|
||||
|
||||
if sys.argv[1] == 'swimlanes':
|
||||
boardid = sys.argv[2]
|
||||
swimlanes = wekanurl + apiboards + boardid + s + sws
|
||||
# ------- SWIMLANES OF BOARD START -----------
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print("=== SWIMLANES ===\n")
|
||||
body = requests.get(swimlanes, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- SWIMLANES OF BOARD END -----------
|
||||
|
||||
if sys.argv[1] == 'lists':
|
||||
|
||||
# ------- LISTS OF BOARD START -----------
|
||||
boardid = sys.argv[2]
|
||||
attachments = wekanurl + apiboards + boardid
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print("=== LISTS ===\n")
|
||||
body = requests.get(lists, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- LISTS OF BOARD END -----------
|
||||
|
||||
if sys.argv[1] == 'listattachments':
|
||||
|
||||
# ------- LISTS OF ATTACHMENTS START -----------
|
||||
boardid = sys.argv[2]
|
||||
listattachments = wekanurl + apiboards + boardid + s + ats
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print("=== LIST OF ATTACHMENTS ===\n")
|
||||
body = requests.get(listattachments, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- LISTS OF ATTACHMENTS END -----------
|
||||
|
||||
if arguments == 1:
|
||||
|
||||
if sys.argv[1] == 'users':
|
||||
|
||||
# ------- LIST OF USERS START -----------
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print(users)
|
||||
print("=== USERS ===\n")
|
||||
body = requests.get(users, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- LIST OF USERS END -----------
|
||||
@@ -15,11 +15,18 @@ template(name="cardActivities")
|
||||
each activityData in currentCard.activities
|
||||
+activity(activity=activityData card=card mode=mode)
|
||||
|
||||
template(name="editOrDeleteComment")
|
||||
= ' - '
|
||||
a.js-open-inlined-form {{_ "edit"}}
|
||||
= ' - '
|
||||
a.js-delete-comment {{_ "delete"}}
|
||||
|
||||
template(name="activity")
|
||||
.activity
|
||||
+userAvatar(userId=activity.user._id)
|
||||
p.activity-desc
|
||||
+memberName(user=activity.user)
|
||||
span.activity-member
|
||||
+memberName(user=activity.user)
|
||||
|
||||
//- attachment activity -------------------------------------------------
|
||||
if($eq activity.activityType 'deleteAttachment')
|
||||
@@ -34,38 +41,38 @@ template(name="activity")
|
||||
//- board activity ------------------------------------------------------
|
||||
if($eq mode 'board')
|
||||
if($eq activity.activityType 'createBoard')
|
||||
| {{_ 'activity-created' boardLabel}}.
|
||||
| {{{_ 'activity-created' boardLabelLink}}}.
|
||||
|
||||
if($eq activity.activityType 'importBoard')
|
||||
| {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
|
||||
| {{{_ 'activity-imported-board' boardLabelLink sourceLink}}}.
|
||||
|
||||
if($eq activity.activityType 'addBoardMember')
|
||||
| {{{_ 'activity-added' memberLink boardLabel}}}.
|
||||
| {{{_ 'activity-added' memberLink boardLabelLink}}}.
|
||||
|
||||
if($eq activity.activityType 'removeBoardMember')
|
||||
| {{{_ 'activity-excluded' memberLink boardLabel}}}.
|
||||
| {{{_ 'activity-excluded' memberLink boardLabelLink}}}.
|
||||
|
||||
//- card activity -------------------------------------------------------
|
||||
if($eq activity.activityType 'createCard')
|
||||
if($eq mode 'card')
|
||||
| {{{_ 'activity-added' cardLabel activity.listName}}}.
|
||||
| {{{_ 'activity-added' cardLabelLink (sanitize activity.listName)}}}.
|
||||
else
|
||||
| {{{_ 'activity-added' cardLabel boardLabel}}}.
|
||||
| {{{_ 'activity-added' cardLabelLink boardLabelLink}}}.
|
||||
|
||||
if($eq activity.activityType 'importCard')
|
||||
| {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
|
||||
| {{{_ 'activity-imported' cardLink boardLabelLink sourceLink}}}.
|
||||
|
||||
if($eq activity.activityType 'moveCard')
|
||||
| {{{_ 'activity-moved' cardLabel activity.oldList.title activity.list.title}}}.
|
||||
| {{{_ 'activity-moved' cardLabelLink (sanitize activity.oldList.title) (sanitize activity.list.title)}}}.
|
||||
|
||||
if($eq activity.activityType 'moveCardBoard')
|
||||
| {{{_ 'activity-moved' cardLink activity.oldBoardName activity.boardName}}}.
|
||||
| {{{_ 'activity-moved' cardLink (sanitize activity.oldBoardName) (sanitize activity.boardName)}}}.
|
||||
|
||||
if($eq activity.activityType 'archivedCard')
|
||||
| {{{_ 'activity-archived' cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'restoredCard')
|
||||
| {{{_ 'activity-sent' cardLink boardLabel}}}.
|
||||
| {{{_ 'activity-sent' cardLink boardLabelLink}}}.
|
||||
|
||||
//- checklist activity --------------------------------------------------
|
||||
if($eq activity.activityType 'addChecklist')
|
||||
@@ -83,25 +90,25 @@ template(name="activity")
|
||||
| {{{_ 'activity-checklist-removed' cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'completeChecklist')
|
||||
| {{{_ 'activity-checklist-completed' activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-checklist-completed' (sanitize activity.checklist.title) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'uncompleteChecklist')
|
||||
| {{{_ 'activity-checklist-uncompleted' activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-checklist-uncompleted' (sanitize activity.checklist.title) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item' checkItem activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-checked-item' (sanitize checkItem) (sanitize activity.checklist.title) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item' checkItem activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-unchecked-item' (sanitize checkItem) (sanitize activity.checklist.title) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-checklist-item-added' (sanitize activity.checklist.title) cardLink}}}.
|
||||
.activity-checklist(href="{{ activity.card.absoluteUrl }}")
|
||||
+viewer
|
||||
= activity.checklistItem.title
|
||||
|
||||
if($eq activity.activityType 'removedChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-removed' activity.checklist.title cardLink}}}.
|
||||
| {{{_ 'activity-checklist-item-removed' (sanitize activity.checklist.title) cardLink}}}.
|
||||
|
||||
//- comment activity ----------------------------------------------------
|
||||
if($eq mode 'card')
|
||||
@@ -118,11 +125,10 @@ template(name="activity")
|
||||
+viewer
|
||||
= activity.comment.text
|
||||
span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
|
||||
if ($eq currentUser._id activity.comment.userId)
|
||||
= ' - '
|
||||
a.js-open-inlined-form {{_ "edit"}}
|
||||
= ' - '
|
||||
a.js-delete-comment {{_ "delete"}}
|
||||
if($eq currentUser._id activity.comment.userId)
|
||||
+editOrDeleteComment
|
||||
else if currentUser.isBoardAdmin
|
||||
+editOrDeleteComment
|
||||
|
||||
if($eq activity.activityType 'deleteComment')
|
||||
| {{{_ 'activity-deleteComment' currentData.commentId}}}.
|
||||
@@ -137,37 +143,64 @@ template(name="activity")
|
||||
+viewer
|
||||
= activity.comment.text
|
||||
|
||||
//- date activity ------------------------------------------------
|
||||
if($eq mode 'card')
|
||||
if($eq activity.activityType 'a-receivedAt')
|
||||
| {{{_ 'activity-receivedDate' (sanitize receivedDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-startAt')
|
||||
| {{{_ 'activity-startDate' (sanitize startDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-dueAt')
|
||||
| {{{_ 'activity-dueDate' (sanitize dueDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-endAt')
|
||||
| {{{_ 'activity-endDate' (sanitize endDate) cardLink}}}.
|
||||
|
||||
if($eq mode 'board')
|
||||
if($eq activity.activityType 'a-receivedAt')
|
||||
| {{{_ 'activity-receivedDate' (sanitize receivedDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-startAt')
|
||||
| {{{_ 'activity-startDate' (sanitize startDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-dueAt')
|
||||
| {{{_ 'activity-dueDate' (sanitize dueDate) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'a-endAt')
|
||||
| {{{_ 'activity-endDate' (sanitize endDate) cardLink}}}.
|
||||
|
||||
//- customField activity ------------------------------------------------
|
||||
if($eq mode 'board')
|
||||
if($eq activity.activityType 'createCustomField')
|
||||
| {{_ 'activity-customfield-created' customField}}.
|
||||
|
||||
if($eq activity.activityType 'setCustomField')
|
||||
| {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
|
||||
| {{{_ 'activity-set-customfield' (sanitize lastCustomField) (sanitize lastCustomFieldValue) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'unsetCustomField')
|
||||
| {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
|
||||
| {{{_ 'activity-unset-customfield' (sanitize lastCustomField) cardLink}}}.
|
||||
|
||||
//- label activity ------------------------------------------------------
|
||||
if($eq activity.activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label' lastLabel cardLink}}}.
|
||||
| {{{_ 'activity-added-label' (sanitize lastLabel) cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
|
||||
| {{{_ 'activity-removed-label' (sanitize lastLabel) cardLink}}}.
|
||||
|
||||
//- list activity -------------------------------------------------------
|
||||
if($neq mode 'card')
|
||||
if($eq activity.activityType 'createList')
|
||||
| {{{_ 'activity-added' listLabel boardLabel}}}.
|
||||
| {{{_ 'activity-added' (sanitize listLabel) boardLabelLink}}}.
|
||||
|
||||
if($eq activity.activityType 'importList')
|
||||
| {{{_ 'activity-imported' listLabel boardLabel sourceLink}}}.
|
||||
| {{{_ 'activity-imported' (sanitize listLabel) boardLabelLink sourceLink}}}.
|
||||
|
||||
if($eq activity.activityType 'removeList')
|
||||
| {{{_ 'activity-removed' activity.title boardLabel}}}.
|
||||
| {{{_ 'activity-removed' (sanitize activity.title) boardLabelLink}}}.
|
||||
|
||||
if($eq activity.activityType 'archivedList')
|
||||
| {{_ 'activity-archived' listLabel}}.
|
||||
| {{_ 'activity-archived' (sanitize listLabel)}}.
|
||||
|
||||
//- member activity ----------------------------------------------------
|
||||
if($eq activity.activityType 'joinMember')
|
||||
@@ -185,15 +218,15 @@ template(name="activity")
|
||||
//- swimlane activity --------------------------------------------------
|
||||
if($neq mode 'card')
|
||||
if($eq activity.activityType 'createSwimlane')
|
||||
| {{{_ 'activity-added' activity.swimlane.title boardLabel}}}.
|
||||
| {{_ 'activity-added' (sanitize activity.swimlane.title) boardLabelLink}}.
|
||||
|
||||
if($eq activity.activityType 'archivedSwimlane')
|
||||
| {{_ 'activity-archived' activity.swimlane.title}}.
|
||||
| {{_ 'activity-archived' (sanitize activity.swimlane.title)}}.
|
||||
|
||||
|
||||
//- I don't understand this part ----------------------------------------
|
||||
if(currentData.timeKey)
|
||||
| {{{_ activity.activityType }}}
|
||||
| {{_ activity.activityType }}
|
||||
= ' '
|
||||
i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
|
||||
if (currentData.timeOldValue)
|
||||
@@ -203,6 +236,6 @@ template(name="activity")
|
||||
i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
|
||||
= ' @'
|
||||
else if(currentData.timeValue)
|
||||
| {{{_ activity.activityType currentData.timeValue}}}
|
||||
| {{_ activity.activityType currentData.timeValue}}
|
||||
|
||||
span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
|
||||
@@ -1,3 +1,5 @@
|
||||
import sanitizeXss from 'xss';
|
||||
|
||||
const activitiesPerPage = 20;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -5,8 +7,9 @@ BlazeComponent.extendComponent({
|
||||
// XXX Should we use ReactiveNumber?
|
||||
this.page = new ReactiveVar(1);
|
||||
this.loadNextPageLocked = false;
|
||||
const sidebar = this.parentComponent(); // XXX for some reason not working
|
||||
sidebar.callFirstWith(null, 'resetNextPeak');
|
||||
// TODO is sidebar always available? E.g. on small screens/mobile devices
|
||||
const sidebar = Sidebar;
|
||||
sidebar && sidebar.callFirstWith(null, 'resetNextPeak');
|
||||
this.autorun(() => {
|
||||
let mode = this.data().mode;
|
||||
const capitalizedMode = Utils.capitalize(mode);
|
||||
@@ -27,6 +30,8 @@ BlazeComponent.extendComponent({
|
||||
this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
|
||||
// TODO the guard can be removed as soon as the TODO above is resolved
|
||||
if (!sidebar) return;
|
||||
// If the sibear peak hasn't increased, that mean that there are no more
|
||||
// activities, and we can stop calling new subscriptions.
|
||||
// XXX This is hacky! We need to know excatly and reactively how many
|
||||
@@ -41,23 +46,22 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
});
|
||||
},
|
||||
}).register('activities');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
loadNextPage() {
|
||||
if (this.loadNextPageLocked === false) {
|
||||
this.page.set(this.page.get() + 1);
|
||||
this.loadNextPageLocked = true;
|
||||
}
|
||||
},
|
||||
}).register('activities');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
checkItem() {
|
||||
const checkItemId = this.currentData().activity.checklistItemId;
|
||||
const checkItem = ChecklistItems.findOne({ _id: checkItemId });
|
||||
return checkItem && checkItem.title;
|
||||
},
|
||||
|
||||
boardLabel() {
|
||||
boardLabelLink() {
|
||||
const data = this.currentData();
|
||||
if (data.mode !== 'board') {
|
||||
return createBoardLink(data.activity.board(), data.activity.listName);
|
||||
@@ -65,10 +69,10 @@ BlazeComponent.extendComponent({
|
||||
return TAPi18n.__('this-board');
|
||||
},
|
||||
|
||||
cardLabel() {
|
||||
cardLabelLink() {
|
||||
const data = this.currentData();
|
||||
if (data.mode !== 'card') {
|
||||
return createCardLink(this.currentData().activity.card());
|
||||
return createCardLink(data.activity.card());
|
||||
}
|
||||
return TAPi18n.__('this-card');
|
||||
},
|
||||
@@ -77,6 +81,30 @@ BlazeComponent.extendComponent({
|
||||
return createCardLink(this.currentData().activity.card());
|
||||
},
|
||||
|
||||
receivedDate() {
|
||||
const receivedDate = this.currentData().activity.card();
|
||||
if (!receivedDate) return null;
|
||||
return receivedDate.receivedAt;
|
||||
},
|
||||
|
||||
startDate() {
|
||||
const startDate = this.currentData().activity.card();
|
||||
if (!startDate) return null;
|
||||
return startDate.startAt;
|
||||
},
|
||||
|
||||
dueDate() {
|
||||
const dueDate = this.currentData().activity.card();
|
||||
if (!dueDate) return null;
|
||||
return dueDate.dueAt;
|
||||
},
|
||||
|
||||
endDate() {
|
||||
const endDate = this.currentData().activity.card();
|
||||
if (!endDate) return null;
|
||||
return endDate.endAt;
|
||||
},
|
||||
|
||||
lastLabel() {
|
||||
const lastLabelId = this.currentData().activity.labelId;
|
||||
if (!lastLabelId) return null;
|
||||
@@ -134,11 +162,11 @@ BlazeComponent.extendComponent({
|
||||
{
|
||||
href: source.url,
|
||||
},
|
||||
source.system,
|
||||
sanitizeXss(source.system),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return source.system;
|
||||
return sanitizeXss(source.system);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -162,10 +190,10 @@ BlazeComponent.extendComponent({
|
||||
href: attachment.url({ download: true }),
|
||||
target: '_blank',
|
||||
},
|
||||
attachment.name(),
|
||||
sanitizeXss(attachment.name()),
|
||||
),
|
||||
)) ||
|
||||
this.currentData().activity.attachmentName
|
||||
sanitizeXss(this.currentData().activity.attachmentName)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -202,7 +230,14 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('activity');
|
||||
|
||||
Template.activity.helpers({
|
||||
sanitize(value) {
|
||||
return sanitizeXss(value);
|
||||
},
|
||||
});
|
||||
|
||||
function createCardLink(card) {
|
||||
if (!card) return '';
|
||||
return (
|
||||
card &&
|
||||
Blaze.toHTML(
|
||||
@@ -211,7 +246,7 @@ function createCardLink(card) {
|
||||
href: card.absoluteUrl(),
|
||||
class: 'action-card',
|
||||
},
|
||||
card.title,
|
||||
sanitizeXss(card.title),
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -228,7 +263,7 @@ function createBoardLink(board, list) {
|
||||
href: board.absoluteUrl(),
|
||||
class: 'action-board',
|
||||
},
|
||||
text,
|
||||
sanitizeXss(text),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -10,12 +10,16 @@
|
||||
|
||||
.activity
|
||||
margin: 0.5px 0
|
||||
padding: 6px 0;
|
||||
display: flex
|
||||
|
||||
.member
|
||||
width: 24px
|
||||
width: 32px
|
||||
height: @width
|
||||
|
||||
.activity-member
|
||||
font-weight: 700
|
||||
|
||||
.activity-desc
|
||||
word-wrap: break-word
|
||||
overflow: hidden
|
||||
|
||||
@@ -3,6 +3,10 @@ BlazeComponent.extendComponent({
|
||||
this.subscribe('archivedBoards');
|
||||
},
|
||||
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
|
||||
archivedBoards() {
|
||||
return Boards.find(
|
||||
{ archived: true },
|
||||
|
||||
@@ -15,7 +15,7 @@ template(name="board")
|
||||
template(name="boardBody")
|
||||
.board-wrapper(class=currentBoard.colorClass)
|
||||
+sidebar
|
||||
.board-canvas.js-swimlanes.js-perfect-scrollbar(
|
||||
.board-canvas.js-swimlanes(
|
||||
class="{{#if Sidebar.isOpen}}is-sibling-sidebar-open{{/if}}"
|
||||
class="{{#if MultiSelection.isActive}}is-multiselection-active{{/if}}"
|
||||
class="{{#if draggingActive.get}}is-dragging-active{{/if}}")
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndex } = Utils;
|
||||
const swimlaneWhileSortingHeight = 150;
|
||||
@@ -197,7 +195,7 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
showDesktopDragHandles = (currentUser.profile || {})
|
||||
.showDesktopDragHandles;
|
||||
} else if (cookies.has('showDesktopDragHandles')) {
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
showDesktopDragHandles = true;
|
||||
} else {
|
||||
showDesktopDragHandles = false;
|
||||
@@ -213,7 +211,12 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
|
||||
// Disable drag-dropping if the current user is not a board member
|
||||
$swimlanesDom.sortable('option', 'disabled', !userIsMember());
|
||||
//$swimlanesDom.sortable('option', 'disabled', !userIsMember());
|
||||
$swimlanesDom.sortable(
|
||||
'option',
|
||||
'disabled',
|
||||
!Meteor.user().isBoardAdmin(),
|
||||
);
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
@@ -237,7 +240,9 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).boardView === 'board-view-swimlanes';
|
||||
} else {
|
||||
return cookies.get('boardView') === 'board-view-swimlanes';
|
||||
return (
|
||||
window.localStorage.getItem('boardView') === 'board-view-swimlanes'
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -246,7 +251,7 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).boardView === 'board-view-lists';
|
||||
} else {
|
||||
return cookies.get('boardView') === 'board-view-lists';
|
||||
return window.localStorage.getItem('boardView') === 'board-view-lists';
|
||||
}
|
||||
},
|
||||
|
||||
@@ -255,7 +260,7 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).boardView === 'board-view-cal';
|
||||
} else {
|
||||
return cookies.get('boardView') === 'board-view-cal';
|
||||
return window.localStorage.getItem('boardView') === 'board-view-cal';
|
||||
}
|
||||
},
|
||||
|
||||
@@ -323,7 +328,7 @@ BlazeComponent.extendComponent({
|
||||
header: {
|
||||
left: 'title today prev,next',
|
||||
center:
|
||||
'agendaDay,listDay,timelineDay agendaWeek,listWeek,timelineWeek month,timelineMonth timelineYear',
|
||||
'agendaDay,listDay,timelineDay agendaWeek,listWeek,timelineWeek month,listMonth',
|
||||
right: '',
|
||||
},
|
||||
// height: 'parent', nope, doesn't work as the parent might be small
|
||||
@@ -417,7 +422,7 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).boardView === 'board-view-cal';
|
||||
} else {
|
||||
return cookies.get('boardView') === 'board-view-cal';
|
||||
return window.localStorage.getItem('boardView') === 'board-view-cal';
|
||||
}
|
||||
},
|
||||
}).register('calendarView');
|
||||
@@ -15,7 +15,8 @@ setBoardColor(color)
|
||||
.is-selected .minicard
|
||||
border-left: 3px solid color
|
||||
|
||||
button[type=submit].primary, input[type=submit].primary
|
||||
button[type=submit].primary, input[type=submit].primary,
|
||||
.sidebar .sidebar-content .sidebar-btn
|
||||
background-color: darken(color, 20%)
|
||||
|
||||
&.pop-over .pop-over-list li a:not(.disabled):hover,
|
||||
@@ -589,22 +590,25 @@ setBoardClear(color1,color2)
|
||||
position relative
|
||||
|
||||
&#header-quick-access #header-user-bar .header-user-bar-name
|
||||
margin: 5px 3px 0 0;
|
||||
margin: 5px 3px 0 0
|
||||
|
||||
section#notifications-drawer
|
||||
top: 46px;
|
||||
top: 46px
|
||||
box-shadow: 0 4px 20px rgba(0,0,0,.1)
|
||||
max-width: 100%
|
||||
|
||||
section#notifications-drawer .header
|
||||
top: 46px;
|
||||
top: 46px
|
||||
border-radius: 0 3px
|
||||
height: 21px
|
||||
background: #f7f7f7
|
||||
|
||||
.board-canvas
|
||||
background: #f5f5f5
|
||||
|
||||
/* Swimlane */
|
||||
.swimlane
|
||||
background: #f5f5f5
|
||||
background: none
|
||||
|
||||
.swimlane .swimlane-header-wrap .swimlane-header
|
||||
font-family: Poppins
|
||||
@@ -739,3 +743,283 @@ setBoardClear(color1,color2)
|
||||
|
||||
section#notifications-drawer .header .toggle-read
|
||||
top: 18px
|
||||
|
||||
/*
|
||||
Alternate "Modern Dark" Styling
|
||||
*/
|
||||
.board-color-moderndark
|
||||
setBoardColor(#2a2a2a)
|
||||
|
||||
/* General */
|
||||
body
|
||||
background: #2a2a2a
|
||||
|
||||
.board-wrapper .board-canvas .board-overlay
|
||||
opacity: .6
|
||||
|
||||
/* Forms */
|
||||
button[type=submit].primary, .board-color-modern input[type=submit].primary
|
||||
background-color: #819C5D
|
||||
|
||||
.toggle-switch:checked~.toggle-label
|
||||
background-color: #D2E9B4
|
||||
|
||||
.toggle-label:after, .board-color-modern .toggle-switch:checked~.toggle-label:after
|
||||
background-color: #819C5D !important
|
||||
|
||||
/* Headers */
|
||||
&#header-quick-access, .background-box, #header
|
||||
background-color: #333333
|
||||
|
||||
&#header-quick-access
|
||||
padding: 4px
|
||||
font-size: 14px
|
||||
|
||||
&#header #header-main-bar
|
||||
height: 30px
|
||||
padding-top: 3px
|
||||
padding-bottom: 3px
|
||||
|
||||
&#header
|
||||
box-shadow: 0 6px 6px -6px rgba(0,0,0,0.8)
|
||||
|
||||
&#header-quick-access ul
|
||||
overflow: visible
|
||||
|
||||
&#header-quick-access ul li.current
|
||||
border: 0 !important
|
||||
font-weight: bold
|
||||
|
||||
&#header-quick-access ul li.separator
|
||||
display: none
|
||||
|
||||
&#header-quick-access ul li:nth-child(3)
|
||||
margin-right: 10px
|
||||
|
||||
&#header-quick-access ul li a
|
||||
padding: 5px 10px
|
||||
border-radius: 2px
|
||||
|
||||
&#header-quick-access ul li.current a
|
||||
border-radius: 2px
|
||||
background: rgba(255,255,255,.2)
|
||||
|
||||
&#header #header-main-bar h1
|
||||
font-family: Poppins
|
||||
font-weight: bold
|
||||
line-height: 0.8em
|
||||
padding-top: 10px
|
||||
|
||||
/* Content */
|
||||
.board-canvas
|
||||
background: #2a2a2a
|
||||
padding: 10px 10px 0
|
||||
|
||||
/* Swimlanes */
|
||||
.swimlane .swimlane-header-wrap
|
||||
background-color: #666666
|
||||
color: #cccccc
|
||||
padding: 4px 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.swimlane .swimlane-header-wrap .swimlane-header
|
||||
font-family: Poppins
|
||||
|
||||
.swimlane
|
||||
background: #2a2a2a
|
||||
line-height: 15px
|
||||
max-height: 100%
|
||||
|
||||
/* Lists */
|
||||
.swimlane .list
|
||||
background: #666666
|
||||
border-radius: 0
|
||||
border: 0px solid #666666
|
||||
flex: 0 0 265px;
|
||||
|
||||
.swimlane .list:nth-child(even)
|
||||
background: #5f5f5f
|
||||
|
||||
.list-header
|
||||
background: #333333
|
||||
padding-top: 10px
|
||||
border-bottom: 6px solid #333333
|
||||
|
||||
.list-header .viewer
|
||||
padding-left: 10px
|
||||
|
||||
.list-header .list-header-name
|
||||
line-height: 14px
|
||||
color: #eeeeee
|
||||
|
||||
.list-header .list-header-menu
|
||||
padding-top: 17px
|
||||
|
||||
.list-body
|
||||
scrollbar-width: thin
|
||||
scrollbar-color: #343434 #999999
|
||||
|
||||
.list-body::-webkit-scrollbar
|
||||
width: 10px
|
||||
|
||||
.list-body::-webkit-scrollbar-track
|
||||
background: #343434
|
||||
border-radius: 3px
|
||||
margin: 4px 0
|
||||
|
||||
.list-body::-webkit-scrollbar-thumb
|
||||
background-color: #999999
|
||||
border-radius: 6px
|
||||
border: 3px solid #343434
|
||||
|
||||
.list-body .open-minicard-composer:hover
|
||||
background: none
|
||||
box-shadow: none
|
||||
border-bottom: 0
|
||||
|
||||
.list-body a.open-minicard-composer, .list-body a.open-minicard-composer i, .list .list-composer .open-list-composer i
|
||||
color: #bbbbbb
|
||||
|
||||
.list-body a.open-minicard-composer:hover, .list-body a.open-minicard-composer:hover i, .list .list-composer .open-list-composer:hover i
|
||||
color: #ffffff
|
||||
|
||||
/* Mini Card */
|
||||
.minicard
|
||||
background-color: #444444
|
||||
color: #cccccc
|
||||
border-radius: 2px
|
||||
font-size: 0.9em
|
||||
padding: 10px
|
||||
box-shadow: 0 4px 3px -3px rgba(0,0,0,0.8)
|
||||
border-bottom: 1px solid #666666
|
||||
|
||||
.minicard:hover
|
||||
background-color: #555555 !important
|
||||
|
||||
.minicard .card-label
|
||||
font-size: 11px
|
||||
font-weight: 400
|
||||
padding: 2px 6px 0
|
||||
|
||||
.minicard .badges
|
||||
color: #bbbbbb
|
||||
|
||||
.minicard .date
|
||||
margin-top: 7px
|
||||
font-size: 11px
|
||||
|
||||
.card-date
|
||||
color: #555555
|
||||
|
||||
.card-date.almost-due
|
||||
color: #666666
|
||||
|
||||
.minicard.minicard-composer textarea.minicard-composer-textarea:focus
|
||||
background-color: #eeeeee
|
||||
color: #333333
|
||||
padding: 6px
|
||||
|
||||
.is-selected .minicard
|
||||
background-color: #666666
|
||||
|
||||
/* Card Details */
|
||||
.card-details
|
||||
position: absolute
|
||||
top: 30px
|
||||
left: calc(50% - 384px)
|
||||
width: 768px
|
||||
max-height: calc(100% - 60px)
|
||||
background-color: #454545
|
||||
color: #cccccc
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)
|
||||
border: 1px solid #111111
|
||||
z-index: 100 !important
|
||||
|
||||
.card-details
|
||||
scrollbar-width: thin
|
||||
scrollbar-color: #343434 #999999
|
||||
|
||||
.card-details::-webkit-scrollbar
|
||||
width: 16px
|
||||
|
||||
.card-details::-webkit-scrollbar-track
|
||||
background: #343434
|
||||
|
||||
.card-details::-webkit-scrollbar-thumb
|
||||
background-color: #999999
|
||||
border-radius: 6px
|
||||
border: 4px solid #343434
|
||||
|
||||
.card-details .card-details-header
|
||||
background: #333333
|
||||
color: #cccccc
|
||||
border-bottom: 2px solid #2d2d2d
|
||||
|
||||
.card-details hr
|
||||
background: #2d2d2d
|
||||
|
||||
.card-details .card-details-item-title
|
||||
color: #ffffff
|
||||
|
||||
.card-details .new-description textarea, .card-details .new-comment textarea
|
||||
background-color: #dddddd
|
||||
color: #111111
|
||||
|
||||
.card-details .checklist
|
||||
background-color: transparent
|
||||
margin-bottom: 10px
|
||||
|
||||
.card-details .checklist-item
|
||||
background-color: rgba(255,255,255,0.1)
|
||||
padding: 2px 8px
|
||||
border-radius: 3px
|
||||
font-size: 13px
|
||||
margin-top: 5px
|
||||
|
||||
.card-details .check-box.materialCheckBox
|
||||
border-color: #ffffff
|
||||
|
||||
.card-details .check-box.materialCheckBox.is-checked
|
||||
border-bottom: 2px solid #819C5D
|
||||
border-right: 2px solid #819C5D
|
||||
border-top: 0
|
||||
border-left: 0
|
||||
|
||||
.card-details .js-add-checklist-item
|
||||
margin-top: 4px
|
||||
|
||||
.checklist-items .add-checklist-item
|
||||
margin-top: .7em
|
||||
|
||||
.card-details .activities .activity .activity-desc .activity-comment
|
||||
background-color: #cccccc
|
||||
color: #222222
|
||||
|
||||
/* Sidebar */
|
||||
.sidebar .sidebar-shadow
|
||||
background-color: #222222
|
||||
box-shadow: -10px 0 5px -10px #444444
|
||||
border-left: 1px solid #333333
|
||||
color: #cccccc
|
||||
|
||||
.activities .activity .activity-desc .activity-comment
|
||||
background-color: #cccccc
|
||||
color: #222222
|
||||
|
||||
/* Pop-Ups for "Modern Dark" */
|
||||
.pop-over.board-color-moderndark
|
||||
background-color: #454545
|
||||
color: #cccccc
|
||||
border: 1px solid #111111
|
||||
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19)
|
||||
|
||||
.pop-over.board-color-moderndark .header
|
||||
background-color: #333333
|
||||
|
||||
.pop-over.board-color-moderndark .header-title
|
||||
font-family: Poppins
|
||||
font-size: 16px
|
||||
color: #cccccc
|
||||
|
||||
.pop-over.board-color-moderndark .pop-over-list li:hover > a
|
||||
background-color: #819C5D !important
|
||||
@@ -99,13 +99,13 @@ template(name="boardHeaderBar")
|
||||
a.board-header-btn.js-toggle-board-view(
|
||||
title="{{_ 'board-view'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq boardView 'board-view-lists'
|
||||
i.fa.fa-trello
|
||||
if $eq boardView 'board-view-swimlanes'
|
||||
i.fa.fa-th-large
|
||||
if $eq boardView 'board-view-lists'
|
||||
i.fa.fa-trello
|
||||
if $eq boardView 'board-view-cal'
|
||||
i.fa.fa-calendar
|
||||
span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}
|
||||
span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-swimlanes'}}{{/if}}
|
||||
|
||||
if canModifyBoard
|
||||
a.board-header-btn.js-multiselection-activate(
|
||||
@@ -172,13 +172,6 @@ template(name="boardChangeWatchPopup")
|
||||
|
||||
template(name="boardChangeViewPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "board-view-lists"
|
||||
a.js-open-lists-view
|
||||
i.fa.fa-trello.colorful
|
||||
| {{_ 'board-view-lists'}}
|
||||
if $eq Utils.boardView "board-view-lists"
|
||||
i.fa.fa-check
|
||||
li
|
||||
with "board-view-swimlanes"
|
||||
a.js-open-swimlanes-view
|
||||
@@ -186,6 +179,13 @@ template(name="boardChangeViewPopup")
|
||||
| {{_ 'board-view-swimlanes'}}
|
||||
if $eq Utils.boardView "board-view-swimlanes"
|
||||
i.fa.fa-check
|
||||
li
|
||||
with "board-view-lists"
|
||||
a.js-open-lists-view
|
||||
i.fa.fa-trello.colorful
|
||||
| {{_ 'board-view-lists'}}
|
||||
if $eq Utils.boardView "board-view-lists"
|
||||
i.fa.fa-check
|
||||
li
|
||||
with "board-view-cal"
|
||||
a.js-open-cal-view
|
||||
|
||||
@@ -60,10 +60,10 @@ template(name="boardList")
|
||||
|
||||
template(name="boardListHeaderBar")
|
||||
h1 {{_ title }}
|
||||
.board-header-btns.right
|
||||
a.board-header-btn.js-open-archived-board
|
||||
i.fa.fa-archive
|
||||
span {{_ 'archives'}}
|
||||
a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
|
||||
i.fa.fa-clone
|
||||
span {{_ 'templates'}}
|
||||
//.board-header-btns.right
|
||||
// a.board-header-btn.js-open-archived-board
|
||||
// i.fa.fa-archive
|
||||
// span {{_ 'archives'}}
|
||||
// a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
|
||||
// i.fa.fa-clone
|
||||
// span {{_ 'templates'}}
|
||||
@@ -25,10 +25,6 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
function userIsAllowedToMove() {
|
||||
return Meteor.user();
|
||||
}
|
||||
|
||||
const itemsSelector = '.js-board:not(.placeholder)';
|
||||
|
||||
const $boards = this.$('.js-boards');
|
||||
@@ -77,8 +73,6 @@ BlazeComponent.extendComponent({
|
||||
handle: '.board-handle',
|
||||
});
|
||||
}
|
||||
|
||||
$boards.sortable('option', 'disabled', !userIsAllowedToMove());
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ $spaceBetweenTiles = 16px
|
||||
|
||||
li
|
||||
float: left
|
||||
width: 25%
|
||||
width: 20%
|
||||
box-sizing: border-box
|
||||
position: relative
|
||||
|
||||
@@ -33,13 +33,12 @@ $spaceBetweenTiles = 16px
|
||||
overflow: hidden;
|
||||
background-color: #999
|
||||
color: #f6f6f6
|
||||
height: auto
|
||||
min-height: 100px
|
||||
font-size: 16px
|
||||
line-height: 22px
|
||||
border-radius: 3px
|
||||
display: block
|
||||
font-weight: 700
|
||||
min-height: 18px
|
||||
padding: 8px
|
||||
margin: ($spaceBetweenTiles/2)
|
||||
position: relative
|
||||
|
||||
@@ -46,9 +46,10 @@ template(name="attachmentsGalery")
|
||||
| {{_ 'remove-cover'}}
|
||||
else
|
||||
| {{_ 'add-cover'}}
|
||||
a.js-confirm-delete
|
||||
i.fa.fa-close
|
||||
| {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
a.js-confirm-delete
|
||||
i.fa.fa-close
|
||||
| {{_ 'delete'}}
|
||||
|
||||
if currentUser.isBoardMember
|
||||
unless currentUser.isCommentOnly
|
||||
|
||||
@@ -45,6 +45,12 @@ Template.attachmentsGalery.events({
|
||||
},
|
||||
});
|
||||
|
||||
Template.attachmentsGalery.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
});
|
||||
|
||||
Template.previewAttachedImagePopup.events({
|
||||
'click .js-large-image-clicked'() {
|
||||
Popup.close();
|
||||
|
||||
@@ -4,8 +4,7 @@ template(name="cardCustomFieldsPopup")
|
||||
li.item(class="")
|
||||
a.name.js-select-field(href="#")
|
||||
span.full-name
|
||||
+viewer
|
||||
= name
|
||||
= name
|
||||
if hasCustomField
|
||||
i.fa.fa-check
|
||||
hr
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
|
||||
template(name="descriptionForm")
|
||||
.new-description.js-new-description(
|
||||
class="{{#if descriptionFormIsOpen}}is-open{{/if}}")
|
||||
form.js-new-description-form
|
||||
+editor(class="js-new-description-input" data-meteor-emoji-large="true" autofocus="autofocus")
|
||||
| {{getUnsavedValue 'cardDescription' _id getDescription}}
|
||||
@@ -0,0 +1,33 @@
|
||||
const descriptionFormIsOpen = new ReactiveVar(false);
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onDestroyed() {
|
||||
descriptionFormIsOpen.set(false);
|
||||
},
|
||||
|
||||
descriptionFormIsOpen() {
|
||||
return descriptionFormIsOpen.get();
|
||||
},
|
||||
|
||||
getInput() {
|
||||
return this.$('.js-new-description-input');
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'submit .js-card-description'(event) {
|
||||
event.preventDefault();
|
||||
const description = this.currentComponent().getValue();
|
||||
this.data().setDescription(description);
|
||||
},
|
||||
// Pressing Ctrl+Enter should submit the form
|
||||
'keydown form textarea'(evt) {
|
||||
if (evt.keyCode === 13 && (evt.metaKey || evt.ctrlKey)) {
|
||||
this.find('button[type=submit]').click();
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('descriptionForm');
|
||||
@@ -0,0 +1,60 @@
|
||||
@import 'nib'
|
||||
|
||||
.new-description
|
||||
position: relative
|
||||
margin: 0 0 20px 0
|
||||
|
||||
|
||||
&.is-open
|
||||
.helper
|
||||
display: inline-block
|
||||
|
||||
textarea
|
||||
min-height: 100px
|
||||
color: #4d4d4d
|
||||
cursor: auto
|
||||
overflow: hidden
|
||||
word-wrap: break-word
|
||||
|
||||
.too-long
|
||||
margin-top: 8px
|
||||
|
||||
textarea
|
||||
background-color: #fff
|
||||
border: 0
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
|
||||
color: #8c8c8c
|
||||
height: 36px
|
||||
margin: 4px 4px 6px 0
|
||||
padding: 9px 11px
|
||||
width: 100%
|
||||
|
||||
&:hover,
|
||||
&:is-open
|
||||
background-color: #fff
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, .33)
|
||||
border: 0
|
||||
cursor: pointer
|
||||
|
||||
&:is-open
|
||||
cursor: auto
|
||||
|
||||
.description-item
|
||||
background-color: #fff
|
||||
border: 0
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
|
||||
color: #8c8c8c
|
||||
height: 36px
|
||||
margin: 4px 4px 6px 0
|
||||
width: 92%
|
||||
|
||||
&:hover
|
||||
background: darken(white, 12%)
|
||||
|
||||
&.add-description
|
||||
display: flex
|
||||
margin: 5px
|
||||
|
||||
a
|
||||
display: block
|
||||
margin: auto
|
||||
@@ -1,5 +1,5 @@
|
||||
template(name="cardDetails")
|
||||
section.card-details.js-card-details.js-perfect-scrollbar: .card-details-canvas
|
||||
section.card-details.js-card-details: .card-details-canvas
|
||||
.card-details-header(class='{{#if colorClass}}card-details-{{colorClass}}{{/if}}')
|
||||
+inlinedForm(classNames="js-card-details-title")
|
||||
+editCardTitleForm
|
||||
@@ -43,11 +43,27 @@ template(name="cardDetails")
|
||||
p.warning {{_ 'card-archived'}}
|
||||
|
||||
.card-details-items
|
||||
if currentBoard.allowsLabels
|
||||
.card-details-item.card-details-item-labels
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-tags
|
||||
| {{_ 'labels'}}
|
||||
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
|
||||
each labels
|
||||
span.card-label(class="card-label-{{color}}" title=name)
|
||||
+viewer
|
||||
= name
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
if currentBoard.allowsReceivedDate
|
||||
hr
|
||||
.card-details-item.card-details-item-received
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-sign-out
|
||||
card-details-item-title {{_ 'card-received'}}
|
||||
| {{_ 'card-received'}}
|
||||
if getReceived
|
||||
+cardReceivedDate
|
||||
else
|
||||
@@ -58,9 +74,9 @@ template(name="cardDetails")
|
||||
|
||||
if currentBoard.allowsStartDate
|
||||
.card-details-item.card-details-item-start
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-hourglass-start
|
||||
card-details-item-title {{_ 'card-start'}}
|
||||
| {{_ 'card-start'}}
|
||||
if getStart
|
||||
+cardStartDate
|
||||
else
|
||||
@@ -71,9 +87,9 @@ template(name="cardDetails")
|
||||
|
||||
if currentBoard.allowsDueDate
|
||||
.card-details-item.card-details-item-due
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-sign-in
|
||||
card-details-item-title {{_ 'card-due'}}
|
||||
| {{_ 'card-due'}}
|
||||
if getDue
|
||||
+cardDueDate
|
||||
else
|
||||
@@ -84,9 +100,9 @@ template(name="cardDetails")
|
||||
|
||||
if currentBoard.allowsEndDate
|
||||
.card-details-item.card-details-item-end
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-hourglass-end
|
||||
card-details-item-title {{_ 'card-end'}}
|
||||
| {{_ 'card-end'}}
|
||||
if getEnd
|
||||
+cardEndDate
|
||||
else
|
||||
@@ -97,10 +113,11 @@ template(name="cardDetails")
|
||||
|
||||
//.card-details-items
|
||||
if currentBoard.allowsMembers
|
||||
hr
|
||||
.card-details-item.card-details-item-members
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-users
|
||||
card-details-item-title {{_ 'members'}}
|
||||
| {{_ 'members'}}
|
||||
each getMembers
|
||||
+userAvatar(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
@@ -112,9 +129,9 @@ template(name="cardDetails")
|
||||
//if assigneeSelected
|
||||
if currentBoard.allowsAssignee
|
||||
.card-details-item.card-details-item-assignees
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-user
|
||||
card-details-item-title {{_ 'assignee'}}
|
||||
| {{_ 'assignee'}}
|
||||
each getAssignees
|
||||
+userAvatarAssignee(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
@@ -126,44 +143,23 @@ template(name="cardDetails")
|
||||
a.assignee.add-assignee.card-details-item-add-button.js-add-assignees(title="{{_ 'assignee'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
if currentBoard.allowsLabels
|
||||
.card-details-item.card-details-item-labels
|
||||
h3
|
||||
i.fa.fa-tags
|
||||
card-details-item-title {{_ 'labels'}}
|
||||
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
|
||||
each labels
|
||||
span.card-label(class="card-label-{{color}}" title=name)
|
||||
+viewer
|
||||
= name
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
//.card-details-items
|
||||
each customFieldsWD
|
||||
.card-details-item.card-details-item-customfield
|
||||
h3.card-details-item-title
|
||||
+viewer
|
||||
= definition.name
|
||||
+cardCustomField
|
||||
|
||||
//.card-details-items
|
||||
if getSpentTime
|
||||
.card-details-item.card-details-item-spent
|
||||
if getIsOvertime
|
||||
h3.card-details-item-title {{_ 'overtime-hours'}}
|
||||
h3.card-details-item-title
|
||||
| {{_ 'overtime-hours'}}
|
||||
else
|
||||
h3.card-details-item-title {{_ 'spent-time-hours'}}
|
||||
h3.card-details-item-title
|
||||
| {{_ 'spent-time-hours'}}
|
||||
+cardSpentTime
|
||||
|
||||
//.card-details-items
|
||||
if currentBoard.allowsRequestedBy
|
||||
.card-details-item.card-details-item-name
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-shopping-cart
|
||||
card-details-item-title {{_ 'requested-by'}}
|
||||
| {{_ 'requested-by'}}
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
+inlinedForm(classNames="js-card-details-requester")
|
||||
@@ -181,9 +177,9 @@ template(name="cardDetails")
|
||||
|
||||
if currentBoard.allowsAssignedBy
|
||||
.card-details-item.card-details-item-name
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-user-plus
|
||||
card-details-item-title {{_ 'assigned-by'}}
|
||||
| {{_ 'assigned-by'}}
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
+inlinedForm(classNames="js-card-details-assigner")
|
||||
@@ -199,6 +195,16 @@ template(name="cardDetails")
|
||||
+viewer
|
||||
= getAssignedBy
|
||||
|
||||
//.card-details-items
|
||||
if customFieldsWD
|
||||
hr
|
||||
each customFieldsWD
|
||||
.card-details-item.card-details-item-customfield
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-list-alt
|
||||
= definition.name
|
||||
+cardCustomField
|
||||
|
||||
if getVoteQuestion
|
||||
hr
|
||||
.vote-title
|
||||
@@ -220,21 +226,26 @@ template(name="cardDetails")
|
||||
+viewer
|
||||
= getVoteQuestion
|
||||
if showVotingButtons
|
||||
button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}") {{_ 'vote-for-it'}}
|
||||
button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}") {{_ 'vote-against'}}
|
||||
button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}")
|
||||
if voteState
|
||||
i.fa.fa-thumbs-up
|
||||
| {{_ 'vote-for-it'}}
|
||||
button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}")
|
||||
if $eq voteState false
|
||||
i.fa.fa-thumbs-down
|
||||
| {{_ 'vote-against'}}
|
||||
|
||||
//- XXX We should use "editable" to avoid repetiting ourselves
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
if currentBoard.allowsDescriptionTitle
|
||||
hr
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-align-left
|
||||
card-details-item-title {{_ 'description'}}
|
||||
| {{_ 'description'}}
|
||||
if currentBoard.allowsDescriptionText
|
||||
+inlinedCardDescription(classNames="card-description js-card-description")
|
||||
+editor(autofocus=true)
|
||||
| {{getUnsavedValue 'cardDescription' _id getDescription}}
|
||||
+descriptionForm
|
||||
.edit-controls.clearfix
|
||||
button.primary(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
@@ -270,7 +281,7 @@ template(name="cardDetails")
|
||||
+subtasks(cardId = _id)
|
||||
if currentBoard.allowsAttachments
|
||||
hr
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
.card-checklist-attachmentGalery.card-attachmentGalery
|
||||
@@ -279,7 +290,7 @@ template(name="cardDetails")
|
||||
hr
|
||||
unless currentUser.isNoComments
|
||||
.activity-title
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-history
|
||||
| {{ _ 'activity'}}
|
||||
if currentUser.isBoardMember
|
||||
@@ -343,10 +354,11 @@ template(name="cardDetailsActionsPopup")
|
||||
a.js-start-voting
|
||||
i.fa.fa-thumbs-up
|
||||
| {{_ 'card-edit-voting'}}
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'card-edit-custom-fields'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'card-edit-custom-fields'}}
|
||||
//li: a.js-received-date {{_ 'editCardReceivedDatePopup-title'}}
|
||||
//li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
||||
//li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||
@@ -369,17 +381,19 @@ template(name="cardDetailsActionsPopup")
|
||||
a.js-move-card-to-bottom
|
||||
i.fa.fa-arrow-down
|
||||
| {{_ 'moveCardToBottom-title'}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
ul.pop-over-list
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-move-card
|
||||
i.fa.fa-arrow-right
|
||||
| {{_ 'moveCardPopup-title'}}
|
||||
unless currentUser.isWorker
|
||||
li
|
||||
a.js-copy-card
|
||||
i.fa.fa-copy
|
||||
| {{_ 'copyCardPopup-title'}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
@@ -418,13 +432,14 @@ template(name="copyChecklistToManyCardsPopup")
|
||||
+boardsAndLists
|
||||
|
||||
template(name="boardsAndLists")
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
unless currentUser.isWorker
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
@@ -549,7 +564,8 @@ template(name="cardMorePopup")
|
||||
br
|
||||
| {{_ 'added'}}
|
||||
span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
|
||||
a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
|
||||
|
||||
template(name="setCardColorPopup")
|
||||
form.edit-label
|
||||
@@ -596,7 +612,8 @@ template(name="cardStartVotingPopup")
|
||||
|
||||
button.primary.js-submit {{_ 'save'}}
|
||||
if getVoteQuestion
|
||||
button.js-remove-vote.negate.wide.right {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
button.js-remove-vote.negate.wide.right {{_ 'delete'}}
|
||||
|
||||
template(name="positiveVoteMembersPopup")
|
||||
ul.pop-over-list.js-card-member-list
|
||||
|
||||
@@ -8,7 +8,7 @@ Meteor.startup(() => {
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
return [Mixins.InfiniteScrolling];
|
||||
},
|
||||
|
||||
calculateNextPeak() {
|
||||
@@ -38,22 +38,6 @@ BlazeComponent.extendComponent({
|
||||
Meteor.subscribe('unsaved-edits');
|
||||
},
|
||||
|
||||
voteState() {
|
||||
const card = this.currentData();
|
||||
const userId = Meteor.userId();
|
||||
let state;
|
||||
if (card.vote) {
|
||||
if (card.vote.positive) {
|
||||
state = _.contains(card.vote.positive, userId);
|
||||
if (state === true) return true;
|
||||
}
|
||||
if (card.vote.negative) {
|
||||
state = _.contains(card.vote.negative, userId);
|
||||
if (state === true) return false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
isWatching() {
|
||||
const card = this.currentData();
|
||||
return card.findWatcher(Meteor.userId());
|
||||
@@ -73,7 +57,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
scrollParentContainer() {
|
||||
const cardPanelWidth = 510;
|
||||
const cardPanelWidth = 600;
|
||||
const parentComponent = this.parentComponent();
|
||||
// TODO sometimes parentComponent is not available, maybe because it's not
|
||||
// yet created?!
|
||||
@@ -187,13 +171,6 @@ BlazeComponent.extendComponent({
|
||||
|
||||
if (!Utils.isMiniScreen()) {
|
||||
Meteor.setTimeout(() => {
|
||||
$('.card-details').mCustomScrollbar({
|
||||
theme: 'minimal-dark',
|
||||
setWidth: false,
|
||||
setLeft: 0,
|
||||
scrollbarPosition: 'outside',
|
||||
mouseWheel: true,
|
||||
});
|
||||
this.scrollParentContainer();
|
||||
}, 500);
|
||||
}
|
||||
@@ -273,12 +250,15 @@ BlazeComponent.extendComponent({
|
||||
|
||||
// Disable sorting if the current user is not a board member
|
||||
this.autorun(() => {
|
||||
const disabled = !userIsMember() || Utils.isMiniScreen();
|
||||
const disabled = !userIsMember();
|
||||
if (
|
||||
$checklistsDom.data('uiSortable') ||
|
||||
$checklistsDom.data('sortable')
|
||||
) {
|
||||
$checklistsDom.sortable('option', 'disabled', disabled);
|
||||
if (Utils.isMiniScreenOrShowDesktopDragHandles()) {
|
||||
$checklistsDom.sortable({ handle: '.checklist-handle' });
|
||||
}
|
||||
}
|
||||
if ($subtasksDom.data('uiSortable') || $subtasksDom.data('sortable')) {
|
||||
$subtasksDom.sortable('option', 'disabled', disabled);
|
||||
@@ -412,9 +392,9 @@ BlazeComponent.extendComponent({
|
||||
const forIt = $(e.target).hasClass('js-vote-positive');
|
||||
let newState = null;
|
||||
if (
|
||||
this.voteState() === null ||
|
||||
(this.voteState() === false && forIt) ||
|
||||
(this.voteState() === true && !forIt)
|
||||
this.data().voteState() === null ||
|
||||
(this.data().voteState() === false && forIt) ||
|
||||
(this.data().voteState() === true && !forIt)
|
||||
) {
|
||||
newState = forIt;
|
||||
}
|
||||
@@ -587,6 +567,10 @@ Template.cardDetailsActionsPopup.helpers({
|
||||
return this.findWatcher(Meteor.userId());
|
||||
},
|
||||
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
|
||||
canModifyCard() {
|
||||
return (
|
||||
Meteor.user() &&
|
||||
@@ -691,7 +675,11 @@ Template.moveCardPopup.events({
|
||||
// instead from a “component” state.
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
const bSelect = $('.js-select-boards')[0];
|
||||
const boardId = bSelect.options[bSelect.selectedIndex].value;
|
||||
let boardId;
|
||||
// if we are a worker, we won't have a board select so we just use the
|
||||
// current boardId of the card.
|
||||
if (bSelect) boardId = bSelect.options[bSelect.selectedIndex].value;
|
||||
else boardId = card.boardId;
|
||||
const lSelect = $('.js-select-lists')[0];
|
||||
const listId = lSelect.options[lSelect.selectedIndex].value;
|
||||
const slSelect = $('.js-select-swimlanes')[0];
|
||||
|
||||
@@ -89,7 +89,7 @@ avatar-radius = 50%
|
||||
.card-details
|
||||
padding: 0
|
||||
flex-shrink: 0
|
||||
flex-basis: 510px
|
||||
flex-basis: 600px
|
||||
will-change: flex-basis
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
@@ -104,17 +104,13 @@ avatar-radius = 50%
|
||||
.mCustomScrollBox
|
||||
padding-left: 0
|
||||
|
||||
.ps-scrollbar-y-rail
|
||||
pointer-event: all
|
||||
position: absolute
|
||||
|
||||
.card-details-canvas
|
||||
width: 470px
|
||||
padding-left: 20px
|
||||
width: auto
|
||||
padding: 0 20px
|
||||
|
||||
.card-details-header
|
||||
margin: 0 -20px 5px
|
||||
padding 7px 16px
|
||||
padding 7px 20px
|
||||
background: darken(white, 7%)
|
||||
border-bottom: 1px solid darken(white, 14%)
|
||||
|
||||
@@ -202,23 +198,32 @@ avatar-radius = 50%
|
||||
margin-right: 0.5em
|
||||
&:last-child
|
||||
margin-right: 0
|
||||
&.card-details-item-labels,
|
||||
&.card-details-item-labels
|
||||
display: block
|
||||
word-wrap: break-word
|
||||
max-width: 95%
|
||||
flex-grow: 1
|
||||
&.card-details-item-members,
|
||||
&.card-details-item-assignees,
|
||||
&.card-details-item-received,
|
||||
&.card-details-item-start,
|
||||
&.card-details-item-due,
|
||||
&.card-details-item-end,
|
||||
&.card-details-item-customfield,
|
||||
&.card-details-item-name
|
||||
display: block
|
||||
word-wrap: break-word
|
||||
max-width: 48%
|
||||
max-width: 36%
|
||||
flex-grow: 1
|
||||
&.card-details-item-received,
|
||||
&.card-details-item-start,
|
||||
&.card-details-item-due,
|
||||
&.card-details-item-end
|
||||
display: block
|
||||
word-wrap: break-word
|
||||
max-width: 28%
|
||||
flex-grow: 1
|
||||
|
||||
.card-details-item-title
|
||||
font-size: 16px
|
||||
color: #000
|
||||
font-weight: bold
|
||||
color: #4d4d4d
|
||||
|
||||
.card-label
|
||||
padding-top: 5px
|
||||
|
||||
@@ -1,7 +1,17 @@
|
||||
template(name="checklists")
|
||||
h3
|
||||
i.fa.fa-check
|
||||
| {{_ 'checklists'}}
|
||||
.checklists-title
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-check
|
||||
| {{_ 'checklists'}}
|
||||
if currentUser.isBoardMember
|
||||
.material-toggle-switch
|
||||
span.toggle-switch-title {{_ 'hide-checked-items'}}
|
||||
if hideCheckedItems
|
||||
input.toggle-switch(type="checkbox" id="toggleHideCheckedItemsButton" checked="checked")
|
||||
else
|
||||
input.toggle-switch(type="checkbox" id="toggleHideCheckedItemsButton")
|
||||
label.toggle-label(for="toggleHideCheckedItemsButton")
|
||||
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+checklistDeleteDialog(checklist = checklistToDelete)
|
||||
@@ -31,6 +41,8 @@ template(name="checklistDetail")
|
||||
|
||||
if canModifyCard
|
||||
h2.title.js-open-inlined-form.is-editable
|
||||
if isMiniScreenOrShowDesktopDragHandles
|
||||
span.fa.checklist-handle(class="fa-arrows" title="{{_ 'dragChecklist'}}")
|
||||
+viewer
|
||||
= checklist.title
|
||||
else
|
||||
@@ -86,10 +98,12 @@ template(name="checklistItems")
|
||||
| {{_ 'add-checklist-item'}}...
|
||||
|
||||
template(name='checklistItemDetail')
|
||||
.js-checklist-item.checklist-item
|
||||
.js-checklist-item.checklist-item(class="{{#if item.isFinished }}is-checked{{#if hideCheckedItems}} invisible{{/if}}{{/if}}")
|
||||
if canModifyCard
|
||||
.check-box-container
|
||||
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
if isMiniScreenOrShowDesktopDragHandles
|
||||
span.fa.checklistitem-handle(class="fa-arrows" title="{{_ 'dragChecklistItem'}}")
|
||||
.item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
+viewer
|
||||
= item.title
|
||||
|
||||
@@ -6,7 +6,7 @@ function initSorting(items) {
|
||||
helper: 'clone',
|
||||
items: '.js-checklist-item:not(.placeholder)',
|
||||
connectWith: '.js-checklist-items',
|
||||
appendTo: '.board-canvas',
|
||||
appendTo: 'parent',
|
||||
distance: 7,
|
||||
placeholder: 'checklist-item placeholder',
|
||||
scroll: false,
|
||||
@@ -55,11 +55,12 @@ BlazeComponent.extendComponent({
|
||||
self.autorun(() => {
|
||||
const $itemsDom = $(self.itemsDom);
|
||||
if ($itemsDom.data('uiSortable') || $itemsDom.data('sortable')) {
|
||||
$(self.itemsDom).sortable(
|
||||
'option',
|
||||
'disabled',
|
||||
!userIsMember() || Utils.isMiniScreen(),
|
||||
);
|
||||
$(self.itemsDom).sortable('option', 'disabled', !userIsMember());
|
||||
if (Utils.isMiniScreenOrShowDesktopDragHandles()) {
|
||||
$(self.itemsDom).sortable({
|
||||
handle: 'span.fa.checklistitem-handle',
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -193,6 +194,9 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
this.toggleDeleteDialog.set(!this.toggleDeleteDialog.get());
|
||||
},
|
||||
'click #toggleHideCheckedItemsButton'() {
|
||||
Meteor.call('toggleHideCheckedItems');
|
||||
},
|
||||
};
|
||||
|
||||
return [
|
||||
@@ -211,6 +215,22 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('checklists');
|
||||
|
||||
Template.checklists.helpers({
|
||||
hideCheckedItems() {
|
||||
const currentUser = Meteor.user();
|
||||
if (currentUser) return currentUser.hasHideCheckedItems();
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
Template.addChecklistItemForm.onRendered(() => {
|
||||
autosize($('textarea.js-add-checklist-item'));
|
||||
});
|
||||
|
||||
Template.editChecklistItemForm.onRendered(() => {
|
||||
autosize($('textarea.js-edit-checklist-item'));
|
||||
});
|
||||
|
||||
Template.checklistDeleteDialog.onCreated(() => {
|
||||
const $cardDetails = this.$('.card-details');
|
||||
this.scrollState = {
|
||||
@@ -246,6 +266,11 @@ Template.checklistItemDetail.helpers({
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
hideCheckedItems() {
|
||||
const user = Meteor.user();
|
||||
if (user) return user.hasHideCheckedItems();
|
||||
return false;
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
|
||||
@@ -16,6 +16,10 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
&:hover
|
||||
color: inherit
|
||||
|
||||
.checklists-title
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
|
||||
.checklist-title
|
||||
.checkbox
|
||||
float: left
|
||||
@@ -38,6 +42,11 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
.js-delete-checklist
|
||||
@extends .delete-text
|
||||
|
||||
span.fa.checklist-handle
|
||||
padding-right: 20px
|
||||
padding-top: 6px
|
||||
float: right
|
||||
|
||||
|
||||
.js-confirm-checklist-delete
|
||||
background-color: darken(white, 3%)
|
||||
@@ -99,6 +108,17 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
margin-top: 3px
|
||||
display: flex
|
||||
background: darken(white, 3%)
|
||||
opacity: 1
|
||||
transition: height 0ms 400ms, opacity 400ms 0ms
|
||||
height: auto
|
||||
overflow: hidden
|
||||
|
||||
&.is-checked.invisible
|
||||
opacity: 0
|
||||
height: 0
|
||||
transition: height 0ms 0ms, opacity 600ms 0ms
|
||||
margin-top: 0
|
||||
margin-bottom: 0
|
||||
|
||||
&.placeholder
|
||||
background: darken(white, 20%)
|
||||
@@ -114,7 +134,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
background-color: darken(white, 8%)
|
||||
|
||||
.check-box-container
|
||||
padding-right: 1px;
|
||||
padding-right: 10px;
|
||||
|
||||
.check-box
|
||||
margin: 0.1em 0 0 0;
|
||||
@@ -124,10 +144,10 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
|
||||
.item-title
|
||||
flex: 1
|
||||
margin-left: 10px;
|
||||
&.is-checked
|
||||
color: #8c8c8c
|
||||
font-style: italic
|
||||
text-decoration: line-through
|
||||
& .viewer
|
||||
p
|
||||
margin-bottom: 2px
|
||||
@@ -135,6 +155,10 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
word-wrap: break-word
|
||||
max-width: 420px
|
||||
|
||||
span.fa.checklistitem-handle
|
||||
padding-top: 2px
|
||||
padding-right: 10px;
|
||||
|
||||
.js-delete-checklist-item
|
||||
margin: 0 0 0.5em 1.33em
|
||||
@extends .delete-text
|
||||
|
||||
@@ -85,7 +85,7 @@ template(name="minicard")
|
||||
.minicard-assignees.js-minicard-assignees
|
||||
each getAssignees
|
||||
+userAvatar(userId=this)
|
||||
hr
|
||||
hr(class="assigneehr" title="{{_ 'assignee'}}")
|
||||
|
||||
if getMembers
|
||||
.minicard-members.js-minicard-members
|
||||
@@ -106,9 +106,9 @@ template(name="minicard")
|
||||
span.badge-icon.fa.fa-align-left
|
||||
if getVoteQuestion
|
||||
.badge.badge-state-image-only(title=getVoteQuestion)
|
||||
span.badge-icon.fa.fa-thumbs-up
|
||||
span.badge-icon.fa.fa-thumbs-up(class="{{#if voteState}}text-green{{/if}}")
|
||||
span.badge-text {{ voteCountPositive }}
|
||||
span.badge-icon.fa.fa-thumbs-down
|
||||
span.badge-icon.fa.fa-thumbs-down(class="{{#if $eq voteState false}}text-red{{/if}}")
|
||||
span.badge-text {{ voteCountNegative }}
|
||||
if attachments.count
|
||||
.badge
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
// Template.cards.events({
|
||||
// 'click .member': Popup.open('cardMember')
|
||||
// });
|
||||
@@ -34,10 +32,10 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
{
|
||||
'click .js-toggle-minicard-label-text'() {
|
||||
if (cookies.has('hiddenMinicardLabelText')) {
|
||||
cookies.remove('hiddenMinicardLabelText'); //true
|
||||
if (window.localStorage.getItem('hiddenMinicardLabelText')) {
|
||||
window.localStorage.removeItem('hiddenMinicardLabelText'); //true
|
||||
} else {
|
||||
cookies.set('hiddenMinicardLabelText', 'true'); //true
|
||||
window.localStorage.setItem('hiddenMinicardLabelText', 'true'); //true
|
||||
}
|
||||
},
|
||||
},
|
||||
@@ -50,7 +48,7 @@ Template.minicard.helpers({
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).showDesktopDragHandles;
|
||||
} else if (cookies.has('showDesktopDragHandles')) {
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -60,7 +58,7 @@ Template.minicard.helpers({
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).hiddenMinicardLabelText;
|
||||
} else if (cookies.has('hiddenMinicardLabelText')) {
|
||||
} else if (window.localStorage.getItem('hiddenMinicardLabelText')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -87,7 +87,9 @@
|
||||
width: 11px
|
||||
height: @width
|
||||
border-radius: 2px
|
||||
margin-left: 3px
|
||||
margin-right: 3px
|
||||
margin-bottom: 3px
|
||||
|
||||
.minicard-custom-fields
|
||||
display:block;
|
||||
.minicard-custom-field
|
||||
@@ -163,7 +165,11 @@
|
||||
.minicard-members,
|
||||
.minicard-assignees
|
||||
float: right
|
||||
margin: 2px -8px 12px 0
|
||||
margin-left: 5px
|
||||
|
||||
.assigneehr
|
||||
border-top: 1px solid red
|
||||
margin-bottom: 4px
|
||||
|
||||
.member
|
||||
float: right
|
||||
@@ -178,7 +184,7 @@
|
||||
width: @height
|
||||
|
||||
+ .badges
|
||||
margin-top: 10px
|
||||
margin-top: 5px
|
||||
|
||||
.minicard-members:empty,
|
||||
.minicard-assignees:empty
|
||||
@@ -299,3 +305,8 @@ minicard-color(background, color...)
|
||||
|
||||
.minicard-indigo
|
||||
minicard-color(#4b0082, #ffffff) //White text for better visibility
|
||||
|
||||
.text-red
|
||||
color:red
|
||||
.text-green
|
||||
color:green
|
||||
@@ -0,0 +1,23 @@
|
||||
template(name="resultCard")
|
||||
.result-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(this)
|
||||
//= card.title
|
||||
ul.result-card-context-list
|
||||
li.result-card-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= getBoard.title
|
||||
li.result-card-context.result-card-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.result-card-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= getSwimlane.title
|
||||
li.result-card-context.result-card-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.result-card-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= getList.title
|
||||
@@ -0,0 +1,11 @@
|
||||
Template.resultCard.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{}];
|
||||
},
|
||||
}).register('resultCard');
|
||||
@@ -0,0 +1,21 @@
|
||||
.result-card-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.result-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.result-card-context
|
||||
display: inline-block
|
||||
|
||||
.result-card-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.result-card-context-list
|
||||
margin-bottom: 0.7rem
|
||||
@@ -1,11 +1,11 @@
|
||||
template(name="subtasks")
|
||||
h3
|
||||
h3.card-details-item-title
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtasks'}}
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+subtaskDeleteDialog(subtask = subtaskToDelete)
|
||||
|
||||
if currentUser.isBoardAdmin
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+subtaskDeleteDialog(subtask = subtaskToDelete)
|
||||
|
||||
.card-subtasks-items
|
||||
each subtask in currentCard.subtasks
|
||||
@@ -28,7 +28,8 @@ template(name="subtaskDetail")
|
||||
span
|
||||
a.js-view-subtask(title="{{ subtask.title }}") {{_ "view-it"}}
|
||||
if canModifyCard
|
||||
a.js-delete-subtask.toggle-delete-subtask-dialog {{_ "delete"}}...
|
||||
if currentUser.isBoardAdmin
|
||||
a.js-delete-subtask.toggle-delete-subtask-dialog {{_ "delete"}}...
|
||||
|
||||
if canModifyCard
|
||||
h2.title.js-open-inlined-form.is-editable
|
||||
@@ -68,7 +69,8 @@ template(name="editSubtaskItemForm")
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
span(title=createdAt) {{ moment createdAt }}
|
||||
if canModifyCard
|
||||
a.js-delete-subtask-item {{_ "delete"}}...
|
||||
if currentUser.isBoardAdmin
|
||||
a.js-delete-subtask-item {{_ "delete"}}...
|
||||
|
||||
template(name="subtasksItems")
|
||||
.subtasks-items.js-subtasks-items
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function getMembersToMap(data) {
|
||||
export function csvGetMembersToMap(data) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import trelloMembersMapper from './trelloMembersMapper';
|
||||
import wekanMembersMapper from './wekanMembersMapper';
|
||||
import csvMembersMapper from './csvMembersMapper';
|
||||
import { trelloGetMembersToMap } from './trelloMembersMapper';
|
||||
import { wekanGetMembersToMap } from './wekanMembersMapper';
|
||||
import { csvGetMembersToMap } from './csvMembersMapper';
|
||||
|
||||
const Papa = require('papaparse');
|
||||
|
||||
@@ -99,13 +99,13 @@ BlazeComponent.extendComponent({
|
||||
let membersToMap;
|
||||
switch (importSource) {
|
||||
case 'trello':
|
||||
membersToMap = trelloMembersMapper.getMembersToMap(dataObject);
|
||||
membersToMap = trelloGetMembersToMap(dataObject);
|
||||
break;
|
||||
case 'wekan':
|
||||
membersToMap = wekanMembersMapper.getMembersToMap(dataObject);
|
||||
membersToMap = wekanGetMembersToMap(dataObject);
|
||||
break;
|
||||
case 'csv':
|
||||
membersToMap = csvMembersMapper.getMembersToMap(dataObject);
|
||||
membersToMap = csvGetMembersToMap(dataObject);
|
||||
break;
|
||||
}
|
||||
return membersToMap;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function getMembersToMap(data) {
|
||||
export function trelloGetMembersToMap(data) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export function getMembersToMap(data) {
|
||||
export function wekanGetMembersToMap(data) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
const { calculateIndex } = Utils;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -124,7 +122,7 @@ BlazeComponent.extendComponent({
|
||||
if (currentUser) {
|
||||
showDesktopDragHandles = (currentUser.profile || {})
|
||||
.showDesktopDragHandles;
|
||||
} else if (cookies.has('showDesktopDragHandles')) {
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
showDesktopDragHandles = true;
|
||||
} else {
|
||||
showDesktopDragHandles = false;
|
||||
@@ -185,7 +183,7 @@ Template.list.helpers({
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).showDesktopDragHandles;
|
||||
} else if (cookies.has('showDesktopDragHandles')) {
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
|
||||
@@ -120,9 +120,6 @@
|
||||
form
|
||||
margin-bottom: 9px
|
||||
|
||||
.ps-scrollbar-y-rail
|
||||
transform: translateX(2px)
|
||||
|
||||
.open-minicard-composer
|
||||
border-radius: 2px
|
||||
color: #8c8c8c
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
template(name="listBody")
|
||||
.list-body.js-perfect-scrollbar
|
||||
.list-body
|
||||
.minicards.clearfix.js-minicards(class="{{#if reachedWipLimit}}js-list-full{{/if}}")
|
||||
if cards.count
|
||||
+inlinedForm(autoclose=false position="top")
|
||||
@@ -105,8 +105,10 @@ template(name="searchElementPopup")
|
||||
each boards
|
||||
option(value="{{_id}}") {{title}}
|
||||
form.js-search-term-form
|
||||
label
|
||||
| {{_ 'template'}}
|
||||
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
|
||||
.list-body.js-perfect-scrollbar.search-card-results
|
||||
.list-body.search-card-results
|
||||
.minicards.clearfix.js-minicards
|
||||
if isBoardTemplateSearch
|
||||
each results
|
||||
|
||||
@@ -8,7 +8,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
mixins() {
|
||||
return [Mixins.PerfectScrollbar];
|
||||
return [];
|
||||
},
|
||||
|
||||
openForm(options) {
|
||||
@@ -523,7 +523,7 @@ BlazeComponent.extendComponent({
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.PerfectScrollbar];
|
||||
return [];
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
@@ -721,7 +721,7 @@ BlazeComponent.extendComponent({
|
||||
|
||||
onRendered() {
|
||||
this.spinner = this.find('.sk-spinner-list');
|
||||
this.container = this.$(this.spinner).parents('.js-perfect-scrollbar')[0];
|
||||
this.container = this.$(this.spinner).parents('.list-body')[0];
|
||||
|
||||
$(this.container).on(
|
||||
`scroll.spinner_${this.swimlaneId}_${this.listId}`,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="listHeader")
|
||||
.list-header.js-list-header(
|
||||
class="{{#if limitToShowCardsCount}}list-header-card-count{{/if}}"
|
||||
class="{{#if colorClass}}list-header-{{colorClass}}{{/if}}")
|
||||
class=colorClass)
|
||||
+inlinedForm
|
||||
+editListTitleForm
|
||||
else
|
||||
@@ -43,8 +43,9 @@ template(name="listHeader")
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
if showDesktopDragHandles
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
if currentUser.isBoardAdmin
|
||||
if showDesktopDragHandles
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
|
||||
template(name="editListTitleForm")
|
||||
.list-composer
|
||||
@@ -115,8 +116,9 @@ template(name="listMorePopup")
|
||||
input.inline-input(type="text" readonly value="{{ rootUrl }}")
|
||||
| {{_ 'added'}}
|
||||
span.date(title=list.createdAt) {{ moment createdAt 'LLL' }}
|
||||
unless currentUser.isWorker
|
||||
a.js-delete {{_ 'delete'}}
|
||||
//unless currentUser.isWorker
|
||||
// if currentUser.isBoardAdmin
|
||||
// a.js-delete {{_ 'delete'}}
|
||||
|
||||
template(name="listDeletePopup")
|
||||
p {{_ "list-delete-pop"}}
|
||||
@@ -151,7 +153,7 @@ template(name="setListColorPopup")
|
||||
form.edit-label
|
||||
.palette-colors: each colors
|
||||
// note: we use the swimlane palette to have more than just the border
|
||||
span.card-label.palette-color.js-palette-color(class="swimlane-{{color}}")
|
||||
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
|
||||
if(isSelected color)
|
||||
i.fa.fa-check
|
||||
button.primary.confirm.js-submit {{_ 'save'}}
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
let listsColors;
|
||||
Meteor.startup(() => {
|
||||
listsColors = Lists.simpleSchema()._schema.color.allowedValues;
|
||||
@@ -106,11 +104,15 @@ BlazeComponent.extendComponent({
|
||||
}).register('listHeader');
|
||||
|
||||
Template.listHeader.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
|
||||
showDesktopDragHandles() {
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).showDesktopDragHandles;
|
||||
} else if (cookies.has('showDesktopDragHandles')) {
|
||||
} else if (window.localStorage.getItem('showDesktopDragHandles')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -119,6 +121,10 @@ Template.listHeader.helpers({
|
||||
});
|
||||
|
||||
Template.listActionPopup.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
|
||||
isWipLimitEnabled() {
|
||||
return Template.currentData().getWipLimit('enabled');
|
||||
},
|
||||
@@ -256,6 +262,12 @@ Template.listMorePopup.events({
|
||||
}),
|
||||
});
|
||||
|
||||
Template.listHeader.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentList = this.currentData();
|
||||
@@ -267,7 +279,11 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
isSelected(color) {
|
||||
return this.currentColor.get() === color;
|
||||
if (this.currentColor.get() === null) {
|
||||
return color === 'white';
|
||||
} else {
|
||||
return this.currentColor.get() === color;
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
template(name="brokenCardsHeaderBar")
|
||||
h1
|
||||
| {{_ 'broken-cards'}}
|
||||
|
||||
template(name="brokenCards")
|
||||
.wrapper
|
||||
.broken-cards-wrapper
|
||||
each card in brokenCardsList
|
||||
.broken-cards-card-wrapper
|
||||
.broken-cards-card-title
|
||||
= card.title
|
||||
ul.broken-cards-context-list
|
||||
li.broken-cards-context(title="{{_ 'board'}}")
|
||||
if card.boardId
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
else
|
||||
.broken-cards-null
|
||||
| NULL
|
||||
li.broken-cards-context.broken-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.broken-cards-context(title="{{_ 'swimlane'}}")
|
||||
if card.swimlaneId
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
else
|
||||
.broken-cards-null
|
||||
| NULL
|
||||
li.broken-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.broken-cards-context(title="{{_ 'list'}}")
|
||||
if card.listId
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
.broken-cards-null
|
||||
| NULL
|
||||
@@ -0,0 +1,28 @@
|
||||
BlazeComponent.extendComponent({}).register('brokenCardsHeaderBar');
|
||||
|
||||
Template.brokenCards.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('brokenCards');
|
||||
},
|
||||
|
||||
brokenCardsList() {
|
||||
const selector = {
|
||||
$or: [
|
||||
{ boardId: { $in: [null, ''] } },
|
||||
{ swimlaneId: { $in: [null, ''] } },
|
||||
{ listId: { $in: [null, ''] } },
|
||||
{ permission: 'public' },
|
||||
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||
],
|
||||
};
|
||||
|
||||
return Cards.find(selector);
|
||||
},
|
||||
}).register('brokenCards');
|
||||
@@ -0,0 +1,31 @@
|
||||
.broken-cards-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
border-width: 3px !important
|
||||
border-color: grey !important
|
||||
border-style: solid
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
background-color: white
|
||||
|
||||
.broken-cards-wrapper
|
||||
max-width: 500px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.broken-cards-card-title
|
||||
font-weight: bold
|
||||
//padding: 10px
|
||||
|
||||
.broken-cards-context
|
||||
display: inline-block
|
||||
|
||||
.broken-cards-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.broken-cards-context-list
|
||||
//margin-bottom: 0.7rem
|
||||
|
||||
.broken-cards-null
|
||||
color: darkred
|
||||
font-style: italic
|
||||
@@ -0,0 +1,73 @@
|
||||
template(name="dueCardsHeaderBar")
|
||||
if currentUser
|
||||
h1
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'dueCards-title'}}
|
||||
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-due-cards-view-change(title="{{_ 'dueCardsViewChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq dueCardsView 'me'
|
||||
i.fa.fa-user
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq dueCardsView 'all'
|
||||
i.fa.fa-users
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
|
||||
template(name="dueCardsModalTitle")
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'dueCards-title'}}
|
||||
|
||||
template(name="dueCards")
|
||||
if currentUser
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
.due-cards-dueat-list-wrapper
|
||||
each card in dueCardsList
|
||||
.due-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.due-cards-context-list
|
||||
li.due-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
li.due-cards-context.due-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.due-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.due-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
|
||||
template(name="dueCardsViewChangePopup")
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "dueCardsViewChange-choice-me"
|
||||
a.js-due-cards-view-me
|
||||
i.fa.fa-user.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-me'}}
|
||||
if $eq Utils.dueCardsView "me"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "dueCardsViewChange-choice-all"
|
||||
a.js-due-cards-view-all
|
||||
i.fa.fa-users.colorful
|
||||
| {{_ 'dueCardsViewChange-choice-all'}}
|
||||
span.sub-name
|
||||
+viewer
|
||||
| {{_ 'dueCardsViewChange-choice-all-description' }}
|
||||
if $eq Utils.dueCardsView "all"
|
||||
i.fa.fa-check
|
||||
@@ -0,0 +1,154 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
dueCardsView() {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('sort:', Utils.dueCardsView());
|
||||
return Utils.dueCardsView();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-change': Popup.open('dueCardsViewChange'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('dueCardsHeaderBar');
|
||||
|
||||
Template.dueCards.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-me'() {
|
||||
Utils.setDueCardsView('me');
|
||||
Popup.close();
|
||||
},
|
||||
|
||||
'click .js-due-cards-view-all'() {
|
||||
Utils.setDueCardsView('all');
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('dueCardsViewChangePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.isPageReady = new ReactiveVar(false);
|
||||
|
||||
this.autorun(() => {
|
||||
const handle = subManager.subscribe(
|
||||
'dueCards',
|
||||
Utils.dueCardsView() === 'all',
|
||||
);
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
this.isPageReady.set(handle.ready());
|
||||
});
|
||||
});
|
||||
});
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
dueCardsView() {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('sort:', Utils.dueCardsView());
|
||||
return Utils.dueCardsView();
|
||||
},
|
||||
|
||||
sortByBoard() {
|
||||
return this.dueCardsView() === 'board';
|
||||
},
|
||||
|
||||
dueCardsList() {
|
||||
const allUsers = Utils.dueCardsView() === 'all';
|
||||
|
||||
const user = Meteor.user();
|
||||
|
||||
const archivedBoards = [];
|
||||
Boards.find({ archived: true }).forEach(board => {
|
||||
archivedBoards.push(board._id);
|
||||
});
|
||||
|
||||
const permiitedBoards = [];
|
||||
let selector = {
|
||||
archived: false,
|
||||
};
|
||||
// for every user including admin allow her to see cards only from public boards
|
||||
// or those where she is a member
|
||||
//if (!user.isAdmin) {
|
||||
selector.$or = [
|
||||
{ permission: 'public' },
|
||||
{ members: { $elemMatch: { userId: user._id, isActive: true } } },
|
||||
];
|
||||
//}
|
||||
Boards.find(selector).forEach(board => {
|
||||
permiitedBoards.push(board._id);
|
||||
});
|
||||
|
||||
const archivedSwimlanes = [];
|
||||
Swimlanes.find({ archived: true }).forEach(swimlane => {
|
||||
archivedSwimlanes.push(swimlane._id);
|
||||
});
|
||||
|
||||
const archivedLists = [];
|
||||
Lists.find({ archived: true }).forEach(list => {
|
||||
archivedLists.push(list._id);
|
||||
});
|
||||
|
||||
selector = {
|
||||
archived: false,
|
||||
boardId: {
|
||||
$nin: archivedBoards,
|
||||
$in: permiitedBoards,
|
||||
},
|
||||
swimlaneId: { $nin: archivedSwimlanes },
|
||||
listId: { $nin: archivedLists },
|
||||
dueAt: { $ne: null },
|
||||
endAt: null,
|
||||
};
|
||||
|
||||
if (!allUsers) {
|
||||
selector.$or = [{ members: user._id }, { assignees: user._id }];
|
||||
}
|
||||
|
||||
const cards = [];
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('cards selector:', selector);
|
||||
Cards.find(selector).forEach(card => {
|
||||
cards.push(card);
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log(
|
||||
// 'board:',
|
||||
// card.board(),
|
||||
// 'swimlane:',
|
||||
// card.swimlane(),
|
||||
// 'list:',
|
||||
// card.list(),
|
||||
// );
|
||||
});
|
||||
|
||||
cards.sort((a, b) => {
|
||||
const x = a.dueAt === null ? Date('2100-12-31') : a.dueAt;
|
||||
const y = b.dueAt === null ? Date('2100-12-31') : b.dueAt;
|
||||
|
||||
if (x > y) return 1;
|
||||
else if (x < y) return -1;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('cards:', cards);
|
||||
return cards;
|
||||
},
|
||||
}).register('dueCards');
|
||||
@@ -0,0 +1,69 @@
|
||||
.due-cards-board-wrapper
|
||||
border-radius: 8px
|
||||
//padding: 0.5rem
|
||||
min-width: 400px
|
||||
border-width: 8px
|
||||
border-color: grey
|
||||
border-style: solid
|
||||
margin-bottom: 2rem
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.due-cards-board-title
|
||||
font-size: 1.4rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
background-color: grey
|
||||
color: white
|
||||
|
||||
.due-cards-swimlane-title
|
||||
font-size: 1.1rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
padding-bottom: 0.4rem
|
||||
margin-top: 0
|
||||
margin-bottom: 0.5rem
|
||||
//border-top: black 1px solid
|
||||
//border-bottom: black 1px solid
|
||||
text-align: center
|
||||
|
||||
.swimlane-default-color
|
||||
background-color: lightgrey
|
||||
|
||||
.due-cards-list-title
|
||||
font-weight: bold
|
||||
font-size: 1.1rem
|
||||
//padding-bottom: 0
|
||||
//margin-bottom: 0
|
||||
text-align: center
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.due-cards-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.due-cards-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.due-cards-dueat-list-wrapper
|
||||
max-width: 500px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.due-cards-field-name
|
||||
font-weight: bold
|
||||
|
||||
.due-cards-context
|
||||
display: inline-block
|
||||
|
||||
.due-cards-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.due-cards-context-list
|
||||
margin-bottom: 0.7rem
|
||||
@@ -91,6 +91,7 @@ Template.editor.onRendered(() => {
|
||||
};
|
||||
const editor = '.editor';
|
||||
const selectors = [
|
||||
`.js-new-description-form ${editor}`,
|
||||
`.js-new-comment-form ${editor}`,
|
||||
`.js-edit-comment ${editor}`,
|
||||
].join(','); // only new comment and edit comment
|
||||
@@ -264,6 +265,32 @@ Template.editor.onRendered(() => {
|
||||
|
||||
import sanitizeXss from 'xss';
|
||||
|
||||
// Additional safeAttrValue function to allow for other specific protocols
|
||||
// See https://github.com/leizongmin/js-xss/issues/52#issuecomment-241354114
|
||||
function mySafeAttrValue(tag, name, value, cssFilter) {
|
||||
// only when the tag is 'a' and attribute is 'href'
|
||||
// then use your custom function
|
||||
if (tag === 'a' && name === 'href') {
|
||||
// only filter the value if starts with 'cbthunderlink:' or 'aodroplink'
|
||||
if (
|
||||
/^thunderlink:/gi.test(value) ||
|
||||
/^cbthunderlink:/gi.test(value) ||
|
||||
/^aodroplink:/gi.test(value) ||
|
||||
/^onenote:/gi.test(value) ||
|
||||
/^file:/gi.test(value) ||
|
||||
/^mailspring:/gi.test(value)
|
||||
) {
|
||||
return value;
|
||||
} else {
|
||||
// use the default safeAttrValue function to process all non cbthunderlinks
|
||||
return sanitizeXss.safeAttrValue(tag, name, value, cssFilter);
|
||||
}
|
||||
} else {
|
||||
// use the default safeAttrValue function to process it
|
||||
return sanitizeXss.safeAttrValue(tag, name, value, cssFilter);
|
||||
}
|
||||
}
|
||||
|
||||
// XXX I believe we should compute a HTML rendered field on the server that
|
||||
// would handle markdown and user mentions. We can simply have two
|
||||
// fields, one source, and one compiled version (in HTML) and send only the
|
||||
@@ -277,7 +304,8 @@ Blaze.Template.registerHelper(
|
||||
const view = this;
|
||||
let content = Blaze.toHTML(view.templateContentBlock);
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (!currentBoard) return HTML.Raw(sanitizeXss(content));
|
||||
if (!currentBoard)
|
||||
return HTML.Raw(sanitizeXss(content, { safeAttrValue: mySafeAttrValue }));
|
||||
const knowedUsers = currentBoard.members.map(member => {
|
||||
const u = Users.findOne(member.userId);
|
||||
if (u) {
|
||||
@@ -321,7 +349,7 @@ Blaze.Template.registerHelper(
|
||||
content = content.replace(fullMention, Blaze.toHTML(link));
|
||||
}
|
||||
|
||||
return HTML.Raw(sanitizeXss(content));
|
||||
return HTML.Raw(sanitizeXss(content, { safeAttrValue: mySafeAttrValue }));
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
template(name="globalSearchHeaderBar")
|
||||
if currentUser
|
||||
h1
|
||||
i.fa.fa-search
|
||||
| {{_ 'globalSearch-title'}}
|
||||
|
||||
template(name="globalSearchModalTitle")
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'globalSearch-title'}}
|
||||
|
||||
template(name="globalSearch")
|
||||
if currentUser
|
||||
.wrapper
|
||||
form.global-search-instructions.js-search-query-form
|
||||
input.global-search-query-input(type="text" name="searchQuery" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
|
||||
if searching.get
|
||||
+spinner
|
||||
else if hasResults.get
|
||||
.global-search-dueat-list-wrapper
|
||||
h1
|
||||
if $eq resultsCount.get 0
|
||||
| {{_ 'no-cards-found' }}
|
||||
else if $eq resultsCount.get 1
|
||||
| {{_ 'one-card-found' }}
|
||||
else if $eq resultsCount.get totalHits.get
|
||||
| {{_ 'n-cards-found' resultsCount.get }}
|
||||
else
|
||||
| {{_ 'n-n-of-n-cards-found' 1 resultsCount.get totalHits.get }}
|
||||
if queryErrors.get
|
||||
div
|
||||
each msg in errorMessages
|
||||
span.global-search-error-messages
|
||||
| {{_ msg.tag msg.value }}
|
||||
each card in results
|
||||
+resultCard(card)
|
||||
else
|
||||
.global-search-instructions
|
||||
h1 Search Operators
|
||||
+viewer
|
||||
= 'Searches can include operators to refine the search. Operators are specified by writing the operator'
|
||||
= 'name and value separated by a colon. For example, an operator specification of `list:Blocked` would limit the search'
|
||||
= 'to cards that are contained in a list named *Blocked*. If the value contains spaces or special characters'
|
||||
= 'it must be enclosed in quotation marks (e.g. `list:"To Review"`).\n'
|
||||
= 'Available operators are:\n'
|
||||
= '* `board:title` - cards in boards matching the specified title\n'
|
||||
= '* `list:title` - cards in lists matching the specified title\n'
|
||||
= '* `swimlane:title` - cards in swimlanes matching the specified title\n'
|
||||
= '* `label:color` - cards that have a label matching the given color\n'
|
||||
= '* `label:name` - cards that have a label matching the given name\n'
|
||||
= '* `user:username` - cards where the specified user is a member or assignee\n'
|
||||
= '* `@username` - shorthand for `user:username`\n'
|
||||
= '* `#label` - shorthand for `label:color-or-name`\n'
|
||||
= '## Notes\n'
|
||||
= '* Multiple operators may be specified.\n'
|
||||
= '* Similar operators are *OR*ed together. Cards that match any of the conditions will be returned.\n'
|
||||
= ' `list:Available list:Blocked` would return cards contained in any list named *Blocked* or *Available*.\n'
|
||||
= '* Differing operators are *AND*ed together. Only cards that match all of the differing operators are returned.\n'
|
||||
= '`list:Available label:red` returns only cards in the list *Available* with a *red* label.\n'
|
||||
= '* Text searches are case insensitive.\n'
|
||||
|
||||
template(name="globalSearchViewChangePopup")
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "globalSearchViewChange-choice-me"
|
||||
a.js-global-search-view-me
|
||||
i.fa.fa-user.colorful
|
||||
| {{_ 'globalSearchViewChange-choice-me'}}
|
||||
if $eq Utils.globalSearchView "me"
|
||||
i.fa.fa-check
|
||||
li
|
||||
with "globalSearchViewChange-choice-all"
|
||||
a.js-global-search-view-all
|
||||
i.fa.fa-users.colorful
|
||||
| {{_ 'globalSearchViewChange-choice-all'}}
|
||||
span.sub-name
|
||||
+viewer
|
||||
| {{_ 'globalSearchViewChange-choice-all-description' }}
|
||||
if $eq Utils.globalSearchView "all"
|
||||
i.fa.fa-check
|
||||
@@ -0,0 +1,201 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-change': Popup.open('globalSearchViewChange'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearchHeaderBar');
|
||||
|
||||
Template.globalSearch.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-due-cards-view-me'() {
|
||||
Utils.setDueCardsView('me');
|
||||
Popup.close();
|
||||
},
|
||||
|
||||
'click .js-due-cards-view-all'() {
|
||||
Utils.setDueCardsView('all');
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearchViewChangePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.isPageReady = new ReactiveVar(true);
|
||||
this.searching = new ReactiveVar(false);
|
||||
this.hasResults = new ReactiveVar(false);
|
||||
this.query = new ReactiveVar('');
|
||||
this.queryParams = null;
|
||||
this.resultsCount = new ReactiveVar(0);
|
||||
this.totalHits = new ReactiveVar(0);
|
||||
this.queryErrors = new ReactiveVar(null);
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
results() {
|
||||
if (this.queryParams) {
|
||||
const results = Cards.globalSearch(this.queryParams);
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('user:', Meteor.user());
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('user:', Meteor.user().sessionData);
|
||||
// console.log('errors:', results.errors);
|
||||
this.totalHits.set(Meteor.user().sessionData.totalHits);
|
||||
this.resultsCount.set(results.cards.count());
|
||||
this.queryErrors.set(results.errors);
|
||||
return results.cards;
|
||||
}
|
||||
this.resultsCount.set(0);
|
||||
return [];
|
||||
},
|
||||
|
||||
errorMessages() {
|
||||
const errors = this.queryErrors.get();
|
||||
const messages = [];
|
||||
|
||||
errors.notFound.boards.forEach(board => {
|
||||
messages.push({ tag: 'board-title-not-found', value: board });
|
||||
});
|
||||
errors.notFound.swimlanes.forEach(swim => {
|
||||
messages.push({ tag: 'swimlane-title-not-found', value: swim });
|
||||
});
|
||||
errors.notFound.lists.forEach(list => {
|
||||
messages.push({ tag: 'list-title-not-found', value: list });
|
||||
});
|
||||
errors.notFound.users.forEach(user => {
|
||||
messages.push({ tag: 'user-username-not-found', value: user });
|
||||
});
|
||||
|
||||
return messages;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'submit .js-search-query-form'(evt) {
|
||||
evt.preventDefault();
|
||||
this.query.set(evt.target.searchQuery.value);
|
||||
this.queryErrors.set(null);
|
||||
|
||||
if (!this.query.get()) {
|
||||
this.searching.set(false);
|
||||
this.hasResults.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
this.searching.set(true);
|
||||
this.hasResults.set(false);
|
||||
|
||||
let query = this.query.get();
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('query:', query);
|
||||
|
||||
const reOperator1 = /^((?<operator>\w+):|(?<abbrev>[#@]))(?<value>\w+)(\s+|$)/;
|
||||
const reOperator2 = /^((?<operator>\w+):|(?<abbrev>[#@]))(?<quote>["']*)(?<value>.*?)\k<quote>(\s+|$)/;
|
||||
const reText = /^(?<text>\S+)(\s+|$)/;
|
||||
const reQuotedText = /^(?<quote>["'])(?<text>\w+)\k<quote>(\s+|$)/;
|
||||
|
||||
const operatorMap = {};
|
||||
operatorMap[TAPi18n.__('operator-board')] = 'boards';
|
||||
operatorMap[TAPi18n.__('operator-board-abbrev')] = 'boards';
|
||||
operatorMap[TAPi18n.__('operator-swimlane')] = 'swimlanes';
|
||||
operatorMap[TAPi18n.__('operator-swimlane-abbrev')] = 'swimlanes';
|
||||
operatorMap[TAPi18n.__('operator-list')] = 'lists';
|
||||
operatorMap[TAPi18n.__('operator-list-abbrev')] = 'lists';
|
||||
operatorMap[TAPi18n.__('operator-label')] = 'labels';
|
||||
operatorMap[TAPi18n.__('operator-label-abbrev')] = 'labels';
|
||||
operatorMap[TAPi18n.__('operator-user')] = 'users';
|
||||
operatorMap[TAPi18n.__('operator-user-abbrev')] = 'users';
|
||||
operatorMap[TAPi18n.__('operator-is')] = 'is';
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('operatorMap:', operatorMap);
|
||||
const params = {
|
||||
boards: [],
|
||||
swimlanes: [],
|
||||
lists: [],
|
||||
users: [],
|
||||
labels: [],
|
||||
is: [],
|
||||
};
|
||||
|
||||
let text = '';
|
||||
while (query) {
|
||||
m = query.match(reOperator1);
|
||||
if (!m) {
|
||||
m = query.match(reOperator2);
|
||||
if (m) {
|
||||
query = query.replace(reOperator2, '');
|
||||
}
|
||||
} else {
|
||||
query = query.replace(reOperator1, '');
|
||||
}
|
||||
if (m) {
|
||||
let op;
|
||||
if (m.groups.operator) {
|
||||
op = m.groups.operator.toLowerCase();
|
||||
} else {
|
||||
op = m.groups.abbrev;
|
||||
}
|
||||
if (op in operatorMap) {
|
||||
params[operatorMap[op]].push(m.groups.value);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
m = query.match(reQuotedText);
|
||||
if (!m) {
|
||||
m = query.match(reText);
|
||||
if (m) {
|
||||
query = query.replace(reText, '');
|
||||
}
|
||||
} else {
|
||||
query = query.replace(reQuotedText, '');
|
||||
}
|
||||
if (m) {
|
||||
text += (text ? ' ' : '') + m.groups.text;
|
||||
}
|
||||
}
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('text:', text);
|
||||
params.text = text;
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('params:', params);
|
||||
|
||||
this.queryParams = params;
|
||||
|
||||
this.autorun(() => {
|
||||
const handle = subManager.subscribe('globalSearch', params);
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('ready:', handle.ready());
|
||||
if (handle.ready()) {
|
||||
this.searching.set(false);
|
||||
this.hasResults.set(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('globalSearch');
|
||||
@@ -0,0 +1,97 @@
|
||||
.global-search-board-wrapper
|
||||
border-radius: 8px
|
||||
//padding: 0.5rem
|
||||
min-width: 400px
|
||||
border-width: 8px
|
||||
border-color: grey
|
||||
border-style: solid
|
||||
margin-bottom: 2rem
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-board-title
|
||||
font-size: 1.4rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
background-color: grey
|
||||
color: white
|
||||
|
||||
.global-search-swimlane-title
|
||||
font-size: 1.1rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
padding-bottom: 0.4rem
|
||||
margin-top: 0
|
||||
margin-bottom: 0.5rem
|
||||
//border-top: black 1px solid
|
||||
//border-bottom: black 1px solid
|
||||
text-align: center
|
||||
|
||||
.swimlane-default-color
|
||||
background-color: lightgrey
|
||||
|
||||
.global-search-list-title
|
||||
font-weight: bold
|
||||
font-size: 1.1rem
|
||||
//padding-bottom: 0
|
||||
//margin-bottom: 0
|
||||
text-align: center
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.global-search-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.global-search-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.global-search-dueat-list-wrapper
|
||||
max-width: 500px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-field-name
|
||||
font-weight: bold
|
||||
|
||||
.global-search-context
|
||||
display: inline-block
|
||||
|
||||
.global-search-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.global-search-context-list
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.global-search-error-messages
|
||||
color: darkred
|
||||
|
||||
.global-search-instructions
|
||||
width: 40%
|
||||
min-width: 400px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
line-height: 150%
|
||||
|
||||
.global-search-query-input
|
||||
width: 90% !important
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.global-search-operator
|
||||
font-family: Courier
|
||||
|
||||
.global-search-value
|
||||
font-family: Courier
|
||||
font-style: italic
|
||||
|
||||
code
|
||||
color: white
|
||||
background-color: grey
|
||||
padding: 0.1rem !important
|
||||
font-size: 0.7rem !important
|
||||
@@ -19,16 +19,29 @@ template(name="header")
|
||||
= title
|
||||
#header-new-board-icon
|
||||
else
|
||||
//-
|
||||
On sandstorm, the logo shouldn't be clickable, because we only have one
|
||||
page/document on it, and we don't want to see the home page containing
|
||||
the list of all boards.
|
||||
unless currentSetting.hideLogo
|
||||
if currentSetting.customTopLeftCornerLogoImageUrl
|
||||
if currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
a(href="{{currentSetting.customTopLeftCornerLogoLinkUrl}}")
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0")
|
||||
unless currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0")
|
||||
unless currentSetting.customTopLeftCornerLogoImageUrl
|
||||
img(src="{{pathFor '/logo-header.png'}}" alt="")
|
||||
ul
|
||||
li
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
li.separator -
|
||||
li
|
||||
a(href="{{pathFor 'public'}}")
|
||||
span.fa.fa-globe
|
||||
| {{_ 'public'}}
|
||||
//li
|
||||
// a(href="{{pathFor 'public'}}")
|
||||
// span.fa.fa-globe
|
||||
// | {{_ 'public'}}
|
||||
each currentUser.starredBoards
|
||||
li.separator -
|
||||
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
|
||||
@@ -37,8 +50,13 @@ template(name="header")
|
||||
else
|
||||
li.current {{_ 'quick-access-description'}}
|
||||
|
||||
a#header-new-board-icon.js-create-board
|
||||
i.fa.fa-plus(title="Create a new board")
|
||||
// Next line is used only for spacing at header,
|
||||
// there is no visible clickable icon.
|
||||
#header-new-board-icon
|
||||
// Hide duplicate create board button,
|
||||
// because it did not show board templates correctly.
|
||||
//a#header-new-board-icon.js-create-board
|
||||
// i.fa.fa-plus(title="Create a new board")
|
||||
|
||||
+notifications
|
||||
|
||||
@@ -52,17 +70,6 @@ template(name="header")
|
||||
#header-main-bar(class="{{#if wrappedHeader}}wrapper{{/if}}")
|
||||
+Template.dynamic(template=headerBar)
|
||||
|
||||
//unless hideLogo
|
||||
|
||||
//-
|
||||
On sandstorm, the logo shouldn't be clickable, because we only have one
|
||||
page/document on it, and we don't want to see the home page containing
|
||||
the list of all boards.
|
||||
|
||||
// unless currentSetting.hideLogo
|
||||
// a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
|
||||
// img(src="{{pathFor '/logo-header.png'}}" alt="")
|
||||
|
||||
if appIsOffline
|
||||
+offlineWarning
|
||||
|
||||
|
||||
@@ -19,6 +19,27 @@ head
|
||||
|
||||
template(name="userFormsLayout")
|
||||
section.auth-layout
|
||||
if currentSetting.hideLogo
|
||||
h1.at-form-landing-logo
|
||||
br
|
||||
br
|
||||
unless currentSetting.hideLogo
|
||||
h1.at-form-landing-logo
|
||||
if currentSetting.customLoginLogoImageUrl
|
||||
if currentSetting.customLoginLogoLinkUrl
|
||||
a(href="{{currentSetting.customLoginLogoLinkUrl}}")
|
||||
img(src="{{currentSetting.customLoginLogoImageUrl}}" width="300" height="auto")
|
||||
br
|
||||
unless currentSetting.customLoginLogoLinkUrl
|
||||
img(src="{{currentSetting.customLoginLogoImageUrl}}" width="300" height="auto")
|
||||
br
|
||||
unless currentSetting.customLoginLogoImageUrl
|
||||
img(src="{{pathFor '/wekan-logo.svg'}}" alt="" width="300" height="auto")
|
||||
br
|
||||
if currentSetting.textBelowCustomLoginLogo
|
||||
+viewer
|
||||
| {{currentSetting.textBelowCustomLoginLogo}}
|
||||
br
|
||||
section.auth-dialog
|
||||
if isLoading
|
||||
+loader
|
||||
|
||||
@@ -74,10 +74,24 @@ Template.userFormsLayout.helpers({
|
||||
let name = lang.name;
|
||||
if (lang.name === 'br') {
|
||||
name = 'Brezhoneg';
|
||||
} else if (lang.name === 'es-PY') {
|
||||
name = 'Español de Paraguayo';
|
||||
} else if (lang.name === 'fr-BE') {
|
||||
name = 'Français (Belgique)';
|
||||
} else if (lang.name === 'fr-CA') {
|
||||
name = 'Français (Canada)';
|
||||
} else if (lang.name === 'fr-CA') {
|
||||
name = 'Français (Canada)';
|
||||
} else if (lang.name === 'ig') {
|
||||
name = 'Igbo';
|
||||
} else if (lang.name === 'lv') {
|
||||
name = 'Latviešu';
|
||||
} else if (lang.name === 'latviešu valoda') {
|
||||
name = 'Latviešu';
|
||||
} else if (lang.name === 'oc') {
|
||||
name = 'Occitan';
|
||||
} else if (lang.name === 'st') {
|
||||
name = 'Sãotomense';
|
||||
} else if (lang.name === '繁体中文(台湾)') {
|
||||
name = '繁體中文(台灣)';
|
||||
}
|
||||
@@ -145,6 +159,19 @@ async function authentication(event, templateInstance) {
|
||||
});
|
||||
});
|
||||
|
||||
case 'saml':
|
||||
return new Promise(resolve => {
|
||||
const provider = Meteor.settings.public.SAML_PROVIDER;
|
||||
Meteor.loginWithSaml(
|
||||
{
|
||||
provider,
|
||||
},
|
||||
function() {
|
||||
resolve(FlowRouter.go('/'));
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
case 'cas':
|
||||
return new Promise(resolve => {
|
||||
Meteor.loginWithCas(match, password, function() {
|
||||
|
||||
@@ -276,7 +276,7 @@ kbd
|
||||
padding-bottom: 0
|
||||
|
||||
.wrapper
|
||||
max-width: 1200px
|
||||
width: calc(100% - 20px)
|
||||
margin: 0 auto
|
||||
|
||||
.relative
|
||||
@@ -388,10 +388,12 @@ a
|
||||
ol
|
||||
list-style-type: decimal
|
||||
padding-left: 20px
|
||||
padding-bottom: 10px
|
||||
|
||||
ul
|
||||
list-style-type: initial
|
||||
padding-left: 20px
|
||||
padding-bottom: 10px
|
||||
|
||||
em
|
||||
font-style : italic
|
||||
@@ -447,7 +449,6 @@ a
|
||||
flex-direction: column
|
||||
align-items: center
|
||||
justify-content: center
|
||||
height: 100%
|
||||
|
||||
.auth-dialog
|
||||
margin: 0 !important
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
template(name="myCardsHeaderBar")
|
||||
if currentUser
|
||||
h1
|
||||
//a.back-btn(href="{{pathFor 'home'}}")
|
||||
// i.fa.fa-chevron-left
|
||||
i.fa.fa-list
|
||||
| {{_ 'my-cards'}}
|
||||
|
||||
.board-header-btns.left
|
||||
a.board-header-btn.js-toggle-my-cards-choose-sort(title="{{_ 'myCardsSortChange-title'}}")
|
||||
i.fa.fa-caret-down
|
||||
if $eq myCardsSort 'board'
|
||||
i.fa.fa-th-large
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq myCardsSort 'dueAt'
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
|
||||
template(name="myCardsModalTitle")
|
||||
if currentUser
|
||||
h2
|
||||
i.fa.fa-keyboard-o
|
||||
| {{_ 'my-cards'}}
|
||||
|
||||
template(name="myCards")
|
||||
if currentUser
|
||||
if isPageReady.get
|
||||
.wrapper
|
||||
if $eq myCardsSort 'board'
|
||||
each board in myCardsList
|
||||
.my-cards-board-wrapper
|
||||
.my-cards-board-title
|
||||
+viewer
|
||||
= board.title
|
||||
each swimlane in board.mySwimlanes
|
||||
.my-cards-swimlane-title(class="{{#if swimlane.colorClass}}{{ swimlane.colorClass }}{{else}}swimlane-default-color{{/if}}")
|
||||
+viewer
|
||||
= swimlane.title
|
||||
each list in swimlane.myLists
|
||||
.my-cards-list-wrapper
|
||||
.my-cards-list-title(class=list.colorClass)
|
||||
+viewer
|
||||
= list.title
|
||||
each card in list.myCards
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
else
|
||||
.my-cards-dueat-list-wrapper
|
||||
each card in myDueCardsList
|
||||
.my-cards-card-wrapper
|
||||
a.minicard-wrapper.card-title(href=card.absoluteUrl)
|
||||
+minicard(card)
|
||||
ul.my-cards-context-list
|
||||
li.my-cards-context(title="{{_ 'board'}}")
|
||||
+viewer
|
||||
= card.getBoard.title
|
||||
li.my-cards-context.my-cards-context-separator
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'swimlane'}}")
|
||||
+viewer
|
||||
= card.getSwimlane.title
|
||||
li.my-cards-context
|
||||
= ' '
|
||||
| {{_ 'context-separator'}}
|
||||
= ' '
|
||||
li.my-cards-context(title="{{_ 'list'}}")
|
||||
+viewer
|
||||
= card.getList.title
|
||||
else
|
||||
+spinner
|
||||
|
||||
template(name="myCardsSortChangePopup")
|
||||
if currentUser
|
||||
ul.pop-over-list
|
||||
li
|
||||
with "my-cards-sort-board"
|
||||
a.js-my-cards-sort-board
|
||||
i.fa.fa-th-large.colorful
|
||||
| {{_ 'myCardsSortChange-choice-board'}}
|
||||
if $eq Utils.myCardsSort "board"
|
||||
i.fa.fa-check
|
||||
hr
|
||||
li
|
||||
with "my-cards-sort-dueat"
|
||||
a.js-my-cards-sort-dueat
|
||||
i.fa.fa-calendar.colorful
|
||||
| {{_ 'myCardsSortChange-choice-dueat'}}
|
||||
if $eq Utils.myCardsSort "dueAt"
|
||||
i.fa.fa-check
|
||||
@@ -0,0 +1,250 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
myCardsSort() {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('sort:', Utils.myCardsSort());
|
||||
return Utils.myCardsSort();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-toggle-my-cards-choose-sort': Popup.open(
|
||||
'myCardsSortChange',
|
||||
),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('myCardsHeaderBar');
|
||||
|
||||
Template.myCards.helpers({
|
||||
userId() {
|
||||
return Meteor.userId();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-my-cards-sort-board'() {
|
||||
Utils.setMyCardsSort('board');
|
||||
Popup.close();
|
||||
},
|
||||
|
||||
'click .js-my-cards-sort-dueat'() {
|
||||
Utils.setMyCardsSort('dueAt');
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('myCardsSortChangePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.isPageReady = new ReactiveVar(false);
|
||||
|
||||
this.autorun(() => {
|
||||
const handle = subManager.subscribe('myCards');
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
this.isPageReady.set(handle.ready());
|
||||
});
|
||||
});
|
||||
});
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
myCardsSort() {
|
||||
// eslint-disable-next-line no-console
|
||||
//console.log('sort:', Utils.myCardsSort());
|
||||
return Utils.myCardsSort();
|
||||
},
|
||||
|
||||
sortByBoard() {
|
||||
return this.myCardsSort() === 'board';
|
||||
},
|
||||
|
||||
myCardsList() {
|
||||
const userId = Meteor.userId();
|
||||
const boards = [];
|
||||
let board = null;
|
||||
let swimlane = null;
|
||||
let list = null;
|
||||
|
||||
const cursor = Cards.find(
|
||||
{
|
||||
$or: [{ members: userId }, { assignees: userId }],
|
||||
archived: false,
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
boardId: 1,
|
||||
swimlaneId: 1,
|
||||
listId: 1,
|
||||
sort: 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
let newBoard = false;
|
||||
let newSwimlane = false;
|
||||
let newList = false;
|
||||
|
||||
cursor.forEach(card => {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('card:', card.title);
|
||||
if (list === null || card.listId !== list._id) {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('new list');
|
||||
list = card.getList();
|
||||
if (list.archived) {
|
||||
list = null;
|
||||
return;
|
||||
}
|
||||
list.myCards = [card];
|
||||
newList = true;
|
||||
}
|
||||
if (swimlane === null || card.swimlaneId !== swimlane._id) {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('new swimlane');
|
||||
swimlane = card.getSwimlane();
|
||||
if (swimlane.archived) {
|
||||
swimlane = null;
|
||||
return;
|
||||
}
|
||||
swimlane.myLists = [list];
|
||||
newSwimlane = true;
|
||||
}
|
||||
if (board === null || card.boardId !== board._id) {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('new board');
|
||||
board = card.getBoard();
|
||||
if (board.archived) {
|
||||
board = null;
|
||||
return;
|
||||
}
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('board:', b, b._id, b.title);
|
||||
board.mySwimlanes = [swimlane];
|
||||
newBoard = true;
|
||||
}
|
||||
|
||||
if (newBoard) {
|
||||
boards.push(board);
|
||||
} else if (newSwimlane) {
|
||||
board.mySwimlanes.push(swimlane);
|
||||
} else if (newList) {
|
||||
swimlane.myLists.push(list);
|
||||
} else {
|
||||
list.myCards.push(card);
|
||||
}
|
||||
|
||||
newBoard = false;
|
||||
newSwimlane = false;
|
||||
newList = false;
|
||||
});
|
||||
|
||||
// sort the data structure
|
||||
boards.forEach(board => {
|
||||
board.mySwimlanes.forEach(swimlane => {
|
||||
swimlane.myLists.forEach(list => {
|
||||
list.myCards.sort((a, b) => {
|
||||
return a.sort - b.sort;
|
||||
});
|
||||
});
|
||||
swimlane.myLists.sort((a, b) => {
|
||||
return a.sort - b.sort;
|
||||
});
|
||||
});
|
||||
board.mySwimlanes.sort((a, b) => {
|
||||
return a.sort - b.sort;
|
||||
});
|
||||
});
|
||||
|
||||
boards.sort((a, b) => {
|
||||
let x = a.sort;
|
||||
let y = b.sort;
|
||||
|
||||
// show the template board last
|
||||
if (a.type === 'template-container') {
|
||||
x = 99999999;
|
||||
} else if (b.type === 'template-container') {
|
||||
y = 99999999;
|
||||
}
|
||||
return x - y;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('boards:', boards);
|
||||
return boards;
|
||||
},
|
||||
|
||||
myDueCardsList() {
|
||||
const userId = Meteor.userId();
|
||||
|
||||
const cursor = Cards.find(
|
||||
{
|
||||
$or: [{ members: userId }, { assignees: userId }],
|
||||
archived: false,
|
||||
},
|
||||
{
|
||||
sort: {
|
||||
dueAt: -1,
|
||||
boardId: 1,
|
||||
swimlaneId: 1,
|
||||
listId: 1,
|
||||
sort: 1,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('cursor:', cursor);
|
||||
|
||||
const cards = [];
|
||||
cursor.forEach(card => {
|
||||
if (
|
||||
!card.getBoard().archived &&
|
||||
!card.getSwimlane().archived &&
|
||||
!card.getList().archived
|
||||
) {
|
||||
cards.push(card);
|
||||
}
|
||||
});
|
||||
|
||||
cards.sort((a, b) => {
|
||||
const x = a.dueAt === null ? Date('2100-12-31') : a.dueAt;
|
||||
const y = b.dueAt === null ? Date('2100-12-31') : b.dueAt;
|
||||
|
||||
if (x > y) return 1;
|
||||
else if (x < y) return -1;
|
||||
|
||||
return 0;
|
||||
});
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('cursor:', cards);
|
||||
return cards;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
// 'click .js-my-card'(evt) {
|
||||
// const card = this.currentData().card;
|
||||
// // eslint-disable-next-line no-console
|
||||
// console.log('currentData():', this.currentData());
|
||||
// // eslint-disable-next-line no-console
|
||||
// console.log('card:', card);
|
||||
// if (card) {
|
||||
// Utils.goCardId(card._id);
|
||||
// }
|
||||
// evt.preventDefault();
|
||||
// },
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('myCards');
|
||||
@@ -0,0 +1,69 @@
|
||||
.my-cards-board-wrapper
|
||||
border-radius: 8px
|
||||
//padding: 0.5rem
|
||||
min-width: 400px
|
||||
border-width: 8px
|
||||
border-color: grey
|
||||
border-style: solid
|
||||
margin-bottom: 2rem
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.my-cards-board-title
|
||||
font-size: 1.4rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
background-color: grey
|
||||
color: white
|
||||
|
||||
.my-cards-swimlane-title
|
||||
font-size: 1.1rem
|
||||
font-weight: bold
|
||||
padding: 0.5rem
|
||||
padding-bottom: 0.4rem
|
||||
margin-top: 0
|
||||
margin-bottom: 0.5rem
|
||||
//border-top: black 1px solid
|
||||
//border-bottom: black 1px solid
|
||||
text-align: center
|
||||
|
||||
.swimlane-default-color
|
||||
background-color: lightgrey
|
||||
|
||||
.my-cards-list-title
|
||||
font-weight: bold
|
||||
font-size: 1.1rem
|
||||
//padding-bottom: 0
|
||||
//margin-bottom: 0
|
||||
text-align: center
|
||||
margin-bottom: 0.7rem
|
||||
|
||||
.my-cards-list-wrapper
|
||||
margin: 1rem
|
||||
border-radius: 5px
|
||||
padding: 1.5rem
|
||||
padding-top: 0.75rem
|
||||
display: inline-block
|
||||
min-width: 250px
|
||||
max-width: 350px
|
||||
|
||||
.my-cards-card-wrapper
|
||||
margin-top: 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.my-cards-dueat-list-wrapper
|
||||
max-width: 500px
|
||||
margin-right: auto
|
||||
margin-left: auto
|
||||
|
||||
.my-cards-field-name
|
||||
font-weight: bold
|
||||
|
||||
.my-cards-context
|
||||
display: inline-block
|
||||
|
||||
.my-cards-context-separator
|
||||
font-weight: bold
|
||||
|
||||
.my-cards-context-list
|
||||
margin-bottom: 0.7rem
|
||||
@@ -107,11 +107,6 @@ $popupWidth = 300px
|
||||
padding: 8px 4px 8px 10px
|
||||
margin-right: 8px
|
||||
|
||||
&::-webkit-scrollbar-button
|
||||
display: block
|
||||
height: 4px
|
||||
width: 4px
|
||||
|
||||
.at-form
|
||||
.at-error, .at-result
|
||||
padding: 8px 12px
|
||||
|
||||
@@ -1,16 +0,0 @@
|
||||
const { isTouchDevice } = Utils;
|
||||
|
||||
Mixins.PerfectScrollbar = BlazeComponent.extendComponent({
|
||||
onRendered() {
|
||||
if (!isTouchDevice()) {
|
||||
const component = this.mixinParent();
|
||||
const domElement = component.find('.js-perfect-scrollbar');
|
||||
Ps.initialize(domElement);
|
||||
|
||||
// XXX We should create an event map to be consistent with other components
|
||||
// but since BlazeComponent doesn't merge Mixins events transparently I
|
||||
// prefered to use a jQuery event (which is what an event map ends up doing)
|
||||
component.$(domElement).on('mouseenter', () => Ps.update(domElement));
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -1,2 +0,0 @@
|
||||
.ps-container
|
||||
position: relative
|
||||
@@ -26,6 +26,10 @@ template(name='notificationIcon')
|
||||
i.fa.fa-code.activity-type(title="custom field")
|
||||
else if($in activityType 'addedLabel' 'removedLabel')
|
||||
i.fa.fa-tag.activity-type(title="label")
|
||||
else if($in activityType 'a-startAt' 'a-receivedAt')
|
||||
i.fa.fa-clock-o.activity-type(title="date")
|
||||
else if($in activityType 'a-dueAt' 'a-endAt')
|
||||
i.fa.fa-clock-o.activity-type(title="date")
|
||||
|
||||
else if($in activityType 'createList' 'removeList' 'archivedList')
|
||||
+listNotificationIcon
|
||||
|
||||
@@ -3,32 +3,32 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-action")
|
||||
option(value="setDate") {{{_'r-set'}}}
|
||||
option(value="updateDate") {{{_'r-update'}}}
|
||||
option(value="setDate") {{_'r-set'}}
|
||||
option(value="updateDate") {{_'r-update'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-datefield'}}}
|
||||
| {{_'r-datefield'}}
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-datefield")
|
||||
option(value="startAt") {{{_'r-df-start-at'}}}
|
||||
option(value="dueAt") {{{_'r-df-due-at'}}}
|
||||
option(value="endAt") {{{_'r-df-end-at'}}}
|
||||
option(value="receivedAt") {{{_'r-df-received-at'}}}
|
||||
option(value="startAt") {{_'r-df-start-at'}}
|
||||
option(value="dueAt") {{_'r-df-due-at'}}
|
||||
option(value="endAt") {{_'r-df-end-at'}}
|
||||
option(value="receivedAt") {{_'r-df-received-at'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-to-current-datetime'}}}
|
||||
| {{_'r-to-current-datetime'}}
|
||||
div.trigger-button.js-set-date-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-remove-value-from'}}}
|
||||
| {{{_'r-datefield'}}}
|
||||
| {{_'r-remove-value-from'}}
|
||||
| {{_'r-datefield'}}
|
||||
div.trigger-dropdown
|
||||
select(id="setdate-removedatefieldvalue")
|
||||
option(value="startAt") {{{_'r-df-start-at'}}}
|
||||
option(value="dueAt") {{{_'r-df-due-at'}}}
|
||||
option(value="endAt") {{{_'r-df-end-at'}}}
|
||||
option(value="receivedAt") {{{_'r-df-received-at'}}}
|
||||
option(value="startAt") {{_'r-df-start-at'}}
|
||||
option(value="dueAt") {{_'r-df-due-at'}}
|
||||
option(value="endAt") {{_'r-df-end-at'}}
|
||||
option(value="receivedAt") {{_'r-df-received-at'}}
|
||||
div.trigger-button.js-remove-datevalue-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -36,10 +36,10 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="label-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-label'}}}
|
||||
| {{_'r-label'}}
|
||||
div.trigger-dropdown
|
||||
select(id="label-id")
|
||||
each labels
|
||||
@@ -52,30 +52,30 @@ template(name="cardActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="member-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-member'}}}
|
||||
| {{_'r-member'}}
|
||||
div.trigger-dropdown
|
||||
input(id="member-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="member-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-member-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-remove-all'}}}
|
||||
| {{_'r-remove-all'}}
|
||||
div.trigger-button.js-add-removeall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-set-color'}}}
|
||||
| {{_'r-set-color'}}
|
||||
button.trigger-button.trigger-button-color.js-show-color-palette(
|
||||
id="color-action"
|
||||
class="card-details-{{cardColorButton}}")
|
||||
| {{{_ cardColorButtonText }}}
|
||||
| {{_ cardColorButtonText }}
|
||||
div.trigger-button.js-set-color-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
option(value="add") {{_'r-add'}}
|
||||
option(value="remove") {{_'r-remove'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist'}}}
|
||||
| {{_'r-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-checklist-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -16,12 +16,12 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="checkall-action")
|
||||
option(value="check") {{{_'r-check-all'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck-all'}}}
|
||||
option(value="check") {{_'r-check-all'}}
|
||||
option(value="uncheck") {{_'r-uncheck-all'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-items-check'}}}
|
||||
| {{_'r-items-check'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name2",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name2",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-checkall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -30,36 +30,36 @@ template(name="checklistActions")
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-item-action")
|
||||
option(value="check") {{{_'r-check'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck'}}}
|
||||
option(value="check") {{_'r-check'}}
|
||||
option(value="uncheck") {{_'r-uncheck'}}
|
||||
div.trigger-text
|
||||
| {{{_'r-item'}}}
|
||||
| {{_'r-item'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checkitem-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checkitem-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-of-checklist'}}}
|
||||
| {{_'r-of-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name3",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-check-item-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-add-checklist'}}}
|
||||
| {{_'r-add-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name-3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
input(id="checklist-name-3",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-with-items'}}}
|
||||
| {{_'r-with-items'}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-items",type=text,placeholder="{{{_'r-items-list'}}}")
|
||||
input(id="checklist-items",type=text,placeholder="{{_'r-items-list'}}")
|
||||
div.trigger-button.js-add-checklist-items-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist-note'}}}
|
||||
| {{_'r-checklist-note'}}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2,14 +2,18 @@ template(name="ruleDetails")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule-details' }}}
|
||||
| {{_ 'r-rule-details' }}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-main-body
|
||||
h4
|
||||
| {{_ 'r-trigger'}}
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
= trigger
|
||||
= trigger
|
||||
h4
|
||||
| {{_ 'r-action'}}
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
@@ -17,4 +21,4 @@ template(name="ruleDetails")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -2,10 +2,12 @@
|
||||
overflow:hidden
|
||||
overflow-y:scroll
|
||||
max-height: 400px
|
||||
padding-right: 5px
|
||||
.rules-lists-item
|
||||
display: block
|
||||
position: relative
|
||||
overflow: auto
|
||||
border-bottom: 1px solid #bfbfbf
|
||||
p
|
||||
display: inline-block
|
||||
float: left
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="rulesActions")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-action'}}}
|
||||
| {{_ 'r-rule' }} "#{data.ruleName.get}" - {{_ 'r-add-action'}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
@@ -26,4 +26,4 @@ template(name="rulesActions")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -2,7 +2,7 @@ template(name="rulesList")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-board-rules' }}}
|
||||
| {{_ 'r-board-rules' }}
|
||||
|
||||
ul.rules-list
|
||||
each rules
|
||||
@@ -12,26 +12,26 @@ template(name="rulesList")
|
||||
div.rules-btns-group
|
||||
button.js-goto-details
|
||||
i.fa.fa-eye
|
||||
| {{{_ 'r-view-rule'}}}
|
||||
| {{_ 'r-view-rule'}}
|
||||
if currentUser.isAdmin
|
||||
button.js-delete-rule
|
||||
i.fa.fa-trash-o
|
||||
| {{{_ 'r-delete-rule'}}}
|
||||
| {{_ 'r-delete-rule'}}
|
||||
else if currentUser.isBoardAdmin
|
||||
button.js-delete-rule
|
||||
i.fa.fa-trash-o
|
||||
| {{{_ 'r-delete-rule'}}}
|
||||
| {{_ 'r-delete-rule'}}
|
||||
else
|
||||
li.no-items-message {{{_ 'r-no-rules' }}}
|
||||
li.no-items-message {{_ 'r-no-rules' }}
|
||||
if currentUser.isAdmin
|
||||
div.rules-add
|
||||
button.js-goto-trigger
|
||||
i.fa.fa-plus
|
||||
| {{{_ 'r-add-rule'}}}
|
||||
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
|
||||
| {{_ 'r-add-rule'}}
|
||||
input(type=text,placeholder="{{_ 'r-new-rule-name' }}",id="ruleTitle")
|
||||
else if currentUser.isBoardAdmin
|
||||
div.rules-add
|
||||
button.js-goto-trigger
|
||||
i.fa.fa-plus
|
||||
| {{{_ 'r-add-rule'}}}
|
||||
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
|
||||
| {{_ 'r-add-rule'}}
|
||||
input(type=text,placeholder="{{_ 'r-new-rule-name' }}",id="ruleTitle")
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="rulesTriggers")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-trigger'}}}
|
||||
| {{_ 'r-rule' }} "#{data.ruleName.get}" - {{_ 'r-add-trigger'}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
@@ -22,4 +22,4 @@ template(name="rulesTriggers")
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
| {{_ 'back'}}
|
||||
@@ -100,7 +100,7 @@ template(name="boardTriggers")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-board-note'}}}
|
||||
| {{_'r-board-note'}}
|
||||
|
||||
template(name="boardCardTitlePopup")
|
||||
form
|
||||
@@ -109,8 +109,3 @@ template(name="boardCardTitlePopup")
|
||||
input.js-card-filter-name(type="text" value=title autofocus)
|
||||
input.js-card-filter-button.primary.wide(type="submit" value="{{_ 'set-filter'}}")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5,34 +5,105 @@ template(name="people")
|
||||
else
|
||||
.content-title.ext-box
|
||||
.ext-box-left
|
||||
span
|
||||
i.fa.fa-users
|
||||
| {{_ 'people'}}
|
||||
input#searchInput(placeholder="{{_ 'search'}}")
|
||||
button#searchButton
|
||||
i.fa.fa-search
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{_ 'people-number'}} #{peopleNumber}
|
||||
if loading.get
|
||||
+spinner
|
||||
else if orgSetting.get
|
||||
span
|
||||
i.fa.fa-sitemap
|
||||
unless isMiniScreen
|
||||
| {{_ 'organizations'}}
|
||||
input#searchOrgInput(placeholder="{{_ 'search'}}")
|
||||
button#searchOrgButton
|
||||
i.fa.fa-search
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{#unless isMiniScreen}}{{_ 'org-number'}}{{/unless}} #{orgNumber}
|
||||
else if teamSetting.get
|
||||
span
|
||||
i.fa.fa-users
|
||||
unless isMiniScreen
|
||||
| {{_ 'teams'}}
|
||||
input#searchTeamInput(placeholder="{{_ 'search'}}")
|
||||
button#searchTeamButton
|
||||
i.fa.fa-search
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{#unless isMiniScreen}}{{_ 'team-number'}}{{/unless}} #{teamNumber}
|
||||
else if peopleSetting.get
|
||||
span
|
||||
i.fa.fa-user
|
||||
unless isMiniScreen
|
||||
| {{_ 'people'}}
|
||||
input#searchInput(placeholder="{{_ 'search'}}")
|
||||
button#searchButton
|
||||
i.fa.fa-search
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{#unless isMiniScreen}}{{_ 'people-number'}}{{/unless}} #{peopleNumber}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="people-setting")
|
||||
a.js-org-menu(data-id="org-setting")
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'organizations'}}
|
||||
li
|
||||
a.js-team-menu(data-id="team-setting")
|
||||
i.fa.fa-users
|
||||
| {{_ 'teams'}}
|
||||
li
|
||||
a.js-people-menu(data-id="people-setting")
|
||||
i.fa.fa-user
|
||||
| {{_ 'people'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if people.get
|
||||
else if orgSetting.get
|
||||
+orgGeneral
|
||||
else if teamSetting.get
|
||||
+teamGeneral
|
||||
else if peopleSetting.get
|
||||
+peopleGeneral
|
||||
|
||||
|
||||
template(name="orgGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'displayName'}}
|
||||
th {{_ 'description'}}
|
||||
th {{_ 'shortName'}}
|
||||
th {{_ 'website'}}
|
||||
th {{_ 'teams'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
th
|
||||
+newOrgRow
|
||||
each org in orgList
|
||||
+orgRow(orgId=org._id)
|
||||
|
||||
template(name="teamGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'displayName'}}
|
||||
th {{_ 'description'}}
|
||||
th {{_ 'shortName'}}
|
||||
th {{_ 'website'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
th
|
||||
+newTeamRow
|
||||
each team in teamList
|
||||
+teamRow(teamId=team._id)
|
||||
|
||||
template(name="peopleGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'username'}}
|
||||
th {{_ 'fullname'}}
|
||||
th {{_ 'initials'}}
|
||||
th {{_ 'admin'}}
|
||||
th {{_ 'email'}}
|
||||
th {{_ 'verified'}}
|
||||
@@ -44,11 +115,93 @@ template(name="peopleGeneral")
|
||||
each user in peopleList
|
||||
+peopleRow(userId=user._id)
|
||||
|
||||
template(name="newOrgRow")
|
||||
a.new-org
|
||||
i.fa.fa-edit
|
||||
| {{_ 'new'}}
|
||||
|
||||
template(name="newTeamRow")
|
||||
a.new-team
|
||||
i.fa.fa-edit
|
||||
| {{_ 'new'}}
|
||||
|
||||
template(name="newUserRow")
|
||||
a.new-user
|
||||
i.fa.fa-edit
|
||||
| {{_ 'new'}}
|
||||
|
||||
template(name="orgRow")
|
||||
tr
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.displayName }}</s>
|
||||
else
|
||||
td {{ orgData.displayName }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.orgDesc }}</s>
|
||||
else
|
||||
td {{ orgData.desc }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.name }}</s>
|
||||
else
|
||||
td {{ orgData.name }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.website }}</s>
|
||||
else
|
||||
td {{ orgData.website }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.teams }}</s>
|
||||
else
|
||||
td {{ orgData.teams }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ moment orgData.createdAt 'LLL' }}</s>
|
||||
else
|
||||
td {{ moment orgData.createdAt 'LLL' }}
|
||||
td
|
||||
if orgData.loginDisabled
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
td
|
||||
a.edit-org
|
||||
i.fa.fa-edit
|
||||
| {{_ 'edit'}}
|
||||
a.more-settings-org
|
||||
i.fa.fa-ellipsis-h
|
||||
|
||||
template(name="teamRow")
|
||||
tr
|
||||
if teamData.loginDisabled
|
||||
td <s>{{ teamData.displayName }}</s>
|
||||
else
|
||||
td {{ teamData.displayName }}
|
||||
if teamData.loginDisabled
|
||||
td <s>{{ teamData.desc }}</s>
|
||||
else
|
||||
td {{ teamData.desc }}
|
||||
if teamData.loginDisabled
|
||||
td <s>{{ teamData.dame }}</s>
|
||||
else
|
||||
td {{ teamData.name }}
|
||||
if teamData.loginDisabled
|
||||
td <s>{{ teamData.website }}</s>
|
||||
else
|
||||
td {{ teamData.website }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ moment teamData.createdAt 'LLL' }}</s>
|
||||
else
|
||||
td {{ moment teamData.createdAt 'LLL' }}
|
||||
td
|
||||
if teamData.loginDisabled
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
td
|
||||
a.edit-team
|
||||
i.fa.fa-edit
|
||||
| {{_ 'edit'}}
|
||||
a.more-settings-team
|
||||
i.fa.fa-ellipsis-h
|
||||
|
||||
template(name="peopleRow")
|
||||
tr
|
||||
if userData.loginDisabled
|
||||
@@ -59,6 +212,10 @@ template(name="peopleRow")
|
||||
td <s>{{ userData.profile.fullname }}</s>
|
||||
else
|
||||
td {{ userData.profile.fullname }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.profile.initials }}</s>
|
||||
else
|
||||
td {{ userData.profile.initials }}
|
||||
if userData.loginDisabled
|
||||
td
|
||||
if userData.isAdmin
|
||||
@@ -104,13 +261,64 @@ template(name="peopleRow")
|
||||
a.edit-user
|
||||
i.fa.fa-edit
|
||||
| {{_ 'edit'}}
|
||||
a.more-settings-user
|
||||
i.fa.fa-ellipsis-h
|
||||
|
||||
template(name="editOrgPopup")
|
||||
form
|
||||
label.hide.orgId(type="text" value=org._id)
|
||||
label
|
||||
| {{_ 'orgDisplayName'}}
|
||||
input.js-orgDisplayName(type="text" value=org.displayName required)
|
||||
span.error.hide.orgname-taken
|
||||
| {{_ 'error-orgname-taken'}}
|
||||
label
|
||||
| {{_ 'orgDesc'}}
|
||||
input.js-orgDesc(type="text" value=org.desc required)
|
||||
label
|
||||
| {{_ 'orgName'}}
|
||||
input.js-orgName(type="text" value=org.name required)
|
||||
label
|
||||
| {{_ 'orgWebsite'}}
|
||||
input.js-orgWebsite(type="text" value=org.website required)
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-org-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{org.loginDisabled}}") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="editTeamPopup")
|
||||
form
|
||||
label.hide.teamId(type="text" value=team._id)
|
||||
label
|
||||
| {{_ 'displayName'}}
|
||||
input.js-teamDisplayName(type="text" value=team.displayName required)
|
||||
span.error.hide.teamname-taken
|
||||
| {{_ 'error-teamname-taken'}}
|
||||
label
|
||||
| {{_ 'description'}}
|
||||
input.js-orgDesc(type="text" value=org.desc required)
|
||||
label
|
||||
| {{_ 'name'}}
|
||||
input.js-orgName(type="text" value=org.name required)
|
||||
label
|
||||
| {{_ 'website'}}
|
||||
input.js-orgWebsite(type="text" value=org.website required)
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-team-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{team.loginDisabled}}") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="editUserPopup")
|
||||
form
|
||||
label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname)
|
||||
label
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
@@ -118,7 +326,18 @@ template(name="editUserPopup")
|
||||
if isLdap
|
||||
input.js-profile-username(type="text" value=user.username readonly)
|
||||
else
|
||||
input.js-profile-username(type="text" value=user.username)
|
||||
input.js-profile-username(type="text" value=user.username required)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname required)
|
||||
label
|
||||
| {{_ 'initials'}}
|
||||
input.js-profile-initials(type="text" value=user.profile.initials)
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
option(value="false") {{_ 'no'}}
|
||||
option(value="true" selected="{{user.isAdmin}}") {{_ 'yes'}}
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
@@ -126,12 +345,12 @@ template(name="editUserPopup")
|
||||
if isLdap
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
|
||||
else
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}")
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}" required)
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
| {{_ 'verified'}}
|
||||
select.select-verified.js-profile-email-verified
|
||||
option(value="false") {{_ 'no'}}
|
||||
option(value="true" selected="{{user.isAdmin}}") {{_ 'yes'}}
|
||||
option(value="true" selected="{{userData.emails.[0].verified}}") {{_ 'yes'}}
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-profile-isactive
|
||||
@@ -151,15 +370,64 @@ template(name="editUserPopup")
|
||||
input.js-profile-password(type="password")
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
// div
|
||||
// input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
|
||||
|
||||
template(name="newOrgPopup")
|
||||
form
|
||||
//label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'displayName'}}
|
||||
input.js-displayName(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'description'}}
|
||||
input.js-desc(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'shortName'}}
|
||||
input.js-name(type="text" value="")
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
input.js-teams(type="text" value="")
|
||||
label
|
||||
| {{_ 'website'}}
|
||||
input.js-website(type="text" value="")
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-profile-isactive
|
||||
option(value="false" selected="selected") {{_ 'yes'}}
|
||||
option(value="true") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="newTeamPopup")
|
||||
form
|
||||
//label.hide.teamId(type="text" value=team._id)
|
||||
label
|
||||
| {{_ 'displayName'}}
|
||||
input.js-teamDisplayName(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'description'}}
|
||||
input.js-teamDesc(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'shortName'}}
|
||||
input.js-teamName(type="text" value="")
|
||||
label
|
||||
| {{_ 'website'}}
|
||||
input.js-teamWebsite(type="text" value="")
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-profile-isactive
|
||||
option(value="false" selected="selected") {{_ 'yes'}}
|
||||
option(value="true") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="newUserPopup")
|
||||
form
|
||||
//label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value="")
|
||||
input.js-profile-fullname(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
@@ -167,7 +435,7 @@ template(name="newUserPopup")
|
||||
//if isLdap
|
||||
// input.js-profile-username(type="text" value=user.username readonly)
|
||||
//else
|
||||
input.js-profile-username(type="text" value="")
|
||||
input.js-profile-username(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
@@ -175,7 +443,7 @@ template(name="newUserPopup")
|
||||
//if isLdap
|
||||
// input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
|
||||
//else
|
||||
input.js-profile-email(type="email" value="")
|
||||
input.js-profile-email(type="email" value="" required)
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
@@ -197,6 +465,56 @@ template(name="newUserPopup")
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
input.js-profile-password(type="password")
|
||||
input.js-profile-password(type="password" required)
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="settingsOrgPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.impersonate-org
|
||||
i.fa.fa-user
|
||||
| {{_ 'impersonate-org'}}
|
||||
// Delete is not enabled yet, because it does leave empty user avatars
|
||||
// to boards: boards members, card members and assignees have
|
||||
// empty users. See:
|
||||
// - wekan/client/components/settings/peopleBody.jade deleteButton
|
||||
// - wekan/client/components/settings/peopleBody.js deleteButton
|
||||
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
|
||||
// that does now remove member from board, card members and assignees correctly,
|
||||
// but that should be used to remove user from all boards similarly
|
||||
// - wekan/models/users.js Delete is not enabled
|
||||
//li
|
||||
// br
|
||||
// br
|
||||
// hr
|
||||
//li
|
||||
// form
|
||||
// label.hide.userId(type="text" value=user._id)
|
||||
// div.buttonsContainer
|
||||
// input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
|
||||
|
||||
template(name="settingsUserPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.impersonate-user
|
||||
i.fa.fa-user
|
||||
| {{_ 'impersonate-user'}}
|
||||
// Delete is not enabled yet, because it does leave empty user avatars
|
||||
// to boards: boards members, card members and assignees have
|
||||
// empty users. See:
|
||||
// - wekan/client/components/settings/peopleBody.jade deleteButton
|
||||
// - wekan/client/components/settings/peopleBody.js deleteButton
|
||||
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
|
||||
// that does now remove member from board, card members and assignees correctly,
|
||||
// but that should be used to remove user from all boards similarly
|
||||
// - wekan/models/users.js Delete is not enabled
|
||||
//li
|
||||
// br
|
||||
// br
|
||||
// hr
|
||||
//li
|
||||
// form
|
||||
// label.hide.userId(type="text" value=user._id)
|
||||
// div.buttonsContainer
|
||||
// input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
|
||||
@@ -1,3 +1,5 @@
|
||||
const orgsPerPage = 25;
|
||||
const teamsPerPage = 25;
|
||||
const usersPerPage = 25;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -7,17 +9,45 @@ BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.people = new ReactiveVar(true);
|
||||
this.orgSetting = new ReactiveVar(true);
|
||||
this.teamSetting = new ReactiveVar(true);
|
||||
this.peopleSetting = new ReactiveVar(true);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
this.findTeamsOptions = new ReactiveVar({});
|
||||
this.findUsersOptions = new ReactiveVar({});
|
||||
this.number = new ReactiveVar(0);
|
||||
this.numberOrgs = new ReactiveVar(0);
|
||||
this.numberTeams = new ReactiveVar(0);
|
||||
this.numberPeople = new ReactiveVar(0);
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.loadNextPageLocked = false;
|
||||
this.callFirstWith(null, 'resetNextPeak');
|
||||
this.autorun(() => {
|
||||
const limit = this.page.get() * usersPerPage;
|
||||
const limitOrgs = this.page.get() * orgsPerPage;
|
||||
const limitTeams = this.page.get() * teamsPerPage;
|
||||
const limitUsers = this.page.get() * usersPerPage;
|
||||
|
||||
this.subscribe('people', this.findUsersOptions.get(), limit, () => {
|
||||
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
|
||||
this.calculateNextPeak();
|
||||
const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
|
||||
if (nextPeakBefore === nextPeakAfter) {
|
||||
this.callFirstWith(null, 'resetNextPeak');
|
||||
}
|
||||
});
|
||||
|
||||
this.subscribe('team', this.findTeamsOptions.get(), limitTeams, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
|
||||
this.calculateNextPeak();
|
||||
const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
|
||||
if (nextPeakBefore === nextPeakAfter) {
|
||||
this.callFirstWith(null, 'resetNextPeak');
|
||||
}
|
||||
});
|
||||
|
||||
this.subscribe('people', this.findUsersOptions.get(), limitUsers, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
|
||||
this.calculateNextPeak();
|
||||
@@ -31,6 +61,22 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click #searchOrgButton'() {
|
||||
this.filterOrg();
|
||||
},
|
||||
'keydown #searchOrgInput'(event) {
|
||||
if (event.keyCode === 13 && !event.shiftKey) {
|
||||
this.filterOrg();
|
||||
}
|
||||
},
|
||||
'click #searchTeamButton'() {
|
||||
this.filterTeam();
|
||||
},
|
||||
'keydown #searchTeamInput'(event) {
|
||||
if (event.keyCode === 13 && !event.shiftKey) {
|
||||
this.filterTeam();
|
||||
}
|
||||
},
|
||||
'click #searchButton'() {
|
||||
this.filterPeople();
|
||||
},
|
||||
@@ -39,9 +85,18 @@ BlazeComponent.extendComponent({
|
||||
this.filterPeople();
|
||||
}
|
||||
},
|
||||
'click #newOrgButton'() {
|
||||
Popup.open('newOrg');
|
||||
},
|
||||
'click #newTeamButton'() {
|
||||
Popup.open('newTeam');
|
||||
},
|
||||
'click #newUserButton'() {
|
||||
Popup.open('newUser');
|
||||
},
|
||||
'click a.js-org-menu': this.switchMenu,
|
||||
'click a.js-team-menu': this.switchMenu,
|
||||
'click a.js-people-menu': this.switchMenu,
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -84,18 +139,63 @@ BlazeComponent.extendComponent({
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
orgList() {
|
||||
const orgs = Org.find(this.findOrgsOptions.get(), {
|
||||
fields: { _id: true },
|
||||
});
|
||||
this.numberOrgs.set(org.count(false));
|
||||
return orgs;
|
||||
},
|
||||
teamList() {
|
||||
const teams = Team.find(this.findTeamsOptions.get(), {
|
||||
fields: { _id: true },
|
||||
});
|
||||
this.numberTeams.set(team.count(false));
|
||||
return teams;
|
||||
},
|
||||
peopleList() {
|
||||
const users = Users.find(this.findUsersOptions.get(), {
|
||||
fields: { _id: true },
|
||||
});
|
||||
this.number.set(users.count(false));
|
||||
this.numberPeople.set(users.count(false));
|
||||
return users;
|
||||
},
|
||||
orgNumber() {
|
||||
return this.numberOrgs.get();
|
||||
},
|
||||
teamNumber() {
|
||||
return this.numberTeams.get();
|
||||
},
|
||||
peopleNumber() {
|
||||
return this.number.get();
|
||||
return this.numberPeople.get();
|
||||
},
|
||||
switchMenu(event) {
|
||||
const target = $(event.target);
|
||||
if (!target.hasClass('active')) {
|
||||
$('.side-menu li.active').removeClass('active');
|
||||
target.parent().addClass('active');
|
||||
const targetID = target.data('id');
|
||||
this.orgSetting.set('org-setting' === targetID);
|
||||
this.teamSetting.set('team-setting' === targetID);
|
||||
this.peopleSetting.set('people-setting' === targetID);
|
||||
}
|
||||
},
|
||||
}).register('people');
|
||||
|
||||
Template.orgRow.helpers({
|
||||
orgData() {
|
||||
const orgCollection = this.esSearch ? ESSearchResults : Org;
|
||||
return orgCollection.findOne(this.orgId);
|
||||
},
|
||||
});
|
||||
|
||||
Template.teamRow.helpers({
|
||||
teamData() {
|
||||
const teamCollection = this.esSearch ? ESSearchResults : Team;
|
||||
return teamCollection.findOne(this.teamId);
|
||||
},
|
||||
});
|
||||
|
||||
Template.peopleRow.helpers({
|
||||
userData() {
|
||||
const userCollection = this.esSearch ? ESSearchResults : Users;
|
||||
@@ -122,6 +222,24 @@ Template.editUserPopup.onCreated(function() {
|
||||
});
|
||||
});
|
||||
|
||||
Template.editOrgPopup.helpers({
|
||||
org() {
|
||||
return Org.findOne(this.orgId);
|
||||
},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
Template.editTeamPopup.helpers({
|
||||
team() {
|
||||
return Team.findOne(this.teamId);
|
||||
},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
Template.editUserPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
@@ -144,6 +262,14 @@ Template.editUserPopup.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.newOrgPopup.onCreated(function() {
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
});
|
||||
|
||||
Template.newTeamPopup.onCreated(function() {
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
});
|
||||
|
||||
Template.newUserPopup.onCreated(function() {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
@@ -163,28 +289,76 @@ Template.newUserPopup.onCreated(function() {
|
||||
});
|
||||
});
|
||||
|
||||
Template.newUserPopup.helpers({
|
||||
//user() {
|
||||
// return Users.findOne(this.userId);
|
||||
//},
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
Template.newOrgPopup.helpers({
|
||||
org() {
|
||||
return Org.findOne(this.orgId);
|
||||
},
|
||||
//isSelected(match) {
|
||||
// const userId = Template.instance().data.userId;
|
||||
// const selected = Users.findOne(userId).authenticationMethod;
|
||||
// return selected === match;
|
||||
//},
|
||||
//isLdap() {
|
||||
// const userId = Template.instance().data.userId;
|
||||
// const selected = Users.findOne(userId).authenticationMethod;
|
||||
// return selected === 'ldap';
|
||||
//},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
Template.newTeamPopup.helpers({
|
||||
team() {
|
||||
return Team.findOne(this.teamId);
|
||||
},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
Template.newUserPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
isSelected(match) {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === match;
|
||||
},
|
||||
isLdap() {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === 'ldap';
|
||||
},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
org() {
|
||||
return Org.findOne(this.orgId);
|
||||
},
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.edit-org': Popup.open('editOrg'),
|
||||
'click a.more-settings-org': Popup.open('settingsOrg'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('orgRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
team() {
|
||||
return Team.findOne(this.teamId);
|
||||
},
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.edit-team': Popup.open('editTeam'),
|
||||
'click a.more-settings-team': Popup.open('settingsTeam'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('teamRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
user() {
|
||||
@@ -194,11 +368,32 @@ BlazeComponent.extendComponent({
|
||||
return [
|
||||
{
|
||||
'click a.edit-user': Popup.open('editUser'),
|
||||
'click a.more-settings-user': Popup.open('settingsUser'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('peopleRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.new-org': Popup.open('newOrg'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('newOrgRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.new-team': Popup.open('newTeam'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('newTeamRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
@@ -213,20 +408,32 @@ Template.editUserPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const user = Users.findOne(this.userId);
|
||||
const fullname = templateInstance.find('.js-profile-fullname').value.trim();
|
||||
const username = templateInstance.find('.js-profile-username').value.trim();
|
||||
const fullname = templateInstance.find('.js-profile-fullname').value.trim();
|
||||
const initials = templateInstance.find('.js-profile-initials').value.trim();
|
||||
const password = templateInstance.find('.js-profile-password').value;
|
||||
const isAdmin = templateInstance.find('.js-profile-isadmin').value.trim();
|
||||
const isActive = templateInstance.find('.js-profile-isactive').value.trim();
|
||||
const email = templateInstance.find('.js-profile-email').value.trim();
|
||||
const verified = templateInstance
|
||||
.find('.js-profile-email-verified')
|
||||
.value.trim();
|
||||
const authentication = templateInstance
|
||||
.find('.js-authenticationMethod')
|
||||
.value.trim();
|
||||
|
||||
const isChangePassword = password.length > 0;
|
||||
const isChangeUserName = username !== user.username;
|
||||
const isChangeInitials = initials.length > 0;
|
||||
const isChangeEmailVerified = verified !== user.emails[0].verified;
|
||||
|
||||
// If previously email address has not been set, it is undefined,
|
||||
// check for undefined, and allow adding email address.
|
||||
const isChangeEmail =
|
||||
email.toLowerCase() !== user.emails[0].address.toLowerCase();
|
||||
email.toLowerCase() !==
|
||||
(typeof user.emails !== 'undefined'
|
||||
? user.emails[0].address.toLowerCase()
|
||||
: false);
|
||||
|
||||
Users.update(this.userId, {
|
||||
$set: {
|
||||
@@ -241,6 +448,14 @@ Template.editUserPopup.events({
|
||||
Meteor.call('setPassword', password, this.userId);
|
||||
}
|
||||
|
||||
if (isChangeEmailVerified) {
|
||||
Meteor.call('setEmailVerified', email, verified === 'true', this.userId);
|
||||
}
|
||||
|
||||
if (isChangeInitials) {
|
||||
Meteor.call('setInitials', initials, this.userId);
|
||||
}
|
||||
|
||||
if (isChangeUserName && isChangeEmail) {
|
||||
Meteor.call(
|
||||
'setUsernameAndEmail',
|
||||
@@ -296,11 +511,47 @@ Template.editUserPopup.events({
|
||||
});
|
||||
} else Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
'click #deleteButton': Popup.afterConfirm('userDelete', function() {
|
||||
Users.remove(this.userId);
|
||||
Template.newOrgPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const displayName = templateInstance.find('.js-displayName').value.trim();
|
||||
const desc = templateInstance.find('.js-desc').value.trim();
|
||||
const name = templateInstance.find('.js-name').value.trim();
|
||||
const teams = templateInstance.find('.js-teams').value.trim();
|
||||
const website = templateInstance.find('.js-website').value.trim();
|
||||
const isActive = templateInstance.find('.js-profile-isactive').value.trim();
|
||||
|
||||
Meteor.call(
|
||||
'setCreateOrg',
|
||||
displayName,
|
||||
desc,
|
||||
name,
|
||||
teams,
|
||||
website,
|
||||
isActive,
|
||||
email.toLowerCase(),
|
||||
function(error) {
|
||||
const nameMessageElement = templateInstance.$('.name-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'name-already-taken') {
|
||||
nameMessageElement.show();
|
||||
emailMessageElement.hide();
|
||||
} else if (errorElement === 'email-already-taken') {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
Popup.close();
|
||||
}),
|
||||
},
|
||||
});
|
||||
|
||||
Template.newUserPopup.events({
|
||||
@@ -343,3 +594,70 @@ Template.newUserPopup.events({
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
Template.settingsUserPopup.events({
|
||||
'click .impersonate-user'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
Meteor.call('impersonate', this.userId, err => {
|
||||
if (!err) {
|
||||
FlowRouter.go('/');
|
||||
Meteor.connection.setUserId(this.userId);
|
||||
}
|
||||
});
|
||||
},
|
||||
'click #deleteButton'(event) {
|
||||
event.preventDefault();
|
||||
/*
|
||||
// Delete is not enabled yet, because it does leave empty user avatars
|
||||
// to boards: boards members, card members and assignees have
|
||||
// empty users. See:
|
||||
// - wekan/client/components/settings/peopleBody.jade deleteButton
|
||||
// - wekan/client/components/settings/peopleBody.js deleteButton
|
||||
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
|
||||
// that does now remove member from board, card members and assignees correctly,
|
||||
// but that should be used to remove user from all boards similarly
|
||||
// - wekan/models/users.js Delete is not enabled
|
||||
//
|
||||
//console.log('user id: ' + this.userId);
|
||||
//Popup.afterConfirm('userDelete', function(event) {
|
||||
//Boards.find({ members: this.userId }).forEach(board => {
|
||||
// console.log('board id: ' + board._id);
|
||||
//Cards.find({ boardId: board._id, members: this.userId }).forEach(card => {
|
||||
// card.unassignMember(this.userId);
|
||||
//});
|
||||
//Cards.find({ boardId: board._id, members: this.userId }).forEach(card => {
|
||||
// card.unassignMember(this.userId);
|
||||
//});
|
||||
//Cards.find({ boardId: board._id, assignees: this.userId }).forEach(card => {
|
||||
// card.unassignAssignee(this.userId);
|
||||
//});
|
||||
//Boards.findOne({ boardId: board._id }).removeMember(this.userId);
|
||||
//});
|
||||
//Users.remove(this.userId);
|
||||
*/
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
Template.settingsUserPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
isSelected(match) {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === match;
|
||||
},
|
||||
isLdap() {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === 'ldap';
|
||||
},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
@@ -21,7 +21,7 @@ table
|
||||
|
||||
.ext-box-left
|
||||
display: flex;
|
||||
width: 40%
|
||||
width: 100%
|
||||
|
||||
span
|
||||
vertical-align: center;
|
||||
@@ -46,3 +46,6 @@ table
|
||||
|
||||
div
|
||||
margin: auto
|
||||
|
||||
.more-settings-user,.more-settings-team,.more-settings-org
|
||||
margin-left: 10px;
|
||||
@@ -163,13 +163,6 @@ template(name='announcementSettings')
|
||||
|
||||
template(name='layoutSettings')
|
||||
ul#layout-setting.setting-detail
|
||||
//li.layout-form
|
||||
.title {{_ 'hide-logo'}}
|
||||
.form-group.flex
|
||||
input.wekan-form-control#hide-logo(type="radio" name="hideLogo" value="true" checked="{{#if currentSetting.hideLogo}}checked{{/if}}")
|
||||
span {{_ 'yes'}}
|
||||
input.wekan-form-control#hide-logo(type="radio" name="hideLogo" value="false" checked="{{#unless currentSetting.hideLogo}}checked{{/unless}}")
|
||||
span {{_ 'no'}}
|
||||
li.layout-form
|
||||
.title {{_ 'display-authentication-method'}}
|
||||
.form-group.flex
|
||||
@@ -184,10 +177,40 @@ template(name='layoutSettings')
|
||||
.title {{_ 'custom-product-name'}}
|
||||
.form-group
|
||||
input.wekan-form-control#product-name(type="text", placeholder="" value="{{currentSetting.productName}}")
|
||||
li.layout-form
|
||||
.title {{_ 'hide-logo'}}
|
||||
.form-group.flex
|
||||
input.wekan-form-control#hide-logo(type="radio" name="hideLogo" value="true" checked="{{#if currentSetting.hideLogo}}checked{{/if}}")
|
||||
span {{_ 'yes'}}
|
||||
input.wekan-form-control#hide-logo(type="radio" name="hideLogo" value="false" checked="{{#unless currentSetting.hideLogo}}checked{{/unless}}")
|
||||
span {{_ 'no'}}
|
||||
li.layout-form
|
||||
.title {{_ 'custom-login-logo-image-url'}}
|
||||
.form-group
|
||||
input.wekan-form-control#custom-login-logo-image-url(type="text", placeholder="" value="{{currentSetting.customLoginLogoImageUrl}}")
|
||||
li.layout-form
|
||||
.title {{_ 'custom-login-logo-link-url'}}
|
||||
.form-group
|
||||
input.wekan-form-control#custom-login-logo-link-url(type="text", placeholder="" value="{{currentSetting.customLoginLogoLinkUrl}}")
|
||||
li.layout-form
|
||||
.title {{_ 'text-below-custom-login-logo'}}
|
||||
.form-group
|
||||
textarea#text-below-custom-login-logo.wekan-form-control= currentSetting.textBelowCustomLoginLogo
|
||||
li.layout-form
|
||||
.title {{_ 'custom-top-left-corner-logo-image-url'}}
|
||||
.form-group
|
||||
input.wekan-form-control#custom-top-left-corner-logo-image-url(type="text", placeholder="" value="{{currentSetting.customTopLeftCornerLogoImageUrl}}")
|
||||
li.layout-form
|
||||
.title {{_ 'custom-top-left-corner-logo-link-url'}}
|
||||
.form-group
|
||||
input.wekan-form-control#custom-top-left-corner-logo-link-url(type="text", placeholder="" value="{{currentSetting.customTopLeftCornerLogoLinkUrl}}")
|
||||
li.layout-form
|
||||
.title {{_ 'custom-top-left-corner-logo-height'}}
|
||||
.form-group
|
||||
input.wekan-form-control#custom-top-left-corner-logo-height(type="text", placeholder="" value="{{currentSetting.customTopLeftCornerLogoHeight}}")
|
||||
li
|
||||
button.js-save-layout.primary {{_ 'save'}}
|
||||
|
||||
|
||||
template(name='selectAuthenticationMethod')
|
||||
select#defaultAuthenticationMethod
|
||||
each authentications
|
||||
|
||||
@@ -167,6 +167,30 @@ BlazeComponent.extendComponent({
|
||||
const productName = $('#product-name')
|
||||
.val()
|
||||
.trim();
|
||||
const customLoginLogoImageUrl = $('#custom-login-logo-image-url')
|
||||
.val()
|
||||
.trim();
|
||||
const customLoginLogoLinkUrl = $('#custom-login-logo-link-url')
|
||||
.val()
|
||||
.trim();
|
||||
const textBelowCustomLoginLogo = $('#text-below-custom-login-logo')
|
||||
.val()
|
||||
.trim();
|
||||
const customTopLeftCornerLogoImageUrl = $(
|
||||
'#custom-top-left-corner-logo-image-url',
|
||||
)
|
||||
.val()
|
||||
.trim();
|
||||
const customTopLeftCornerLogoLinkUrl = $(
|
||||
'#custom-top-left-corner-logo-link-url',
|
||||
)
|
||||
.val()
|
||||
.trim();
|
||||
const customTopLeftCornerLogoHeight = $(
|
||||
'#custom-top-left-corner-logo-height',
|
||||
)
|
||||
.val()
|
||||
.trim();
|
||||
const hideLogoChange = $('input[name=hideLogo]:checked').val() === 'true';
|
||||
const displayAuthenticationMethod =
|
||||
$('input[name=displayAuthenticationMethod]:checked').val() === 'true';
|
||||
@@ -177,6 +201,12 @@ BlazeComponent.extendComponent({
|
||||
$set: {
|
||||
productName,
|
||||
hideLogo: hideLogoChange,
|
||||
customLoginLogoImageUrl,
|
||||
customLoginLogoLinkUrl,
|
||||
textBelowCustomLoginLogo,
|
||||
customTopLeftCornerLogoImageUrl,
|
||||
customTopLeftCornerLogoLinkUrl,
|
||||
customTopLeftCornerLogoHeight,
|
||||
displayAuthenticationMethod,
|
||||
defaultAuthenticationMethod,
|
||||
},
|
||||
|
||||
@@ -3,22 +3,21 @@ template(name="settingHeaderBar")
|
||||
span {{_ 'admin-panel'}}
|
||||
|
||||
.setting-header-btns.left
|
||||
unless isMiniScreen
|
||||
if currentUser
|
||||
a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
|
||||
i.fa(class="fa-cog")
|
||||
span {{_ 'settings'}}
|
||||
if currentUser
|
||||
a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
|
||||
i.fa(class="fa-cog")
|
||||
span {{_ 'settings'}}
|
||||
|
||||
a.setting-header-btn.people(href="{{pathFor 'people'}}")
|
||||
i.fa(class="fa-users")
|
||||
span {{_ 'people'}}
|
||||
a.setting-header-btn.people(href="{{pathFor 'people'}}")
|
||||
i.fa(class="fa-users")
|
||||
span {{_ 'people'}}
|
||||
|
||||
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
|
||||
i.fa(class="fa-info-circle")
|
||||
span {{_ 'info'}}
|
||||
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
|
||||
i.fa(class="fa-info-circle")
|
||||
span {{_ 'info'}}
|
||||
|
||||
else
|
||||
a.setting-header-btn.js-log-in(
|
||||
title="{{_ 'log-in'}}")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
||||
else
|
||||
a.setting-header-btn.js-log-in(
|
||||
title="{{_ 'log-in'}}")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
||||
@@ -9,7 +9,7 @@ template(name="sidebar")
|
||||
a.board-header-btn.js-shortcuts
|
||||
i.fa.fa-keyboard-o
|
||||
span {{_ 'keyboard-shortcuts' }}
|
||||
.sidebar-content.js-board-sidebar-content.js-perfect-scrollbar
|
||||
.sidebar-content.js-board-sidebar-content
|
||||
//a.hide-btn.js-hide-sidebar
|
||||
// i.fa.fa-navicon
|
||||
unless isDefaultView
|
||||
@@ -269,14 +269,16 @@ template(name="outgoingWebhooksPopup")
|
||||
|
||||
template(name="boardMenuPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rules'}}
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'custom-fields'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rules'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'custom-fields'}}
|
||||
li
|
||||
a.js-open-archives
|
||||
i.fa.fa-archive
|
||||
@@ -286,79 +288,35 @@ template(name="boardMenuPopup")
|
||||
a.js-change-board-color
|
||||
i.fa.fa-paint-brush
|
||||
| {{_ 'board-change-color'}}
|
||||
|
||||
//-
|
||||
XXX Language should be handled by sandstorm, but for now display a
|
||||
language selection link in the board menu. This link is normally present
|
||||
in the header bar that is not displayed on sandstorm.
|
||||
if isSandstorm
|
||||
li
|
||||
a.js-change-language
|
||||
i.fa.fa-flag
|
||||
| {{_ 'language'}}
|
||||
unless isSandstorm
|
||||
if currentUser.isBoardAdmin
|
||||
hr
|
||||
ul.pop-over-list
|
||||
if withApi
|
||||
li
|
||||
a.js-export-board
|
||||
i.fa.fa-share-alt
|
||||
| {{_ 'export-board'}}
|
||||
li
|
||||
a.js-outgoing-webhooks
|
||||
i.fa.fa-globe
|
||||
| {{_ 'outgoing-webhooks'}}
|
||||
li
|
||||
a.js-card-settings
|
||||
i.fa.fa-id-card-o
|
||||
| {{_ 'card-settings'}}
|
||||
li
|
||||
a.js-subtask-settings
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtask-settings'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-archive-board
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-board'}}
|
||||
|
||||
if isSandstorm
|
||||
hr
|
||||
ul.pop-over-list
|
||||
hr
|
||||
ul.pop-over-list
|
||||
if withApi
|
||||
li
|
||||
a.js-export-board
|
||||
i.fa.fa-share-alt
|
||||
| {{_ 'export-board'}}
|
||||
li
|
||||
a.js-import-board
|
||||
i.fa.fa-share-alt
|
||||
i.fa.fa-sign-in
|
||||
| {{_ 'import-board-c'}}
|
||||
li
|
||||
a.js-archive-board
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-board'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-outgoing-webhooks
|
||||
i.fa.fa-globe
|
||||
| {{_ 'outgoing-webhooks'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-card-settings
|
||||
i.fa.fa-id-card-o
|
||||
| {{_ 'card-settings'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-subtask-settings
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtask-settings'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
if currentUser.isBoardAdmin
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-archive-board
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-board'}}
|
||||
|
||||
template(name="exportBoard")
|
||||
ul.pop-over-list
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
Sidebar = null;
|
||||
|
||||
const defaultView = 'home';
|
||||
@@ -16,7 +14,7 @@ const viewTitles = {
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
return [Mixins.InfiniteScrolling];
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
@@ -112,10 +110,12 @@ BlazeComponent.extendComponent({
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
Meteor.call('toggleMinicardLabelText');
|
||||
} else if (cookies.has('hiddenMinicardLabelText')) {
|
||||
cookies.remove('hiddenMinicardLabelText');
|
||||
} else if (window.localStorage.getItem('hiddenMinicardLabelText')) {
|
||||
window.localStorage.removeItem('hiddenMinicardLabelText');
|
||||
location.reload();
|
||||
} else {
|
||||
cookies.set('hiddenMinicardLabelText', 'true');
|
||||
window.localStorage.setItem('hiddenMinicardLabelText', 'true');
|
||||
location.reload();
|
||||
}
|
||||
},
|
||||
'click .js-shortcuts'() {
|
||||
@@ -133,7 +133,7 @@ Template.homeSidebar.helpers({
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return (currentUser.profile || {}).hiddenMinicardLabelText;
|
||||
} else if (cookies.has('hiddenMinicardLabelText')) {
|
||||
} else if (window.localStorage.getItem('hiddenMinicardLabelText')) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
@@ -155,6 +155,9 @@ Template.memberPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
memberType() {
|
||||
const type = Users.findOne(this.userId).isBoardAdmin() ? 'admin' : 'normal';
|
||||
if (type === 'normal') {
|
||||
@@ -224,6 +227,9 @@ Template.boardMenuPopup.onCreated(function() {
|
||||
});
|
||||
|
||||
Template.boardMenuPopup.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
withApi() {
|
||||
return Template.instance().apiEnabled.get();
|
||||
},
|
||||
@@ -238,7 +244,7 @@ Template.boardMenuPopup.helpers({
|
||||
},
|
||||
exportFilename() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return `wekan-export-board-${boardId}.json`;
|
||||
return `export-board-${boardId}.json`;
|
||||
},
|
||||
});
|
||||
|
||||
@@ -249,11 +255,15 @@ Template.memberPopup.events({
|
||||
},
|
||||
'click .js-change-role': Popup.open('changePermissions'),
|
||||
'click .js-remove-member': Popup.afterConfirm('removeMember', function() {
|
||||
// This works from removing member from board, card members and assignees.
|
||||
const boardId = Session.get('currentBoard');
|
||||
const memberId = this.userId;
|
||||
Cards.find({ boardId, members: memberId }).forEach(card => {
|
||||
card.unassignMember(memberId);
|
||||
});
|
||||
Cards.find({ boardId, assignees: memberId }).forEach(card => {
|
||||
card.unassignAssignee(memberId);
|
||||
});
|
||||
Boards.findOne(boardId).removeMember(memberId);
|
||||
Popup.close();
|
||||
}),
|
||||
@@ -294,6 +304,9 @@ Template.membersWidget.helpers({
|
||||
return false;
|
||||
}
|
||||
},
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
});
|
||||
|
||||
Template.membersWidget.events({
|
||||
@@ -451,15 +464,15 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
exportJsonFilename() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return `wekan-export-board-${boardId}.json`;
|
||||
return `export-board-${boardId}.json`;
|
||||
},
|
||||
exportCsvFilename() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return `wekan-export-board-${boardId}.csv`;
|
||||
return `export-board-${boardId}.csv`;
|
||||
},
|
||||
exportTsvFilename() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return `wekan-export-board-${boardId}.tsv`;
|
||||
return `export-board-${boardId}.tsv`;
|
||||
},
|
||||
}).register('exportBoardPopup');
|
||||
|
||||
@@ -475,6 +488,12 @@ Template.labelsWidget.events({
|
||||
'click .js-add-label': Popup.open('createLabel'),
|
||||
});
|
||||
|
||||
Template.labelsWidget.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
});
|
||||
|
||||
// Board members can assign people or labels by drag-dropping elements from the
|
||||
// sidebar to the cards on the board. In order to re-initialize the jquery-ui
|
||||
// plugin any time a draggable member or label is modified or removed we use a
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
color: darken(white, 50%)
|
||||
font-size: 1em
|
||||
margin-bottom: 10px
|
||||
font-weight: bold
|
||||
|
||||
i.fa
|
||||
margin-right: 3px
|
||||
@@ -167,8 +168,8 @@
|
||||
button
|
||||
float: right
|
||||
margin: 0
|
||||
margin-bottom: 5px
|
||||
padding: 0 2px 0 10px
|
||||
margin: 0 0 5px 5px
|
||||
padding: 0 10px 0 10px
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
.board-sidebar
|
||||
|
||||
@@ -5,8 +5,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-cards {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-cards {{_ 'delete-all'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-all-cards {{_ 'delete-all'}}
|
||||
each archivedCards
|
||||
.minicard-wrapper.js-minicard
|
||||
+minicard(this)
|
||||
@@ -14,8 +15,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-card {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-card {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-card {{_ 'delete'}}
|
||||
if cardIsInArchivedList
|
||||
p.quiet.small ({{_ 'warn-list-archived'}})
|
||||
else
|
||||
@@ -25,8 +27,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-lists {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-lists {{_ 'delete-all'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-all-lists {{_ 'delete-all'}}
|
||||
ul.archived-lists
|
||||
each archivedLists
|
||||
li.archived-lists-item
|
||||
@@ -35,8 +38,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-list {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-list {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-list {{_ 'delete'}}
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-lists'}}
|
||||
|
||||
@@ -44,8 +48,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-swimlanes {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-swimlanes {{_ 'delete-all'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-all-swimlanes {{_ 'delete-all'}}
|
||||
ul.archived-lists
|
||||
each archivedSwimlanes
|
||||
li.archived-lists-item
|
||||
@@ -54,8 +59,9 @@ template(name="archivesSidebar")
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-swimlane {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-swimlane {{_ 'delete'}}
|
||||
if currentUser.isBoardAdmin
|
||||
| -
|
||||
a.js-delete-swimlane {{_ 'delete'}}
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-swimlanes'}}
|
||||
else
|
||||
|
||||
@@ -141,6 +141,9 @@ BlazeComponent.extendComponent({
|
||||
}).register('archivesSidebar');
|
||||
|
||||
Template.archivesSidebar.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
isWorker() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return (
|
||||
|
||||
@@ -4,10 +4,14 @@
|
||||
and #each x in y constructors to fix this.
|
||||
|
||||
template(name="filterSidebar")
|
||||
h3 {{_ 'list-filter-label'}}
|
||||
ul.sidebar-list
|
||||
span {{_ 'list-filter-label'}}
|
||||
form.js-list-filter
|
||||
input(type="text")
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-tags
|
||||
| {{_ 'filter-labels-label'}}
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.labelIds.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-label-filter
|
||||
@@ -27,6 +31,9 @@ template(name="filterSidebar")
|
||||
if Filter.labelIds.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-users
|
||||
| {{_ 'filter-member-label'}}
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.members.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-member-filter
|
||||
@@ -45,6 +52,9 @@ template(name="filterSidebar")
|
||||
if Filter.members.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-user
|
||||
| {{_ 'filter-assignee-label'}}
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.assignees.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-assignee-filter
|
||||
@@ -63,6 +73,9 @@ template(name="filterSidebar")
|
||||
if Filter.assignees.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'filter-custom-fields-label'}}
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.customFields.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-custom-fields-filter
|
||||
@@ -78,6 +91,8 @@ template(name="filterSidebar")
|
||||
if Filter.customFields.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
h3
|
||||
| {{_ 'other-filters-label'}}
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.archive.isSelected _id}}active{{/if}}")
|
||||
a.name.js-toggle-archive-filter
|
||||
@@ -85,7 +100,6 @@ template(name="filterSidebar")
|
||||
| {{_ 'filter-show-archive'}}
|
||||
if Filter.archive.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.hideEmpty.isSelected _id}}active{{/if}}")
|
||||
a.name.js-toggle-hideEmpty-filter
|
||||
@@ -94,7 +108,7 @@ template(name="filterSidebar")
|
||||
if Filter.hideEmpty.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
span {{_ 'advanced-filter-label'}}
|
||||
h3 {{_ 'advanced-filter-label'}}
|
||||
input.js-field-advanced-filter(type="text")
|
||||
span {{_ 'advanced-filter-description'}}
|
||||
if Filter.isActive
|
||||
@@ -107,6 +121,9 @@ template(name="filterSidebar")
|
||||
span {{_ 'filter-to-selection'}}
|
||||
|
||||
template(name="multiselectionSidebar")
|
||||
h3
|
||||
i.fa.fa-tags
|
||||
| {{_ 'multi-selection-label'}}
|
||||
ul.sidebar-list
|
||||
each currentBoard.labels
|
||||
li
|
||||
@@ -122,6 +139,9 @@ template(name="multiselectionSidebar")
|
||||
else if someSelectedElementHave 'label' _id
|
||||
i.fa.fa-ellipsis-h
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-users
|
||||
| {{_ 'multi-selection-member'}}
|
||||
ul.sidebar-list
|
||||
each currentBoard.activeMembers
|
||||
with getUser userId
|
||||
@@ -135,7 +155,7 @@ template(name="multiselectionSidebar")
|
||||
i.fa.fa-check
|
||||
else if someSelectedElementHave 'member' _id
|
||||
i.fa.fa-ellipsis-h
|
||||
unless currentUser.isWorker
|
||||
if currentUser.isBoardAdmin
|
||||
hr
|
||||
a.sidebar-btn.js-move-selection
|
||||
i.fa.fa-share
|
||||
|
||||
@@ -134,6 +134,15 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('multiselectionSidebar');
|
||||
|
||||
Template.multiselectionSidebar.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
isCommentOnly() {
|
||||
return Meteor.user().isCommentOnly();
|
||||
},
|
||||
});
|
||||
|
||||
Template.disambiguateMultiLabelPopup.events({
|
||||
'click .js-remove-label'() {
|
||||
mutateSelectedCards('removeLabel', this._id);
|
||||
|
||||
Loaded 100 of 284 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user