Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a573083291 | ||
|
|
6a42f738c9 | ||
|
|
9bee6ae666 | ||
|
|
533af4b39e | ||
|
|
99a200d0b2 | ||
|
|
889ec1339a | ||
|
|
0bdc3d04b4 | ||
|
|
bd9fbedbf9 | ||
|
|
6c0a958481 | ||
|
|
45a39ec213 | ||
|
|
800304270e | ||
|
|
9defed2680 | ||
|
|
7be9d7ff49 | ||
|
|
287abe7640 | ||
|
|
262df6c4a0 | ||
|
|
10e3d963ef | ||
|
|
d23920c886 | ||
|
|
be2647556d | ||
|
|
ea57864bcc | ||
|
|
0c121a5894 | ||
|
|
c19723ae27 | ||
|
|
00b43df267 | ||
|
|
edb6355960 | ||
|
|
8626b466b8 | ||
|
|
a80ab6e47a | ||
|
|
2b2978b8e7 | ||
|
|
3bdea42f6d | ||
|
|
b56ea161cd | ||
|
|
cde74a9c0b | ||
|
|
79b00f88b0 | ||
|
|
0da84f8f3e | ||
|
|
4f164a46a6 | ||
|
|
3d9b7eb7ab | ||
|
|
d3eb0ced83 | ||
|
|
08ac1f6b69 | ||
|
|
cc63be8ff0 | ||
|
|
b1d8b0c7d4 | ||
|
|
3f6fde033b | ||
|
|
0a9e10b21e | ||
|
|
25e17fedb9 | ||
|
|
8ec54ffa5b | ||
|
|
b516275c24 | ||
|
|
aea5d62556 | ||
|
|
de2fc69315 | ||
|
|
8629537c3f | ||
|
|
57401e48c1 | ||
|
|
76f4b8316b | ||
|
|
ef0e4e36f4 | ||
|
|
55296b676b | ||
|
|
5b9a2a8bac | ||
|
|
8031b184f3 | ||
|
|
1efd7bb33a | ||
|
|
53d663f77b | ||
|
|
9969523b70 | ||
|
|
2cd0a414d5 | ||
|
|
256a673a7f | ||
|
|
6d8a062e50 | ||
|
|
35a7159be4 | ||
|
|
764d9fa806 | ||
|
|
292ff3c961 | ||
|
|
071929d3a6 | ||
|
|
c7cc9273a6 | ||
|
|
55a11a24f4 | ||
|
|
d1f443bcd8 | ||
|
|
52fafe9976 | ||
|
|
9aa7b792be | ||
|
|
07e9fe3403 | ||
|
|
858967f420 | ||
|
|
e07df35b61 | ||
|
|
2a3aa9331f | ||
|
|
4863689248 | ||
|
|
8a53aa9fa4 | ||
|
|
57a990d91e | ||
|
|
76c0393c53 | ||
|
|
62d472fa54 | ||
|
|
6d9d69e01d | ||
|
|
38666cbda2 | ||
|
|
b3b81546f6 | ||
|
|
9c2151f802 | ||
|
|
1f2c4b5a9e | ||
|
|
c9ef28b2ad | ||
|
|
03a5f46131 | ||
|
|
f1e4297e00 | ||
|
|
9bb1425a81 | ||
|
|
b6277233a1 | ||
|
|
7bed8a7abb | ||
|
|
787df04419 | ||
|
|
8e142dfdcf | ||
|
|
2a216d41f0 | ||
|
|
241eb9df0f | ||
|
|
0bdd7c8973 | ||
|
|
a59932af00 | ||
|
|
c2a073dec0 | ||
|
|
7808fdd22f | ||
|
|
bf2f3ccec1 | ||
|
|
9c7c481f48 | ||
|
|
df26bc9013 | ||
|
|
b36a7621e0 | ||
|
|
f2c242f49e | ||
|
|
5175f13881 | ||
|
|
75a1854cc3 | ||
|
|
48c3263e28 | ||
|
|
f5e26fb2e6 | ||
|
|
1fadf204c2 | ||
|
|
f03b14a46b | ||
|
|
ab8e56e16a | ||
|
|
2f33a1ecff | ||
|
|
abadeb5e14 | ||
|
|
19c68895e9 | ||
|
|
bed6d6c591 | ||
|
|
b2652edf56 | ||
|
|
94bb3bee77 | ||
|
|
e909ece2da | ||
|
|
7bc250ce84 | ||
|
|
7706839fbe | ||
|
|
68ad58431d | ||
|
|
2059752fc6 | ||
|
|
302afae0bb | ||
|
|
3d1d94d628 | ||
|
|
d51fc2f12c | ||
|
|
2dee14b0d5 | ||
|
|
e75849da98 | ||
|
|
508c7b7a90 | ||
|
|
de67e051d7 | ||
|
|
9ce65c601a | ||
|
|
10d7eeb762 | ||
|
|
104a6dd0b3 | ||
|
|
2977120129 | ||
|
|
d8e8512d66 | ||
|
|
7bfbcf7e03 | ||
|
|
91cad7b49e | ||
|
|
26f1defc56 | ||
|
|
9a03654062 | ||
|
|
2576ef75bd | ||
|
|
752b45af42 | ||
|
|
23c70ac252 | ||
|
|
ad4de9e85d | ||
|
|
855d60f28e | ||
|
|
781a94c05f | ||
|
|
b3cc01b041 | ||
|
|
e23ced47ae | ||
|
|
f406b51a5f | ||
|
|
c81cb786ed | ||
|
|
846f1244c7 | ||
|
|
3ea723329a | ||
|
|
698c9ed1ea | ||
|
|
63044ac13a | ||
|
|
68d9de8946 | ||
|
|
92a7717e50 | ||
|
|
d5c0a5d377 | ||
|
|
c0b7fb0b84 | ||
|
|
9b4e556837 | ||
|
|
1aec0b5f0d | ||
|
|
c5d4e06ea3 | ||
|
|
97bf907448 | ||
|
|
7ef2a2a9f4 | ||
|
|
547d82fe57 | ||
|
|
977821d293 | ||
|
|
f4e5306181 | ||
|
|
f01b440fb7 | ||
|
|
2fd741bf54 | ||
|
|
e8522c323f | ||
|
|
def2ec46e0 | ||
|
|
4e17d5a10f | ||
|
|
dcba6909e2 | ||
|
|
fc74324d1a | ||
|
|
8bb33c53f0 | ||
|
|
236b6c3552 | ||
|
|
28e9a6ac33 | ||
|
|
f91cc25b11 | ||
|
|
6fd45ce74b | ||
|
|
b57eae14d4 | ||
|
|
12db3714f9 | ||
|
|
7a1f42fa4e | ||
|
|
74064324cf | ||
|
|
f3baa32d6c | ||
|
|
33eed50290 | ||
|
|
11d9d1c889 | ||
|
|
5a7860ac8e | ||
|
|
b13f691389 | ||
|
|
d70e876388 | ||
|
|
36c2cb9573 | ||
|
|
88a47780a8 | ||
|
|
d30ce3c5cf | ||
|
|
0fa8fc8b50 | ||
|
|
6d73618a48 | ||
|
|
db493f1571 | ||
|
|
2b51afaedf | ||
|
|
18b6381d79 | ||
|
|
c65d8ed6a9 | ||
|
|
b3ba156d20 | ||
|
|
e1de787f19 | ||
|
|
e1f08b157b | ||
|
|
508915462d | ||
|
|
7c2ef6fbd5 | ||
|
|
ae73029dda | ||
|
|
542972fc5c | ||
|
|
d7cb143b0a | ||
|
|
d594555227 | ||
|
|
fe25ed5202 | ||
|
|
f6c36d6edd | ||
|
|
fe40f35d6d | ||
|
|
789d1d1d1c | ||
|
|
70265deb47 | ||
|
|
c0d1ed714e | ||
|
|
0555b7e34c | ||
|
|
c1c2eb22ba | ||
|
|
697d7613f2 | ||
|
|
33836af1f9 | ||
|
|
4f0c2dafca | ||
|
|
84801010d5 | ||
|
|
cb418f5e23 | ||
|
|
f7d6ac9401 | ||
|
|
d939ab0d76 | ||
|
|
d538a01d19 | ||
|
|
8770326ed3 | ||
|
|
b2e96746db | ||
|
|
6ce0be635b | ||
|
|
1001e95a87 | ||
|
|
609adcdf10 | ||
|
|
9de2580e30 | ||
|
|
9eb9081c6d | ||
|
|
f551b03dc7 | ||
|
|
1d5dd5e60f | ||
|
|
35a7036d4a | ||
|
|
7024929881 | ||
|
|
90058f25bf | ||
|
|
24ec9018fb | ||
|
|
ec01e5182d | ||
|
|
06d2880a7e | ||
|
|
2a611a8935 | ||
|
|
b236d95636 | ||
|
|
b1abfc768a | ||
|
|
9b97810109 | ||
|
|
4feffd90e3 | ||
|
|
dd8d2ea276 | ||
|
|
4c29b72242 | ||
|
|
ebe39771a6 | ||
|
|
63605ee42e | ||
|
|
b7f047db88 | ||
|
|
96289210d7 | ||
|
|
3b4a44abb1 | ||
|
|
e0797c83f8 | ||
|
|
30ffcc9246 | ||
|
|
a0945d2a2e | ||
|
|
c4cea9e71b | ||
|
|
35ec61726d | ||
|
|
f18a57b059 | ||
|
|
4ba180fbc4 | ||
|
|
0f34d407a4 | ||
|
|
4b29e9fbcb | ||
|
|
7f648720af | ||
|
|
58081c13cf | ||
|
|
78555f57a7 | ||
|
|
1ad40134dd | ||
|
|
9e16a405d8 | ||
|
|
9122a339cb | ||
|
|
56197274b6 | ||
|
|
6cf65ba82a | ||
|
|
aa59007409 | ||
|
|
66729e4c05 | ||
|
|
6387d32c2f | ||
|
|
48dbeb1e14 | ||
|
|
20452d7296 | ||
|
|
7daa67c792 | ||
|
|
4d9ba8d73b | ||
|
|
3650ef4805 | ||
|
|
be9154a015 | ||
|
|
0e00ca2350 | ||
|
|
2c0549a67a | ||
|
|
59e23e4296 | ||
|
|
3aa7a6e244 | ||
|
|
838c74a83b | ||
|
|
7f17bc9fb0 | ||
|
|
2dca6e8e7c | ||
|
|
a1bb3f9031 | ||
|
|
d1d4453120 | ||
|
|
48dcb02328 | ||
|
|
0a0cec6ef0 | ||
|
|
c3dd9f47fb | ||
|
|
5417f9b190 | ||
|
|
f03c873815 | ||
|
|
80adca5134 | ||
|
|
6efcac2a0e | ||
|
|
5162317298 | ||
|
|
90139b978c | ||
|
|
080fcb9c62 | ||
|
|
c437c2048d | ||
|
|
f80fcfd7c0 | ||
|
|
e9670aa5cb | ||
|
|
164b6e9070 | ||
|
|
5af18809a7 | ||
|
|
a719e8fda1 | ||
|
|
50fa8a0743 | ||
|
|
250f95deb6 | ||
|
|
bc98d82acf | ||
|
|
9e160d2431 | ||
|
|
77cff95c07 | ||
|
|
ecd780962f | ||
|
|
ab06597b7c | ||
|
|
b98a46b78c | ||
|
|
49e31707e5 | ||
|
|
92122e1fdd | ||
|
|
7238a65a6f | ||
|
|
e68ccf8532 | ||
|
|
220c52373a | ||
|
|
362fd86dbf | ||
|
|
8aba58188d | ||
|
|
41848dd99e | ||
|
|
f2fcfd6a47 | ||
|
|
33cdb906e2 | ||
|
|
19e73009b1 | ||
|
|
401e256d84 | ||
|
|
e1cd87433a | ||
|
|
23e5e1e3bd | ||
|
|
8f19f043a1 | ||
|
|
b1f07149c0 | ||
|
|
17acf18848 | ||
|
|
f52f589f7d | ||
|
|
e3e25bc233 | ||
|
|
a2f2ce1135 | ||
|
|
90152ab9f5 | ||
|
|
7a25f542e8 | ||
|
|
8c57250243 | ||
|
|
2e1eb1e224 | ||
|
|
b9a15e68de | ||
|
|
a9d2e03b65 | ||
|
|
d84b04dc35 | ||
|
|
7f3f082557 | ||
|
|
c810c68923 | ||
|
|
865a585c7f | ||
|
|
8703dd4229 | ||
|
|
d0c417b17d | ||
|
|
d09151d8f3 | ||
|
|
01a28860fe | ||
|
|
488b765f95 | ||
|
|
8a21b69fb0 | ||
|
|
eda3ed59df | ||
|
|
611ac0ab57 | ||
|
|
d485154a12 | ||
|
|
0caff7d5d5 | ||
|
|
6df7657c8e | ||
|
|
55d0f0bacd | ||
|
|
a74fac4cbf | ||
|
|
8aa58c0b11 | ||
|
|
4b9f8ab2b1 | ||
|
|
ba41533128 | ||
|
|
38069c6d63 | ||
|
|
1d66058240 | ||
|
|
43ac328e8a | ||
|
|
7519abf3fe | ||
|
|
849deae11e | ||
|
|
06a2b08780 | ||
|
|
4f9d3d8be5 | ||
|
|
ac3d658cb1 | ||
|
|
8f00191617 | ||
|
|
762391965e | ||
|
|
0fa3a2729d | ||
|
|
54640bb125 | ||
|
|
57d35a294d | ||
|
|
39069b322d | ||
|
|
540ce3a6ed | ||
|
|
ab22fb27ce | ||
|
|
0f564365f4 | ||
|
|
cccb7e4a39 | ||
|
|
1e837dec11 | ||
|
|
be3325ce35 | ||
|
|
c042d54714 | ||
|
|
77e2f95c66 | ||
|
|
403b416b2a | ||
|
|
b0901ccd01 | ||
|
|
6d2f8a97af | ||
|
|
bbd3324b79 | ||
|
|
5697b89817 | ||
|
|
6bf6bcb192 | ||
|
|
df74b31541 | ||
|
|
0b34bcdfa8 | ||
|
|
09a060a57b | ||
|
|
2a5147a0c1 | ||
|
|
4caa0e2f2e | ||
|
|
8f5c0af88e | ||
|
|
665d7eb831 | ||
|
|
d08b208bc6 | ||
|
|
c5d8117052 | ||
|
|
b769d18f73 | ||
|
|
b17760d228 | ||
|
|
2983c51db1 | ||
|
|
d6e11940cc | ||
|
|
17f15f546f | ||
|
|
688ef08cd5 | ||
|
|
8607a18a26 | ||
|
|
c5df78fd8b | ||
|
|
62bd96e06e | ||
|
|
399fd098b8 | ||
|
|
f9c21a9b52 | ||
|
|
41893cf06a | ||
|
|
83a8d4c14f | ||
|
|
6ce5ab40a7 | ||
|
|
328fa194a0 | ||
|
|
482b9c9333 | ||
|
|
122757ca9c | ||
|
|
49dd2204f4 | ||
|
|
07a3a0b388 | ||
|
|
56efbf1de7 | ||
|
|
57f31d443f | ||
|
|
65f308434a | ||
|
|
007e0f1c16 | ||
|
|
c249a2d187 | ||
|
|
78324263c1 | ||
|
|
c20229b56a | ||
|
|
1fd10771b0 | ||
|
|
1637920170 | ||
|
|
87ba966db8 | ||
|
|
258391cd8c | ||
|
|
481404e8d7 | ||
|
|
48737dcd01 | ||
|
|
b95585b0f6 | ||
|
|
14b2c1309f | ||
|
|
7e036b9df3 | ||
|
|
72fa32151d | ||
|
|
f5dbe8c6f6 | ||
|
|
93950a3b2e | ||
|
|
eec818f9fd | ||
|
|
a6f15af270 | ||
|
|
646497c3f0 | ||
|
|
2342c27ced | ||
|
|
80f6004404 | ||
|
|
a94946c77c | ||
|
|
659a65b8b9 | ||
|
|
c4b55e862f | ||
|
|
f8a75930b3 | ||
|
|
3a04b1b787 | ||
|
|
ad61a15611 | ||
|
|
d21bc0c277 | ||
|
|
fa3d117372 | ||
|
|
26249f5928 | ||
|
|
b7e6600e88 | ||
|
|
6e46cad56c | ||
|
|
e7340c5021 | ||
|
|
05d6c5f15a | ||
|
|
428442b310 | ||
|
|
753d247cf6 | ||
|
|
802f544cd5 | ||
|
|
bf62a947fb | ||
|
|
5b08ae12a6 | ||
|
|
46e881bea3 | ||
|
|
5d1714dbd5 | ||
|
|
bd1de94312 | ||
|
|
06937d0aa0 | ||
|
|
9e39731133 | ||
|
|
3908cd5413 | ||
|
|
6be1a33093 | ||
|
|
c656cbf6ae | ||
|
|
83045a6512 | ||
|
|
199485640f | ||
|
|
2e41ff1121 | ||
|
|
487c6fae8d | ||
|
|
ea64b17b82 | ||
|
|
6d0578fd5a | ||
|
|
76a4deda78 | ||
|
|
595abd303c | ||
|
|
5dd6466c0a | ||
|
|
38655ee478 | ||
|
|
23ca25a1ca | ||
|
|
120cb4820e | ||
|
|
3ee0add6f6 | ||
|
|
8911fe5c8d | ||
|
|
1d9346513e | ||
|
|
62150ce6c4 | ||
|
|
b2d4135dca | ||
|
|
49e3e01ece | ||
|
|
23c2ff0e29 | ||
|
|
a550c255e6 | ||
|
|
6b897faaa8 | ||
|
|
48255f6f1e | ||
|
|
45bc3bd3db | ||
|
|
5ab20a9257 | ||
|
|
88e4918208 | ||
|
|
521ef8b6da | ||
|
|
0d86dfa571 | ||
|
|
472350e56f | ||
|
|
68569b9640 | ||
|
|
823f11d5dd | ||
|
|
ae19018831 | ||
|
|
d5b09c7b3e | ||
|
|
d3b4aa4dc7 | ||
|
|
c2da477735 | ||
|
|
843ff8eaaa | ||
|
|
c5143e2c54 | ||
|
|
0596f5e864 | ||
|
|
8ca1b25daf | ||
|
|
1f76159bfe | ||
|
|
39ece35f52 | ||
|
|
63c1bb9e17 | ||
|
|
354622c5ad | ||
|
|
df7fd8c900 | ||
|
|
7957690fca | ||
|
|
63d19447a0 | ||
|
|
018a84ec59 | ||
|
|
e5c0e623a0 | ||
|
|
9a2d3e15e8 | ||
|
|
c07e262e68 | ||
|
|
cacb2b91ee | ||
|
|
6f269d598f | ||
|
|
57ea254bff | ||
|
|
7e183c838f | ||
|
|
3ffdfd9736 | ||
|
|
621c701bef | ||
|
|
3c24c9966c | ||
|
|
995de525d9 | ||
|
|
ae30b1220a | ||
|
|
e380ad26c2 | ||
|
|
9bb31d2380 | ||
|
|
8ec1e4f3fa | ||
|
|
9f0f6841b0 | ||
|
|
5d18f98b44 | ||
|
|
e738177e08 | ||
|
|
bb201935b9 | ||
|
|
bcfe6bd616 | ||
|
|
9c6352a7bc | ||
|
|
9110e41f20 | ||
|
|
7ae871d3a6 | ||
|
|
0ddf027d43 | ||
|
|
45124a39f3 | ||
|
|
4940af0573 | ||
|
|
924b5d1733 | ||
|
|
2119a3a51e | ||
|
|
dcda99ddf3 | ||
|
|
0e35dcd5ad | ||
|
|
991d42ca0b | ||
|
|
ac242c96b7 | ||
|
|
79d45c8e33 | ||
|
|
8e9f7102f9 | ||
|
|
1952dc309b | ||
|
|
5e7767247f | ||
|
|
676bf686c7 | ||
|
|
5cd6985368 | ||
|
|
807e72dcce | ||
|
|
71702b5821 | ||
|
|
40c56248f1 | ||
|
|
74ac7d8d3f | ||
|
|
e7186b47b0 | ||
|
|
12aa7ea2cb | ||
|
|
ef584e2826 | ||
|
|
f902be10b6 | ||
|
|
29b835de59 | ||
|
|
6ff9c5b58d | ||
|
|
1b86aeb4f5 | ||
|
|
dce99c00be | ||
|
|
e47c700c36 | ||
|
|
09506c78f3 | ||
|
|
9ec1fc0902 | ||
|
|
0b3ec2c19e | ||
|
|
a94bec921c | ||
|
|
3884da3c06 | ||
|
|
d3fa177c7f | ||
|
|
d2176e2c08 | ||
|
|
8d9c59486d | ||
|
|
0e7c2b4b94 | ||
|
|
5c9bc1c745 | ||
|
|
5e7efa0098 | ||
|
|
424862e313 | ||
|
|
9b80ad5a3c | ||
|
|
96c6fa0276 | ||
|
|
69305e1833 | ||
|
|
8aa74ab65e | ||
|
|
aee12c2494 | ||
|
|
83976b3229 | ||
|
|
39f8a138d7 | ||
|
|
120e4af7b2 | ||
|
|
15bddbc86a | ||
|
|
4e8b193801 | ||
|
|
37b65996a0 | ||
|
|
9cd0d3488f | ||
|
|
eaf07cef07 | ||
|
|
02a8775537 | ||
|
|
f2d5698acb | ||
|
|
b0c0e456af | ||
|
|
0857a2ea91 | ||
|
|
1f2e6d33ce | ||
|
|
250e0690d1 | ||
|
|
e709094533 | ||
|
|
4a5b16ee2e | ||
|
|
378d64f99a | ||
|
|
4395760a40 | ||
|
|
8417fae89c | ||
|
|
6c8fae944c | ||
|
|
decab9256b | ||
|
|
183ed35ce8 | ||
|
|
2fcf85fd61 | ||
|
|
3613c1c75e | ||
|
|
e7813046f6 | ||
|
|
9871bf1963 | ||
|
|
b32e7b659b | ||
|
|
2201372744 | ||
|
|
7431a082e2 | ||
|
|
6fe3edebb1 | ||
|
|
4b6406c264 | ||
|
|
86f6bdf9af | ||
|
|
1eeed6645d | ||
|
|
bb8c4325c6 | ||
|
|
07a3301414 | ||
|
|
1590701fc9 | ||
|
|
1d4a65d0b4 | ||
|
|
c845d25ae5 | ||
|
|
ceec27bf90 | ||
|
|
4b90424773 | ||
|
|
31eb9b26b4 | ||
|
|
a8a3c9ad19 | ||
|
|
5cfa03ec07 | ||
|
|
17ab5978ad | ||
|
|
d4c69c3932 | ||
|
|
3778a9ebcf | ||
|
|
880d94e220 | ||
|
|
37607f72b2 | ||
|
|
b1c26e6f64 | ||
|
|
8164af281d | ||
|
|
af676c8f26 | ||
|
|
b8dc7ff18e | ||
|
|
4aee129cdc | ||
|
|
03d29dd674 | ||
|
|
5a6f84ce34 | ||
|
|
0e593c7d81 | ||
|
|
4de830d663 | ||
|
|
769bb7a55d | ||
|
|
ed6c6e5a25 | ||
|
|
302ba75729 | ||
|
|
69dc8f304c | ||
|
|
e43002d5ad | ||
|
|
edd07befe2 | ||
|
|
5cc6a2f7d0 | ||
|
|
926f39c96b | ||
|
|
abd38082de | ||
|
|
5ca90f4d22 | ||
|
|
c9586e579a | ||
|
|
fe7962e10a |
No files matched your search
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"presets": [
|
||||
"@babel/preset-stage-3"
|
||||
]
|
||||
],
|
||||
"env": {
|
||||
"COVERAGE": {
|
||||
"plugins": [
|
||||
"istanbul"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
+64
-19
@@ -1,16 +1,12 @@
|
||||
FROM quay.io/wekan/ubuntu:groovy-20201125.2
|
||||
FROM quay.io/wekan/ubuntu:groovy-20210115
|
||||
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 BUILD_DEPS="gnupg gosu libarchive-tools wget curl bzip2 g++ build-essential python git ca-certificates iproute2"
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
ENV \
|
||||
DEBUG=false \
|
||||
NODE_VERSION=v12.22.0 \
|
||||
NODE_VERSION=v12.22.6 \
|
||||
METEOR_RELEASE=1.10.2 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
@@ -134,23 +130,24 @@ ENV \
|
||||
SAML_PUBLIC_CERTFILE="" \
|
||||
SAML_IDENTIFIER_FORMAT="" \
|
||||
SAML_LOCAL_PROFILE_MATCH_ATTRIBUTE="" \
|
||||
SAML_ATTRIBUTES=""
|
||||
SAML_ATTRIBUTES="" \
|
||||
DEFAULT_WAIT_SPINNER=""
|
||||
|
||||
# Install OS
|
||||
RUN set -o xtrace \
|
||||
&& useradd --user-group -m --system --home-dir /home/wekan wekan \
|
||||
&& apt-get update \
|
||||
&& apt-get install --assume-yes --no-install-recommends apt-utils apt-transport-https ca-certificates 2>&1 \
|
||||
&& apt-get install --assume-yes --no-install-recommends ${BUILD_DEPS}
|
||||
&& apt-get install --assume-yes --no-install-recommends apt-utils apt-transport-https ca-certificates 2>&1 \
|
||||
&& apt-get install --assume-yes --no-install-recommends ${BUILD_DEPS}
|
||||
|
||||
# Install NodeJS
|
||||
RUN set -o xtrace \
|
||||
&& cd /tmp \
|
||||
&& curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-$ARCHITECTURE.tar.xz" \
|
||||
&& curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/SHASUMS256.txt.asc" \
|
||||
&& grep " node-v$NODE_VERSION-$ARCHITECTURE.tar.xz\$" SHASUMS256.txt.asc | sha256sum -c - \
|
||||
&& tar -xJf "node-v$NODE_VERSION-$ARCHITECTURE.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
|
||||
&& rm "node-v$NODE_VERSION-$ARCHITECTURE.tar.xz" SHASUMS256.txt.asc \
|
||||
&& curl -fsSLO --compressed "https://nodejs.org/dist/$NODE_VERSION/node-$NODE_VERSION-$ARCHITECTURE.tar.xz" \
|
||||
&& curl -fsSLO --compressed "https://nodejs.org/dist/$NODE_VERSION/SHASUMS256.txt.asc" \
|
||||
&& grep " node-$NODE_VERSION-$ARCHITECTURE.tar.xz\$" SHASUMS256.txt.asc | sha256sum -c - \
|
||||
&& tar -xJf "node-$NODE_VERSION-$ARCHITECTURE.tar.xz" -C /usr/local --strip-components=1 --no-same-owner \
|
||||
&& rm "node-$NODE_VERSION-$ARCHITECTURE.tar.xz" SHASUMS256.txt.asc \
|
||||
&& ln -s /usr/local/bin/node /usr/local/bin/nodejs \
|
||||
&& mkdir -p /usr/local/lib/node_modules/fibers/.node-gyp /root/.node-gyp/${NODE_VERSION} /home/wekan/.config \
|
||||
&& npm install -g npm@${NPM_VERSION} \
|
||||
@@ -172,17 +169,65 @@ RUN set -o xtrace \
|
||||
|
||||
ENV PATH=$PATH:/home/wekan/.meteor/
|
||||
|
||||
# Copy source dir
|
||||
USER root
|
||||
|
||||
RUN echo "export PATH=$PATH" >> /etc/environment
|
||||
|
||||
RUN set -o xtrace \
|
||||
&& mkdir /home/wekan/app
|
||||
USER wekan
|
||||
|
||||
COPY ${SRC_PATH} /home/wekan/app/
|
||||
# Copy source dir
|
||||
RUN set -o xtrace \
|
||||
&& mkdir -p /home/wekan/app/.meteor \
|
||||
&& mkdir -p /home/wekan/app/packages
|
||||
|
||||
COPY \
|
||||
.meteor/.finished-upgraders \
|
||||
.meteor/.id \
|
||||
.meteor/cordova-plugins \
|
||||
.meteor/packages \
|
||||
.meteor/platforms \
|
||||
.meteor/release \
|
||||
.meteor/versions \
|
||||
/home/wekan/app/.meteor/
|
||||
|
||||
COPY \
|
||||
package.json \
|
||||
settings.json \
|
||||
/home/wekan/app/
|
||||
|
||||
COPY \
|
||||
packages \
|
||||
/home/wekan/app/packages/
|
||||
|
||||
USER root
|
||||
|
||||
RUN set -o xtrace \
|
||||
&& chown -R wekan:wekan /home/wekan/app /home/wekan/.meteor
|
||||
|
||||
USER wekan
|
||||
|
||||
RUN \
|
||||
set -o xtrace && \
|
||||
sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' /home/wekan/app/packages/meteor-useraccounts-core/package.js && \
|
||||
cd /home/wekan/.meteor && \
|
||||
/home/wekan/.meteor/meteor -- help;
|
||||
|
||||
RUN \
|
||||
set -o xtrace && \
|
||||
# Build app
|
||||
cd /home/wekan/app && \
|
||||
/home/wekan/.meteor/meteor add standard-minifier-js && \
|
||||
/home/wekan/.meteor/meteor npm install && \
|
||||
/home/wekan/.meteor/meteor build --directory /home/wekan/app_build
|
||||
|
||||
RUN \
|
||||
set -o xtrace && \
|
||||
cd /home/wekan/app_build/bundle/programs/server/ && \
|
||||
chmod u+w package.json npm-shrinkwrap.json && \
|
||||
npm install
|
||||
|
||||
ENV PORT=3000
|
||||
EXPOSE $PORT
|
||||
WORKDIR /home/wekan/app
|
||||
|
||||
CMD ["/home/wekan/.meteor/meteor", "run", "--verbose", "--settings", "settings.json"]
|
||||
@@ -3,17 +3,18 @@ version: '3.7'
|
||||
services:
|
||||
|
||||
wekandb-dev:
|
||||
image: mongo:4.0.12
|
||||
image: mongo:4.4
|
||||
container_name: wekan-dev-db
|
||||
restart: unless-stopped
|
||||
command: mongod --smallfiles --oplogSize 128
|
||||
command: mongod --oplogSize 128
|
||||
networks:
|
||||
- wekan-dev-tier
|
||||
expose:
|
||||
- 27017
|
||||
volumes:
|
||||
- wekan-dev-db:/data/db
|
||||
- wekan-dev-db-dump:/dump
|
||||
- ./volumes/wekan-db:/data/db
|
||||
- ./volumes/wekan-db-dump:/dump
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
wekan-dev:
|
||||
container_name: wekan-dev-app
|
||||
@@ -35,9 +36,13 @@ services:
|
||||
depends_on:
|
||||
- wekandb-dev
|
||||
volumes:
|
||||
- ..:/app:delegated
|
||||
command:
|
||||
sleep infinity
|
||||
- ../client:/home/wekan/app/client
|
||||
- ../models:/home/wekan/app/models
|
||||
- ../config:/home/wekan/app/config
|
||||
- ../i18n:/home/wekan/app/i18n
|
||||
- ../server:/home/wekan/app/server
|
||||
- ../public:/home/wekan/app/public
|
||||
- /etc/localtime:/etc/localtime:ro
|
||||
|
||||
volumes:
|
||||
wekan-dev-db:
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
*~
|
||||
*.swp
|
||||
.meteor-spk
|
||||
*.sublime-workspace
|
||||
tmp/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.gitmodules
|
||||
.vscode/
|
||||
.idea/
|
||||
.build/*
|
||||
**/parts/
|
||||
**/stage
|
||||
**/prime
|
||||
**/*.snap
|
||||
snap/.snapcraft/
|
||||
.idea
|
||||
.DS_Store
|
||||
.DS_Store?
|
||||
.build*
|
||||
*.browserify.js.cached
|
||||
*.browserify.js.map
|
||||
.build*
|
||||
versions.json
|
||||
.versions
|
||||
.npm
|
||||
.build*
|
||||
._*
|
||||
.Trashes
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
.eslintcache
|
||||
.meteor/local
|
||||
.devcontainer/docker-compose.extend.yml
|
||||
.devcontainer/volumes*/
|
||||
.git
|
||||
@@ -122,6 +122,7 @@
|
||||
"Activities": true,
|
||||
"Attachments": true,
|
||||
"Boards": true,
|
||||
"CardCommentReactions": true,
|
||||
"CardComments": true,
|
||||
"DatePicker": true,
|
||||
"Cards": true,
|
||||
@@ -156,6 +157,7 @@
|
||||
"Integrations": true,
|
||||
"HTTP": true,
|
||||
"AccountSettings": true,
|
||||
"TableVisibilityModeSettings": true,
|
||||
"Announcements": true,
|
||||
"Swimlanes": true,
|
||||
"ChecklistItems": true,
|
||||
|
||||
@@ -81,7 +81,7 @@ parts:
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.22.0
|
||||
node-engine: 12.22.6
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
|
||||
@@ -83,7 +83,7 @@ parts:
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.22.0
|
||||
node-engine: 12.22.6
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
## Issue
|
||||
|
||||
Note: With Docker, please don't use latest tag. Only use release tags.
|
||||
See https://github.com/wekan/wekan/issues/3874
|
||||
|
||||
If you can not login for any reason:
|
||||
- https://github.com/wekan/wekan/wiki/Forgot-Password
|
||||
|
||||
Email settings:
|
||||
- https://github.com/wekan/wekan/wiki/Troubleshooting-Mail
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
on: [push]
|
||||
|
||||
jobs:
|
||||
zap_scan:
|
||||
runs-on: ubuntu-latest
|
||||
name: Scan the webapplication
|
||||
steps:
|
||||
- name: OWASP ZAP Scan
|
||||
runs-on: ubuntu-latest
|
||||
uses: zaproxy/action-baseline@v0.4.0
|
||||
with:
|
||||
target: 'https://boards.wekan.team/sign-in'
|
||||
@@ -0,0 +1,160 @@
|
||||
name: Test suite
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
# the following are optional jobs and need to be configured according
|
||||
# to this project's settings:
|
||||
#
|
||||
# lintcode:
|
||||
# name: Javascript lint
|
||||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v2
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: '12.x'
|
||||
#
|
||||
# - name: cache dependencies
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ~/.npm
|
||||
# key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-node-
|
||||
#
|
||||
# - run: npm install
|
||||
# - run: npm run lint:code
|
||||
#
|
||||
# lintstyle:
|
||||
# name: SCSS lint
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: [lintcode]
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v2
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: '12.x'
|
||||
#
|
||||
# - name: cache dependencies
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ~/.npm
|
||||
# key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-node-
|
||||
# - run: npm install
|
||||
# - run: npm run lint:style
|
||||
#
|
||||
# lintdocs:
|
||||
# name: documentation lint
|
||||
# runs-on: ubuntu-latest
|
||||
# needs: [lintcode,lintstyle]
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v2
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
# with:
|
||||
# node-version: '12.x'
|
||||
#
|
||||
# - name: cache dependencies
|
||||
# uses: actions/cache@v1
|
||||
# with:
|
||||
# path: ~/.npm
|
||||
# key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
# restore-keys: |
|
||||
# ${{ runner.os }}-node-
|
||||
#
|
||||
# - run: npm install
|
||||
# - run: npm run lint:markdown
|
||||
|
||||
tests:
|
||||
name: Meteor ${{ matrix.meteor }} tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
# CHECKOUTS
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
# CACHING
|
||||
- name: Install Meteor
|
||||
id: cache-meteor-install
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.meteor
|
||||
key: v1-meteor-${{ hashFiles('.meteor/versions') }}
|
||||
restore-keys: |
|
||||
v1-meteor-
|
||||
|
||||
- name: Cache NPM dependencies
|
||||
id: cache-meteor-npm
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: v1-npm-${{ hashFiles('package-lock.json') }}
|
||||
restore-keys: |
|
||||
v1-npm-
|
||||
|
||||
- name: Cache Meteor build
|
||||
id: cache-meteor-build
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: |
|
||||
.meteor/local/resolver-result-cache.json
|
||||
.meteor/local/plugin-cache
|
||||
.meteor/local/isopacks
|
||||
.meteor/local/bundler-cache/scanner
|
||||
key: v1-meteor_build_cache-${{ github.ref }}-${{ github.sha }}
|
||||
restore-key: |
|
||||
v1-meteor_build_cache-
|
||||
|
||||
- name: Setup meteor
|
||||
uses: meteorengineer/setup-meteor@v1
|
||||
with:
|
||||
meteor-release: '2.2'
|
||||
|
||||
- name: Install NPM Dependencies
|
||||
run: meteor npm ci
|
||||
|
||||
- name: Run Tests
|
||||
run: sh ./test-wekan.sh -cv
|
||||
|
||||
- name: Upload coverage
|
||||
uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: coverage-folder
|
||||
path: .coverage/
|
||||
|
||||
coverage:
|
||||
name: Coverage report
|
||||
runs-on: ubuntu-latest
|
||||
needs: [tests]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download coverage
|
||||
uses: actions/download-artifact@v2
|
||||
with:
|
||||
name: coverage-folder
|
||||
path: .coverage/
|
||||
|
||||
|
||||
- name: Coverage Report
|
||||
uses: VeryGoodOpenSource/very_good_coverage@v1.1.1
|
||||
with:
|
||||
path: ".coverage/lcov.info"
|
||||
min_coverage: 1 # TODO add tests and increase to 95!
|
||||
@@ -32,3 +32,9 @@ ehthumbs.db
|
||||
.eslintcache
|
||||
.meteor/local
|
||||
.devcontainer/docker-compose.extend.yml
|
||||
.devcontainer/volumes*/
|
||||
.coverage
|
||||
|
||||
# Helm chart
|
||||
# Chart dependencies
|
||||
/helm/wekan/**/*.tgz
|
||||
+9
-7
@@ -6,7 +6,7 @@
|
||||
meteor-base@1.4.0
|
||||
|
||||
# Build system
|
||||
ecmascript@0.15.0
|
||||
ecmascript@0.15.1
|
||||
standard-minifier-css@1.7.2
|
||||
standard-minifier-js@2.6.0
|
||||
mquandalle:jade
|
||||
@@ -17,13 +17,13 @@ es5-shim@4.8.0
|
||||
|
||||
# Collections
|
||||
aldeed:collection2
|
||||
cfs:standard-packages
|
||||
wekan-cfs-standard-packages
|
||||
cottz:publish-relations
|
||||
dburles:collection-helpers
|
||||
idmontie:migrations
|
||||
matb33:collection-hooks
|
||||
matteodem:easy-search
|
||||
mongo@1.10.1
|
||||
mongo@1.11.0
|
||||
mquandalle:collection-mutations
|
||||
|
||||
# Account system
|
||||
@@ -75,7 +75,7 @@ horka:swipebox
|
||||
dynamic-import@0.6.0
|
||||
|
||||
accounts-password@1.7.0
|
||||
cfs:gridfs
|
||||
wekan-cfs-gridfs
|
||||
rzymek:fullcalendar
|
||||
momentjs:moment@2.22.2
|
||||
browser-policy-framing@1.1.0
|
||||
@@ -83,7 +83,6 @@ mquandalle:moment
|
||||
msavin:usercache
|
||||
# Keep stylus in 1.1.0, because building v2 takes extra 52 minutes.
|
||||
coagmano:stylus@1.1.0!
|
||||
lucasantoniassi:accounts-lockout
|
||||
meteorhacks:subs-manager
|
||||
meteorhacks:picker
|
||||
lamhieu:unblock
|
||||
@@ -91,8 +90,7 @@ meteorhacks:aggregate@1.3.0
|
||||
wekan-markdown
|
||||
konecty:mongo-counter
|
||||
percolate:synced-cron
|
||||
cfs:filesystem
|
||||
tmeasday:check-npm-versions
|
||||
wekan-cfs-filesystem
|
||||
steffo:meteor-accounts-saml
|
||||
rajit:bootstrap3-datepicker-fi
|
||||
rajit:bootstrap3-datepicker-ar
|
||||
@@ -145,3 +143,7 @@ rajit:bootstrap3-datepicker-zh-tw
|
||||
staringatlights:fast-render
|
||||
spacebars
|
||||
easylogic:summernote
|
||||
pascoual:pdfkit
|
||||
wekan-accounts-lockout
|
||||
lmieulet:meteor-coverage
|
||||
meteortesting:mocha
|
||||
+1
-1
@@ -1 +1 @@
|
||||
METEOR@2.1
|
||||
METEOR@2.2
|
||||
+56
-51
@@ -1,7 +1,7 @@
|
||||
3stack:presence@1.1.2
|
||||
accounts-base@1.8.0
|
||||
accounts-base@1.9.0
|
||||
accounts-oauth@1.2.0
|
||||
accounts-password@1.7.0
|
||||
accounts-password@1.7.1
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
@@ -11,36 +11,19 @@ allow-deny@1.1.0
|
||||
arillo:flow-router-helpers@0.5.2
|
||||
audit-argument-checks@1.0.7
|
||||
autoupdate@1.7.0
|
||||
babel-compiler@7.6.0
|
||||
babel-compiler@7.6.1
|
||||
babel-runtime@1.5.0
|
||||
base64@1.0.12
|
||||
binary-heap@1.0.11
|
||||
blaze@2.3.4
|
||||
blaze-tools@1.0.10
|
||||
blaze@2.5.0
|
||||
blaze-tools@1.1.2
|
||||
boilerplate-generator@1.7.1
|
||||
browser-policy-common@1.0.11
|
||||
browser-policy-framing@1.1.0
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.1.3
|
||||
caching-html-compiler@1.2.0
|
||||
callback-hook@1.3.0
|
||||
cfs:access-point@0.1.49
|
||||
cfs:base-package@0.0.30
|
||||
cfs:collection@0.5.5
|
||||
cfs:collection-filters@0.2.4
|
||||
cfs:data-man@0.0.6
|
||||
cfs:file@0.1.17
|
||||
cfs:filesystem@0.1.2
|
||||
cfs:gridfs@0.0.34
|
||||
cfs:http-methods@0.0.32
|
||||
cfs:http-publish@0.0.13
|
||||
cfs:power-queue@0.9.11
|
||||
cfs:reactive-list@0.0.9
|
||||
cfs:reactive-property@0.0.4
|
||||
cfs:standard-packages@0.5.10
|
||||
cfs:storage-adapter@0.2.4
|
||||
cfs:tempstore@0.1.6
|
||||
cfs:upload-http@0.0.20
|
||||
cfs:worker@0.1.5
|
||||
check@1.3.1
|
||||
chuangbo:cookie@1.1.0
|
||||
coagmano:stylus@1.1.0
|
||||
@@ -49,18 +32,18 @@ coffeescript-compiler@2.4.1
|
||||
cottz:publish-relations@2.0.8
|
||||
dburles:collection-helpers@1.1.0
|
||||
ddp@1.4.0
|
||||
ddp-client@2.4.0
|
||||
ddp-client@2.4.1
|
||||
ddp-common@1.4.0
|
||||
ddp-rate-limiter@1.0.9
|
||||
ddp-server@2.3.2
|
||||
ddp-server@2.3.3
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.1
|
||||
dynamic-import@0.6.0
|
||||
easylogic:summernote@0.8.8
|
||||
ecmascript@0.15.0
|
||||
ecmascript@0.15.1
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.11.0
|
||||
ecmascript-runtime-server@0.10.0
|
||||
ecmascript-runtime-client@0.11.1
|
||||
ecmascript-runtime-server@0.10.1
|
||||
ejson@1.1.1
|
||||
email@2.0.0
|
||||
es5-shim@4.8.0
|
||||
@@ -70,10 +53,10 @@ fortawesome:fontawesome@4.7.0
|
||||
geojson-utils@1.0.10
|
||||
horka:swipebox@1.0.2
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.11
|
||||
htmljs@1.0.11
|
||||
http@1.4.3
|
||||
id-map@1.1.0
|
||||
html-tools@1.1.2
|
||||
htmljs@1.1.1
|
||||
http@1.4.4
|
||||
id-map@1.1.1
|
||||
idmontie:migrations@1.0.3
|
||||
inter-process-messaging@0.1.1
|
||||
jquery@1.11.11
|
||||
@@ -84,11 +67,11 @@ kenton:accounts-sandstorm@0.7.0
|
||||
konecty:mongo-counter@0.0.5_3
|
||||
lamhieu:meteorx@2.1.1
|
||||
lamhieu:unblock@1.0.0
|
||||
launch-screen@1.2.0
|
||||
launch-screen@1.2.1
|
||||
livedata@1.0.18
|
||||
lmieulet:meteor-coverage@3.2.0
|
||||
localstorage@1.2.0
|
||||
logging@1.2.0
|
||||
lucasantoniassi:accounts-lockout@1.0.0
|
||||
matb33:collection-hooks@0.9.1
|
||||
matteodem:easy-search@1.6.4
|
||||
mdg:validation-error@0.5.1
|
||||
@@ -100,19 +83,22 @@ 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.3
|
||||
meteortesting:browser-tests@1.3.4
|
||||
meteortesting:mocha@2.0.1
|
||||
meteortesting:mocha-core@8.0.1
|
||||
minifier-css@1.5.4
|
||||
minifier-js@2.6.0
|
||||
minifiers@1.1.8-faster-rebuild.0
|
||||
minimongo@1.6.1
|
||||
minimongo@1.6.2
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.5
|
||||
modules@0.16.0
|
||||
modules-runtime@0.12.0
|
||||
momentjs:moment@2.29.1
|
||||
mongo@1.10.1
|
||||
mongo@1.11.1
|
||||
mongo-decimal@0.1.2
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.7
|
||||
mongo-id@1.0.8
|
||||
mongo-livedata@1.0.12
|
||||
mousetrap:mousetrap@1.4.6_1
|
||||
mquandalle:autofocus@1.0.0
|
||||
@@ -124,13 +110,14 @@ mquandalle:jquery-ui-drag-drop-sort@0.2.0
|
||||
mquandalle:moment@1.0.1
|
||||
mquandalle:mousetrap-bindglobal@0.0.1
|
||||
msavin:usercache@1.8.0
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@3.8.1
|
||||
npm-bcrypt@0.9.4
|
||||
npm-mongo@3.9.0
|
||||
oauth@1.3.2
|
||||
oauth2@1.3.0
|
||||
observe-sequence@1.0.16
|
||||
ongoworks:speakingurl@1.1.0
|
||||
ordered-dict@1.1.0
|
||||
pascoual:pdfkit@1.0.7
|
||||
peerlibrary:assert@0.3.0
|
||||
peerlibrary:base-component@0.16.0
|
||||
peerlibrary:blaze-components@0.15.1
|
||||
@@ -191,7 +178,7 @@ 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
|
||||
react-fast-refresh@0.1.0
|
||||
react-fast-refresh@0.1.1
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.3.1
|
||||
@@ -208,10 +195,10 @@ 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.1
|
||||
socket-stream-client@0.3.3
|
||||
softwarerero:accounts-t9n@1.3.11
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.3
|
||||
spacebars@1.2.0
|
||||
spacebars-compiler@1.2.1
|
||||
srp@1.1.0
|
||||
standard-minifier-css@1.7.2
|
||||
standard-minifier-js@2.6.0
|
||||
@@ -220,24 +207,42 @@ 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
|
||||
templating@1.4.0
|
||||
templating-compiler@1.4.1
|
||||
templating-runtime@1.4.0
|
||||
templating-tools@1.2.0
|
||||
tracker@1.2.0
|
||||
twbs:bootstrap@3.3.6
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.3.1
|
||||
url@1.3.2
|
||||
useraccounts:core@1.14.2
|
||||
useraccounts:flow-routing@1.14.2
|
||||
useraccounts:unstyled@1.14.2
|
||||
verron:autosize@3.0.8
|
||||
webapp@1.10.0
|
||||
webapp@1.10.1
|
||||
webapp-hashing@1.1.0
|
||||
wekan-accounts-cas@0.1.0
|
||||
wekan-accounts-lockout@1.0.0
|
||||
wekan-accounts-oidc@1.0.10
|
||||
wekan-cfs-access-point@0.1.50
|
||||
wekan-cfs-base-package@0.0.30
|
||||
wekan-cfs-collection@0.5.5
|
||||
wekan-cfs-collection-filters@0.2.4
|
||||
wekan-cfs-data-man@0.0.6
|
||||
wekan-cfs-file@0.1.17
|
||||
wekan-cfs-filesystem@0.1.2
|
||||
wekan-cfs-gridfs@0.0.34
|
||||
wekan-cfs-http-methods@0.0.32
|
||||
wekan-cfs-http-publish@0.0.13
|
||||
wekan-cfs-power-queue@0.9.11
|
||||
wekan-cfs-reactive-list@0.0.9
|
||||
wekan-cfs-reactive-property@0.0.4
|
||||
wekan-cfs-standard-packages@0.5.10
|
||||
wekan-cfs-storage-adapter@0.2.4
|
||||
wekan-cfs-tempstore@0.1.6
|
||||
wekan-cfs-upload-http@0.0.21
|
||||
wekan-cfs-worker@0.1.5
|
||||
wekan-ldap@0.0.2
|
||||
wekan-markdown@1.0.9
|
||||
wekan-oidc@1.0.12
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ sudo: required
|
||||
|
||||
env:
|
||||
TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
|
||||
TRAVIS_NODE_VERSION: 12.22.0
|
||||
TRAVIS_NODE_VERSION: 12.22.6
|
||||
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 = ar_EG:ar-EG, bg_BG:bg, en_GB:en-GB, es_AR:es-AR, es_CL:es-CL, es_419:es-LA, es_PE:es-PE, es_MX:es-MX, es_TX:es-TX, es_PY:es-PY, el_GR:el, fa_IR:fa-IR, 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 = ar_EG:ar-EG, bg_BG:bg, de_CH:de-CH, en_IT:en-IT, en_GB:en-GB, es_AR:es-AR, es_CL:es-CL, es_419:es-LA, es_PE:es-PE, es_MX:es-MX, es_TX:es-TX, es_PY:es-PY, el_GR:el, fa_IR:fa-IR, fi_FI:fi, fr_CH:fr-CH, hu_HU:hu, id_ID:id, mn_MN:mn, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, sl_SI:sl, zh_CN:zh-CN, zh_TW:zh-TW, zh_Hans:zh-Hans, zh_HK:zh-HK
|
||||
|
||||
[wekan.application]
|
||||
file_filter = i18n/<lang>.i18n.json
|
||||
|
||||
+817
-3
@@ -1,3 +1,817 @@
|
||||
[Mac ChangeLog](https://github.com/wekan/wekan/wiki/Mac)
|
||||
|
||||
Note: With Docker, please don't use latest tag. Only use release tags.
|
||||
See https://github.com/wekan/wekan/issues/3874
|
||||
|
||||
# v5.59 2021-09-17 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Admin Panel/People: Possibility of adding a team to all selected users](https://github.com/wekan/wekan/pull/3996).
|
||||
Thanks to Emile840.
|
||||
- [Add / remove team members as board members when adding / removing team from board](https://github.com/wekan/wekan/pull/4000).
|
||||
Thanks to Emile840.
|
||||
- [Added more translations to: Admin Panel/People: Possibility of adding a team to all selected users](https://github.com/wekan/wekan/commit/3d9b7eb7ab41c6450b473f6f349d894f516c5487).
|
||||
Thanks to xet7.
|
||||
- [Enter new password 2 times when registering](https://github.com/wekan/wekan/commit/0da84f8f3eb91c5bf726e058f5ec74a7891d734b).
|
||||
Thanks to sh2515 and xet7.
|
||||
- Sum of cards. In Progress, not ready yet.
|
||||
[Part 1: Add Custom Field options for field sum](https://github.com/wekan/wekan/commit/8626b466b830adf6c671211bbd61b53b96ac5a49).
|
||||
[Part 2: Show option for custom field sum only for currency and number custom fields](https://github.com/wekan/wekan/commit/9bee6ae6663a5e1c974de2811f6a5fdd2d66efe5).
|
||||
Thanks to xet7.
|
||||
- [Admin Panel/Settings/Layout: Customize OIDC button text](https://github.com/wekan/wekan/pull/4011.
|
||||
Thanks to Emile840.
|
||||
- [At card attachments, show play and fullscreen controls for video webm/mp4/ogg, and play controls for audio mp3/ogg](https://github.com/wekan/wekan/commit/bd9fbedbf9fbe0181913876b930b335261cd2a0a).
|
||||
Thanks to luistiktok and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Links to devel branch are broken; use master instead](https://github.com/wekan/wekan/pull/3993).
|
||||
Thanks to garrison.
|
||||
- [Fix first user creation for via OIDC](https://github.com/wekan/wekan/pull/3994).
|
||||
Thanks to ww-daniel-mora.
|
||||
- [When list has just one card, to show 'card' instead of 'cards'](https://github.com/wekan/wekan/pull/3999).
|
||||
Thanks to helioguardabaxo.
|
||||
- [Fix: Linked card cannot change date](https://github.com/wekan/wekan/pull/4002).
|
||||
Thanks to Ben0it-T.
|
||||
- [Try to fix: Can't delete attachment](https://github.com/wekan/wekan/commit/889ec1339a025a68ec919f059b9d58e8d94a3376).
|
||||
Thanks to luistiktok and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.58 2021-09-01 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [1) Edit profile and modify password menus are not displayed if SSO authentication is used.
|
||||
2) Board filtering will be displayed only if user belongs to atleast one team or
|
||||
organization](https://github.com/wekan/wekan/pull/3983).
|
||||
Thanks to Emile840.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.57 2021-08-31 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Updated build scripts](https://github.com/wekan/wekan/commit/52fafe997659e933e403acb0ee0cffc99f74e35f).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.56 2021-08-31 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/858967f4200783cadaa62d0e3436f661c772ede7).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.55 2021-08-31 Wekan release
|
||||
|
||||
This release adds to following CRITICAL SECURITY UPDATES:
|
||||
|
||||
- [Updated to Node.js v12.22.6](https://github.com/wekan/wekan/commit/48636892489dd01c6f6b930bafb94651c00859d8).
|
||||
Thanks to Node.js developers.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fixed bugs](https://github.com/wekan/wekan/pull/3981):
|
||||
1) Public Boards page shows only "Add Board" button, not any Public Boards.
|
||||
2) When at Admin Panel / Boards visibility / Private only, public board still accessible publicly by it's
|
||||
public board URL.
|
||||
Thanks to Emile840.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.54 2021-08-28 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Admin panel: Added a parameter to display or not the visibility of a board in private mode only](https://github.com/wekan/wekan/pull/3976).
|
||||
Thanks to Emile840.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: Incorrect card numbers for sub tasks](https://github.com/wekan/wekan/pull/3977).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.53 2021-08-27 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Try to fix MAIL_FROM](https://github.com/wekan/wekan/commit/787df044190915c46e22159f3c40fb611846dc07).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.52 2021-08-26 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Added MAIL_SERVICE settings for Well Known Email Services
|
||||
[Part 1](https://github.com/wekan/wekan/commit/ab8e56e16a02ef0afb7b4023a43b4adf2558a8ff),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/1fadf204c2d5fa96ea41b9cb39f003cc05e2fe46).
|
||||
https://github.com/wekan/wekan/wiki/Troubleshooting-Mail . Please test.
|
||||
Thanks to xet7.
|
||||
- [All Boards page: Possibility of filtering board by team or organization](https://github.com/wekan/wekan/pull/3964).
|
||||
Thanks to Emile840.
|
||||
- [Fixed translation of "Clear Filter" for "All boards page: Possibility of filtering board by team or organization"](https://github.com/wekan/wekan/commit/b36a7621e0feca5c22fc4a24eceba1a9fc584ab0).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following new translations:
|
||||
|
||||
- [Added Chinese (Simplified) (zh-Hans or zh-CN)](https://github.com/wekan/wekan/commit/f2c242f49e18e2197f1f90c9b2dac5934a08325d).
|
||||
Thanks to translators.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Initials not required for new user that is created at Admin Panel](https://github.com/wekan/wekan/commit/9c7c481f48cb66406715f7571439f9d7fa332b87).
|
||||
Thanks to xet7.
|
||||
- [Delete user is now possible at Admin Panel](https://github.com/wekan/wekan/commit/7808fdd22f04cc482b7df21187aaf3e9623f19e6).
|
||||
But you should remove user first from all boards, because otherwise there could be
|
||||
bug of empty avatars at boards, that need to be removed manually from database.
|
||||
Thanks to xet7.
|
||||
- [Fixed Save button not clickable in maximized card view](https://github.com/wekan/wekan/commit/a59932af00c066871102970d252b78d262d06fa0).
|
||||
Thanks to hatl, urmel1960 and syndimann.
|
||||
- [Fixed New wide card edit view is all jumbled on mobile](https://github.com/wekan/wekan/commit/241eb9df0fb446b3775704848281b0cc032c4921).
|
||||
Thanks to jdaviescoates and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.51 2021-08-17 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fixed exception in global search](https://github.com/wekan/wekan/pull/3949).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.50 2021-08-15 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix: Save user initials and fullname when a new user is created](https://github.com/wekan/wekan/pull/3946).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.49 2021-08-14 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Text "Search" now translatable at Card Add Member/Assignee](https://github.com/wekan/wekan/commit/9ce65c601a875a4259fb69fdda45124b8412ae6f).
|
||||
Thanks to xet7.
|
||||
- [Add Card Comment Reactions](https://github.com/wekan/wekan/pull/3945).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.48 2021-08-11 Wekan release
|
||||
|
||||
This release adds the following CRITICAL SECURITY UPDATES:
|
||||
|
||||
- [Updated to Node.js v12.22.5](https://github.com/wekan/wekan/commit/91cad7b49e25cecdf417321dadcdd9ea5cd8b020).
|
||||
Thanks to Node.js developers.
|
||||
- Also jszip update in some of included update commits.
|
||||
|
||||
and adds the following new features:
|
||||
|
||||
- [Searchfields for members and assignees card popups](https://github.com/wekan/wekan/pull/3942).
|
||||
Thanks to syndimann.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/b3cc01b04167bd67dde02c6c899baf8917ae09c1).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and adds the following new translations:
|
||||
|
||||
- [French (Switzerland) (fr_CH)](https://github.com/wekan/wekan/commit/23c70ac252494b464cd2a268d7e680370775ddc4).
|
||||
Thanks to translators.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fixed: Can't save user without Initials](https://github.com/wekan/wekan/commit/9a03654062f9c8ac7aac257f11b386a054cd39e7).
|
||||
Thanks to devagleo and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.47 2021-08-05 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/68d9de89466611521db7d942dcf8daf58ba15a3e).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.46 2021-08-05 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/d5c0a5d377d31bedadf3730756406355a17a563a).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.45 2021-08-05 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Special handles to notify board or card members in a comment](https://github.com/wekan/wekan/pull/3937).
|
||||
Thanks to syndimann.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: Show missing user mentions popover when posting comments in maximized card layout](https://github.com/wekan/wekan/pull/3939).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.44 2021-08-03 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Wekan v5.43](https://github.com/wekan/wekan/commit/4e17d5a10f95fcea420c794ed8b30ea18dc2a725) and v5.44 for helm.
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: Consecutive Card numbering when a card is moved to another board or copied](https://github.com/wekan/wekan/pull/3936).
|
||||
Thanks to syndimann.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.43 2021-08-03 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Consecutive boardwise card numbering](https://github.com/wekan/wekan/pull/3935).
|
||||
Thanks to syndimann.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Update Helm Chart apiVersion, pin image version](https://github.com/wekan/wekan/pulls/3933).
|
||||
This makes this Chart compatible with [flux](https://fluxcd.io)
|
||||
[helm-controller](https://fluxcd.io/docs/components/helm), which requires v2 charts.
|
||||
Thanks to varac.
|
||||
- [Wekan v5.42 for helm](https://github.com/wekan/wekan/commit/7a1f42fa4e153ff4a0fb481ca5a363ac62033b7f).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.42 2021-08-01 Wekan release
|
||||
|
||||
This release adds the following CRITICAL SECURITY UPDATES:
|
||||
|
||||
- [Updated to Node.js v12.22.4](https://github.com/wekan/wekan/commit/b13f6913896f787e1cae485381d98345d9f8b830).
|
||||
Thanks to Node.js developers.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.41 2021-07-26 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fixed Wekan JSON import fails](https://github.com/wekan/wekan/commit/0fa8fc8b506831a60649d100ce93c96f8f7b76f5).
|
||||
Thanks to BartoszBroda and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.40 2021-07-25 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fixed Delete of Planning Poker doesn't work](https://github.com/wekan/wekan/commit/18b6381d790848062752b211d48c84a2de268bd0).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.39 2021-07-24 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [LDAP AD Simple Auth](https://github.com/wekan/wekan/pull/3909).
|
||||
Thanks to indika-dev.
|
||||
- [LDAP AD Simple Auth: Added settings for all remaining Wekan Standalone (non-Sandstorm)
|
||||
platforms](https://github.com/wekan/wekan/commit/fe40f35d6d9b6293f3bdbf5bc0f3e8e708c59518)
|
||||
and Docs to https://github.com/wekan/wekan/wiki/LDAP-AD-Simple-Auth .
|
||||
Thanks to xet7.
|
||||
- [Convert Checklist Item to Card](https://github.com/wekan/wekan/pull/3910).
|
||||
Thanks to helioguardabaxo.
|
||||
- [Organizations and Teams are taken into account when displaying board at
|
||||
`All Boards` page](https://github.com/wekan/wekan/pull/3912).
|
||||
Thanks to Emile840.
|
||||
|
||||
and adds the following new translations:
|
||||
|
||||
- [English (Italy)](https://github.com/wekan/wekan/commit/ae73029dda63db361925e378202e6f8c137cf5bd).
|
||||
Thanks to translators.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.38 2021-07-18 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Added Code View `</>` button when `RICHER_CARD_COMMENT_EDITOR=true` and in desktop view
|
||||
where is enough screen space for buttons (not added to mobile
|
||||
view)](https://github.com/wekan/wekan/commit/ec01e5182d6b8c848d752540887a8113472b0226).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- Updated dependencies
|
||||
[Part 1](https://github.com/wekan/wekan/commit/7024929881c05cad472de74c86517cf80c8e240c),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/609adcdf100db226c5f310577195afa4b1a4aead).
|
||||
Thanks to developers of dependencies.
|
||||
- [Updated to Node.js v12.22.3](https://github.com/wekan/wekan/commit/d538a01d1962464cf4cb001462669150eeafaa99).
|
||||
Thanks to Node.js developers.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fixed Line break which is wrongly added in Cards description and Cards
|
||||
comments](https://github.com/wekan/wekan/commit/ec01e5182d6b8c848d752540887a8113472b0226).
|
||||
Thanks to Emile840 and xet7.
|
||||
- [Fixed rebuild-wekan.sh](https://github.com/wekan/wekan/commit/1d5dd5e60fec151de6c7dce7ef4e758b562923b9).
|
||||
Thanks to xet7.
|
||||
- [Small fixes for ModernDark theme](https://github.com/wekan/wekan/pull/3902).
|
||||
Thanks to jghaanstra.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.37 2021-07-04 Wekan release
|
||||
|
||||
This release adds the following CRITICAL SECURITY UPDATES:
|
||||
|
||||
- [Updated to Node.js v12.22.2](https://github.com/wekan/wekan/commit/4feffd90e3f466609e09524e0ddccdafa2faef32).
|
||||
Thanks to Node.js developers.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Building OpenAPI docs is broken in Wekan v3.56](https://github.com/wekan/wekan/pull/3889).
|
||||
Thanks to bentiss.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.36 2021-06-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Added some controls and warning messages when user try to delete an organization or team that has
|
||||
at least one user belongs to it](https://github.com/wekan/wekan/pull/3865).
|
||||
Thanks to Emile840.
|
||||
- Shared Templates. In Progress.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/0a0cec6ef0eb55391608aade897004db430ba10a).
|
||||
Template Containers visible at All Boards page, with white border around board icon.
|
||||
[Part 2](https://github.com/wekan/wekan/commit/d1d4453120005de61eaf2cbadc6a7b9d80e75fc1).
|
||||
Ablity to Add Template Container, checkbox in Create Board popup.
|
||||
Do not create Template Container by default, when creating user.
|
||||
[Part 3](https://github.com/wekan/wekan/commit/7f17bc9fb03d6f4b43a2cd71ecc372e0f1b0f491).
|
||||
Template container titles "Card/List/Board Templates" automatically translated.
|
||||
Thanks to xet7.
|
||||
[Part 4](https://github.com/wekan/wekan/commit/3b4a44abb1c1c4339c3d1b00dfac1c69ec3684cd).
|
||||
Hide this Shared Templates feature while it's not finished yet.
|
||||
Added back creating Template Container by default, when creating user.
|
||||
Thanks to xet7.
|
||||
- [Added testsuite](https://github.com/wekan/wekan/pull/3872).
|
||||
Thanks to jankapunkt.
|
||||
- [Delete user at REST API and `Admin Panel/People/People`](https://github.com/wekan/wekan/commit/9e16a405d8ca32a4e1be9cf89f8f978a2985593c).
|
||||
There is still bug of leaving empty user avatars to boards: boards members, card members and assignees have
|
||||
empty users. So it would be better to delete user from all boards before deleting user.
|
||||
Thanks to darren-teo and xet7.
|
||||
|
||||
and adds the following improvements:
|
||||
|
||||
- [Removed unused exceljs from client bundle](https://github.com/wekan/wekan/pull/3871).
|
||||
This decreased Wekan browserside frontend amount of Javascript from 5.4 MB to 4.3 MB.
|
||||
Thanks to jankapunkt.
|
||||
- Added note: With Docker, please don't use latest tag. Only use release tags.
|
||||
See https://github.com/wekan/wekan/issues/3874 .
|
||||
[Part 1](https://github.com/wekan/wekan/commit/f18a57b059994b8a6a3588a69cf095fe599b3a90),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/c4cea9e71b467731fd8290538dd039b7691097af).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fixed tests, that need to be in tests directory to not get build
|
||||
errors](https://github.com/wekan/wekan/commit/56197274b6c4782fa20c7d9b5b9d58255d1f830a).
|
||||
Thanks to xet7.
|
||||
- Try to fix tests.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/78555f57a7c2ba0fb3e3986608bcf11509af9a21),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/7f648720afa42a2b53bfdee7e709fd891eb33373),
|
||||
[Part 3](https://github.com/wekan/wekan/commit/0f34d407a43c8a63d882e69ea64ea17fc4b22c7b).
|
||||
Thanks to xet7.
|
||||
- [Fixed "Search All Boards" instructions are gone](https://github.com/wekan/wekan/commit/30ffcc924663f39406b250d93b14384a2f38ab6a).
|
||||
Thanks to ClaudiaK21 and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.35 2021-06-14 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Wait Spinners can now be translated
|
||||
[Part 1](https://github.com/wekan/wekan/commit/8703dd42296d531450eb21a3d3adea17558a8500),
|
||||
[Part 1](https://github.com/wekan/wekan/commit/7f3f0825573b1f8a7b0388e4bacbb0bd2525e886).
|
||||
Added Wait Spinners docs: https://github.com/wekan/wekan/wiki/Wait-Spinners .
|
||||
Thanks to xet7.
|
||||
- Maximize Card.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/8c572502436a2eb22bd1eb1e4069c1c9145e2070),
|
||||
[Part 2](https://github.com/wekan/wekan/pull/3863).
|
||||
Thanks to mfilser and xet7.
|
||||
- Export Card to PDF. In Progress, does not work yet.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/a2f2ce11354a8dbfdd6759e3b65797e4be4cc6ec),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/17acf1884850d8d95ae79493289adf18966df652).
|
||||
Thanks to xet7.
|
||||
|
||||
and removes some not needed files:
|
||||
|
||||
- [Reduced Wekan bundle size from 636 MB to 467 MB by deleting all dependencies of lucasantoniassi:accounts-lockout and including
|
||||
only required 10 files](https://github.com/wekan/wekan/commit/23e5e1e3bd081699ce39ce5887db7e612616014d).
|
||||
Wekan Docker image size changed from 269.6 MB to 165.1 MB.
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following improvements:
|
||||
|
||||
- [Add border and update label colors for better visibility](https://github.com/wekan/wekan/commit/2e1eb1e224c83f16a384316626d7a4183639d4cd).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/f80fcfd7c0a83f4181c7a0b8beb52da9ba1446d3).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Manual sort number 0 accepted](https://github.com/wekan/wekan/pull/3861).
|
||||
Thanks to mfilser.
|
||||
- Allow board members to use more of API. Please add issue (or pull request) if this allows too much.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/a719e8fda1f78bcbf9af6e7b4341f8be1d141e90),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/164b6e9070199dca36d12fa3048d6b22bf6850b0).
|
||||
Thanks to JayVii and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.34 2021-06-11 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [View and change card sort number](https://github.com/wekan/wekan/pull/3857).
|
||||
Thanks to mfilser.
|
||||
- [More spinners + configureable in admin panel](https://github.com/wekan/wekan/pull/3858).
|
||||
Thanks to mfilser.
|
||||
- [Added remaining spinner settings](https://github.com/wekan/wekan/commit/488b765f95ad67b19630cd125543836c04eaa24f).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following new improvements:
|
||||
|
||||
- [Card Description has now the same color on view and editing](https://github.com/wekan/wekan/pull/3851).
|
||||
Thanks to mfilser.
|
||||
- [Development in docker container](https://github.com/wekan/wekan/pull/3852).
|
||||
Thanks to mfilser.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Google SSO to access Wekan has not been working by reverting Wekan v5.31 not-working fixes
|
||||
to OAUTH2_LOGIN_STYLE=redirect Has No Effect](https://github.com/wekan/wekan/commit/1e837dec11dc5cb266b83efcff4f462aa02d733d).
|
||||
Thanks to unpokitodxfavor and xet7.
|
||||
- [CustomFields were not created after adding 1 card](https://github.com/wekan/wekan/pull/3856).
|
||||
Thanks to mfilser.
|
||||
- [Try to fix BUG: Database error attempting to change a account](https://github.com/wekan/wekan/commit/762391965e6ae3cd5682d5b164131500e7d92338).
|
||||
Thanks to bbyszio and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.33 2021-06-10 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Assigning a user to a team or an organization](https://github.com/wekan/wekan/pull/3850).
|
||||
Thanks to Emile840.
|
||||
|
||||
and adds the following new improvements:
|
||||
|
||||
- [Custom Fields stringtemplate, autofocus the last input box](https://github.com/wekan/wekan/pull/3849).
|
||||
Thanks to mfilser.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.32 2021-06-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Moved many button texts etc to tooltips. Added more tooltips](https://github.com/wekan/wekan/commit/6ce5ab40a7dc013247717b5107a306eb0402cd63).
|
||||
Thanks to JFa-Orkis and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.31 2021-06-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Admin Panel: Edit Organizations and Teams](https://github.com/wekan/wekan/issues/802).
|
||||
Thanks to Emile840.
|
||||
- [Admin Panel: Delete Organizations and Teams](https://github.com/wekan/wekan/commit/14b2c1309f0f910c1e46b5681d3612d7ff0cbf81).
|
||||
Thanks to xet7.
|
||||
- [Admin Panel Organizations/Teams: Show confirm text above delete button](https://github.com/wekan/wekan/commit/16379201704ea1a43ce14859633ffb1b9fae6710).
|
||||
Thanks to xet7.
|
||||
- [Gantt: Retain links created between tasks. Part 1: Database changes, not active in
|
||||
MIT Wekan](https://github.com/wekan/wekan/commit/07a3a0b3882147effac890514b19ff84f1d76bdb).
|
||||
Thanks to benjaminhrivera.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Removed extra package](https://github.com/wekan/wekan/commit/646497c3f041e2f562d032fe28ef29169f671ac1).
|
||||
Thanks to xet7.
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/122757ca9c091e98b31d34c3abc25caa295dbdc0).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Now new boards do not have any labels added by default](https://github.com/wekan/wekan/commit/481404e8d7bad7799c2ad34d6a94eaf5e87602c2).
|
||||
Thanks to tedkoch and xet7.
|
||||
- [Try to fix OAUTH2_LOGIN_STYLE=redirect Has No Effect](https://github.com/wekan/wekan/commit/78324263c1c78e7e9e99f153e3158e39f564b67a).
|
||||
Thanks to 1ubuntuuser and xet7.
|
||||
- [Try to fix: Wekan UI fails to finish import of closed Trello boards](https://github.com/wekan/wekan/commit/007e0f1c16c935ce580093a6aec31305c75d1e45).
|
||||
Thanks to berezovskyi and xet7.
|
||||
- [Partial Fix: Vote and Planning Poker: Setting date and time now works for some languages that have
|
||||
ascii characters in date format](https://github.com/wekan/wekan/commit/57f31d443faaa32d6c7b53d81af3be133af5f040).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.30 2021-06-03 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Planning Poker / Scrum Poker](https://github.com/wekan/wekan/pull/3836),
|
||||
see https://github.com/wekan/wekan/wiki/Planning-Poker .
|
||||
Thanks to helioguardabaxo.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fixed Python API example: Edit card, etc](https://github.com/wekan/wekan/commit/bf62a947fbfa7d387074550288376e682fd6ad47).
|
||||
Thanks to Lucky-Shi and xet7.
|
||||
- [Default language is still used although this one has been modified previously](https://github.com/wekan/wekan/pull/3833).
|
||||
Thanks to Emile840.
|
||||
- [Moved Keyboard Shortcuts from bottom to top of Sidebar](https://github.com/wekan/wekan/commit/659a65b8b919a49ba0beef5cc53d8e61e0f794aa).
|
||||
Thanks to ClaudiaK21 and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.29 2021-05-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Excel parent card name export](https://github.com/wekan/wekan/pull/3799).
|
||||
Thanks to marcungeschikts and Enishowk.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- Updated dependencies
|
||||
[Part 1](https://github.com/wekan/wekan/commit/62150ce6c406359fba068552b4526c60faf392bb),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/1d9346513e4f378379b9f5192e8dad5535287f8a),
|
||||
[Part 3](https://github.com/wekan/wekan/commit/6be1a330936c89fcf478efe98dd15244a98d266d).
|
||||
Thanks to developers of dependencies.
|
||||
- Added updated `Forgot Password` page to GitHub issue template
|
||||
[Part 1](https://github.com/wekan/wekan/commit/6d0578fd5ad5f13f5ff9a285577e35fd62bba95f),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/ea64b17b82cd52320c0495e16385f11031dfbe3a).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Try to fix Snap: Removed linting packages](https://github.com/wekan/wekan/commit/8911fe5c8de941808585a7d3462305d5b3d2763d).
|
||||
Thanks to xet7.
|
||||
- [Removed not working GitHub workflow](https://github.com/wekan/wekan/commit/5dd6466c0aa7479015c72519f36c2485b16e3341).
|
||||
Thanks to xet7.
|
||||
- [Fix typos](https://github.com/wekan/wekan/pull/3813).
|
||||
Thanks to spasche.
|
||||
- [Fix: Impersonate user can now export Excel/CSV/TSV/JSON.
|
||||
Impersonate user and export Excel/CSV/TSV/JSON is now logged into database table
|
||||
impersonatedUsers](https://github.com/wekan/wekan/commit/3908cd5413b775d1ee549f0a95304cf9998d3855).
|
||||
Thanks to xet7.
|
||||
- [Fixed Importing JSON exports fails](https://github.com/wekan/wekan/commit/bd1de94312e428e56d6cf5f343098475573cba0b).
|
||||
Thanks to KeptnArgo and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.28 2021-05-07 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Mermaid Diagram](https://github.com/wekan/wekan/wiki/Mermaid-Diagram).
|
||||
Thanks to xuguotong and xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- Updated dependencies
|
||||
[Part 1](https://github.com/wekan/wekan/commit/521ef8b6dad4f00662f22702331193c16b91b482),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/48255f6f1e4a0caf0be006196f28295d0825eb95),
|
||||
[Part 3](https://github.com/wekan/wekan/commit/a550c255e6c3bd2d609a1a45a213cdae7ab4f74d).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: BG color of StartDate](https://github.com/wekan/wekan/pull/3793).
|
||||
Thanks to listenerri.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.27 2021-04-29 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fixed Non-ASCII attachment filename will crash when downloading](https://github.com/wekan/wekan/commit/c2da47773552a61d45b010a095f73d2e441f687c).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.26 2021-04-28 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Feature/mini card subtask count](https://github.com/wekan/wekan/pull/3765).
|
||||
Thanks to ryanMushy.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Bring back Almost-Due for Start Date](https://github.com/wekan/wekan/commit/8ca1b25daf3be60c2dc64f03830dea8437bbd8ad).
|
||||
Thanks to darren-teo.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.25 2021-04-27 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Swimlane in Export to Excel](https://github.com/wekan/wekan/pull/3764).
|
||||
Thanks to Keelan and ryanMushy.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Updated release scripts](https://github.com/wekan/wekan/commit/9f0f6841b01b88f5559724b047d5e245617a02c8).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Added missing PostgreSQL password to ToroDB](https://github.com/wekan/wekan/commit/995de525d96946702536f0cdcb98ef281b9df94e).
|
||||
Thanks to xet7.
|
||||
- [Fixed language name of Deutsch (Schweiz)](https://github.com/wekan/wekan/commit/621c701bef1d09d4ddfc93be411cfad98869f0ae).
|
||||
Thanks to urmel1960.
|
||||
- [Bugfix/Summernote on paste](https://github.com/wekan/wekan/pull/3761).
|
||||
Thanks to ryanMushy.
|
||||
- [OpenAPI: Better handle nested schemas](https://github.com/wekan/wekan/pull/3762).
|
||||
Thanks to bentiss.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.24 2021-04-24 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Copy Swimlane](https://github.com/wekan/wekan/pull/3753).
|
||||
Thanks to jrsupplee.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/e738177e081e4a7e83fed3389f47847403551fc2).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Snap: Delete extra symlink that prevented building Snap](https://github.com/wekan/wekan/commit/45124a39f34a918b251a4a36fb016639b558f119).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.23 2021-04-22 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Filtering by due date](https://github.com/wekan/wekan/pull/3731).
|
||||
Thanks to mcrute.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Updated dependencies](https://github.com/wekan/wekan/commit/676bf686c7a121b0da744afce5911807a6be48fe).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: Trello data without labels definition](https://github.com/wekan/wekan/pull/3733).
|
||||
Thanks to jrsupplee.
|
||||
- [Bug fix for Due Cards](https://github.com/wekan/wekan/pull/3741).
|
||||
Thanks to jrsupplee.
|
||||
- [Fix: The bg color of start at button is almost-due](https://github.com/wekan/wekan/pull/3749).
|
||||
Thanks to listenerri.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.22 2021-04-16 Wekan release
|
||||
|
||||
This release adds the following new translations:
|
||||
|
||||
- Added German (Switzerland) (de_CH) (Schwiizerdütsch). Updated translations.
|
||||
[Part 1](https://github.com/wekan/wekan/commit/09506c78f3c3439db622574eb851fa0c20d3a066),
|
||||
[Part 2](https://github.com/wekan/wekan/commit/dce99c00be80cceba686fd73b4b78b6c778d78a6),
|
||||
[Part 3](https://github.com/wekan/wekan/commit/6ff9c5b58d25ba52b11e5429c9cfe6ed6a97000e).
|
||||
Thanks to translators.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Remove allowedValues from Cards.type schema](https://github.com/wekan/wekan/pull/3724).
|
||||
Thanks to jrsupplee.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.21 2021-04-16 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Summernote Rich Text Editor](https://github.com/wekan/wekan/pull/3720):
|
||||
1) Add new button to insert a URL link.
|
||||
2) Add new popover allowing you to edit existing URL links.
|
||||
3) Enable spell check.
|
||||
4) Allow client side grammerly extension.
|
||||
Thanks to ryanMushy.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Upgraded to Meteor 2.2](https://github.com/wekan/wekan/commit/0e7c2b4b94b1c48e8839cfba635b53cdc1a797b1).
|
||||
Thanks to Meteor developers.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Bugfix, date format not changed to local format](https://github.com/wekan/wekan/pull/3723).
|
||||
Thanks to mfilser.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.20 2021-04-14 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [OpenAPI: rework the allowedValues to allow for imported variables](https://github.com/wekan/wekan/pull/3715).
|
||||
Thanks to bentiss.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.19 2021-04-14 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Custom Field "String Template"](https://github.com/wekan/wekan/pull/3701).
|
||||
Thanks to tod31.
|
||||
- [1) Admin reports. An option added to the admin panel that has reports an admin can run.
|
||||
Right now it has two reports for attachments and broken cards.
|
||||
2) Add the creator avatar to `cardDetails` and `minicard`. Avatar is only shown if it is selected in card settings.
|
||||
3) Added a new search operator `creator`.
|
||||
4) Bug fix for multiple label predicates](https://github.com/wekan/wekan/pull/3705).
|
||||
Thanks to jrsupplee.
|
||||
- [Update Admin Panel Rules report icon and add missing translations](https://github.com/wekan/wekan/commit/8417fae89cc89adb4559874050ff7c56cc08eb00).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Upgraded to Meteor 2.1.1 an updated dependencies](https://github.com/wekan/wekan/commit/bb8c4325c60582cdcda5d406071586f18681e737).
|
||||
Thanks to developers of dependencies.
|
||||
- [Updated to Node.js v12.22.1](https://github.com/wekan/wekan/commit/2201372744639ade3ba74b6ff9115988f011b9ac).
|
||||
Thanks to Node.js developers.
|
||||
- [Updated release scripts](https://github.com/wekan/wekan/commit/9871bf196352edcb5475e1b0ee4983e8f312e449).
|
||||
Thanks to xet7.
|
||||
- [Updated caniuse-lite etc dependencies](https://github.com/wekan/wekan/commit/0857a2ea91f672201ba96f2ba635165784b30fd8).
|
||||
Thanks to developers of dependencies.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Revert stable tag, because it did break Wekan version numbers](https://github.com/wekan/wekan/commit/5ca90f4d2245910580cb0af885fac17dcec44ef0).
|
||||
Thanks to xet7.
|
||||
- [Updating ARM Dockerfile](https://github.com/wekan/wekan/pull/3692).
|
||||
Thanks to loganballard.
|
||||
- [Added latest arm64 bundle symlink](https://github.com/wekan/wekan/commit/6fe3edebb18414ebe7e69b2de3269438662b6163).
|
||||
Thanks to xet7.
|
||||
- [Bug fix: Rules for moving from list/swimlane](https://github.com/wekan/wekan/pull/3706).
|
||||
Thanks to jrsupplee.
|
||||
- [Fixed Elements are duplicated on the view "My cards".
|
||||
Rewrite routine for building the My Cards hierarchical list.
|
||||
Use a separate publication for retrieving My Cards.
|
||||
Fixed bug with limit and skip projection](https://github.com/wekan/wekan/pull/3708).
|
||||
Thanks to jrsupplee.
|
||||
- [Popover needs to be destroyed anytime the details panel is closed](https://github.com/wekan/wekan/pull/3712).
|
||||
Thanks to ryanMushy.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v5.18 2021-04-14 Wekan release
|
||||
|
||||
Not released version, because some version numbers not changed in all release files.
|
||||
|
||||
# v5.17 2021-04-01 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
@@ -4962,7 +5776,7 @@ This release adds the following new features:
|
||||
and fixes the following bugs:
|
||||
|
||||
- Revert [Sandstorm API changes](https://github.com/wekan/wekan/commit/be03a191c4321c2f80116c0ee1ae6c826d882535)
|
||||
that were done at [Wekan v2.05](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md#v205-2019-01-27-wekan-release)
|
||||
that were done at [Wekan v2.05](https://github.com/wekan/wekan/blob/master/CHANGELOG.md#v205-2019-01-27-wekan-release)
|
||||
to fix #2143. Thanks to pantraining and xet7.
|
||||
|
||||
Thanks to above GitHub users and translators for contributions.
|
||||
@@ -5109,7 +5923,7 @@ Update translations. Thanks to translators.
|
||||
This release adds the following new features:
|
||||
|
||||
- [IFTTT Rules improvements](https://github.com/wekan/wekan/pull/2088). Thanks to Angtrim.
|
||||
- Add [find.sh](https://github.com/wekan/wekan/blob/devel/find.sh) bash script that ignores
|
||||
- Add [find.sh](https://github.com/wekan/wekan/blob/master/find.sh) bash script that ignores
|
||||
extra directories when searching. xet7 uses this a lot when developing. Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
@@ -6620,7 +7434,7 @@ This release adds the following new features:
|
||||
|
||||
- [Checklist templates](https://github.com/wekan/wekan/pull/1470);
|
||||
- Added [Finnish language changelog](https://github.com/wekan/wekan/tree/devel/meta/t9n-changelog)
|
||||
and [more Finnish traslations](https://github.com/wekan/wekan/blob/devel/sandstorm-pkgdef.capnp)
|
||||
and [more Finnish traslations](https://github.com/wekan/wekan/blob/master/sandstorm-pkgdef.capnp)
|
||||
to Sandstorm.
|
||||
|
||||
Thanks to GitHub users erikturk and xet7 for their contributions.
|
||||
|
||||
+6
-4
@@ -12,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.22.0 \
|
||||
NODE_VERSION=v12.22.6 \
|
||||
METEOR_RELEASE=1.10.2 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
@@ -64,6 +64,9 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
LDAP_ENABLE=false \
|
||||
LDAP_PORT=389 \
|
||||
LDAP_HOST="" \
|
||||
LDAP_AD_SIMPLE_AUTH="" \
|
||||
LDAP_USER_AUTHENTICATION=false \
|
||||
LDAP_USER_AUTHENTICATION_FIELD=uid \
|
||||
LDAP_BASEDN="" \
|
||||
LDAP_LOGIN_FALLBACK=false \
|
||||
LDAP_RECONNECT=true \
|
||||
@@ -81,8 +84,6 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
LDAP_ENCRYPTION=false \
|
||||
LDAP_CA_CERT="" \
|
||||
LDAP_REJECT_UNAUTHORIZED=false \
|
||||
LDAP_USER_AUTHENTICATION=false \
|
||||
LDAP_USER_AUTHENTICATION_FIELD=uid \
|
||||
LDAP_USER_SEARCH_FILTER="" \
|
||||
LDAP_USER_SEARCH_SCOPE="" \
|
||||
LDAP_USER_SEARCH_FIELD="" \
|
||||
@@ -137,7 +138,8 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
SAML_IDENTIFIER_FORMAT="" \
|
||||
SAML_LOCAL_PROFILE_MATCH_ATTRIBUTE="" \
|
||||
SAML_ATTRIBUTES="" \
|
||||
ORACLE_OIM_ENABLED=false
|
||||
ORACLE_OIM_ENABLED=false \
|
||||
WAIT_SPINNER=""
|
||||
|
||||
# Copy the app to the image
|
||||
COPY ${SRC_PATH} /home/wekan/app
|
||||
|
||||
+9
-9
@@ -4,16 +4,16 @@ FROM amd64/alpine:3.7 AS builder
|
||||
ENV QEMU_VERSION=v4.2.0-6 \
|
||||
QEMU_ARCHITECTURE=aarch64 \
|
||||
NODE_ARCHITECTURE=linux-arm64 \
|
||||
NODE_VERSION=v12.22.0 \
|
||||
WEKAN_VERSION=3.96 \
|
||||
NODE_VERSION=v12.22.6 \
|
||||
WEKAN_VERSION=latest \
|
||||
WEKAN_ARCHITECTURE=arm64
|
||||
|
||||
# Install dependencies
|
||||
RUN apk update && apk add ca-certificates outils-sha1 && \
|
||||
\
|
||||
# Download qemu static for our architecture
|
||||
wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-${QEMU_ARCHITECTURE}-static.tar.gz -O - | tar -xz && \
|
||||
\
|
||||
# Install dependencies
|
||||
RUN apk update && apk add ca-certificates outils-sha1 && \
|
||||
\
|
||||
# Download qemu static for our architecture
|
||||
wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-${QEMU_ARCHITECTURE}-static.tar.gz -O - | tar -xz && \
|
||||
\
|
||||
# Download wekan and shasum
|
||||
wget https://releases.wekan.team/raspi3/wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip && \
|
||||
wget https://releases.wekan.team/raspi3/SHA256SUMS.txt && \
|
||||
@@ -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.22.0 \
|
||||
NODE_VERSION=v12.22.6 \
|
||||
NODE_ENV=production \
|
||||
NPM_VERSION=latest \
|
||||
WITH_API=true \
|
||||
|
||||
@@ -30,6 +30,11 @@ It's better than at chat where details get lost when chat scrolls up.
|
||||
|
||||
[Wekan IRC FAQ](https://github.com/wekan/wekan/wiki/IRC-FAQ)
|
||||
|
||||
## Docker: Please only use Docker release tags
|
||||
|
||||
Note: With Docker, please don't use latest tag. Only use release tags.
|
||||
See https://github.com/wekan/wekan/issues/3874
|
||||
|
||||
## FAQ
|
||||
|
||||
**NOTE**:
|
||||
@@ -52,7 +57,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 62 languages.
|
||||
- Wekan has been [translated](https://transifex.com/wekan/wekan) to about 63 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.
|
||||
@@ -70,7 +75,7 @@ that by providing one-click installation on various platforms.
|
||||
Old versions have security issues because of old versions Node.js etc. Only newest Wekan is supported.
|
||||
Wekan on Sandstorm is not usually affected by any Standalone Wekan (Snap/Docker/Source) security issues.
|
||||
- [Reporting all new bugs immediately](https://github.com/wekan/wekan/issues).
|
||||
New features and fixes are added to Wekan [many times a day](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md).
|
||||
New features and fixes are added to Wekan [many times a day](https://github.com/wekan/wekan/blob/master/CHANGELOG.md).
|
||||
- [Backups](https://github.com/wekan/wekan/wiki/Backup) of Wekan database once a day miminum.
|
||||
Bugs, updates, users deleting list or card, harddrive full, harddrive crash etc can eat your data. There is no undo yet.
|
||||
Some bug can cause Wekan board to not load at all, requiring manual fixing of database content.
|
||||
@@ -82,7 +87,7 @@ that by providing one-click installation on various platforms.
|
||||
[Developer Documentation][dev_docs]
|
||||
|
||||
- There is many companies and individuals contributing code to Wekan, to add features and bugfixes
|
||||
[many times a day](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md).
|
||||
[many times a day](https://github.com/wekan/wekan/blob/master/CHANGELOG.md).
|
||||
- [Please add Add new Feature Requests and Bug Reports immediately](https://github.com/wekan/wekan/issues).
|
||||
- [Commercial Support](https://wekan.team/commercial-support/).
|
||||
|
||||
|
||||
+4
-4
@@ -51,8 +51,8 @@ This also means all Standalone Wekan functionality works in offline local networ
|
||||
Wekan is used by companies that have [thousands of users](https://github.com/wekan/wekan/wiki/AWS) and at healthcare.
|
||||
|
||||
Wekan uses xss package for input fields like cards, as you can see from
|
||||
[package.json](https://github.com/wekan/wekan/blob/devel/package.json). Other used versions can be seen from
|
||||
[Meteor versions file](https://github.com/wekan/wekan/blob/devel/.meteor/versions).
|
||||
[package.json](https://github.com/wekan/wekan/blob/master/package.json). Other used versions can be seen from
|
||||
[Meteor versions file](https://github.com/wekan/wekan/blob/master/.meteor/versions).
|
||||
Forms can include markdown links, html, image tags etc like you see at https://wekan.github.io .
|
||||
It's possible to add attachments to cards, and markdown/html links to files.
|
||||
|
||||
@@ -69,7 +69,7 @@ access to outside of Wekan grain.
|
||||
Standalone Wekan only has password auth currently, there is work in progress to add
|
||||
[oauth2](https://github.com/wekan/wekan/pull/1578), [Openid](https://github.com/wekan/wekan/issues/538),
|
||||
[LDAP](https://github.com/wekan/wekan/issues/119) etc. If you need more login security for Standalone Wekan now,
|
||||
it's possible add additional [Google Auth proxybouncer](https://github.com/wekan/wekan/wiki/Let's-Encrypt-and-Google-Auth) in front of password auth, and then use Google Authenticator for Google Auth. Standalone Wekan does have [brute force protection with eluck:accounts-lockout and browser-policy clickjacking protection](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md#v080-2018-04-04-wekan-release). You can also optionally use some [WAF](https://en.wikipedia.org/wiki/Web_application_firewall)
|
||||
it's possible add additional [Google Auth proxybouncer](https://github.com/wekan/wekan/wiki/Let's-Encrypt-and-Google-Auth) in front of password auth, and then use Google Authenticator for Google Auth. Standalone Wekan does have [brute force protection with eluck:accounts-lockout and browser-policy clickjacking protection](https://github.com/wekan/wekan/blob/master/CHANGELOG.md#v080-2018-04-04-wekan-release). You can also optionally use some [WAF](https://en.wikipedia.org/wiki/Web_application_firewall)
|
||||
like for example [AWS WAF](https://aws.amazon.com/waf/).
|
||||
|
||||
[All Wekan Platforms](https://github.com/wekan/wekan/wiki/Platforms)
|
||||
@@ -106,7 +106,7 @@ a security issue, we'd like to know about it, and also how to fix it:
|
||||
Typical already known or "no impact" bugs such as:
|
||||
|
||||
- Brute force password guessign. Currently there is
|
||||
[brute force protection with eluck:accounts-lockout](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md#v080-2018-04-04-wekan-release).
|
||||
[brute force protection with eluck:accounts-lockout](https://github.com/wekan/wekan/blob/master/CHANGELOG.md#v080-2018-04-04-wekan-release).
|
||||
- Security issues related to that Wekan uses Meteor 1.6.0.1 related packages, and upgrading to newer
|
||||
Meteor 1.6.1 is complicated process that requires lots of changes to many dependency packages.
|
||||
Upgrading [has been tried many times, spending a lot of time](https://github.com/meteor/meteor/issues/9609)
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v5.17.0"
|
||||
appVersion: "v5.59.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -28,12 +28,16 @@ if arguments == 0:
|
||||
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 list BOARDID LISTID # Info of LISTID")
|
||||
print(" python3 api.py createlist BOARDID LISTTITLE # Create list")
|
||||
print(" python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION")
|
||||
print(" python3 api.py editcard BOARDID LISTID CARDID NEWCARDTITLE NEWCARDDESCRIPTION")
|
||||
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")
|
||||
# print(" python3 api.py attachmentjson BOARDID ATTACHMENTID # One attachment as JSON base64")
|
||||
# print(" python3 api.py attachmentbinary BOARDID ATTACHMENTID # One attachment as binary file")
|
||||
# print(" python3 api.py attachmentdownload BOARDID ATTACHMENTID # One attachment as file")
|
||||
# print(" python3 api.py attachmentsdownload BOARDID # All attachments as files")
|
||||
exit
|
||||
|
||||
# ------- SETTINGS START -------------
|
||||
@@ -61,13 +65,15 @@ chmod +x 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 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 list BOARDID LISTID # Info of LISTID
|
||||
python3 api.py createlist BOARDID LISTTITLE # Create list
|
||||
python3 api.py addcard AUTHORID BOARDID SWIMLANEID LISTID CARDTITLE CARDDESCRIPTION
|
||||
python3 api.py editcard BOARDID LISTID CARDID NEWCARDTITLE NEWCARDDESCRIPTION
|
||||
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
|
||||
@@ -162,6 +168,27 @@ if arguments == 7:
|
||||
print(body.text)
|
||||
# ------- WRITE TO CARD END -----------
|
||||
|
||||
if arguments == 6:
|
||||
|
||||
if sys.argv[1] == 'editcard':
|
||||
|
||||
# ------- LIST OF BOARD START -----------
|
||||
boardid = sys.argv[2]
|
||||
listid = sys.argv[3]
|
||||
cardid = sys.argv[4]
|
||||
newcardtitle = sys.argv[5]
|
||||
newcarddescription = sys.argv[6]
|
||||
edcard = wekanurl + apiboards + boardid + s + l + s + listid + s + cs + s + cardid
|
||||
print(edcard)
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
put_data = {'title': '{}'.format(newcardtitle), 'description': '{}'.format(newcarddescription)}
|
||||
body = requests.put(edcard, data=put_data, headers=headers)
|
||||
print("=== EDIT CARD ===\n")
|
||||
body = requests.get(edcard, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- LISTS OF BOARD END -----------
|
||||
|
||||
if arguments == 3:
|
||||
|
||||
if sys.argv[1] == 'createlist':
|
||||
@@ -177,6 +204,19 @@ if arguments == 3:
|
||||
print(body.text)
|
||||
# ------- CREATE LIST END -----------
|
||||
|
||||
if sys.argv[1] == 'list':
|
||||
|
||||
# ------- LIST OF BOARD START -----------
|
||||
boardid = sys.argv[2]
|
||||
listid = sys.argv[3]
|
||||
listone = wekanurl + apiboards + boardid + s + l + s + listid
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print("=== INFO OF ONE LIST ===\n")
|
||||
body = requests.get(listone, headers=headers)
|
||||
data2 = body.text.replace('}',"}\n")
|
||||
print(data2)
|
||||
# ------- LISTS OF BOARD END -----------
|
||||
|
||||
if arguments == 2:
|
||||
|
||||
# ------- BOARDS LIST START -----------
|
||||
@@ -217,7 +257,7 @@ if arguments == 2:
|
||||
|
||||
# ------- LISTS OF BOARD START -----------
|
||||
boardid = sys.argv[2]
|
||||
attachments = wekanurl + apiboards + boardid
|
||||
lists = wekanurl + apiboards + boardid + s + l
|
||||
headers = {'Accept': 'application/json', 'Authorization': 'Bearer {}'.format(apikey)}
|
||||
print("=== LISTS ===\n")
|
||||
body = requests.get(lists, headers=headers)
|
||||
|
||||
@@ -21,6 +21,22 @@ template(name="editOrDeleteComment")
|
||||
= ' - '
|
||||
a.js-delete-comment {{_ "delete"}}
|
||||
|
||||
template(name="commentReactions")
|
||||
.reactions
|
||||
each reaction in reactions
|
||||
span.reaction(class="{{#if isSelected reaction.userIds}}selected{{/if}}" data-codepoint="#{reaction.reactionCodepoint}" title="{{userNames reaction.userIds}}")
|
||||
span.reaction-codepoint !{reaction.reactionCodepoint}
|
||||
span.reaction-count #{reaction.userIds.length}
|
||||
if (currentUser.isBoardMember)
|
||||
a.open-comment-reaction-popup(title="{{_ 'addReactionPopup-title'}}")
|
||||
i.fa.fa-smile-o
|
||||
i.fa.fa-plus
|
||||
|
||||
template(name="addReactionPopup")
|
||||
.reactions-popup
|
||||
each codepoint in codepoints
|
||||
span.add-comment-reaction(data-codepoint="#{codepoint}") !{codepoint}
|
||||
|
||||
template(name="activity")
|
||||
.activity
|
||||
+userAvatar(userId=activity.user._id)
|
||||
@@ -124,6 +140,7 @@ template(name="activity")
|
||||
.activity-comment
|
||||
+viewer
|
||||
= activity.comment.text
|
||||
+commentReactions(reactions=activity.comment.reactions commentId=activity.comment._id)
|
||||
span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
|
||||
if($eq currentUser._id activity.comment.userId)
|
||||
+editOrDeleteComment
|
||||
@@ -150,20 +167,20 @@ template(name="activity")
|
||||
|
||||
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}}}.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import sanitizeXss from 'xss';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
const activitiesPerPage = 500;
|
||||
|
||||
@@ -162,11 +162,15 @@ BlazeComponent.extendComponent({
|
||||
{
|
||||
href: source.url,
|
||||
},
|
||||
sanitizeXss(source.system),
|
||||
DOMPurify.sanitize(source.system, {
|
||||
ALLOW_UNKNOWN_PROTOCOLS: true,
|
||||
}),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return sanitizeXss(source.system);
|
||||
return DOMPurify.sanitize(source.system, {
|
||||
ALLOW_UNKNOWN_PROTOCOLS: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return null;
|
||||
@@ -190,10 +194,10 @@ BlazeComponent.extendComponent({
|
||||
href: attachment.url({ download: true }),
|
||||
target: '_blank',
|
||||
},
|
||||
sanitizeXss(attachment.name()),
|
||||
DOMPurify.sanitize(attachment.name()),
|
||||
),
|
||||
)) ||
|
||||
sanitizeXss(this.currentData().activity.attachmentName)
|
||||
DOMPurify.sanitize(this.currentData().activity.attachmentName)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -232,10 +236,64 @@ BlazeComponent.extendComponent({
|
||||
|
||||
Template.activity.helpers({
|
||||
sanitize(value) {
|
||||
return sanitizeXss(value);
|
||||
return DOMPurify.sanitize(value, { ALLOW_UNKNOWN_PROTOCOLS: true });
|
||||
},
|
||||
});
|
||||
|
||||
Template.commentReactions.events({
|
||||
'click .reaction'(event) {
|
||||
if (Meteor.user().isBoardMember()) {
|
||||
const codepoint = event.currentTarget.dataset['codepoint'];
|
||||
const commentId = Template.instance().data.commentId;
|
||||
const cardComment = CardComments.findOne({_id: commentId});
|
||||
cardComment.toggleReaction(codepoint);
|
||||
}
|
||||
},
|
||||
'click .open-comment-reaction-popup': Popup.open('addReaction'),
|
||||
})
|
||||
|
||||
Template.addReactionPopup.events({
|
||||
'click .add-comment-reaction'(event) {
|
||||
if (Meteor.user().isBoardMember()) {
|
||||
const codepoint = event.currentTarget.dataset['codepoint'];
|
||||
const commentId = Template.instance().data.commentId;
|
||||
const cardComment = CardComments.findOne({_id: commentId});
|
||||
cardComment.toggleReaction(codepoint);
|
||||
}
|
||||
Popup.close();
|
||||
},
|
||||
})
|
||||
|
||||
Template.addReactionPopup.helpers({
|
||||
codepoints() {
|
||||
// Starting set of unicode codepoints as comment reactions
|
||||
return [
|
||||
'👍',
|
||||
'👎',
|
||||
'👀',
|
||||
'✅',
|
||||
'❌',
|
||||
'🙏',
|
||||
'👏',
|
||||
'🎉',
|
||||
'🚀',
|
||||
'😊',
|
||||
'🤔',
|
||||
'😔'];
|
||||
}
|
||||
})
|
||||
|
||||
Template.commentReactions.helpers({
|
||||
isSelected(userIds) {
|
||||
return userIds.includes(Meteor.user()._id);
|
||||
},
|
||||
userNames(userIds) {
|
||||
return Users.find({_id: {$in: userIds}})
|
||||
.map(user => user.profile.fullname)
|
||||
.join(', ');
|
||||
}
|
||||
})
|
||||
|
||||
function createCardLink(card) {
|
||||
if (!card) return '';
|
||||
return (
|
||||
@@ -246,7 +304,7 @@ function createCardLink(card) {
|
||||
href: card.originRelativeUrl(),
|
||||
class: 'action-card',
|
||||
},
|
||||
sanitizeXss(card.title),
|
||||
DOMPurify.sanitize(card.title, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
),
|
||||
)
|
||||
);
|
||||
@@ -263,7 +321,7 @@ function createBoardLink(board, list) {
|
||||
href: board.originRelativeUrl(),
|
||||
class: 'action-board',
|
||||
},
|
||||
sanitizeXss(text),
|
||||
DOMPurify.sanitize(text, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
@@ -5,6 +5,20 @@
|
||||
display: flex
|
||||
justify-content:space-between
|
||||
|
||||
.reactions-popup
|
||||
.add-comment-reaction
|
||||
display: inline-block
|
||||
cursor: pointer
|
||||
border-radius: 5px
|
||||
font-size: 22px
|
||||
text-align: center
|
||||
line-height: 30px
|
||||
width: 40px
|
||||
|
||||
&:hover {
|
||||
background-color: #b0c4de
|
||||
}
|
||||
|
||||
.activities
|
||||
clear: both
|
||||
|
||||
@@ -18,7 +32,7 @@
|
||||
height: @width
|
||||
|
||||
.activity-member
|
||||
font-weight: 700
|
||||
font-weight: 700
|
||||
|
||||
.activity-desc
|
||||
word-wrap: break-word
|
||||
@@ -39,6 +53,45 @@
|
||||
margin-top: 5px
|
||||
padding: 5px
|
||||
|
||||
.reactions
|
||||
display: flex
|
||||
margin-top: 5px
|
||||
gap: 5px
|
||||
|
||||
.open-comment-reaction-popup
|
||||
display: flex
|
||||
align-items: center
|
||||
text-decoration: none
|
||||
height: 24px;
|
||||
|
||||
i.fa.fa-smile-o
|
||||
font-size: 17px
|
||||
font-weight: 500
|
||||
margin-left: 2px
|
||||
|
||||
i.fa.fa-plus
|
||||
font-size: 8px;
|
||||
margin-top: -7px;
|
||||
margin-left: 1px;
|
||||
|
||||
.reaction
|
||||
cursor: pointer
|
||||
border: 1px solid grey
|
||||
border-radius: 15px
|
||||
display: flex
|
||||
padding: 2px 5px
|
||||
|
||||
&.selected {
|
||||
background-color: #b0c4de
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: #b0c4de
|
||||
}
|
||||
|
||||
.reaction-count
|
||||
font-size: 12px
|
||||
|
||||
.activity-checklist
|
||||
display: block
|
||||
border-radius: 3px
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="commentForm")
|
||||
.new-comment.js-new-comment(
|
||||
class="{{#if commentFormIsOpen}}is-open{{/if}}")
|
||||
+userAvatar(userId=currentUser._id)
|
||||
+userAvatar(userId=currentUser._id noRemove=true)
|
||||
form.js-new-comment-form
|
||||
+editor(class="js-new-comment-input")
|
||||
| {{getUnsavedValue 'cardComment' currentCard._id}}
|
||||
|
||||
@@ -3,6 +3,7 @@ const commentFormIsOpen = new ReactiveVar(false);
|
||||
BlazeComponent.extendComponent({
|
||||
onDestroyed() {
|
||||
commentFormIsOpen.set(false);
|
||||
$('.note-popover').hide();
|
||||
},
|
||||
|
||||
commentFormIsOpen() {
|
||||
|
||||
@@ -13,26 +13,29 @@ template(name="board")
|
||||
+spinner
|
||||
|
||||
template(name="boardBody")
|
||||
.board-wrapper(class=currentBoard.colorClass)
|
||||
+sidebar
|
||||
.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}}")
|
||||
if showOverlay.get
|
||||
.board-overlay
|
||||
if currentBoard.isTemplatesBoard
|
||||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
else if isViewSwimlanes
|
||||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
else if isViewLists
|
||||
+listsGroup(currentBoard)
|
||||
else if isViewCalendar
|
||||
+calendarView
|
||||
else
|
||||
+listsGroup(currentBoard)
|
||||
if notDisplayThisBoard
|
||||
| {{_ 'tableVisibilityMode-allowPrivateOnly'}}
|
||||
else
|
||||
.board-wrapper(class=currentBoard.colorClass)
|
||||
+sidebar
|
||||
.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}}")
|
||||
if showOverlay.get
|
||||
.board-overlay
|
||||
if currentBoard.isTemplatesBoard
|
||||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
else if isViewSwimlanes
|
||||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
else if isViewLists
|
||||
+listsGroup(currentBoard)
|
||||
else if isViewCalendar
|
||||
+calendarView
|
||||
else
|
||||
+listsGroup(currentBoard)
|
||||
|
||||
template(name="calendarView")
|
||||
if isViewCalendar
|
||||
|
||||
@@ -33,6 +33,7 @@ BlazeComponent.extendComponent({
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
Meteor.subscribe('tableVisibilityModeSettings');
|
||||
this.showOverlay = new ReactiveVar(false);
|
||||
this.draggingActive = new ReactiveVar(false);
|
||||
this._isDragging = false;
|
||||
@@ -235,6 +236,16 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
},
|
||||
|
||||
notDisplayThisBoard(){
|
||||
let allowPrivateVisibilityOnly = TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly');
|
||||
let currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if(allowPrivateVisibilityOnly !== undefined && allowPrivateVisibilityOnly.booleanValue && currentBoard.permission == 'public'){
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
|
||||
isViewSwimlanes() {
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
|
||||
@@ -766,7 +766,15 @@ setBoardClear(color1,color2)
|
||||
.toggle-label:after, .board-color-modern .toggle-switch:checked~.toggle-label:after
|
||||
background-color: #819C5D !important
|
||||
|
||||
button, input:not([type=file]), select, textarea
|
||||
border-radius: 2px
|
||||
|
||||
/* Headers */
|
||||
&#header
|
||||
background-color: #262626
|
||||
border-bottom: 1px solid #555555;
|
||||
border-top: 1px solid #555555;
|
||||
|
||||
&#header-quick-access, .background-box, #header
|
||||
background-color: #333333
|
||||
|
||||
@@ -774,14 +782,16 @@ setBoardClear(color1,color2)
|
||||
padding: 4px
|
||||
font-size: 14px
|
||||
|
||||
&#header-quick-access .allBoards
|
||||
padding: 5px 10px 0 10px;
|
||||
|
||||
&#header-quick-access ul.header-quick-access-list
|
||||
margin: -5px 0 -5px 0
|
||||
|
||||
&#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
|
||||
|
||||
@@ -812,18 +822,23 @@ setBoardClear(color1,color2)
|
||||
/* Content */
|
||||
.board-canvas
|
||||
background: #2a2a2a
|
||||
padding: 10px 10px 0
|
||||
|
||||
/* Swimlanes */
|
||||
.swimlane .swimlane-header-wrap
|
||||
background-color: #666666
|
||||
background-color: #494949
|
||||
color: #cccccc
|
||||
padding: 4px 0
|
||||
margin-bottom: 10px
|
||||
|
||||
.swimlane .swimlane-header-wrap .swimlane-header
|
||||
font-family: Poppins
|
||||
|
||||
.swimlane .swimlane-header-wrap .swimlane-header-menu
|
||||
padding: 6px
|
||||
font-size: 16px
|
||||
|
||||
.swimlane .swimlane-header-wrap .swimlane-header-plus-icon
|
||||
font-size: 16px
|
||||
|
||||
.swimlane
|
||||
background: #2a2a2a
|
||||
line-height: 15px
|
||||
@@ -836,13 +851,19 @@ setBoardClear(color1,color2)
|
||||
border: 0px solid #666666
|
||||
flex: 0 0 265px;
|
||||
|
||||
.swimlane .list:first-child
|
||||
margin-left: 0
|
||||
|
||||
.swimlane .list:nth-child(even)
|
||||
background: #5f5f5f
|
||||
|
||||
.swimlane .list:nth-child(odd) .list-header
|
||||
background: #3b3b3b
|
||||
|
||||
.list-header
|
||||
background: #333333
|
||||
padding-top: 10px
|
||||
border-bottom: 6px solid #333333
|
||||
padding: 10px
|
||||
border-bottom: 0
|
||||
|
||||
.list-header .viewer
|
||||
padding-left: 10px
|
||||
@@ -852,7 +873,11 @@ setBoardClear(color1,color2)
|
||||
color: #eeeeee
|
||||
|
||||
.list-header .list-header-menu
|
||||
padding-top: 17px
|
||||
padding: 10px
|
||||
top: 0
|
||||
|
||||
.list-header .list-header-plus-icon
|
||||
color: #a6a6a6
|
||||
|
||||
.list-body
|
||||
scrollbar-width: thin
|
||||
@@ -883,35 +908,43 @@ setBoardClear(color1,color2)
|
||||
color: #ffffff
|
||||
|
||||
/* Mini Card */
|
||||
.minicard-wrapper
|
||||
margin-bottom: 12px
|
||||
|
||||
.minicard
|
||||
background-color: #444444
|
||||
color: #cccccc
|
||||
border-radius: 2px
|
||||
font-size: 0.9em
|
||||
font-size: 0.95em
|
||||
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
|
||||
background-color: #494949 !important
|
||||
|
||||
.minicard .minicard-labels
|
||||
margin-bottom: 4px
|
||||
|
||||
.minicard .card-label
|
||||
font-size: 11px
|
||||
font-weight: 400
|
||||
padding: 2px 6px 0
|
||||
padding: 1px 6px 0
|
||||
border-radius: 2px
|
||||
|
||||
.minicard .badges
|
||||
color: #bbbbbb
|
||||
|
||||
.minicard .date
|
||||
margin-top: 7px
|
||||
margin-top: 10px
|
||||
font-size: 11px
|
||||
|
||||
.card-date
|
||||
color: #555555
|
||||
color: #444444
|
||||
border-radius: 2px
|
||||
|
||||
.card-date.almost-due
|
||||
color: #666666
|
||||
color: #444444
|
||||
|
||||
.minicard.minicard-composer textarea.minicard-composer-textarea:focus
|
||||
background-color: #eeeeee
|
||||
@@ -970,11 +1003,17 @@ setBoardClear(color1,color2)
|
||||
|
||||
.card-details .checklist-item
|
||||
background-color: rgba(255,255,255,0.1)
|
||||
padding: 2px 8px
|
||||
border-radius: 3px
|
||||
padding: 4px 8px
|
||||
border-radius: 2px
|
||||
font-size: 13px
|
||||
margin-top: 5px
|
||||
|
||||
.card-details .checklist-item:hover
|
||||
background-color: rgba(255,255,255,0.2)
|
||||
|
||||
.card-details .checklist-item .item-title .viewer p
|
||||
max-width: auto
|
||||
|
||||
.card-details .check-box.materialCheckBox
|
||||
border-color: #ffffff
|
||||
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
template(name="boardHeaderBar")
|
||||
h1.header-board-menu
|
||||
with currentBoard
|
||||
+viewer
|
||||
= title
|
||||
if $eq title 'Templates'
|
||||
| {{_ 'templates'}}
|
||||
else
|
||||
+viewer
|
||||
= title
|
||||
|
||||
.board-header-btns.left
|
||||
unless isMiniScreen
|
||||
@@ -131,7 +134,7 @@ template(name="boardHeaderBar")
|
||||
i.fa.fa-times-thin
|
||||
|
||||
.separator
|
||||
a.board-header-btn.js-toggle-sidebar
|
||||
a.board-header-btn.js-toggle-sidebar(title="{{_ 'sidebar-open'}} {{_ 'or'}} {{_ 'sidebar-close'}}")
|
||||
i.fa.fa-navicon
|
||||
|
||||
template(name="boardVisibilityList")
|
||||
@@ -144,14 +147,15 @@ template(name="boardVisibilityList")
|
||||
if visibilityCheck
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'private-desc'}}
|
||||
li
|
||||
with "public"
|
||||
a.js-select-visibility
|
||||
i.fa.fa-globe.colorful
|
||||
| {{_ 'public'}}
|
||||
if visibilityCheck
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'public-desc'}}
|
||||
if notAllowPrivateVisibilityOnly
|
||||
li
|
||||
with "public"
|
||||
a.js-select-visibility
|
||||
i.fa.fa-globe.colorful
|
||||
| {{_ 'public'}}
|
||||
if visibilityCheck
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'public-desc'}}
|
||||
|
||||
template(name="boardChangeVisibilityPopup")
|
||||
+boardVisibilityList
|
||||
@@ -225,6 +229,9 @@ template(name="createBoard")
|
||||
= " "
|
||||
| {{{_ 'board-private-info'}}}
|
||||
a.js-change-visibility {{_ 'change'}}.
|
||||
//a.flex.js-toggle-add-template-container
|
||||
// .materialCheckBox#add-template-container
|
||||
// span {{_ 'add-template-container'}}
|
||||
input.primary.wide(type="submit" value="{{_ 'create'}}")
|
||||
span.quiet
|
||||
| {{_ 'or'}}
|
||||
|
||||
@@ -194,6 +194,11 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
this.visibilityMenuIsOpen = new ReactiveVar(false);
|
||||
this.visibility = new ReactiveVar('private');
|
||||
this.boardId = new ReactiveVar('');
|
||||
Meteor.subscribe('tableVisibilityModeSettings');
|
||||
},
|
||||
|
||||
notAllowPrivateVisibilityOnly(){
|
||||
return !TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly').booleanValue;
|
||||
},
|
||||
|
||||
visibilityCheck() {
|
||||
@@ -209,24 +214,79 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
this.visibilityMenuIsOpen.set(!this.visibilityMenuIsOpen.get());
|
||||
},
|
||||
|
||||
toggleAddTemplateContainer() {
|
||||
$('#add-template-container').toggleClass('is-checked');
|
||||
},
|
||||
|
||||
onSubmit(event) {
|
||||
event.preventDefault();
|
||||
const title = this.find('.js-new-board-title').value;
|
||||
const visibility = this.visibility.get();
|
||||
|
||||
this.boardId.set(
|
||||
Boards.insert({
|
||||
title,
|
||||
permission: visibility,
|
||||
}),
|
||||
);
|
||||
const addTemplateContainer = $('#add-template-container.is-checked').length > 0;
|
||||
if (addTemplateContainer) {
|
||||
//const templateContainerId = Meteor.call('setCreateTemplateContainer');
|
||||
//Utils.goBoardId(templateContainerId);
|
||||
//alert('niinku template ' + Meteor.call('setCreateTemplateContainer'));
|
||||
|
||||
Swimlanes.insert({
|
||||
title: 'Default',
|
||||
boardId: this.boardId.get(),
|
||||
});
|
||||
this.boardId.set(
|
||||
Boards.insert({
|
||||
// title: TAPi18n.__('templates'),
|
||||
title: title,
|
||||
permission: 'private',
|
||||
type: 'template-container',
|
||||
}),
|
||||
);
|
||||
|
||||
Utils.goBoardId(this.boardId.get());
|
||||
// Insert the card templates swimlane
|
||||
Swimlanes.insert({
|
||||
// title: TAPi18n.__('card-templates-swimlane'),
|
||||
title: 'Card Templates',
|
||||
boardId: this.boardId.get(),
|
||||
sort: 1,
|
||||
type: 'template-container',
|
||||
}),
|
||||
|
||||
// Insert the list templates swimlane
|
||||
Swimlanes.insert(
|
||||
{
|
||||
// title: TAPi18n.__('list-templates-swimlane'),
|
||||
title: 'List Templates',
|
||||
boardId: this.boardId.get(),
|
||||
sort: 2,
|
||||
type: 'template-container',
|
||||
},
|
||||
);
|
||||
|
||||
// Insert the board templates swimlane
|
||||
Swimlanes.insert(
|
||||
{
|
||||
//title: TAPi18n.__('board-templates-swimlane'),
|
||||
title: 'Board Templates',
|
||||
boardId: this.boardId.get(),
|
||||
sort: 3,
|
||||
type: 'template-container',
|
||||
},
|
||||
);
|
||||
|
||||
Utils.goBoardId(this.boardId.get());
|
||||
|
||||
} else {
|
||||
const visibility = this.visibility.get();
|
||||
|
||||
this.boardId.set(
|
||||
Boards.insert({
|
||||
title,
|
||||
permission: visibility,
|
||||
}),
|
||||
);
|
||||
|
||||
Swimlanes.insert({
|
||||
title: 'Default',
|
||||
boardId: this.boardId.get(),
|
||||
});
|
||||
|
||||
Utils.goBoardId(this.boardId.get());
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
@@ -240,6 +300,7 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
submit: this.onSubmit,
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
'click .js-board-template': Popup.open('searchElement'),
|
||||
'click .js-toggle-add-template-container': this.toggleAddTemplateContainer,
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -254,6 +315,9 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
}.register('headerBarCreateBoardPopup'));
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
notAllowPrivateVisibilityOnly(){
|
||||
return !TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly').booleanValue;
|
||||
},
|
||||
visibilityCheck() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return this.currentData() === currentBoard.permission;
|
||||
|
||||
@@ -1,10 +1,32 @@
|
||||
template(name="boardList")
|
||||
.wrapper
|
||||
ul.AllBoardTeamsOrgs
|
||||
li.AllBoardTeams
|
||||
if userHasTeams
|
||||
select.js-AllBoardTeams#jsAllBoardTeams("multiple")
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each teamsDatas
|
||||
option(value="{{teamId}}") {{_ teamDisplayName}}
|
||||
|
||||
li.AllBoardOrgs
|
||||
if userHasOrgs
|
||||
select.js-AllBoardOrgs#jsAllBoardOrgs("multiple")
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each orgsDatas
|
||||
option(value="{{orgId}}") {{_ orgDisplayName}}
|
||||
li.AllBoardBtns
|
||||
div.AllBoardButtonsContainer
|
||||
if userHasOrgsOrTeams
|
||||
i.fa.fa-filter
|
||||
input#filterBtn(type="button" value="{{_ 'filter'}}")
|
||||
input#resetBtn(type="button" value="{{_ 'filter-clear'}}")
|
||||
|
||||
ul.board-list.clearfix.js-boards
|
||||
li.js-add-board
|
||||
a.board-list-item.label {{_ 'add-board'}}
|
||||
a.board-list-item.label(title="{{_ 'add-board'}}")
|
||||
| {{_ 'add-board'}}
|
||||
each boards
|
||||
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board
|
||||
li(class="{{_id}}" class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board
|
||||
if isInvited
|
||||
.board-list-item
|
||||
span.details
|
||||
@@ -16,47 +38,90 @@ template(name="boardList")
|
||||
button.js-accept-invite.primary {{_ 'accept'}}
|
||||
button.js-decline-invite {{_ 'decline'}}
|
||||
else
|
||||
a.js-open-board.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name
|
||||
+viewer
|
||||
= title
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
p.board-list-item-desc
|
||||
+viewer
|
||||
= description
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
if isMiniScreen
|
||||
i.fa.board-handle(
|
||||
class="fa-arrows"
|
||||
title="{{_ 'Drag board'}}")
|
||||
unless isMiniScreen
|
||||
if isSandstorm
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if isAdministrable
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if currentUser.isAdmin
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
if $eq type "template-container"
|
||||
a.js-open-board.template-container.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'template-container'}}")
|
||||
+viewer
|
||||
= title
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
p.board-list-item-desc
|
||||
+viewer
|
||||
= description
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
if isMiniScreen
|
||||
i.fa.board-handle(
|
||||
class="fa-arrows"
|
||||
title="{{_ 'Drag board'}}")
|
||||
unless isMiniScreen
|
||||
if isSandstorm
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if isAdministrable
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if currentUser.isAdmin
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else
|
||||
a.js-open-board.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}")
|
||||
+viewer
|
||||
= title
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
p.board-list-item-desc
|
||||
+viewer
|
||||
= description
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
if isMiniScreen
|
||||
i.fa.board-handle(
|
||||
class="fa-arrows"
|
||||
title="{{_ 'Drag board'}}")
|
||||
unless isMiniScreen
|
||||
if isSandstorm
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if isAdministrable
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if currentUser.isAdmin
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
|
||||
template(name="boardListHeaderBar")
|
||||
h1 {{_ title }}
|
||||
|
||||
@@ -22,6 +22,16 @@ Template.boardListHeaderBar.helpers({
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('tableVisibilityModeSettings');
|
||||
let currUser = Meteor.user();
|
||||
let userLanguage;
|
||||
if(currUser && currUser.profile){
|
||||
userLanguage = currUser.profile.language
|
||||
}
|
||||
if (userLanguage) {
|
||||
TAPi18n.setLanguage(userLanguage);
|
||||
T9n.setLanguage(userLanguage);
|
||||
}
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
@@ -75,15 +85,103 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
});
|
||||
},
|
||||
userHasTeams(){
|
||||
if(Meteor.user().teams && Meteor.user().teams.length > 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
},
|
||||
teamsDatas() {
|
||||
if(Meteor.user().teams)
|
||||
return Meteor.user().teams;
|
||||
else
|
||||
return [];
|
||||
},
|
||||
userHasOrgs(){
|
||||
if(Meteor.user().orgs && Meteor.user().orgs.length > 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
},
|
||||
orgsDatas() {
|
||||
if(Meteor.user().orgs)
|
||||
return Meteor.user().orgs;
|
||||
else
|
||||
return [];
|
||||
},
|
||||
userHasOrgsOrTeams(){
|
||||
let boolUserHasOrgs;
|
||||
if(Meteor.user().orgs && Meteor.user().orgs.length > 0)
|
||||
boolUserHasOrgs = true;
|
||||
else
|
||||
boolUserHasOrgs = false;
|
||||
|
||||
let boolUserHasTeams;
|
||||
if(Meteor.user().teams && Meteor.user().teams.length > 0)
|
||||
boolUserHasTeams = true;
|
||||
else
|
||||
boolUserHasTeams = false;
|
||||
|
||||
return (boolUserHasOrgs || boolUserHasTeams);
|
||||
},
|
||||
boards() {
|
||||
const query = {
|
||||
archived: false,
|
||||
type: 'board',
|
||||
let query = {
|
||||
//archived: false,
|
||||
////type: { $in: ['board','template-container'] },
|
||||
//type: 'board',
|
||||
$and: [
|
||||
{ archived: false },
|
||||
{ type: 'board' },
|
||||
{ $or:[] }
|
||||
]
|
||||
};
|
||||
if (FlowRouter.getRouteName() === 'home')
|
||||
query['members.userId'] = Meteor.userId();
|
||||
else query.permission = 'public';
|
||||
|
||||
let allowPrivateVisibilityOnly = TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly');
|
||||
|
||||
if (FlowRouter.getRouteName() === 'home'){
|
||||
query.$and[2].$or.push({'members.userId': Meteor.userId()});
|
||||
|
||||
if(allowPrivateVisibilityOnly !== undefined && allowPrivateVisibilityOnly.booleanValue){
|
||||
query.$and.push({'permission': 'private'});
|
||||
}
|
||||
const currUser = Users.findOne(Meteor.userId());
|
||||
|
||||
// const currUser = Users.findOne(Meteor.userId(), {
|
||||
// fields: {
|
||||
// orgs: 1,
|
||||
// teams: 1,
|
||||
// },
|
||||
// });
|
||||
|
||||
let orgIdsUserBelongs = currUser.teams !== 'undefined' ? currUser.orgIdsUserBelongs() : '';
|
||||
if(orgIdsUserBelongs && orgIdsUserBelongs != ''){
|
||||
let orgsIds = orgIdsUserBelongs.split(',');
|
||||
// for(let i = 0; i < orgsIds.length; i++){
|
||||
// query.$and[2].$or.push({'orgs.orgId': orgsIds[i]});
|
||||
// }
|
||||
|
||||
//query.$and[2].$or.push({'orgs': {$elemMatch : {orgId: orgsIds[0]}}});
|
||||
query.$and[2].$or.push({'orgs.orgId': {$in : orgsIds}});
|
||||
}
|
||||
|
||||
let teamIdsUserBelongs = currUser.teams !== 'undefined' ? currUser.teamIdsUserBelongs() : '';
|
||||
if(teamIdsUserBelongs && teamIdsUserBelongs != ''){
|
||||
let teamsIds = teamIdsUserBelongs.split(',');
|
||||
// for(let i = 0; i < teamsIds.length; i++){
|
||||
// query.$or[2].$or.push({'teams.teamId': teamsIds[i]});
|
||||
// }
|
||||
//query.$and[2].$or.push({'teams': { $elemMatch : {teamId: teamsIds[0]}}});
|
||||
query.$and[2].$or.push({'teams.teamId': {$in : teamsIds}});
|
||||
}
|
||||
}
|
||||
else if(allowPrivateVisibilityOnly !== undefined && !allowPrivateVisibilityOnly.booleanValue){
|
||||
query = {
|
||||
archived: false,
|
||||
//type: { $in: ['board','template-container'] },
|
||||
type: 'board',
|
||||
permission: 'public',
|
||||
};
|
||||
}
|
||||
|
||||
return Boards.find(query, {
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
@@ -160,6 +258,74 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
});
|
||||
},
|
||||
'click #resetBtn'(event){
|
||||
let allBoards = document.getElementsByClassName("js-board");
|
||||
let currBoard;
|
||||
for(let i=0; i < allBoards.length; i++){
|
||||
currBoard = allBoards[i];
|
||||
currBoard.style.display = "block";
|
||||
}
|
||||
},
|
||||
'click #filterBtn'(event) {
|
||||
event.preventDefault();
|
||||
let selectedTeams = document.querySelectorAll('#jsAllBoardTeams option:checked');
|
||||
let selectedTeamsValues = Array.from(selectedTeams).map(function(elt){return elt.value});
|
||||
let index = selectedTeamsValues.indexOf("-1");
|
||||
if (index > -1) {
|
||||
selectedTeamsValues.splice(index, 1);
|
||||
}
|
||||
|
||||
let selectedOrgs = document.querySelectorAll('#jsAllBoardOrgs option:checked');
|
||||
let selectedOrgsValues = Array.from(selectedOrgs).map(function(elt){return elt.value});
|
||||
index = selectedOrgsValues.indexOf("-1");
|
||||
if (index > -1) {
|
||||
selectedOrgsValues.splice(index, 1);
|
||||
}
|
||||
|
||||
if(selectedTeamsValues.length > 0 || selectedOrgsValues.length > 0){
|
||||
const query = {
|
||||
$and: [
|
||||
{ archived: false },
|
||||
{ type: 'board' },
|
||||
{ $or:[] }
|
||||
]
|
||||
};
|
||||
if(selectedTeamsValues.length > 0)
|
||||
{
|
||||
query.$and[2].$or.push({'teams.teamId': {$in : selectedTeamsValues}});
|
||||
}
|
||||
if(selectedOrgsValues.length > 0)
|
||||
{
|
||||
query.$and[2].$or.push({'orgs.orgId': {$in : selectedOrgsValues}});
|
||||
}
|
||||
|
||||
let filteredBoards = Boards.find(query, {}).fetch();
|
||||
let allBoards = document.getElementsByClassName("js-board");
|
||||
let currBoard;
|
||||
if(filteredBoards.length > 0){
|
||||
let currBoardId;
|
||||
let found;
|
||||
for(let i=0; i < allBoards.length; i++){
|
||||
currBoard = allBoards[i];
|
||||
currBoardId = currBoard.classList[0];
|
||||
found = filteredBoards.find(function(board){
|
||||
return board._id == currBoardId;
|
||||
});
|
||||
|
||||
if(found !== undefined)
|
||||
currBoard.style.display = "block";
|
||||
else
|
||||
currBoard.style.display = "none";
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(let i=0; i < allBoards.length; i++){
|
||||
currBoard = allBoards[i];
|
||||
currBoard.style.display = "none";
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@@ -45,6 +45,9 @@ $spaceBetweenTiles = 16px
|
||||
text-decoration: none
|
||||
word-wrap: break-word
|
||||
|
||||
&.template-container
|
||||
border: 4px solid #fff
|
||||
|
||||
&.tile
|
||||
background-size: auto
|
||||
background-repeat: repeat
|
||||
@@ -226,3 +229,25 @@ $spaceBetweenTiles = 16px
|
||||
transform: translateY(-50%)
|
||||
right: 10px
|
||||
font-size: 24px
|
||||
|
||||
.AllBoardTeamsOrgs
|
||||
list-style-type: none;
|
||||
overflow: hidden;
|
||||
|
||||
.AllBoardTeams,.AllBoardOrgs,.AllBoardBtns
|
||||
float: left;
|
||||
|
||||
.js-AllBoardOrgs
|
||||
margin-left: 16px;
|
||||
|
||||
.AllBoardTeams
|
||||
margin-left : 16px;
|
||||
|
||||
.AllBoardButtonsContainer
|
||||
margin: 16px;
|
||||
|
||||
#filterBtn,#resetBtn
|
||||
display: inline;
|
||||
|
||||
.js-board
|
||||
display: block;
|
||||
@@ -26,6 +26,18 @@ template(name="attachmentsGalery")
|
||||
if isUploaded
|
||||
if isImage
|
||||
img.attachment-thumbnail-img(src="{{url}}")
|
||||
else if($eq extension 'mp3')
|
||||
video(width="100%" height="100%" controls="true")
|
||||
source(src="{{url}}" type="audio/mpeg")
|
||||
else if($eq extension 'ogg')
|
||||
video(width="100%" height="100%" controls="true")
|
||||
source(src="{{url}}" type="video/ogg")
|
||||
else if($eq extension 'webm')
|
||||
video(width="100%" height="100%" controls="true")
|
||||
source(src="{{url}}" type="video/webm")
|
||||
else if($eq extension 'mp4')
|
||||
video(width="100%" height="100%" controls="true")
|
||||
source(src="{{url}}" type="video/mp4")
|
||||
else
|
||||
span.attachment-thumbnail-ext= extension
|
||||
else
|
||||
@@ -55,6 +67,5 @@ template(name="attachmentsGalery")
|
||||
unless currentUser.isCommentOnly
|
||||
unless currentUser.isWorker
|
||||
//li.attachment-item.add-attachment
|
||||
a.js-add-attachment
|
||||
a.js-add-attachment(title="{{_ 'add-attachment' }}")
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-attachment' }}
|
||||
@@ -9,7 +9,7 @@
|
||||
margin: 10px 1% 0
|
||||
text-align: center
|
||||
border-radius: 3px
|
||||
overflow: hidden
|
||||
overflow: auto
|
||||
background: darken(white, 7%)
|
||||
min-height: 120px
|
||||
|
||||
|
||||
@@ -119,3 +119,24 @@ template(name="cardCustomField-dropdown")
|
||||
if value
|
||||
+viewer
|
||||
= selectedItem
|
||||
|
||||
template(name="cardCustomField-stringtemplate")
|
||||
if canModifyCard
|
||||
+inlinedForm(classNames="js-card-customfield-stringtemplate")
|
||||
each item in stringtemplateItems.get
|
||||
input.js-card-customfield-stringtemplate-item(type="text" value=item placeholder="")
|
||||
input.js-card-customfield-stringtemplate-item.last(type="text" value="" placeholder="{{_ 'custom-field-stringtemplate-item-placeholder'}}" autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if value
|
||||
+viewer
|
||||
= formattedValue
|
||||
else
|
||||
| {{_ 'edit'}}
|
||||
else
|
||||
if value
|
||||
+viewer
|
||||
= formattedValue
|
||||
@@ -1,3 +1,6 @@
|
||||
import { DatePicker } from '/client/lib/datepicker';
|
||||
import Cards from '/models/cards';
|
||||
|
||||
Template.cardCustomFieldsPopup.helpers({
|
||||
hasCustomField() {
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
@@ -234,3 +237,90 @@ CardCustomField.register('cardCustomField');
|
||||
];
|
||||
}
|
||||
}.register('cardCustomField-dropdown'));
|
||||
|
||||
// cardCustomField-stringtemplate
|
||||
(class extends CardCustomField {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
|
||||
this.stringtemplateFormat = this.data().definition.settings.stringtemplateFormat;
|
||||
this.stringtemplateSeparator = this.data().definition.settings.stringtemplateSeparator;
|
||||
|
||||
this.stringtemplateItems = new ReactiveVar(this.data().value ?? []);
|
||||
}
|
||||
|
||||
formattedValue() {
|
||||
return (this.data().value ?? [])
|
||||
.filter(value => !!value.trim())
|
||||
.map(value => this.stringtemplateFormat.replace(/%\{value\}/gi, value))
|
||||
.join(this.stringtemplateSeparator ?? '');
|
||||
}
|
||||
|
||||
getItems() {
|
||||
return Array.from(this.findAll('input'))
|
||||
.map(input => input.value)
|
||||
.filter(value => !!value.trim());
|
||||
}
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'submit .js-card-customfield-stringtemplate'(event) {
|
||||
event.preventDefault();
|
||||
const items = this.getItems();
|
||||
this.card.setCustomField(this.customFieldId, items);
|
||||
},
|
||||
|
||||
'keydown .js-card-customfield-stringtemplate-item'(event) {
|
||||
if (event.keyCode === 13) {
|
||||
event.preventDefault();
|
||||
|
||||
if (event.metaKey || event.ctrlKey) {
|
||||
this.find('button[type=submit]').click();
|
||||
} else if (event.target.value.trim()) {
|
||||
const inputLast = this.find('input.last');
|
||||
|
||||
let items = this.getItems();
|
||||
|
||||
if (event.target === inputLast) {
|
||||
inputLast.value = '';
|
||||
} else if (event.target.nextSibling === inputLast) {
|
||||
inputLast.focus();
|
||||
} else {
|
||||
event.target.blur();
|
||||
|
||||
const idx = Array.from(this.findAll('input')).indexOf(
|
||||
event.target,
|
||||
);
|
||||
items.splice(idx + 1, 0, '');
|
||||
|
||||
Tracker.afterFlush(() => {
|
||||
const element = this.findAll('input')[idx + 1];
|
||||
element.focus();
|
||||
element.value = '';
|
||||
});
|
||||
}
|
||||
|
||||
this.stringtemplateItems.set(items);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'blur .js-card-customfield-stringtemplate-item'(event) {
|
||||
if (
|
||||
!event.target.value.trim() ||
|
||||
event.target === this.find('input.last')
|
||||
) {
|
||||
const items = this.getItems();
|
||||
this.stringtemplateItems.set(items);
|
||||
this.find('input.last').value = '';
|
||||
}
|
||||
},
|
||||
|
||||
'click .js-close-inlined-form'(event) {
|
||||
this.stringtemplateItems.set(this.data().value ?? []);
|
||||
},
|
||||
},
|
||||
];
|
||||
}
|
||||
}.register('cardCustomField-stringtemplate'));
|
||||
@@ -1,122 +1,4 @@
|
||||
// Helper function to replace HH with H for 24 hours format, because H allows also single-digit hours
|
||||
function adjustedTimeFormat() {
|
||||
return moment
|
||||
.localeData()
|
||||
.longDateFormat('LT')
|
||||
.replace(/HH/i, 'H');
|
||||
}
|
||||
|
||||
// Edit received, start, due & end dates
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
return 'editCardDate';
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.card = this.data();
|
||||
this.date = new ReactiveVar(moment.invalid());
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
const $picker = this.$('.js-datepicker')
|
||||
.datepicker({
|
||||
todayHighlight: true,
|
||||
todayBtn: 'linked',
|
||||
language: TAPi18n.getLanguage(),
|
||||
})
|
||||
.on(
|
||||
'changeDate',
|
||||
function(evt) {
|
||||
this.find('#date').value = moment(evt.date).format('L');
|
||||
this.error.set('');
|
||||
this.find('#time').focus();
|
||||
}.bind(this),
|
||||
);
|
||||
|
||||
if (this.date.get().isValid()) {
|
||||
$picker.datepicker('update', this.date.get().toDate());
|
||||
}
|
||||
},
|
||||
|
||||
showDate() {
|
||||
if (this.date.get().isValid()) return this.date.get().format('L');
|
||||
return '';
|
||||
},
|
||||
showTime() {
|
||||
if (this.date.get().isValid()) return this.date.get().format('LT');
|
||||
return '';
|
||||
},
|
||||
dateFormat() {
|
||||
return moment.localeData().longDateFormat('L');
|
||||
},
|
||||
timeFormat() {
|
||||
return moment.localeData().longDateFormat('LT');
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup .js-date-field'() {
|
||||
// parse for localized date format in strict mode
|
||||
const dateMoment = moment(this.find('#date').value, 'L', true);
|
||||
if (dateMoment.isValid()) {
|
||||
this.error.set('');
|
||||
this.$('.js-datepicker').datepicker('update', dateMoment.toDate());
|
||||
}
|
||||
},
|
||||
'keyup .js-time-field'() {
|
||||
// parse for localized time format in strict mode
|
||||
const dateMoment = moment(
|
||||
this.find('#time').value,
|
||||
adjustedTimeFormat(),
|
||||
true,
|
||||
);
|
||||
if (dateMoment.isValid()) {
|
||||
this.error.set('');
|
||||
}
|
||||
},
|
||||
'submit .edit-date'(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
// if no time was given, init with 12:00
|
||||
const time =
|
||||
evt.target.time.value ||
|
||||
moment(new Date().setHours(12, 0, 0)).format('LT');
|
||||
const newTime = moment(time, adjustedTimeFormat(), true);
|
||||
const newDate = moment(evt.target.date.value, 'L', true);
|
||||
const dateString = `${evt.target.date.value} ${time}`;
|
||||
const newCompleteDate = moment(
|
||||
dateString,
|
||||
'L ' + adjustedTimeFormat(),
|
||||
true,
|
||||
);
|
||||
if (!newTime.isValid()) {
|
||||
this.error.set('invalid-time');
|
||||
evt.target.time.focus();
|
||||
}
|
||||
if (!newDate.isValid()) {
|
||||
this.error.set('invalid-date');
|
||||
evt.target.date.focus();
|
||||
}
|
||||
if (newCompleteDate.isValid()) {
|
||||
this._storeDate(newCompleteDate.toDate());
|
||||
Popup.close();
|
||||
} else {
|
||||
if (!this.error) {
|
||||
this.error.set('invalid');
|
||||
}
|
||||
}
|
||||
},
|
||||
'click .js-delete-date'(evt) {
|
||||
evt.preventDefault();
|
||||
this._deleteDate();
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
});
|
||||
import { DatePicker } from '/client/lib/datepicker';
|
||||
|
||||
Template.dateBadge.helpers({
|
||||
canModifyCard() {
|
||||
@@ -305,7 +187,7 @@ class CardStartDate extends CardDate {
|
||||
// if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
|
||||
if ((endAt && theDate.isAfter(endAt)) || (dueAt && theDate.isAfter(dueAt)))
|
||||
classes += 'long-overdue';
|
||||
else if (theDate.isBefore(now, 'minute')) classes += 'almost-due';
|
||||
else if (theDate.isAfter(now)) classes += '';
|
||||
else classes += 'current';
|
||||
return classes;
|
||||
}
|
||||
@@ -472,3 +354,30 @@ class VoteEndDate extends CardDate {
|
||||
}
|
||||
}
|
||||
VoteEndDate.register('voteEndDate');
|
||||
|
||||
class PokerEndDate extends CardDate {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
const self = this;
|
||||
self.autorun(() => {
|
||||
self.date.set(moment(self.data().getPokerEnd()));
|
||||
});
|
||||
}
|
||||
classes() {
|
||||
const classes = 'end-date' + ' ';
|
||||
return classes;
|
||||
}
|
||||
showDate() {
|
||||
return this.date.get().format('l LT');
|
||||
}
|
||||
showTitle() {
|
||||
return `${TAPi18n.__('card-end-on')} ${this.date.get().format('LLLL')}`;
|
||||
}
|
||||
|
||||
events() {
|
||||
return super.events().concat({
|
||||
'click .js-edit-date': Popup.open('editPokerEndDate'),
|
||||
});
|
||||
}
|
||||
}
|
||||
PokerEndDate.register('pokerEndDate');
|
||||
@@ -3,6 +3,7 @@ const descriptionFormIsOpen = new ReactiveVar(false);
|
||||
BlazeComponent.extendComponent({
|
||||
onDestroyed() {
|
||||
descriptionFormIsOpen.set(false);
|
||||
$('.note-popover').hide();
|
||||
},
|
||||
|
||||
descriptionFormIsOpen() {
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
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
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -110,11 +110,19 @@ avatar-radius = 50%
|
||||
|
||||
.card-details-header
|
||||
margin: 0 -20px 5px
|
||||
padding 7px 20px
|
||||
padding: 7px 20px
|
||||
background: darken(white, 7%)
|
||||
border-bottom: 1px solid darken(white, 14%)
|
||||
|
||||
.card-number {
|
||||
color: darken(white, 30%);
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.close-card-details,
|
||||
.maximize-card-details,
|
||||
.minimize-card-details,
|
||||
.card-details-menu,
|
||||
.card-copy-button,
|
||||
.card-copy-mobile-button,
|
||||
@@ -122,9 +130,11 @@ avatar-radius = 50%
|
||||
.card-details-menu-mobile-web
|
||||
float: right
|
||||
|
||||
.close-card-details
|
||||
.close-card-details,
|
||||
.maximize-card-details,
|
||||
.minimize-card-details
|
||||
font-size: 24px
|
||||
padding: 5px
|
||||
padding: 5px 10px 5px 10px
|
||||
margin-right: -8px
|
||||
|
||||
.close-card-details-mobile-web
|
||||
@@ -211,6 +221,7 @@ avatar-radius = 50%
|
||||
word-wrap: break-word
|
||||
max-width: 36%
|
||||
flex-grow: 1
|
||||
&.card-details-item-creator,
|
||||
&.card-details-item-received,
|
||||
&.card-details-item-start,
|
||||
&.card-details-item-due,
|
||||
@@ -232,6 +243,43 @@ avatar-radius = 50%
|
||||
.activities
|
||||
padding-top: 10px
|
||||
|
||||
@media screen and (min-width: 801px)
|
||||
.card-details-maximized
|
||||
padding: 0
|
||||
flex-shrink: 0
|
||||
flex-basis: calc(100% - 20px)
|
||||
will-change: flex-basis
|
||||
overflow-y: scroll
|
||||
overflow-x: scroll
|
||||
background: darken(white, 3%)
|
||||
border-radius: bottom 3px
|
||||
z-index: 1000 !important
|
||||
animation: flexGrowIn 0.1s
|
||||
box-shadow: 0 0 7px 0 darken(white, 30%)
|
||||
transition: flex-basis 0.1s
|
||||
box-sizing: border-box
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
height: calc(100% - 20px)
|
||||
width: calc(100% - 20px)
|
||||
float: left
|
||||
|
||||
.card-details-left
|
||||
float: left
|
||||
top: 60px
|
||||
left: 20px
|
||||
width: 47%
|
||||
|
||||
.card-details-right
|
||||
position: absolute
|
||||
float: right
|
||||
top: 20px
|
||||
left: 50%
|
||||
|
||||
.card-details-header
|
||||
width: 47%
|
||||
|
||||
input[type="text"].attachment-add-link-input
|
||||
float: left
|
||||
margin: 0 0 8px
|
||||
@@ -259,7 +307,13 @@ input[type="submit"].attachment-add-link-submit
|
||||
margin-right: 0px
|
||||
|
||||
.card-details-menu
|
||||
margin-right: 10px
|
||||
margin-right: 40px
|
||||
|
||||
.maximize-card-details
|
||||
margin-right: 40px
|
||||
|
||||
.minimize-card-details
|
||||
margin-right: 40px
|
||||
|
||||
card-details-color(background, color...)
|
||||
background: background !important
|
||||
@@ -356,3 +410,131 @@ card-details-color(background, color...)
|
||||
display: flex
|
||||
.js-show-positive-votes
|
||||
cursor: pointer
|
||||
|
||||
.poker-voted
|
||||
opacity: .7
|
||||
|
||||
.poker-title
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
|
||||
.js-edit-date
|
||||
align-self: baseline
|
||||
margin-left: 5px
|
||||
|
||||
.poker-result
|
||||
display: flex
|
||||
flex-flow: row wrap
|
||||
.js-show-positive-poker-votes
|
||||
cursor: pointer
|
||||
|
||||
.poker-deck
|
||||
display: grid
|
||||
flex-direction: column
|
||||
text-align: center
|
||||
|
||||
.poker-card-result
|
||||
width: 32px
|
||||
font-size: 1em
|
||||
font-weight: bold
|
||||
padding: 4px 2px 4px 2px
|
||||
cursor: default
|
||||
|
||||
.winner
|
||||
font-weight: bold
|
||||
outline: #2d2d2d solid 2px
|
||||
|
||||
.loser
|
||||
opacity: .5
|
||||
|
||||
.responsive-table
|
||||
overflow-x: auto
|
||||
|
||||
.poker-table
|
||||
display: table
|
||||
width: 100%
|
||||
padding-top: 10px
|
||||
|
||||
.poker-table-row
|
||||
display: table-row
|
||||
|
||||
.poker-table-heading
|
||||
background-color: #EEE
|
||||
display: table-header-group
|
||||
|
||||
.poker-table-cell
|
||||
display: table-cell
|
||||
padding: 0 0 5px 2px
|
||||
border-bottom: 1px solid #d2d0d0
|
||||
text-align: center
|
||||
min-width: 45px
|
||||
|
||||
.poker-table-cell-who
|
||||
width: 150px
|
||||
vertical-align: middle
|
||||
|
||||
.poker-table-heading-left,
|
||||
.poker-table-heading-right
|
||||
display: table-header-group
|
||||
font-weight: bold
|
||||
border-top: 1px solid #808080
|
||||
|
||||
@media (max-width: 400px)
|
||||
.poker-table-heading-right
|
||||
display: none
|
||||
|
||||
.poker-table-body
|
||||
display: table-row-group
|
||||
|
||||
.poker-table-side-left,
|
||||
.poker-table-side-right
|
||||
display: inline-block
|
||||
|
||||
.poker-table-side-right
|
||||
padding-left: 10px
|
||||
|
||||
@media (max-width: 400px)
|
||||
.poker-table-side-right
|
||||
padding-left: 0px
|
||||
|
||||
.estimation-add
|
||||
display: block
|
||||
overflow: auto
|
||||
margin-top: 15px
|
||||
margin-bottom: 5px
|
||||
input
|
||||
display: inline-block
|
||||
float: right
|
||||
margin: auto
|
||||
margin-right: 10px
|
||||
width: 100px
|
||||
button
|
||||
display: inline-block
|
||||
float: right
|
||||
margin: auto
|
||||
|
||||
.poker-card
|
||||
width:48px
|
||||
height:72px
|
||||
float:left
|
||||
background:#fff
|
||||
border-radius:5px
|
||||
display:table
|
||||
box-sizing:border-box
|
||||
padding:5px
|
||||
margin:3px
|
||||
font-size:20px
|
||||
font-weight: bold
|
||||
text-shadow: #2d2d2d 1px 1px 0
|
||||
box-shadow:0 0 5px #aaaaaa
|
||||
text-align:center
|
||||
position:relative
|
||||
cursor: pointer
|
||||
|
||||
.inner
|
||||
display:table-cell
|
||||
vertical-align:middle
|
||||
border-radius:5px
|
||||
overflow:hidden
|
||||
background-color: #cecece
|
||||
|
||||
@@ -4,8 +4,8 @@ template(name="checklists")
|
||||
i.fa.fa-check
|
||||
| {{_ 'checklists'}}
|
||||
if currentUser.isBoardMember
|
||||
.material-toggle-switch
|
||||
span.toggle-switch-title {{_ 'hide-checked-items'}}
|
||||
.material-toggle-switch(title="{{_ 'hide-checked-items'}}")
|
||||
//span.toggle-switch-title
|
||||
if hideCheckedItems
|
||||
input.toggle-switch(type="checkbox" id="toggleHideCheckedItemsButton" checked="checked")
|
||||
else
|
||||
@@ -25,9 +25,8 @@ template(name="checklists")
|
||||
+inlinedForm(autoclose=false classNames="js-add-checklist" cardId = cardId)
|
||||
+addChecklistItemForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
a.js-open-inlined-form(title="{{_ 'add-checklist'}}")
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-checklist'}}...
|
||||
|
||||
template(name="checklistDetail")
|
||||
.js-checklist.checklist
|
||||
@@ -81,6 +80,9 @@ template(name="editChecklistItemForm")
|
||||
span(title=createdAt) {{ moment createdAt }}
|
||||
if canModifyCard
|
||||
a.js-delete-checklist-item {{_ "delete"}}...
|
||||
a.js-convert-checklist-item-to-card
|
||||
i.fa.fa-copy
|
||||
| {{_ 'convertChecklistItemToCardPopup-title'}}
|
||||
|
||||
template(name="checklistItems")
|
||||
.checklist-items.js-checklist-items
|
||||
@@ -93,9 +95,8 @@ template(name="checklistItems")
|
||||
+inlinedForm(autoclose=false classNames="js-add-checklist-item" checklist = checklist)
|
||||
+addChecklistItemForm
|
||||
else
|
||||
a.add-checklist-item.js-open-inlined-form
|
||||
a.add-checklist-item.js-open-inlined-form(title="{{_ 'add-checklist-item'}}")
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-checklist-item'}}...
|
||||
|
||||
template(name='checklistItemDetail')
|
||||
.js-checklist-item.checklist-item(class="{{#if item.isFinished }}is-checked{{#if hideCheckedItems}} invisible{{/if}}{{/if}}")
|
||||
@@ -112,3 +113,32 @@ template(name='checklistItemDetail')
|
||||
.item-title(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
+viewer
|
||||
= item.title
|
||||
|
||||
template(name="convertChecklistItemToCardPopup")
|
||||
label(for='convert-checklist-item-to-card-title') {{_ 'title'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= item.title
|
||||
+boardsSwimlanesAndLists
|
||||
|
||||
template(name="boardsSwimlanesAndLists")
|
||||
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
|
||||
each swimlanes
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each aBoardLists
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-done {{_ 'done'}}
|
||||
@@ -1,3 +1,7 @@
|
||||
import Cards from '/models/cards';
|
||||
import Boards from '/models/boards';
|
||||
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndexData, capitalize } = Utils;
|
||||
|
||||
function initSorting(items) {
|
||||
@@ -206,6 +210,7 @@ BlazeComponent.extendComponent({
|
||||
'submit .js-edit-checklist-title': this.editChecklist,
|
||||
'submit .js-add-checklist-item': this.addChecklistItem,
|
||||
'submit .js-edit-checklist-item': this.editChecklistItem,
|
||||
'click .js-convert-checklist-item-to-card': Popup.open('convertChecklistItemToCard'),
|
||||
'click .js-delete-checklist-item': this.deleteItem,
|
||||
'click .confirm-checklist-delete': this.deleteChecklist,
|
||||
'focus .js-add-checklist-item': this.focusChecklistItem,
|
||||
@@ -215,6 +220,47 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('checklists');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
subManager.subscribe('board', Session.get('currentBoard'), false);
|
||||
this.selectedBoardId = new ReactiveVar(Session.get('currentBoard'));
|
||||
},
|
||||
|
||||
boards() {
|
||||
return Boards.find(
|
||||
{
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: { $ne: Meteor.user().getTemplatesBoardId() },
|
||||
},
|
||||
{
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
swimlanes() {
|
||||
const board = Boards.findOne(this.selectedBoardId.get());
|
||||
return board.swimlanes();
|
||||
},
|
||||
|
||||
aBoardLists() {
|
||||
const board = Boards.findOne(this.selectedBoardId.get());
|
||||
return board.lists();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'change .js-select-boards'(event) {
|
||||
this.selectedBoardId.set($(event.currentTarget).val());
|
||||
subManager.subscribe('board', this.selectedBoardId.get(), false);
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('boardsSwimlanesAndLists');
|
||||
|
||||
Template.checklists.helpers({
|
||||
hideCheckedItems() {
|
||||
const currentUser = Meteor.user();
|
||||
|
||||
@@ -159,7 +159,8 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
padding-top: 2px
|
||||
padding-right: 10px;
|
||||
|
||||
.js-delete-checklist-item
|
||||
.js-delete-checklist-item,
|
||||
.js-convert-checklist-item-to-card
|
||||
margin: 0 0 0.5em 1.33em
|
||||
@extends .delete-text
|
||||
padding: 12px 0 0 0
|
||||
|
||||
@@ -44,9 +44,20 @@
|
||||
align-items: center
|
||||
justify-content: center
|
||||
|
||||
.card-label-white
|
||||
background-color: #ffffff
|
||||
color: #000000 //Black text for better visibility
|
||||
border: 1px solid #c0c0c0
|
||||
|
||||
.card-label-white:hover
|
||||
color: #aaaaaa //grey text for better visibility
|
||||
|
||||
.card-label-green
|
||||
background-color: #3cb500
|
||||
|
||||
.card-label-green:hover
|
||||
color: #000000 //Black hover text for better visibility
|
||||
|
||||
.card-label-yellow
|
||||
background-color: #fad900
|
||||
color: #000000 //Black text for better visibility
|
||||
|
||||
@@ -37,6 +37,9 @@ template(name="minicard")
|
||||
if getArchived
|
||||
span.linked-icon.linked-archived.fa.fa-archive
|
||||
+viewer
|
||||
if currentBoard.allowsCardNumber
|
||||
span.card-number
|
||||
| ##{getCardNumber}
|
||||
= getTitle
|
||||
if $eq 'subtext-with-full-path' currentBoard.presentParentTask
|
||||
.parent-subtext
|
||||
@@ -82,6 +85,9 @@ template(name="minicard")
|
||||
+minicardCustomFieldDate
|
||||
else if $eq definition.type "checkbox"
|
||||
.materialCheckBox(class="{{#if value }}is-checked{{/if}}")
|
||||
else if $eq definition.type "stringtemplate"
|
||||
+viewer
|
||||
= formattedStringtemplateCustomFieldValue(definition)
|
||||
else
|
||||
+viewer
|
||||
= trueValue
|
||||
@@ -96,6 +102,10 @@ template(name="minicard")
|
||||
each getMembers
|
||||
+userAvatar(userId=this)
|
||||
|
||||
if showCreator
|
||||
.minicard-creator
|
||||
+userAvatar(userId=this.userId noRemove=true)
|
||||
|
||||
.badges
|
||||
unless currentUser.isNoComments
|
||||
if comments.count
|
||||
@@ -114,6 +124,11 @@ template(name="minicard")
|
||||
span.badge-text {{ voteCountPositive }}
|
||||
span.badge-icon.fa.fa-thumbs-down(class="{{#if $eq voteState false}}text-red{{/if}}")
|
||||
span.badge-text {{ voteCountNegative }}
|
||||
if getPokerQuestion
|
||||
.badge.badge-state-image-only(title=getPokerQuestion)
|
||||
span.badge-icon.fa.fa-check(class="{{#if pokerState}}text-green{{/if}}")
|
||||
if expiredPoker
|
||||
span.badge-text {{ getPokerEstimation }}
|
||||
if attachments.count
|
||||
.badge
|
||||
span.badge-icon.fa.fa-paperclip
|
||||
@@ -122,3 +137,12 @@ template(name="minicard")
|
||||
.badge(class="{{#if checklistFinished}}is-finished{{/if}}")
|
||||
span.badge-icon.fa.fa-check-square-o
|
||||
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
|
||||
if allSubtasks.count
|
||||
.badge
|
||||
span.badge-icon.fa.fa-sitemap
|
||||
span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}}
|
||||
//{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down
|
||||
if currentBoard.allowsCardSortingByNumber
|
||||
.badge
|
||||
span.badge-icon.fa.fa-sort
|
||||
span.badge-text {{ sort }}
|
||||
@@ -21,6 +21,34 @@ BlazeComponent.extendComponent({
|
||||
}).format(customFieldTrueValue);
|
||||
},
|
||||
|
||||
formattedStringtemplateCustomFieldValue(definition) {
|
||||
const customField = this.data()
|
||||
.customFieldsWD()
|
||||
.find(f => f._id === definition._id);
|
||||
|
||||
const customFieldTrueValue =
|
||||
customField && customField.trueValue ? customField.trueValue : [];
|
||||
|
||||
return customFieldTrueValue
|
||||
.filter(value => !!value.trim())
|
||||
.map(value =>
|
||||
definition.settings.stringtemplateFormat.replace(/%\{value\}/gi, value),
|
||||
)
|
||||
.join(definition.settings.stringtemplateSeparator ?? '');
|
||||
},
|
||||
|
||||
showCreator() {
|
||||
if (this.data().board()) {
|
||||
return (
|
||||
this.data().board.allowsCreator === null ||
|
||||
this.data().board().allowsCreator === undefined ||
|
||||
this.data().board().allowsCreator
|
||||
);
|
||||
// return this.data().board().allowsCreator;
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
border-radius: 2px
|
||||
margin-right: 3px
|
||||
margin-bottom: 3px
|
||||
|
||||
|
||||
.minicard-custom-fields
|
||||
display:block;
|
||||
.minicard-custom-field
|
||||
@@ -114,6 +114,10 @@
|
||||
font-size:20px;
|
||||
color: #ccc;
|
||||
.minicard-title
|
||||
.card-number
|
||||
color: darken(white, 30%);
|
||||
display: inline-block;
|
||||
margin-right: 5px;
|
||||
p:last-child
|
||||
margin-bottom: 0
|
||||
.viewer
|
||||
@@ -163,7 +167,8 @@
|
||||
line-height: 12px
|
||||
|
||||
.minicard-members,
|
||||
.minicard-assignees
|
||||
.minicard-assignees,
|
||||
.minicard-creator
|
||||
float: right
|
||||
margin-left: 5px
|
||||
margin-bottom: 4px
|
||||
@@ -187,6 +192,9 @@
|
||||
.minicard-assignees
|
||||
border-bottom: 1px solid red
|
||||
|
||||
.minicard-creator
|
||||
border-bottom: 1px solid green
|
||||
|
||||
.minicard-members:empty,
|
||||
.minicard-assignees:empty
|
||||
display: none
|
||||
|
||||
@@ -15,9 +15,8 @@ template(name="subtasks")
|
||||
+inlinedForm(autoclose=false classNames="js-add-subtask" cardId = cardId)
|
||||
+addSubtaskItemForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
a.js-open-inlined-form(title="{{_ 'add-subtask'}}")
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-subtask'}}...
|
||||
|
||||
template(name="subtaskDetail")
|
||||
.js-subtasks.subtask
|
||||
|
||||
@@ -37,6 +37,8 @@ BlazeComponent.extendComponent({
|
||||
? targetBoard.getDefaultSwimline()._id
|
||||
: targetSwimlane._id;
|
||||
|
||||
const nextCardNumber = targetBoard.getNextCardNumber();
|
||||
|
||||
if (title) {
|
||||
const _id = Cards.insert({
|
||||
title,
|
||||
@@ -49,6 +51,7 @@ BlazeComponent.extendComponent({
|
||||
sort: sortIndex,
|
||||
swimlaneId,
|
||||
type: 'cardType-card',
|
||||
cardNumber: nextCardNumber
|
||||
});
|
||||
|
||||
// In case the filter is active we need to add the newly inserted card in
|
||||
|
||||
@@ -86,7 +86,7 @@ select
|
||||
margin-bottom: 8px
|
||||
|
||||
&.inline
|
||||
width: 100%
|
||||
width: 100%
|
||||
|
||||
option[disabled]
|
||||
color: #8c8c8c
|
||||
|
||||
@@ -4,6 +4,17 @@ template(name="listBody")
|
||||
if cards.count
|
||||
+inlinedForm(autoclose=false position="top")
|
||||
+addCardForm(listId=_id position="top")
|
||||
ul.sidebar-list
|
||||
each customFieldsSum
|
||||
li
|
||||
+viewer
|
||||
= name
|
||||
if $eq customFieldsSum.type "number"
|
||||
+viewer
|
||||
= value
|
||||
if $eq customFieldsSum.type "currency"
|
||||
+viewer
|
||||
= formattedCurrencyCustomFieldValue(value)
|
||||
each (cardsWithLimit (idOrNull ../../_id))
|
||||
a.minicard-wrapper.js-minicard(href=originRelativeUrl
|
||||
class="{{#if cardIsSelected}}is-selected{{/if}}"
|
||||
@@ -19,19 +30,14 @@ template(name="listBody")
|
||||
+inlinedForm(autoclose=false position="bottom")
|
||||
+addCardForm(listId=_id position="bottom")
|
||||
else
|
||||
a.open-minicard-composer.js-card-composer.js-open-inlined-form
|
||||
a.open-minicard-composer.js-card-composer.js-open-inlined-form(title="{{_ 'add-card-to-bottom-of-list'}}")
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-card'}}
|
||||
|
||||
template(name="spinnerList")
|
||||
.sk-spinner.sk-spinner-wave.sk-spinner-list(
|
||||
class=currentBoard.colorClass
|
||||
.sk-spinner.sk-spinner-list(
|
||||
class="{{currentBoard.colorClass}} {{getSkSpinnerName}}"
|
||||
id="showMoreResults")
|
||||
.sk-rect1
|
||||
.sk-rect2
|
||||
.sk-rect3
|
||||
.sk-rect4
|
||||
.sk-rect5
|
||||
+spinnerRaw
|
||||
|
||||
template(name="addCardForm")
|
||||
.minicard.minicard-composer.js-composer
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { Spinner } from '/client/lib/spinner';
|
||||
|
||||
const subManager = new SubsManager();
|
||||
const InfiniteScrollIter = 10;
|
||||
|
||||
@@ -11,6 +13,13 @@ BlazeComponent.extendComponent({
|
||||
return [];
|
||||
},
|
||||
|
||||
customFieldsSum() {
|
||||
return CustomFields.find({
|
||||
boardIds: { $in: [Session.get('currentBoard')] },
|
||||
showSumAtTopOfList: true,
|
||||
});
|
||||
},
|
||||
|
||||
openForm(options) {
|
||||
options = options || {};
|
||||
options.position = options.position || 'top';
|
||||
@@ -79,7 +88,9 @@ BlazeComponent.extendComponent({
|
||||
Utils.boardView() === 'board-view-cal' ||
|
||||
!Utils.boardView()
|
||||
)
|
||||
swimlaneId = board.getDefaultSwimline()._id;
|
||||
swimlaneId = board.getDefaultSwimline()._id;
|
||||
|
||||
const nextCardNumber = board.getNextCardNumber();
|
||||
|
||||
const _id = Cards.insert({
|
||||
title,
|
||||
@@ -91,6 +102,7 @@ BlazeComponent.extendComponent({
|
||||
sort: sortIndex,
|
||||
swimlaneId,
|
||||
type: cardType,
|
||||
cardNumber: nextCardNumber,
|
||||
linkedId,
|
||||
});
|
||||
|
||||
@@ -116,8 +128,6 @@ BlazeComponent.extendComponent({
|
||||
if (position === 'bottom') {
|
||||
this.scrollToBottom();
|
||||
}
|
||||
|
||||
formComponent.reset();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -241,7 +251,7 @@ BlazeComponent.extendComponent({
|
||||
Boards.findOne(currentBoardId)
|
||||
.customFields()
|
||||
.fetch(),
|
||||
function(field) {
|
||||
function (field) {
|
||||
if (field.automaticallyOnCard || field.alwaysOnCard)
|
||||
arr.push({ _id: field._id, value: null });
|
||||
},
|
||||
@@ -552,7 +562,7 @@ BlazeComponent.extendComponent({
|
||||
board = Boards.findOne((Meteor.user().profile || {}).templatesBoardId);
|
||||
} else {
|
||||
// Prefetch first non-current board id
|
||||
board = Boards.findOne({
|
||||
board = Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {
|
||||
@@ -698,7 +708,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('searchElementPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
(class extends Spinner {
|
||||
onCreated() {
|
||||
this.cardlimit = this.parentComponent().cardlimit;
|
||||
|
||||
@@ -726,7 +736,7 @@ BlazeComponent.extendComponent({
|
||||
.parentComponent()
|
||||
.data()._id;
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
onRendered() {
|
||||
this.spinner = this.find('.sk-spinner-list');
|
||||
@@ -741,21 +751,18 @@ BlazeComponent.extendComponent({
|
||||
);
|
||||
|
||||
this.updateList();
|
||||
},
|
||||
}
|
||||
|
||||
onDestroyed() {
|
||||
$(this.container).off(`scroll.spinner_${this.swimlaneId}_${this.listId}`);
|
||||
$(window).off(`resize.spinner_${this.swimlaneId}_${this.listId}`);
|
||||
},
|
||||
}
|
||||
|
||||
updateList() {
|
||||
// Use fallback when requestIdleCallback is not available on iOS and Safari
|
||||
// https://www.afasterweb.com/2017/11/20/utilizing-idle-moments/
|
||||
checkIdleTime =
|
||||
window.requestIdleCallback ||
|
||||
function(handler) {
|
||||
checkIdleTime() {
|
||||
return window.requestIdleCallback ||
|
||||
function (handler) {
|
||||
const startTime = Date.now();
|
||||
return setTimeout(function() {
|
||||
return setTimeout(function () {
|
||||
handler({
|
||||
didTimeout: false,
|
||||
timeRemaining() {
|
||||
@@ -764,24 +771,38 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
}, 1);
|
||||
};
|
||||
}
|
||||
|
||||
updateList() {
|
||||
// Use fallback when requestIdleCallback is not available on iOS and Safari
|
||||
// https://www.afasterweb.com/2017/11/20/utilizing-idle-moments/
|
||||
|
||||
if (this.spinnerInView()) {
|
||||
this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
|
||||
checkIdleTime(() => this.updateList());
|
||||
this.checkIdleTime(() => this.updateList());
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
spinnerInView() {
|
||||
const parentViewHeight = this.container.clientHeight;
|
||||
const bottomViewPosition = this.container.scrollTop + parentViewHeight;
|
||||
|
||||
const threshold = this.spinner.offsetTop;
|
||||
|
||||
// spinner deleted
|
||||
if (!this.spinner.offsetTop) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return bottomViewPosition > threshold;
|
||||
},
|
||||
}).register('spinnerList');
|
||||
const parentViewHeight = this.container.clientHeight;
|
||||
const bottomViewPosition = this.container.scrollTop + parentViewHeight;
|
||||
|
||||
let spinnerOffsetTop = this.spinner.offsetTop;
|
||||
|
||||
const addCard = $(this.container).find("a.open-minicard-composer").first()[0];
|
||||
if (addCard !== undefined) {
|
||||
spinnerOffsetTop -= addCard.clientHeight;
|
||||
}
|
||||
|
||||
return bottomViewPosition > spinnerOffsetTop;
|
||||
}
|
||||
|
||||
getSkSpinnerName() {
|
||||
return "sk-spinner-" + super.getSpinnerName().toLowerCase();
|
||||
}
|
||||
}.register('spinnerList'));
|
||||
@@ -20,7 +20,7 @@ template(name="listHeader")
|
||||
|
||||
if showCardsCountForList cards.count
|
||||
|
|
||||
span(class="cardCount") {{cardsCount}} {{_ 'cards-count'}}
|
||||
span(class="cardCount") {{cardsCount}} {{cardsCountForListIsOne cards.count}}
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
if isWatching
|
||||
@@ -28,8 +28,8 @@ template(name="listHeader")
|
||||
div.list-header-menu
|
||||
unless currentUser.isCommentOnly
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon(title="{{_ 'add-card-to-top-of-list'}}")
|
||||
a.fa.fa-navicon.js-open-list-menu(title="{{_ 'listActionPopup-title'}}")
|
||||
else
|
||||
a.list-header-menu-icon.fa.fa-angle-right.js-select-list
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
@@ -41,8 +41,8 @@ template(name="listHeader")
|
||||
//if isBoardAdmin
|
||||
// a.fa.js-list-star.list-header-plus-icon(class="fa-star{{#unless starred}}-o{{/unless}}")
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon(title="{{_ 'add-card-to-top-of-list'}}")
|
||||
a.fa.fa-navicon.js-open-list-menu(title="{{_ 'listActionPopup-title'}}")
|
||||
if currentUser.isBoardAdmin
|
||||
if showDesktopDragHandles
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
|
||||
@@ -85,6 +85,14 @@ BlazeComponent.extendComponent({
|
||||
return limit >= 0 && count >= limit;
|
||||
},
|
||||
|
||||
cardsCountForListIsOne(count) {
|
||||
if (count === 1) {
|
||||
return TAPi18n.__('cards-count-one');
|
||||
} else {
|
||||
return TAPi18n.__('cards-count');
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
|
||||
@@ -3,7 +3,7 @@ import {
|
||||
OPERATOR_HAS,
|
||||
OPERATOR_SORT,
|
||||
OPERATOR_USER,
|
||||
ORDER_DESCENDING,
|
||||
ORDER_ASCENDING,
|
||||
PREDICATE_DUE_AT,
|
||||
} from '../../../config/search-const';
|
||||
import { QueryParams } from '../../../config/query-classes';
|
||||
@@ -62,14 +62,14 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
||||
// queryParams[OPERATOR_LIMIT] = 5;
|
||||
queryParams.addPredicate(OPERATOR_SORT, {
|
||||
name: PREDICATE_DUE_AT,
|
||||
order: ORDER_DESCENDING,
|
||||
order: ORDER_ASCENDING,
|
||||
});
|
||||
|
||||
if (Utils.dueCardsView() !== 'all') {
|
||||
queryParams.addPredicate(OPERATOR_USER, Meteor.user().username);
|
||||
}
|
||||
|
||||
this.runGlobalSearch(queryParams.getQueryParams());
|
||||
this.runGlobalSearch(queryParams);
|
||||
}
|
||||
|
||||
dueCardsView() {
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
const specialHandles = [
|
||||
{userId: 'board_members', username: 'board_members'},
|
||||
{userId: 'card_members', username: 'card_members'}
|
||||
];
|
||||
const specialHandleNames = specialHandles.map(m => m.username);
|
||||
|
||||
Template.editor.onRendered(() => {
|
||||
const textareaSelector = 'textarea';
|
||||
const mentions = [
|
||||
@@ -7,13 +13,14 @@ Template.editor.onRendered(() => {
|
||||
search(term, callback) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
callback(
|
||||
_.union(
|
||||
currentBoard
|
||||
.activeMembers()
|
||||
.map(member => {
|
||||
const username = Users.findOne(member.userId).username;
|
||||
return username.includes(term) ? username : null;
|
||||
})
|
||||
.filter(Boolean),
|
||||
.filter(Boolean), [...specialHandleNames])
|
||||
);
|
||||
},
|
||||
template(value) {
|
||||
@@ -49,8 +56,8 @@ Template.editor.onRendered(() => {
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['table', ['table']],
|
||||
//['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
||||
//['insert', ['link', 'picture']], // modal popup has issue somehow :(
|
||||
['view', ['fullscreen', 'help']],
|
||||
['insert', ['link']], //, 'picture']], // modal popup has issue somehow :(
|
||||
['view', ['fullscreen', 'codeview', 'help']],
|
||||
];
|
||||
const cleanPastedHTML = function(input) {
|
||||
const badTags = [
|
||||
@@ -145,6 +152,7 @@ Template.editor.onRendered(() => {
|
||||
const MAX_IMAGE_PIXEL = Utils.MAX_IMAGE_PIXEL;
|
||||
const COMPRESS_RATIO = Utils.IMAGE_COMPRESS_RATIO;
|
||||
const insertImage = src => {
|
||||
// process all image upload types to the description/comment window
|
||||
const img = document.createElement('img');
|
||||
img.src = src;
|
||||
img.setAttribute('width', '100%');
|
||||
@@ -210,7 +218,16 @@ Template.editor.onRendered(() => {
|
||||
}
|
||||
}
|
||||
},
|
||||
onPaste() {
|
||||
onPaste(e) {
|
||||
var clipboardData = e.clipboardData;
|
||||
var pastedData = clipboardData.getData('Text');
|
||||
|
||||
//if pasted data is an image, exit
|
||||
if (!pastedData.length) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
|
||||
// clear up unwanted tag info when user pasted in text
|
||||
const thisNote = this;
|
||||
const updatePastedText = function(object) {
|
||||
@@ -234,17 +251,17 @@ Template.editor.onRendered(() => {
|
||||
},
|
||||
},
|
||||
dialogsInBody: true,
|
||||
disableDragAndDrop: true,
|
||||
spellCheck: true,
|
||||
disableGrammar: false,
|
||||
disableDragAndDrop: false,
|
||||
toolbar,
|
||||
popover: {
|
||||
image: [
|
||||
[
|
||||
'image',
|
||||
['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone'],
|
||||
],
|
||||
['imagesize', ['imageSize100', 'imageSize50', 'imageSize25']],
|
||||
['float', ['floatLeft', 'floatRight', 'floatNone']],
|
||||
['remove', ['removeMedia']],
|
||||
],
|
||||
link: [['link', ['linkDialogShow', 'unlink']]],
|
||||
table: [
|
||||
['add', ['addRowDown', 'addRowUp', 'addColLeft', 'addColRight']],
|
||||
['delete', ['deleteRow', 'deleteCol', 'deleteTable']],
|
||||
@@ -263,10 +280,12 @@ Template.editor.onRendered(() => {
|
||||
}
|
||||
});
|
||||
|
||||
import sanitizeXss from 'xss';
|
||||
import DOMPurify from 'dompurify';
|
||||
|
||||
// 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
|
||||
@@ -292,6 +311,7 @@ function mySafeAttrValue(tag, name, value, cssFilter) {
|
||||
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
|
||||
@@ -307,14 +327,16 @@ Blaze.Template.registerHelper(
|
||||
let content = Blaze.toHTML(view.templateContentBlock);
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (!currentBoard)
|
||||
return HTML.Raw(sanitizeXss(content, { safeAttrValue: mySafeAttrValue }));
|
||||
const knowedUsers = currentBoard.members.map(member => {
|
||||
return HTML.Raw(
|
||||
DOMPurify.sanitize(content, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
);
|
||||
const knowedUsers = _.union(currentBoard.members.map(member => {
|
||||
const u = Users.findOne(member.userId);
|
||||
if (u) {
|
||||
member.username = u.username;
|
||||
}
|
||||
return member;
|
||||
});
|
||||
}), [...specialHandles]);
|
||||
const mentionRegex = /\B@([\w.]*)/gi;
|
||||
|
||||
let currentMention;
|
||||
@@ -351,7 +373,9 @@ Blaze.Template.registerHelper(
|
||||
content = content.replace(fullMention, Blaze.toHTML(link));
|
||||
}
|
||||
|
||||
return HTML.Raw(sanitizeXss(content, { safeAttrValue: mySafeAttrValue }));
|
||||
return HTML.Raw(
|
||||
DOMPurify.sanitize(content, { ALLOW_UNKNOWN_PROTOCOLS: true }),
|
||||
);
|
||||
}),
|
||||
);
|
||||
|
||||
|
||||
@@ -11,9 +11,10 @@ template(name="globalSearchModalTitle")
|
||||
| {{_ 'globalSearch-title'}}
|
||||
|
||||
template(name="resultsPaged")
|
||||
h1
|
||||
= resultsHeading.get
|
||||
a.fa.fa-link(title="{{_ 'link-to-search' }}" href="{{ getSearchHref }}")
|
||||
if resultsHeading.get
|
||||
h1
|
||||
= resultsHeading.get
|
||||
a.fa.fa-link(title="{{_ 'link-to-search' }}" href="{{ getSearchHref }}")
|
||||
each card in results.get
|
||||
+resultCard(card)
|
||||
table.global-search-footer
|
||||
@@ -50,8 +51,7 @@ template(name="globalSearch")
|
||||
each msg in errorMessages
|
||||
li.global-search-error-messages
|
||||
= msg
|
||||
else
|
||||
+resultsPaged(this)
|
||||
+resultsPaged(this)
|
||||
else if serverError.get
|
||||
.global-search-page
|
||||
.global-search-help
|
||||
|
||||
@@ -123,6 +123,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||
operator_member_abbrev: TAPi18n.__('operator-member-abbrev'),
|
||||
operator_assignee: TAPi18n.__('operator-assignee'),
|
||||
operator_assignee_abbrev: TAPi18n.__('operator-assignee-abbrev'),
|
||||
operator_creator: TAPi18n.__('operator-creator'),
|
||||
operator_due: TAPi18n.__('operator-due'),
|
||||
operator_created: TAPi18n.__('operator-created'),
|
||||
operator_modified: TAPi18n.__('operator-modified'),
|
||||
@@ -157,39 +158,42 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||
['# ', 'globalSearch-instructions-heading'],
|
||||
['\n', 'globalSearch-instructions-description'],
|
||||
['\n\n', 'globalSearch-instructions-operators'],
|
||||
['\n* ', 'globalSearch-instructions-operator-board'],
|
||||
['\n* ', 'globalSearch-instructions-operator-list'],
|
||||
['\n* ', 'globalSearch-instructions-operator-swimlane'],
|
||||
['\n* ', 'globalSearch-instructions-operator-comment'],
|
||||
['\n* ', 'globalSearch-instructions-operator-label'],
|
||||
['\n* ', 'globalSearch-instructions-operator-hash'],
|
||||
['\n* ', 'globalSearch-instructions-operator-user'],
|
||||
['\n* ', 'globalSearch-instructions-operator-at'],
|
||||
['\n* ', 'globalSearch-instructions-operator-member'],
|
||||
['\n* ', 'globalSearch-instructions-operator-assignee'],
|
||||
['\n* ', 'globalSearch-instructions-operator-due'],
|
||||
['\n* ', 'globalSearch-instructions-operator-created'],
|
||||
['\n* ', 'globalSearch-instructions-operator-modified'],
|
||||
['\n* ', 'globalSearch-instructions-operator-status'],
|
||||
['\n * ', 'globalSearch-instructions-status-archived'],
|
||||
['\n * ', 'globalSearch-instructions-status-public'],
|
||||
['\n * ', 'globalSearch-instructions-status-private'],
|
||||
['\n * ', 'globalSearch-instructions-status-all'],
|
||||
['\n * ', 'globalSearch-instructions-status-ended'],
|
||||
['\n* ', 'globalSearch-instructions-operator-has'],
|
||||
['\n* ', 'globalSearch-instructions-operator-sort'],
|
||||
['\n* ', 'globalSearch-instructions-operator-limit'],
|
||||
['\n- ', 'globalSearch-instructions-operator-board'],
|
||||
['\n- ', 'globalSearch-instructions-operator-list'],
|
||||
['\n- ', 'globalSearch-instructions-operator-swimlane'],
|
||||
['\n- ', 'globalSearch-instructions-operator-comment'],
|
||||
['\n- ', 'globalSearch-instructions-operator-label'],
|
||||
['\n- ', 'globalSearch-instructions-operator-hash'],
|
||||
['\n- ', 'globalSearch-instructions-operator-user'],
|
||||
['\n- ', 'globalSearch-instructions-operator-at'],
|
||||
['\n- ', 'globalSearch-instructions-operator-member'],
|
||||
['\n- ', 'globalSearch-instructions-operator-assignee'],
|
||||
['\n- ', 'globalSearch-instructions-operator-creator'],
|
||||
['\n- ', 'globalSearch-instructions-operator-due'],
|
||||
['\n- ', 'globalSearch-instructions-operator-created'],
|
||||
['\n- ', 'globalSearch-instructions-operator-modified'],
|
||||
['\n- ', 'globalSearch-instructions-operator-status'],
|
||||
['\n - ', 'globalSearch-instructions-status-archived'],
|
||||
['\n - ', 'globalSearch-instructions-status-public'],
|
||||
['\n - ', 'globalSearch-instructions-status-private'],
|
||||
['\n - ', 'globalSearch-instructions-status-all'],
|
||||
['\n - ', 'globalSearch-instructions-status-ended'],
|
||||
['\n- ', 'globalSearch-instructions-operator-has'],
|
||||
['\n- ', 'globalSearch-instructions-operator-sort'],
|
||||
['\n- ', 'globalSearch-instructions-operator-limit'],
|
||||
['\n## ', 'heading-notes'],
|
||||
['\n* ', 'globalSearch-instructions-notes-1'],
|
||||
['\n* ', 'globalSearch-instructions-notes-2'],
|
||||
['\n* ', 'globalSearch-instructions-notes-3'],
|
||||
['\n* ', 'globalSearch-instructions-notes-3-2'],
|
||||
['\n* ', 'globalSearch-instructions-notes-4'],
|
||||
['\n* ', 'globalSearch-instructions-notes-5'],
|
||||
['\n- ', 'globalSearch-instructions-notes-1'],
|
||||
['\n- ', 'globalSearch-instructions-notes-2'],
|
||||
['\n- ', 'globalSearch-instructions-notes-3'],
|
||||
['\n- ', 'globalSearch-instructions-notes-3-2'],
|
||||
['\n- ', 'globalSearch-instructions-notes-4'],
|
||||
['\n- ', 'globalSearch-instructions-notes-5'],
|
||||
].forEach(([prefix, instruction]) => {
|
||||
text += `${prefix}${TAPi18n.__(instruction, tags)}`;
|
||||
text += `${prefix}${TAPi18n.__(instruction, tags)}`
|
||||
// Replace *<text>* with `<text>` so markdown shows correctly
|
||||
.replace(/\*\</, '`<')
|
||||
.replace(/\>\*/, '\>\`')
|
||||
});
|
||||
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -202,9 +206,8 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||
}
|
||||
|
||||
events() {
|
||||
return [
|
||||
return super.events().concat([
|
||||
{
|
||||
...super.events()[0],
|
||||
'submit .js-search-query-form'(evt) {
|
||||
evt.preventDefault();
|
||||
this.searchAllBoards(evt.target.searchQuery.value);
|
||||
@@ -257,7 +260,7 @@ class GlobalSearchComponent extends CardSearchPagedComponent {
|
||||
this.hasResults.set(false);
|
||||
},
|
||||
},
|
||||
];
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,12 +31,12 @@ template(name="header")
|
||||
unless currentSetting.hideLogo
|
||||
if currentSetting.customTopLeftCornerLogoImageUrl
|
||||
if currentSetting.customTopLeftCornerLogoLinkUrl
|
||||
a(href="{{currentSetting.customTopLeftCornerLogoLinkUrl}}")
|
||||
a(href="{{currentSetting.customTopLeftCornerLogoLinkUrl}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
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")
|
||||
img(src="{{currentSetting.customTopLeftCornerLogoImageUrl}}" height="{{#if currentSetting.customTopLeftCornerLogoHeight}}#{currentSetting.customTopLeftCornerLogoHeight}{{else}}27{{/if}}" width="auto" margin="0" padding="0" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
unless currentSetting.customTopLeftCornerLogoImageUrl
|
||||
img(src="{{pathFor '/logo-header.png'}}" alt="")
|
||||
img(src="{{pathFor '/logo-header.png'}}" alt="{{currentSetting.productName}}" title="{{currentSetting.productName}}")
|
||||
span.allBoards
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
|
||||
@@ -28,6 +28,12 @@ Template.userFormsLayout.onCreated(function() {
|
||||
Meteor.subscribe('setting', {
|
||||
onReady() {
|
||||
templateInstance.currentSetting.set(Settings.findOne());
|
||||
let currSetting = templateInstance.currentSetting.curValue;
|
||||
let oidcBtnElt = $("#at-oidc");
|
||||
if(currSetting && currSetting !== undefined && currSetting.oidcBtnText !== undefined && oidcBtnElt != null && oidcBtnElt != undefined){
|
||||
let htmlvalue = "<i class='fa fa-oidc'></i>" + currSetting.oidcBtnText;
|
||||
oidcBtnElt.html(htmlvalue);
|
||||
}
|
||||
return this.stop();
|
||||
},
|
||||
});
|
||||
@@ -77,6 +83,8 @@ Template.userFormsLayout.helpers({
|
||||
} else if (lang.name === 'ar-EG') {
|
||||
// ar-EG = Arabic (Egypt), simply Masri (مَصرى, [ˈmɑsˤɾi], Egyptian, Masr refers to Cairo)
|
||||
name = 'مَصرى';
|
||||
} else if (lang.name === 'de-CH') {
|
||||
name = 'Deutsch (Schweiz)';
|
||||
} else if (lang.name === 'fa-IR') {
|
||||
// fa-IR = Persian (Iran)
|
||||
name = 'فارسی/پارسی (ایران)';
|
||||
@@ -84,12 +92,16 @@ Template.userFormsLayout.helpers({
|
||||
name = 'Français (Belgique)';
|
||||
} else if (lang.name === 'fr-CA') {
|
||||
name = 'Français (Canada)';
|
||||
} else if (lang.name === 'fr-CH') {
|
||||
name = 'Français (Schweiz)';
|
||||
} 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 === 'en-IT') {
|
||||
name = 'English (Italy)';
|
||||
} else if (lang.name === 'Español') {
|
||||
name = 'español';
|
||||
} else if (lang.name === 'es_419') {
|
||||
|
||||
@@ -317,6 +317,9 @@ kbd
|
||||
.grabbing
|
||||
cursor: grabbing
|
||||
|
||||
.textcomplete-dropdown
|
||||
z-index: 2000 !important;
|
||||
|
||||
// Implement a thiner close icon as suggested in
|
||||
// https://github.com/FortAwesome/Font-Awesome/issues/1540#issuecomment-68689950
|
||||
.fa.fa-times-thin:before
|
||||
|
||||
@@ -6,16 +6,6 @@ template(name="myCardsHeaderBar")
|
||||
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
|
||||
@@ -28,46 +18,22 @@ template(name="myCards")
|
||||
+spinner
|
||||
else
|
||||
.wrapper
|
||||
if $eq myCardsSort 'board'
|
||||
each board in myCardsList
|
||||
.my-cards-board-wrapper
|
||||
.my-cards-board-title(class=board.colorClass, id="header")
|
||||
a(href=board.originRelativeUrl)
|
||||
+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.originRelativeUrl)
|
||||
+minicard(card)
|
||||
else
|
||||
.my-cards-dueat-list-wrapper
|
||||
each card in myDueCardsList
|
||||
+resultCard(card)
|
||||
|
||||
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
|
||||
each board in myCardsList
|
||||
.my-cards-board-wrapper
|
||||
.my-cards-board-title(class=board.colorClass, id="header")
|
||||
a(href=board.originRelativeUrl)
|
||||
+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.originRelativeUrl)
|
||||
+minicard(card)
|
||||
@@ -1,14 +1,4 @@
|
||||
import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
||||
import { QueryParams } from '../../../config/query-classes';
|
||||
import {
|
||||
OPERATOR_LIMIT,
|
||||
OPERATOR_SORT,
|
||||
OPERATOR_USER,
|
||||
ORDER_DESCENDING,
|
||||
PREDICATE_DUE_AT,
|
||||
} from '../../../config/search-const';
|
||||
|
||||
// const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
myCardsSort() {
|
||||
@@ -34,48 +24,21 @@ Template.myCards.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
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');
|
||||
|
||||
class MyCardsComponent extends CardSearchPagedComponent {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
|
||||
const queryParams = new QueryParams();
|
||||
queryParams.addPredicate(OPERATOR_USER, Meteor.user().username);
|
||||
queryParams.addPredicate(OPERATOR_SORT, {
|
||||
name: PREDICATE_DUE_AT,
|
||||
order: ORDER_DESCENDING,
|
||||
});
|
||||
queryParams.addPredicate(OPERATOR_LIMIT, 100);
|
||||
|
||||
this.runGlobalSearch(queryParams);
|
||||
this.runGlobalSearch(null);
|
||||
Meteor.subscribe('setting');
|
||||
}
|
||||
|
||||
myCardsSort() {
|
||||
// eslint-disable-next-line no-console
|
||||
//console.log('sort:', Utils.myCardsSort());
|
||||
return Utils.myCardsSort();
|
||||
}
|
||||
|
||||
sortByBoard() {
|
||||
return this.myCardsSort() === 'board';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
getSubscription(queryParams) {
|
||||
return Meteor.subscribe(
|
||||
'myCards',
|
||||
this.sessionId,
|
||||
this.subscriptionCallbacks,
|
||||
);
|
||||
}
|
||||
|
||||
myCardsList() {
|
||||
@@ -87,35 +50,9 @@ class MyCardsComponent extends CardSearchPagedComponent {
|
||||
const cursor = this.getResults();
|
||||
|
||||
if (cursor) {
|
||||
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');
|
||||
@@ -126,23 +63,38 @@ class MyCardsComponent extends CardSearchPagedComponent {
|
||||
}
|
||||
// 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);
|
||||
board.mySwimlanes = [];
|
||||
swimlane = null;
|
||||
list = null;
|
||||
}
|
||||
|
||||
newBoard = false;
|
||||
newSwimlane = false;
|
||||
newList = false;
|
||||
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;
|
||||
}
|
||||
board.mySwimlanes.push(swimlane);
|
||||
swimlane.myLists = [];
|
||||
list = null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
swimlane.myLists.push(list);
|
||||
list.myCards = [];
|
||||
}
|
||||
|
||||
list.myCards.push(card);
|
||||
});
|
||||
|
||||
// sort the data structure
|
||||
@@ -182,27 +134,5 @@ class MyCardsComponent extends CardSearchPagedComponent {
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
myDueCardsList() {
|
||||
const cursor = this.getResults();
|
||||
const cards = [];
|
||||
cursor.forEach(card => {
|
||||
cards.push(card);
|
||||
});
|
||||
|
||||
cards.sort((a, b) => {
|
||||
const x = a.dueAt === null ? new Date('2100-12-31') : a.dueAt;
|
||||
const y = b.dueAt === null ? new 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;
|
||||
}
|
||||
}
|
||||
MyCardsComponent.register('myCards');
|
||||
@@ -0,0 +1,5 @@
|
||||
template(name="spinner")
|
||||
+Template.dynamic(template=getSpinnerTemplate)
|
||||
|
||||
template(name="spinnerRaw")
|
||||
+Template.dynamic(template=getSpinnerTemplateRaw)
|
||||
@@ -0,0 +1,11 @@
|
||||
import { Spinner } from '/client/lib/spinner';
|
||||
|
||||
(class extends Spinner {
|
||||
}.register('spinner'));
|
||||
|
||||
(class extends Spinner {
|
||||
getSpinnerTemplateRaw() {
|
||||
let ret = super.getSpinnerTemplate() + 'Raw';
|
||||
return ret;
|
||||
}
|
||||
}.register('spinnerRaw'));
|
||||
@@ -1,6 +0,0 @@
|
||||
.sk-spinner.sk-spinner-wave(class=currentBoard.colorClass)
|
||||
.sk-rect1
|
||||
.sk-rect2
|
||||
.sk-rect3
|
||||
.sk-rect4
|
||||
.sk-rect5
|
||||
@@ -0,0 +1,11 @@
|
||||
template(name="spinnerBounce")
|
||||
.sk-spinner.sk-spinner-bounce(class=currentBoard.colorClass)
|
||||
+spinnerBounceRaw
|
||||
|
||||
template(name="spinnerBounceRaw")
|
||||
.sk-bounce1
|
||||
|
|
||||
.sk-bounce2
|
||||
|
|
||||
.sk-bounce3
|
||||
|
|
||||
@@ -0,0 +1,44 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-bounce {
|
||||
margin: 100px auto 0;
|
||||
width: 70px;
|
||||
text-align: center;
|
||||
|
||||
div {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-color: #333;
|
||||
|
||||
border-radius: 100%;
|
||||
display: inline-block;
|
||||
-webkit-animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
animation: sk-bouncedelay 1.4s infinite ease-in-out both;
|
||||
}
|
||||
|
||||
.sk-bounce1 {
|
||||
-webkit-animation-delay: -0.32s;
|
||||
animation-delay: -0.32s;
|
||||
}
|
||||
|
||||
.sk-bounce2 {
|
||||
-webkit-animation-delay: -0.16s;
|
||||
animation-delay: -0.16s;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% { -webkit-transform: scale(0) }
|
||||
40% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bouncedelay {
|
||||
0%, 80%, 100% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 40% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
template(name="spinnerCube")
|
||||
.sk-spinner.sk-spinner-cube(class=currentBoard.colorClass)
|
||||
+spinnerCubeRaw
|
||||
|
||||
template(name="spinnerCubeRaw")
|
||||
.sk-cube1
|
||||
.sk-cube2
|
||||
.sk-cube3
|
||||
@@ -0,0 +1,52 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-cube {
|
||||
margin: 100px auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.sk-cube1, .sk-cube2 {
|
||||
background-color: #333;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
-webkit-animation: sk-cubemove 1.8s infinite ease-in-out;
|
||||
animation: sk-cubemove 1.8s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.sk-cube2 {
|
||||
-webkit-animation-delay: -0.9s;
|
||||
animation-delay: -0.9s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-cubemove {
|
||||
25% { -webkit-transform: translateX(35px) rotate(-90deg) scale(0.5) }
|
||||
50% { -webkit-transform: translateX(35px) translateY(35px) rotate(-180deg) }
|
||||
75% { -webkit-transform: translateX(0px) translateY(35px) rotate(-270deg) scale(0.5) }
|
||||
100% { -webkit-transform: rotate(-360deg) }
|
||||
}
|
||||
|
||||
@keyframes sk-cubemove {
|
||||
25% {
|
||||
transform: translateX(35px) rotate(-90deg) scale(0.5);
|
||||
-webkit-transform: translateX(35px) rotate(-90deg) scale(0.5);
|
||||
} 50% {
|
||||
transform: translateX(35px) translateY(35px) rotate(-179deg);
|
||||
-webkit-transform: translateX(35px) translateY(35px) rotate(-179deg);
|
||||
} 50.1% {
|
||||
transform: translateX(35px) translateY(35px) rotate(-180deg);
|
||||
-webkit-transform: translateX(35px) translateY(35px) rotate(-180deg);
|
||||
} 75% {
|
||||
transform: translateX(0px) translateY(35px) rotate(-270deg) scale(0.5);
|
||||
-webkit-transform: translateX(0px) translateY(35px) rotate(-270deg) scale(0.5);
|
||||
} 100% {
|
||||
transform: rotate(-360deg);
|
||||
-webkit-transform: rotate(-360deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
template(name="spinnerCubeGrid")
|
||||
.sk-spinner.sk-spinner-cube-grid(class=currentBoard.colorClass)
|
||||
+spinnerCubeGridRaw
|
||||
|
||||
template(name="spinnerCubeGridRaw")
|
||||
.sk-cube-grid.sk-cube-grid1
|
||||
.sk-cube-grid.sk-cube-grid2
|
||||
.sk-cube-grid.sk-cube-grid3
|
||||
.sk-cube-grid.sk-cube-grid4
|
||||
.sk-cube-grid.sk-cube-grid5
|
||||
.sk-cube-grid.sk-cube-grid6
|
||||
.sk-cube-grid.sk-cube-grid7
|
||||
.sk-cube-grid.sk-cube-grid8
|
||||
.sk-cube-grid.sk-cube-grid9
|
||||
@@ -0,0 +1,64 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-cube-grid {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
margin: 100px auto;
|
||||
}
|
||||
|
||||
.sk-spinner-cube-grid .sk-cube-grid {
|
||||
width: 33%;
|
||||
height: 33%;
|
||||
background-color: #333;
|
||||
float: left;
|
||||
-webkit-animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
|
||||
animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
|
||||
}
|
||||
.sk-spinner-cube-grid .sk-cube-grid1 {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
animation-delay: 0.2s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid2 {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
animation-delay: 0.3s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid3 {
|
||||
-webkit-animation-delay: 0.4s;
|
||||
animation-delay: 0.4s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid4 {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
animation-delay: 0.1s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid5 {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
animation-delay: 0.2s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid6 {
|
||||
-webkit-animation-delay: 0.3s;
|
||||
animation-delay: 0.3s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid7 {
|
||||
-webkit-animation-delay: 0s;
|
||||
animation-delay: 0s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid8 {
|
||||
-webkit-animation-delay: 0.1s;
|
||||
animation-delay: 0.1s; }
|
||||
.sk-spinner-cube-grid .sk-cube-grid9 {
|
||||
-webkit-animation-delay: 0.2s;
|
||||
animation-delay: 0.2s; }
|
||||
|
||||
@-webkit-keyframes sk-cubeGridScaleDelay {
|
||||
0%, 70%, 100% {
|
||||
-webkit-transform: scale3D(1, 1, 1);
|
||||
transform: scale3D(1, 1, 1);
|
||||
} 35% {
|
||||
-webkit-transform: scale3D(0, 0, 1);
|
||||
transform: scale3D(0, 0, 1);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sk-cubeGridScaleDelay {
|
||||
0%, 70%, 100% {
|
||||
-webkit-transform: scale3D(1, 1, 1);
|
||||
transform: scale3D(1, 1, 1);
|
||||
} 35% {
|
||||
-webkit-transform: scale3D(0, 0, 1);
|
||||
transform: scale3D(0, 0, 1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
template(name="spinnerDot")
|
||||
.sk-spinner.sk-spinner-dot(class=currentBoard.colorClass)
|
||||
+spinnerDotRaw
|
||||
|
||||
template(name="spinnerDotRaw")
|
||||
.sk-dot1
|
||||
.sk-dot2
|
||||
@@ -0,0 +1,51 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-dot {
|
||||
margin: 100px auto;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
|
||||
-webkit-animation: sk-rotate 2.0s infinite linear;
|
||||
animation: sk-rotate 2.0s infinite linear;
|
||||
}
|
||||
|
||||
.sk-dot1, .sk-dot2 {
|
||||
width: 40%;
|
||||
height: 40%;
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
background-color: #333;
|
||||
border-radius: 100%;
|
||||
|
||||
-webkit-animation: sk-bounce 2.0s infinite ease-in-out;
|
||||
animation: sk-bounce 2.0s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.sk-dot2 {
|
||||
top: auto;
|
||||
bottom: 0;
|
||||
-webkit-animation-delay: -1.0s;
|
||||
animation-delay: -1.0s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-rotate { 100% { -webkit-transform: rotate(360deg) }}
|
||||
@keyframes sk-rotate { 100% { transform: rotate(360deg); -webkit-transform: rotate(360deg) }}
|
||||
|
||||
@-webkit-keyframes sk-bounce {
|
||||
0%, 100% { -webkit-transform: scale(0.0) }
|
||||
50% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bounce {
|
||||
0%, 100% {
|
||||
transform: scale(0.0);
|
||||
-webkit-transform: scale(0.0);
|
||||
} 50% {
|
||||
transform: scale(1.0);
|
||||
-webkit-transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
template(name="spinnerDoubleBounce")
|
||||
.sk-spinner.sk-spinner-double-bounce(class=currentBoard.colorClass)
|
||||
+spinnerDoubleBounceRaw
|
||||
|
||||
template(name="spinnerDoubleBounceRaw")
|
||||
.sk-double-bounce1
|
||||
.sk-double-bounce2
|
||||
@@ -0,0 +1,44 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-double-bounce {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
|
||||
position: relative;
|
||||
margin: 100px auto;
|
||||
}
|
||||
|
||||
.sk-double-bounce1, .sk-double-bounce2 {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border-radius: 50%;
|
||||
background-color: #333;
|
||||
opacity: 0.6;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
|
||||
-webkit-animation: sk-bounce 2.0s infinite ease-in-out;
|
||||
animation: sk-bounce 2.0s infinite ease-in-out;
|
||||
}
|
||||
|
||||
.sk-double-bounce2 {
|
||||
-webkit-animation-delay: -1.0s;
|
||||
animation-delay: -1.0s;
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-bounce {
|
||||
0%, 100% { -webkit-transform: scale(0.0) }
|
||||
50% { -webkit-transform: scale(1.0) }
|
||||
}
|
||||
|
||||
@keyframes sk-bounce {
|
||||
0%, 100% {
|
||||
transform: scale(0.0);
|
||||
-webkit-transform: scale(0.0);
|
||||
} 50% {
|
||||
transform: scale(1.0);
|
||||
-webkit-transform: scale(1.0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
template(name="spinnerRotateplane")
|
||||
.sk-spinner.sk-spinner-rotateplane(class=currentBoard.colorClass)
|
||||
+spinnerRotateplaneRaw
|
||||
|
||||
template(name="spinnerRotateplaneRaw")
|
||||
.sk-rotateplane1
|
||||
@@ -0,0 +1,38 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-rotateplane {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
|
||||
margin: 100px auto;
|
||||
-webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;
|
||||
animation: sk-rotateplane 1.2s infinite ease-in-out;
|
||||
|
||||
div {
|
||||
background-color: #333;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-rotateplane {
|
||||
0% { -webkit-transform: perspective(120px) }
|
||||
50% { -webkit-transform: perspective(120px) rotateY(180deg) }
|
||||
100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }
|
||||
}
|
||||
|
||||
@keyframes sk-rotateplane {
|
||||
0% {
|
||||
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
|
||||
-webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)
|
||||
} 50% {
|
||||
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
|
||||
-webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)
|
||||
} 100% {
|
||||
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
-webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
template(name="spinnerScaleout")
|
||||
.sk-spinner.sk-spinner-scaleout(class=currentBoard.colorClass)
|
||||
+spinnerScaleoutRaw
|
||||
|
||||
template(name="spinnerScaleoutRaw")
|
||||
.sk-scaleout1
|
||||
@@ -0,0 +1,40 @@
|
||||
@import 'nib'
|
||||
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-scaleout {
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
text-align: center;
|
||||
|
||||
margin: 100px auto;
|
||||
|
||||
border-radius: 100%;
|
||||
-webkit-animation: sk-scaleout 1.0s infinite ease-in-out;
|
||||
animation: sk-scaleout 1.0s infinite ease-in-out;
|
||||
|
||||
div {
|
||||
background-color: #333;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
||||
@-webkit-keyframes sk-scaleout {
|
||||
0% { -webkit-transform: scale(0) }
|
||||
100% {
|
||||
-webkit-transform: scale(1.0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes sk-scaleout {
|
||||
0% {
|
||||
-webkit-transform: scale(0);
|
||||
transform: scale(0);
|
||||
} 100% {
|
||||
-webkit-transform: scale(1.0);
|
||||
transform: scale(1.0);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
template(name="spinnerWave")
|
||||
.sk-spinner.sk-spinner-wave(class=currentBoard.colorClass)
|
||||
+spinnerWaveRaw
|
||||
|
||||
template(name="spinnerWaveRaw")
|
||||
.sk-rect1
|
||||
|
|
||||
.sk-rect2
|
||||
|
|
||||
.sk-rect3
|
||||
|
|
||||
.sk-rect4
|
||||
|
|
||||
.sk-rect5
|
||||
|
|
||||
@@ -1,21 +1,7 @@
|
||||
@import 'nib'
|
||||
|
||||
/*
|
||||
* From https://github.com/tobiasahlin/SpinKit
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* <div class="sk-spinner sk-spinner-wave">
|
||||
* <div class="sk-rect1"></div>
|
||||
* <div class="sk-rect2"></div>
|
||||
* <div class="sk-rect3"></div>
|
||||
* <div class="sk-rect4"></div>
|
||||
* <div class="sk-rect5"></div>
|
||||
* </div>
|
||||
*
|
||||
*/
|
||||
|
||||
.sk-spinner {
|
||||
// From https://github.com/tobiasahlin/SpinKit
|
||||
.sk-spinner-wave {
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
margin: auto;
|
||||
@@ -1,5 +1,5 @@
|
||||
template(name='notifications')
|
||||
#notifications.board-header-btns.right
|
||||
a.notifications-drawer-toggle.fa.fa-bell(class="{{#if $gt unreadNotifications 0}}alert{{/if}}")
|
||||
a.notifications-drawer-toggle.fa.fa-bell(class="{{#if $gt unreadNotifications 0}}alert{{/if}}" title="{{_ 'notifications'}}")
|
||||
if $.Session.get 'showNotificationsDrawer'
|
||||
+notificationsDrawer(unreadNotifications=unreadNotifications)
|
||||
@@ -0,0 +1,111 @@
|
||||
template(name="adminReports")
|
||||
.setting-content
|
||||
unless currentUser.isAdmin
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li
|
||||
a.js-report-broken(data-id="report-broken")
|
||||
i.fa.fa-chain-broken
|
||||
| {{_ 'broken-cards'}}
|
||||
|
||||
li
|
||||
a.js-report-files(data-id="report-orphaned-files")
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'orphanedFilesReportTitle'}}
|
||||
|
||||
li
|
||||
a.js-report-files(data-id="report-files")
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'filesReportTitle'}}
|
||||
|
||||
li
|
||||
a.js-report-rules(data-id="report-rules")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rulesReportTitle'}}
|
||||
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if showBrokenCardsReport.get
|
||||
+brokenCardsReport
|
||||
else if showFilesReport.get
|
||||
+filesReport
|
||||
else if showOrphanedFilesReport.get
|
||||
+orphanedFilesReport
|
||||
else if showRulesReport.get
|
||||
+rulesReport
|
||||
|
||||
|
||||
template(name="brokenCardsReport")
|
||||
.global-search-results-list-wrapper
|
||||
h1 {{_ 'broken-cards'}}
|
||||
if resultsCount
|
||||
+resultsPaged(this)
|
||||
else
|
||||
div {{_ 'no-results' }}
|
||||
|
||||
template(name="rulesReport")
|
||||
h1 {{_ 'rulesReportTitle'}}
|
||||
if resultsCount
|
||||
table.table
|
||||
tr
|
||||
th Rule Title
|
||||
th Board Title
|
||||
th actionType
|
||||
th activityType
|
||||
|
||||
each rule in rows
|
||||
tr
|
||||
td {{ rule.title }}
|
||||
td {{ rule.boardTitle }}
|
||||
td {{ rule.action.actionType }}
|
||||
td {{ rule.trigger.activityType }}
|
||||
else
|
||||
div {{_ 'no-results' }}
|
||||
|
||||
template(name="filesReport")
|
||||
h1 {{_ 'filesReportTitle'}}
|
||||
if resultsCount
|
||||
table.table
|
||||
tr
|
||||
th Filename
|
||||
th.right Size (kB)
|
||||
th MIME Type
|
||||
th.center Usage
|
||||
th MD5 Sum
|
||||
th ID
|
||||
|
||||
each att in attachmentFiles
|
||||
tr
|
||||
td {{ att.filename }}
|
||||
td.right {{fileSize att.length }}
|
||||
td {{ att.contentType }}
|
||||
td.center {{usageCount att._id.toHexString }}
|
||||
td {{ att.md5 }}
|
||||
td {{ att._id.toHexString }}
|
||||
else
|
||||
div {{_ 'no-results' }}
|
||||
|
||||
template(name="orphanedFilesReport")
|
||||
h1 {{_ 'orphanedFilesReportTitle'}}
|
||||
if resultsCount
|
||||
table.table
|
||||
tr
|
||||
th Filename
|
||||
th.right Size (kB)
|
||||
th MIME Type
|
||||
th MD5 Sum
|
||||
th ID
|
||||
|
||||
each att in attachmentFiles
|
||||
tr
|
||||
td {{ att.filename }}
|
||||
td.right {{fileSize att.length }}
|
||||
td {{ att.contentType }}
|
||||
td {{ att.md5 }}
|
||||
td {{ att._id.toHexString }}
|
||||
else
|
||||
div {{_ 'no-results' }}
|
||||
@@ -0,0 +1,156 @@
|
||||
import { AttachmentStorage } from '/models/attachments';
|
||||
import { CardSearchPagedComponent } from '/client/lib/cardSearch';
|
||||
import SessionData from '/models/usersessiondata';
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
subscription: null,
|
||||
showFilesReport: new ReactiveVar(false),
|
||||
showBrokenCardsReport: new ReactiveVar(false),
|
||||
showOrphanedFilesReport: new ReactiveVar(false),
|
||||
showRulesReport: new ReactiveVar(false),
|
||||
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.js-report-broken': this.switchMenu,
|
||||
'click a.js-report-files': this.switchMenu,
|
||||
'click a.js-report-orphaned-files': this.switchMenu,
|
||||
'click a.js-report-rules': this.switchMenu,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
switchMenu(event) {
|
||||
const target = $(event.target);
|
||||
if (!target.hasClass('active')) {
|
||||
this.loading.set(true);
|
||||
this.showFilesReport.set(false);
|
||||
this.showBrokenCardsReport.set(false);
|
||||
this.showOrphanedFilesReport.set(false);
|
||||
if (this.subscription) {
|
||||
this.subscription.stop();
|
||||
}
|
||||
|
||||
$('.side-menu li.active').removeClass('active');
|
||||
target.parent().addClass('active');
|
||||
const targetID = target.data('id');
|
||||
|
||||
if ('report-broken' === targetID) {
|
||||
this.showBrokenCardsReport.set(true);
|
||||
this.subscription = Meteor.subscribe(
|
||||
'brokenCards',
|
||||
SessionData.getSessionId(),
|
||||
() => {
|
||||
this.loading.set(false);
|
||||
},
|
||||
);
|
||||
} else if ('report-files' === targetID) {
|
||||
this.showFilesReport.set(true);
|
||||
this.subscription = Meteor.subscribe('attachmentsList', () => {
|
||||
this.loading.set(false);
|
||||
});
|
||||
} else if ('report-orphaned-files' === targetID) {
|
||||
this.showOrphanedFilesReport.set(true);
|
||||
this.subscription = Meteor.subscribe('orphanedAttachments', () => {
|
||||
this.loading.set(false);
|
||||
});
|
||||
} else if ('report-rules' === targetID) {
|
||||
this.subscription = Meteor.subscribe('rulesReport', () => {
|
||||
this.showRulesReport.set(true);
|
||||
this.loading.set(false);
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}).register('adminReports');
|
||||
|
||||
Template.filesReport.helpers({
|
||||
attachmentFiles() {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('attachments:', AttachmentStorage.find());
|
||||
// console.log('attachments.count:', AttachmentStorage.find().count());
|
||||
return AttachmentStorage.find();
|
||||
},
|
||||
|
||||
rulesReport() {
|
||||
const rules = [];
|
||||
|
||||
Rules.find().forEach(rule => {
|
||||
rules.push({
|
||||
_id: rule._id,
|
||||
title: rule.title,
|
||||
boardId: rule.boardId,
|
||||
boardTitle: rule.board().title,
|
||||
action: rule.action().fetch(),
|
||||
trigger: rule.trigger().fetch(),
|
||||
});
|
||||
});
|
||||
|
||||
return rules;
|
||||
},
|
||||
|
||||
resultsCount() {
|
||||
return AttachmentStorage.find().count();
|
||||
},
|
||||
|
||||
fileSize(size) {
|
||||
return Math.round(size / 1024);
|
||||
},
|
||||
|
||||
usageCount(key) {
|
||||
return Attachments.find({ 'copies.attachments.key': key }).count();
|
||||
},
|
||||
});
|
||||
|
||||
Template.orphanedFilesReport.helpers({
|
||||
attachmentFiles() {
|
||||
// eslint-disable-next-line no-console
|
||||
// console.log('attachments:', AttachmentStorage.find());
|
||||
// console.log('attachments.count:', AttachmentStorage.find().count());
|
||||
return AttachmentStorage.find();
|
||||
},
|
||||
|
||||
resultsCount() {
|
||||
return AttachmentStorage.find().count();
|
||||
},
|
||||
|
||||
fileSize(size) {
|
||||
return Math.round(size / 1024);
|
||||
},
|
||||
});
|
||||
|
||||
Template.rulesReport.helpers({
|
||||
rows() {
|
||||
const rules = [];
|
||||
|
||||
Rules.find().forEach(rule => {
|
||||
rules.push({
|
||||
_id: rule._id,
|
||||
title: rule.title,
|
||||
boardId: rule.boardId,
|
||||
boardTitle: rule.board().title,
|
||||
action: rule.action(),
|
||||
trigger: rule.trigger(),
|
||||
});
|
||||
});
|
||||
|
||||
console.log('rows:', rules);
|
||||
return rules;
|
||||
},
|
||||
|
||||
resultsCount() {
|
||||
return Rules.find().count();
|
||||
},
|
||||
});
|
||||
|
||||
class BrokenCardsComponent extends CardSearchPagedComponent {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
}
|
||||
}
|
||||
BrokenCardsComponent.register('brokenCardsReport');
|
||||
@@ -40,6 +40,11 @@ template(name="people")
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{#unless isMiniScreen}}{{_ 'people-number'}}{{/unless}} #{peopleNumber}
|
||||
.divAddOrRemoveTeam#divAddOrRemoveTeam
|
||||
button#addOrRemoveTeam
|
||||
i.fa.fa-edit
|
||||
| {{_ 'add'}} / {{_ 'delete'}} {{_ 'teams'}}
|
||||
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
@@ -97,9 +102,12 @@ template(name="teamGeneral")
|
||||
+teamRow(teamId=team._id)
|
||||
|
||||
template(name="peopleGeneral")
|
||||
#divAddOrRemoveTeamContainer
|
||||
+modifyTeamsUsers
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th
|
||||
th {{_ 'username'}}
|
||||
th {{_ 'fullname'}}
|
||||
th {{_ 'initials'}}
|
||||
@@ -110,6 +118,8 @@ template(name="peopleGeneral")
|
||||
th {{_ 'active'}}
|
||||
th {{_ 'authentication-method'}}
|
||||
th {{_ 'import-usernames'}}
|
||||
th {{_ 'organizations'}}
|
||||
th {{_ 'teams'}}
|
||||
th
|
||||
+newUserRow
|
||||
each user in peopleList
|
||||
@@ -132,28 +142,28 @@ template(name="newUserRow")
|
||||
|
||||
template(name="orgRow")
|
||||
tr
|
||||
if orgData.loginDisabled
|
||||
if orgData.orgIsActive
|
||||
td <s>{{ orgData.orgDisplayName }}</s>
|
||||
else
|
||||
td {{ orgData.orgDisplayName }}
|
||||
if orgData.loginDisabled
|
||||
if orgData.orgIsActive
|
||||
td <s>{{ orgData.orgDesc }}</s>
|
||||
else
|
||||
td {{ orgData.orgDesc }}
|
||||
if orgData.loginDisabled
|
||||
td <s>{{ orgData.orgName }}</s>
|
||||
if orgData.orgIsActive
|
||||
td <s>{{ orgData.orgShortName }}</s>
|
||||
else
|
||||
td {{ orgData.orgName }}
|
||||
if orgData.loginDisabled
|
||||
td {{ orgData.orgShortName }}
|
||||
if orgData.orgIsActive
|
||||
td <s>{{ orgData.orgWebsite }}</s>
|
||||
else
|
||||
td {{ orgData.orgWebsite }}
|
||||
if orgData.loginDisabled
|
||||
if orgData.orgIsActive
|
||||
td <s>{{ moment orgData.createdAt 'LLL' }}</s>
|
||||
else
|
||||
td {{ moment orgData.createdAt 'LLL' }}
|
||||
td
|
||||
if orgData.loginDisabled
|
||||
if orgData.orgIsActive
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
@@ -166,28 +176,28 @@ template(name="orgRow")
|
||||
|
||||
template(name="teamRow")
|
||||
tr
|
||||
if teamData.loginDisabled
|
||||
if teamData.teamIsActive
|
||||
td <s>{{ teamData.teamDisplayName }}</s>
|
||||
else
|
||||
td {{ teamData.teamDisplayName }}
|
||||
if teamData.loginDisabled
|
||||
if teamData.teamIsActive
|
||||
td <s>{{ teamData.teamDesc }}</s>
|
||||
else
|
||||
td {{ teamData.teamDesc }}
|
||||
if teamData.loginDisabled
|
||||
td <s>{{ teamData.teamName }}</s>
|
||||
if teamData.teamIsActive
|
||||
td <s>{{ teamData.teamShortName }}</s>
|
||||
else
|
||||
td {{ teamData.teamName }}
|
||||
if teamData.loginDisabled
|
||||
td {{ teamData.teamShortName }}
|
||||
if teamData.teamIsActive
|
||||
td <s>{{ teamData.teamWebsite }}</s>
|
||||
else
|
||||
td {{ teamData.teamWebsite }}
|
||||
if orgData.loginDisabled
|
||||
if teamData.teamIsActive
|
||||
td <s>{{ moment teamData.createdAt 'LLL' }}</s>
|
||||
else
|
||||
td {{ moment teamData.createdAt 'LLL' }}
|
||||
td
|
||||
if teamData.loginDisabled
|
||||
if teamData.teamIsActive
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
@@ -200,6 +210,12 @@ template(name="teamRow")
|
||||
|
||||
template(name="peopleRow")
|
||||
tr
|
||||
if userData.loginDisabled
|
||||
td
|
||||
input.selectUserChkBox(type="checkbox", disabled="disabled", id="{{userData._id}}")
|
||||
else
|
||||
td
|
||||
input.selectUserChkBox(type="checkbox", id="{{userData._id}}")
|
||||
if userData.loginDisabled
|
||||
td.username <s>{{ userData.username }}</s>
|
||||
else
|
||||
@@ -257,6 +273,14 @@ template(name="peopleRow")
|
||||
td <s>{{ userData.importUsernamesString }}</s>
|
||||
else
|
||||
td {{ userData.importUsernamesString }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.orgsUserBelongs }}</s>
|
||||
else
|
||||
td {{ userData.orgsUserBelongs }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.teamsUserBelongs }}</s>
|
||||
else
|
||||
td {{ userData.teamsUserBelongs }}
|
||||
td
|
||||
a.edit-user
|
||||
i.fa.fa-edit
|
||||
@@ -269,7 +293,7 @@ template(name="editOrgPopup")
|
||||
label.hide.orgId(type="text" value=org._id)
|
||||
label
|
||||
| {{_ 'displayName'}}
|
||||
input.js-orgDisplayName(type="text" value=org.displayName required)
|
||||
input.js-orgDisplayName(type="text" value=org.orgDisplayName required)
|
||||
span.error.hide.orgname-taken
|
||||
| {{_ 'error-orgname-taken'}}
|
||||
label
|
||||
@@ -285,7 +309,7 @@ template(name="editOrgPopup")
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-org-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{org.loginDisabled}}") {{_ 'no'}}
|
||||
option(value="true" selected="{{org.orgIsActive}}") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -311,7 +335,7 @@ template(name="editTeamPopup")
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-team-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{team.loginDisabled}}") {{_ 'no'}}
|
||||
option(value="true" selected="{{team.teamIsActive}}") {{_ 'no'}}
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -332,7 +356,7 @@ template(name="editUserPopup")
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname required)
|
||||
label
|
||||
| {{_ 'initials'}}
|
||||
input.js-profile-initials(type="text" value=user.profile.initials required)
|
||||
input.js-profile-initials(type="text" value=user.profile.initials)
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
@@ -367,6 +391,27 @@ template(name="editUserPopup")
|
||||
option(value="{{value}}" selected) {{_ value}}
|
||||
else
|
||||
option(value="{{value}}") {{_ value}}
|
||||
label
|
||||
| {{_ 'organizations'}}
|
||||
i.fa.fa-plus-square#addUserOrg
|
||||
i.fa.fa-minus-square#removeUserOrg
|
||||
select.js-orgs#jsOrgs
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each value in orgsDatas
|
||||
option(value="{{value._id}}") {{_ value.orgDisplayName}}
|
||||
input#jsUserOrgsInPut.js-userOrgs(type="text" value=user.orgsUserBelongs, disabled)
|
||||
input#jsUserOrgIdsInPut.js-userOrgIds.hide(type="text" value=user.orgIdsUserBelongs)
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
i.fa.fa-plus-square#addUserTeam
|
||||
i.fa.fa-minus-square#removeUserTeam
|
||||
select.js-teams#jsTeams
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each value in teamsDatas
|
||||
option(value="{{value._id}}") {{_ value.teamDisplayName}}
|
||||
input#jsUserTeamsInPut.js-userteams(type="text" value=user.teamsUserBelongs, disabled)
|
||||
input#jsUserTeamIdsInPut.js-userteamIds.hide(type="text" value=user.teamIdsUserBelongs)
|
||||
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
@@ -385,7 +430,7 @@ template(name="newOrgPopup")
|
||||
input.js-orgDesc(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'shortName'}}
|
||||
input.js-orgName(type="text" value="" required)
|
||||
input.js-orgShortName(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'website'}}
|
||||
input.js-orgWebsite(type="text" value="" required)
|
||||
@@ -409,7 +454,7 @@ template(name="newTeamPopup")
|
||||
input.js-teamDesc(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'shortName'}}
|
||||
input.js-teamName(type="text" value="" required)
|
||||
input.js-teamShortName(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'website'}}
|
||||
input.js-teamWebsite(type="text" value="" required)
|
||||
@@ -422,6 +467,24 @@ template(name="newTeamPopup")
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="modifyTeamsUsers")
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
select.js-teamsUser#jsteamsUser
|
||||
each value in teamsDatas
|
||||
option(value="{{value._id}}") {{_ value.teamDisplayName}}
|
||||
hr
|
||||
label
|
||||
| {{_ 'r-action'}}
|
||||
.form-group.flex
|
||||
input.wekan-form-control#addAction(type="radio" name="action" value="true" checked="checked")
|
||||
span {{_ 'add'}}
|
||||
input.wekan-form-control#deleteAction(type="radio" name="action" value="false")
|
||||
span {{_ 'delete'}}
|
||||
div.buttonsContainer
|
||||
input.primary.wide#addTeamBtn(type="submit" value="{{_ 'save'}}")
|
||||
input.primary.wide#cancelBtn(type="submit" value="{{_ 'cancel'}}")
|
||||
|
||||
template(name="newUserPopup")
|
||||
form
|
||||
//label.hide.userId(type="text" value=user._id)
|
||||
@@ -438,7 +501,7 @@ template(name="newUserPopup")
|
||||
input.js-profile-username(type="text" value="" required)
|
||||
label
|
||||
| {{_ 'initials'}}
|
||||
input.js-profile-initials(type="text" value="" required)
|
||||
input.js-profile-initials(type="text" value="")
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
@@ -468,6 +531,27 @@ template(name="newUserPopup")
|
||||
option(value="{{value}}" selected) {{_ value}}
|
||||
else
|
||||
option(value="{{value}}") {{_ value}}
|
||||
label
|
||||
| {{_ 'organizations'}}
|
||||
i.fa.fa-plus-square#addUserOrgNewUser
|
||||
i.fa.fa-minus-square#removeUserOrgNewUser
|
||||
select.js-orgsNewUser#jsOrgsNewUser
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each value in orgsDatas
|
||||
option(value="{{value._id}}") {{_ value.orgDisplayName}}
|
||||
input#jsUserOrgsInPutNewUser.js-userOrgsNewUser(type="text" value=user.orgsUserBelongs, disabled)
|
||||
input#jsUserOrgIdsInPutNewUser.js-userOrgIdsNewUser.hide(type="text" value=user.orgIdsUserBelongs)
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
i.fa.fa-plus-square#addUserTeamNewUser
|
||||
i.fa.fa-minus-square#removeUserTeamNewUser
|
||||
select.js-teamsNewUser#jsTeamsNewUser
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each value in teamsDatas
|
||||
option(value="{{value._id}}") {{_ value.teamDisplayName}}
|
||||
input#jsUserTeamsInPutNewUser.js-userteamsNewUser(type="text" value=user.teamsUserBelongs, disabled)
|
||||
input#jsUserTeamIdsInPutNewUser.js-userteamIdsNewUser.hide(type="text" value=user.teamIdsUserBelongs)
|
||||
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
@@ -478,27 +562,40 @@ template(name="newUserPopup")
|
||||
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'}}")
|
||||
form
|
||||
label#deleteOrgWarningMessage.hide
|
||||
| {{_ 'delete-org-warning-message'}}
|
||||
br
|
||||
label
|
||||
| {{_ 'delete-org-confirm-popup'}}
|
||||
br
|
||||
label.hide.orgId(type="text" value=org._id)
|
||||
labeldelete-org-confirm-popup
|
||||
div.buttonsContainer
|
||||
input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
|
||||
// It's not yet possible to impersonate organization. Only impersonate user,
|
||||
// because that changes current user ID. What would it mean in practice
|
||||
// to impersonate organization?
|
||||
// li
|
||||
// a.impersonate-org
|
||||
// i.fa.fa-user
|
||||
// | {{_ 'impersonate-org'}}
|
||||
//
|
||||
//
|
||||
|
||||
template(name="settingsTeamPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
form
|
||||
label#deleteTeamWarningMessage.hide
|
||||
| {{_ 'delete-team-warning-message'}}
|
||||
br
|
||||
label
|
||||
| {{_ 'delete-team-confirm-popup'}}
|
||||
br
|
||||
label.hide.teamId(type="text" value=team._id)
|
||||
div.buttonsContainer
|
||||
input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
|
||||
|
||||
template(name="settingsUserPopup")
|
||||
ul.pop-over-list
|
||||
@@ -506,21 +603,23 @@ template(name="settingsUserPopup")
|
||||
a.impersonate-user
|
||||
i.fa.fa-user
|
||||
| {{_ 'impersonate-user'}}
|
||||
// Delete is not enabled yet, because it does leave empty user avatars
|
||||
br
|
||||
hr
|
||||
li
|
||||
form
|
||||
label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'delete-user-confirm-popup' }}
|
||||
br
|
||||
div.buttonsContainer
|
||||
input#deleteButton.card-details-red.right.wide(type="button" value="{{_ 'delete'}}")
|
||||
// Delete is enabled, but there is still bug of leaving empty user avatars
|
||||
// to boards: boards members, card members and assignees have
|
||||
// empty users. See:
|
||||
// empty users. So it is better to remove user from all boards before removing user.
|
||||
// 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,6 +1,8 @@
|
||||
const orgsPerPage = 25;
|
||||
const teamsPerPage = 25;
|
||||
const usersPerPage = 25;
|
||||
let userOrgsTeamsAction = ""; //poosible actions 'addOrg', 'addTeam', 'removeOrg' or 'removeTeam' when adding or modifying a user
|
||||
let selectedUserChkBoxUserIds = [];
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
@@ -80,6 +82,9 @@ BlazeComponent.extendComponent({
|
||||
'click #searchButton'() {
|
||||
this.filterPeople();
|
||||
},
|
||||
'click #addOrRemoveTeam'(){
|
||||
document.getElementById("divAddOrRemoveTeamContainer").style.display = 'block';
|
||||
},
|
||||
'keydown #searchInput'(event) {
|
||||
if (event.keyCode === 13 && !event.shiftKey) {
|
||||
this.filterPeople();
|
||||
@@ -101,9 +106,7 @@ BlazeComponent.extendComponent({
|
||||
];
|
||||
},
|
||||
filterPeople() {
|
||||
const value = $('#searchInput')
|
||||
.first()
|
||||
.val();
|
||||
const value = $('#searchInput').first().val();
|
||||
if (value === '') {
|
||||
this.findUsersOptions.set({});
|
||||
} else {
|
||||
@@ -150,7 +153,7 @@ BlazeComponent.extendComponent({
|
||||
const teams = Team.find(this.findTeamsOptions.get(), {
|
||||
fields: { _id: true },
|
||||
});
|
||||
this.numberTeams.set(team.count(false));
|
||||
this.numberTeams.set(teams.count(false));
|
||||
return teams;
|
||||
},
|
||||
peopleList() {
|
||||
@@ -203,7 +206,7 @@ Template.peopleRow.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.editUserPopup.onCreated(function() {
|
||||
Template.editUserPopup.onCreated(function () {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
|
||||
@@ -215,8 +218,8 @@ Template.editUserPopup.onCreated(function() {
|
||||
{ value: 'password' },
|
||||
// Gets only the authentication methods availables
|
||||
...Object.entries(result)
|
||||
.filter(e => e[1])
|
||||
.map(e => ({ value: e[0] })),
|
||||
.filter((e) => e[1])
|
||||
.map((e) => ({ value: e[0] })),
|
||||
]);
|
||||
}
|
||||
});
|
||||
@@ -247,6 +250,12 @@ Template.editUserPopup.helpers({
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
orgsDatas() {
|
||||
return Org.find({}, {sort: { createdAt: -1 }});
|
||||
},
|
||||
teamsDatas() {
|
||||
return Team.find({}, {sort: { createdAt: -1 }});
|
||||
},
|
||||
isSelected(match) {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
@@ -262,15 +271,15 @@ Template.editUserPopup.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.newOrgPopup.onCreated(function() {
|
||||
Template.newOrgPopup.onCreated(function () {
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
});
|
||||
|
||||
Template.newTeamPopup.onCreated(function() {
|
||||
Template.newTeamPopup.onCreated(function () {
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
});
|
||||
|
||||
Template.newUserPopup.onCreated(function() {
|
||||
Template.newUserPopup.onCreated(function () {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
|
||||
@@ -282,8 +291,8 @@ Template.newUserPopup.onCreated(function() {
|
||||
{ value: 'password' },
|
||||
// Gets only the authentication methods availables
|
||||
...Object.entries(result)
|
||||
.filter(e => e[1])
|
||||
.map(e => ({ value: e[0] })),
|
||||
.filter((e) => e[1])
|
||||
.map((e) => ({ value: e[0] })),
|
||||
]);
|
||||
}
|
||||
});
|
||||
@@ -314,10 +323,21 @@ Template.newUserPopup.helpers({
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
orgsDatas() {
|
||||
return Org.find({}, {sort: { createdAt: -1 }});
|
||||
},
|
||||
teamsDatas() {
|
||||
return Team.find({}, {sort: { createdAt: -1 }});
|
||||
},
|
||||
isSelected(match) {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === match;
|
||||
if(userId){
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === match;
|
||||
}
|
||||
else{
|
||||
false;
|
||||
}
|
||||
},
|
||||
isLdap() {
|
||||
const userId = Template.instance().data.userId;
|
||||
@@ -369,11 +389,111 @@ BlazeComponent.extendComponent({
|
||||
{
|
||||
'click a.edit-user': Popup.open('editUser'),
|
||||
'click a.more-settings-user': Popup.open('settingsUser'),
|
||||
'click .selectUserChkBox': function(ev){
|
||||
if(ev.currentTarget){
|
||||
if(ev.currentTarget.checked){
|
||||
if(!selectedUserChkBoxUserIds.includes(ev.currentTarget.id)){
|
||||
selectedUserChkBoxUserIds.push(ev.currentTarget.id);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(selectedUserChkBoxUserIds.includes(ev.currentTarget.id)){
|
||||
let index = selectedUserChkBoxUserIds.indexOf(ev.currentTarget.id);
|
||||
if(index > -1)
|
||||
selectedUserChkBoxUserIds.splice(index, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
if(selectedUserChkBoxUserIds.length > 0)
|
||||
document.getElementById("divAddOrRemoveTeam").style.display = 'block';
|
||||
else
|
||||
document.getElementById("divAddOrRemoveTeam").style.display = 'none';
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('peopleRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
teamsDatas() {
|
||||
return Team.find({}, {sort: { createdAt: -1 }});
|
||||
},
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click #cancelBtn': function(){
|
||||
let selectedElt = document.getElementById("jsteamsUser");
|
||||
document.getElementById("divAddOrRemoveTeamContainer").style.display = 'none';
|
||||
},
|
||||
'click #addTeamBtn': function(){
|
||||
let selectedElt;
|
||||
let selectedEltValue;
|
||||
let selectedEltValueId;
|
||||
let userTms = [];
|
||||
let currentUser;
|
||||
let currUserTeamIndex;
|
||||
|
||||
selectedElt = document.getElementById("jsteamsUser");
|
||||
selectedEltValue = selectedElt.options[selectedElt.selectedIndex].text;
|
||||
selectedEltValueId = selectedElt.options[selectedElt.selectedIndex].value;
|
||||
|
||||
if(document.getElementById('addAction').checked){
|
||||
for(let i = 0; i < selectedUserChkBoxUserIds.length; i++){
|
||||
currentUser = Users.findOne(selectedUserChkBoxUserIds[i]);
|
||||
userTms = currentUser.teams;
|
||||
if(userTms == undefined || userTms.length == 0){
|
||||
userTms = [];
|
||||
userTms.push({
|
||||
"teamId": selectedEltValueId,
|
||||
"teamDisplayName": selectedEltValue,
|
||||
})
|
||||
}
|
||||
else if(userTms.length > 0)
|
||||
{
|
||||
currUserTeamIndex = userTms.findIndex(function(t){ return t.teamId == selectedEltValueId});
|
||||
if(currUserTeamIndex == -1){
|
||||
userTms.push({
|
||||
"teamId": selectedEltValueId,
|
||||
"teamDisplayName": selectedEltValue,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Users.update(selectedUserChkBoxUserIds[i], {
|
||||
$set:{
|
||||
teams: userTms
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else{
|
||||
for(let i = 0; i < selectedUserChkBoxUserIds.length; i++){
|
||||
currentUser = Users.findOne(selectedUserChkBoxUserIds[i]);
|
||||
userTms = currentUser.teams;
|
||||
if(userTms !== undefined || userTms.length > 0)
|
||||
{
|
||||
currUserTeamIndex = userTms.findIndex(function(t){ return t.teamId == selectedEltValueId});
|
||||
if(currUserTeamIndex != -1){
|
||||
userTms.splice(currUserTeamIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
Users.update(selectedUserChkBoxUserIds[i], {
|
||||
$set:{
|
||||
teams: userTms
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("divAddOrRemoveTeamContainer").style.display = 'none';
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('modifyTeamsUsers');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
@@ -407,7 +527,7 @@ BlazeComponent.extendComponent({
|
||||
Template.editOrgPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const org = Orgs.findOne(this.orgId);
|
||||
const org = Org.findOne(this.orgId);
|
||||
|
||||
const orgDisplayName = templateInstance
|
||||
.find('.js-orgDisplayName')
|
||||
@@ -415,7 +535,8 @@ Template.editOrgPopup.events({
|
||||
const orgDesc = templateInstance.find('.js-orgDesc').value.trim();
|
||||
const orgShortName = templateInstance.find('.js-orgShortName').value.trim();
|
||||
const orgWebsite = templateInstance.find('.js-orgWebsite').value.trim();
|
||||
const orgIsActive = templateInstance.find('.js-org-isactive').value.trim();
|
||||
const orgIsActive =
|
||||
templateInstance.find('.js-org-isactive').value.trim() == 'true';
|
||||
|
||||
const isChangeOrgDisplayName = orgDisplayName !== org.orgDisplayName;
|
||||
const isChangeOrgDesc = orgDesc !== org.orgDesc;
|
||||
@@ -423,20 +544,22 @@ Template.editOrgPopup.events({
|
||||
const isChangeOrgWebsite = orgWebsite !== org.orgWebsite;
|
||||
const isChangeOrgIsActive = orgIsActive !== org.orgIsActive;
|
||||
|
||||
if (isChangeOrgDisplayName) {
|
||||
Meteor.call('setOrgDisplayName', org, orgDisplayName);
|
||||
}
|
||||
|
||||
if (isChangeOrgDesc) {
|
||||
Meteor.call('setOrgDesc', org, orgDesc);
|
||||
}
|
||||
|
||||
if (isChangeOrgShortName) {
|
||||
Meteor.call('setOrgShortName', org, orgShortName);
|
||||
}
|
||||
|
||||
if (isChangeOrgIsActive) {
|
||||
Meteor.call('setOrgIsActive', org, orgIsActive);
|
||||
if (
|
||||
isChangeOrgDisplayName ||
|
||||
isChangeOrgDesc ||
|
||||
isChangeOrgShortName ||
|
||||
isChangeOrgWebsite ||
|
||||
isChangeOrgIsActive
|
||||
) {
|
||||
Meteor.call(
|
||||
'setOrgAllFields',
|
||||
org,
|
||||
orgDisplayName,
|
||||
orgDesc,
|
||||
orgShortName,
|
||||
orgWebsite,
|
||||
orgIsActive,
|
||||
);
|
||||
}
|
||||
|
||||
Popup.close();
|
||||
@@ -446,7 +569,7 @@ Template.editOrgPopup.events({
|
||||
Template.editTeamPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const team = Teams.findOne(this.teamId);
|
||||
const team = Team.findOne(this.teamId);
|
||||
|
||||
const teamDisplayName = templateInstance
|
||||
.find('.js-teamDisplayName')
|
||||
@@ -456,9 +579,8 @@ Template.editTeamPopup.events({
|
||||
.find('.js-teamShortName')
|
||||
.value.trim();
|
||||
const teamWebsite = templateInstance.find('.js-teamWebsite').value.trim();
|
||||
const teamIsActive = templateInstance
|
||||
.find('.js-team-isactive')
|
||||
.value.trim();
|
||||
const teamIsActive =
|
||||
templateInstance.find('.js-team-isactive').value.trim() == 'true';
|
||||
|
||||
const isChangeTeamDisplayName = teamDisplayName !== team.teamDisplayName;
|
||||
const isChangeTeamDesc = teamDesc !== team.teamDesc;
|
||||
@@ -466,20 +588,22 @@ Template.editTeamPopup.events({
|
||||
const isChangeTeamWebsite = teamWebsite !== team.teamWebsite;
|
||||
const isChangeTeamIsActive = teamIsActive !== team.teamIsActive;
|
||||
|
||||
if (isChangeTeamDisplayName) {
|
||||
Meteor.call('setTeamDisplayName', team, teamDisplayName);
|
||||
}
|
||||
|
||||
if (isChangeTeamDesc) {
|
||||
Meteor.call('setTeamDesc', team, teamDesc);
|
||||
}
|
||||
|
||||
if (isChangeTeamShortName) {
|
||||
Meteor.call('setTeamShortName', team, teamShortName);
|
||||
}
|
||||
|
||||
if (isChangeTeamIsActive) {
|
||||
Meteor.call('setTeamIsActive', team, teamIsActive);
|
||||
if (
|
||||
isChangeTeamDisplayName ||
|
||||
isChangeTeamDesc ||
|
||||
isChangeTeamShortName ||
|
||||
isChangeTeamWebsite ||
|
||||
isChangeTeamIsActive
|
||||
) {
|
||||
Meteor.call(
|
||||
'setTeamAllFields',
|
||||
team,
|
||||
teamDisplayName,
|
||||
teamDesc,
|
||||
teamShortName,
|
||||
teamWebsite,
|
||||
teamIsActive,
|
||||
);
|
||||
}
|
||||
|
||||
Popup.close();
|
||||
@@ -497,15 +621,13 @@ Template.editUserPopup.events({
|
||||
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 importUsernames = templateInstance
|
||||
.find('.js-import-usernames')
|
||||
.value.trim();
|
||||
const verified = templateInstance.find('.js-profile-email-verified').value.trim();
|
||||
const authentication = templateInstance.find('.js-authenticationMethod').value.trim();
|
||||
const importUsernames = templateInstance.find('.js-import-usernames').value.trim();
|
||||
const userOrgs = templateInstance.find('.js-userOrgs').value.trim();
|
||||
const userOrgsIds = templateInstance.find('.js-userOrgIds').value.trim();
|
||||
const userTeams = templateInstance.find('.js-userteams').value.trim();
|
||||
const userTeamsIds = templateInstance.find('.js-userteamIds').value.trim();
|
||||
|
||||
const isChangePassword = password.length > 0;
|
||||
const isChangeUserName = username !== user.username;
|
||||
@@ -530,6 +652,42 @@ Template.editUserPopup.events({
|
||||
},
|
||||
});
|
||||
|
||||
let userTeamsList = userTeams.split(",");
|
||||
let userTeamsIdsList = userTeamsIds.split(",");
|
||||
let userTms = [];
|
||||
if(userTeams != ''){
|
||||
for(let i = 0; i < userTeamsList.length; i++){
|
||||
userTms.push({
|
||||
"teamId": userTeamsIdsList[i],
|
||||
"teamDisplayName": userTeamsList[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Users.update(this.userId, {
|
||||
$set:{
|
||||
teams: userTms
|
||||
}
|
||||
});
|
||||
|
||||
let userOrgsList = userOrgs.split(",");
|
||||
let userOrgsIdsList = userOrgsIds.split(",");
|
||||
let userOrganizations = [];
|
||||
if(userOrgs != ''){
|
||||
for(let i = 0; i < userOrgsList.length; i++){
|
||||
userOrganizations.push({
|
||||
"orgId": userOrgsIdsList[i],
|
||||
"orgDisplayName": userOrgsList[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Users.update(this.userId, {
|
||||
$set:{
|
||||
orgs: userOrganizations
|
||||
}
|
||||
});
|
||||
|
||||
if (isChangePassword) {
|
||||
Meteor.call('setPassword', password, this.userId);
|
||||
}
|
||||
@@ -548,7 +706,7 @@ Template.editUserPopup.events({
|
||||
username,
|
||||
email.toLowerCase(),
|
||||
this.userId,
|
||||
function(error) {
|
||||
function (error) {
|
||||
const usernameMessageElement = templateInstance.$('.username-taken');
|
||||
const emailMessageElement = templateInstance.$('.email-taken');
|
||||
if (error) {
|
||||
@@ -568,7 +726,7 @@ Template.editUserPopup.events({
|
||||
},
|
||||
);
|
||||
} else if (isChangeUserName) {
|
||||
Meteor.call('setUsername', username, this.userId, function(error) {
|
||||
Meteor.call('setUsername', username, this.userId, function (error) {
|
||||
const usernameMessageElement = templateInstance.$('.username-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
@@ -581,24 +739,138 @@ Template.editUserPopup.events({
|
||||
}
|
||||
});
|
||||
} else if (isChangeEmail) {
|
||||
Meteor.call('setEmail', email.toLowerCase(), this.userId, function(
|
||||
error,
|
||||
) {
|
||||
const emailMessageElement = templateInstance.$('.email-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'email-already-taken') {
|
||||
emailMessageElement.show();
|
||||
Meteor.call(
|
||||
'setEmail',
|
||||
email.toLowerCase(),
|
||||
this.userId,
|
||||
function (error) {
|
||||
const emailMessageElement = templateInstance.$('.email-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'email-already-taken') {
|
||||
emailMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
emailMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
} else {
|
||||
emailMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
},
|
||||
);
|
||||
} else Popup.close();
|
||||
},
|
||||
'click #addUserOrg'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "addOrg";
|
||||
document.getElementById("jsOrgs").style.display = 'block';
|
||||
document.getElementById("jsTeams").style.display = 'none';
|
||||
},
|
||||
'click #removeUserOrg'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "removeOrg";
|
||||
document.getElementById("jsOrgs").style.display = 'block';
|
||||
document.getElementById("jsTeams").style.display = 'none';
|
||||
},
|
||||
'click #addUserTeam'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "addTeam";
|
||||
document.getElementById("jsTeams").style.display = 'block';
|
||||
document.getElementById("jsOrgs").style.display = 'none';
|
||||
},
|
||||
'click #removeUserTeam'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "removeTeam";
|
||||
document.getElementById("jsTeams").style.display = 'block';
|
||||
document.getElementById("jsOrgs").style.display = 'none';
|
||||
},
|
||||
'change #jsOrgs'(event) {
|
||||
event.preventDefault();
|
||||
UpdateUserOrgsOrTeamsElement();
|
||||
},
|
||||
'change #jsTeams'(event) {
|
||||
event.preventDefault();
|
||||
UpdateUserOrgsOrTeamsElement();
|
||||
},
|
||||
});
|
||||
|
||||
UpdateUserOrgsOrTeamsElement = function(isNewUser = false){
|
||||
let selectedElt;
|
||||
let selectedEltValue;
|
||||
let selectedEltValueId;
|
||||
let inputElt;
|
||||
let inputEltId;
|
||||
let lstInputValues = [];
|
||||
let lstInputValuesIds = [];
|
||||
let index;
|
||||
let indexId;
|
||||
switch(userOrgsTeamsAction)
|
||||
{
|
||||
case "addOrg":
|
||||
case "removeOrg":
|
||||
inputElt = !isNewUser ? document.getElementById("jsUserOrgsInPut") : document.getElementById("jsUserOrgsInPutNewUser");
|
||||
inputEltId = !isNewUser ? document.getElementById("jsUserOrgIdsInPut") : document.getElementById("jsUserOrgIdsInPutNewUser");
|
||||
selectedElt = !isNewUser ? document.getElementById("jsOrgs") : document.getElementById("jsOrgsNewUser");
|
||||
break;
|
||||
case "addTeam":
|
||||
case "removeTeam":
|
||||
inputElt = !isNewUser ? document.getElementById("jsUserTeamsInPut") : document.getElementById("jsUserTeamsInPutNewUser");
|
||||
inputEltId = !isNewUser ? document.getElementById("jsUserTeamIdsInPut") : document.getElementById("jsUserTeamIdsInPutNewUser");
|
||||
selectedElt = !isNewUser ? document.getElementById("jsTeams") : document.getElementById("jsTeamsNewUser");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
selectedEltValue = selectedElt.options[selectedElt.selectedIndex].text;
|
||||
selectedEltValueId = selectedElt.options[selectedElt.selectedIndex].value;
|
||||
lstInputValues = inputElt.value.trim().split(",");
|
||||
if(lstInputValues.length == 1 && lstInputValues[0] == ''){
|
||||
lstInputValues = [];
|
||||
}
|
||||
lstInputValuesIds = inputEltId.value.trim().split(",");
|
||||
if(lstInputValuesIds.length == 1 && lstInputValuesIds[0] == ''){
|
||||
lstInputValuesIds = [];
|
||||
}
|
||||
index = lstInputValues.indexOf(selectedEltValue);
|
||||
indexId = lstInputValuesIds.indexOf(selectedEltValueId);
|
||||
if(userOrgsTeamsAction == "addOrg" || userOrgsTeamsAction == "addTeam"){
|
||||
if(index <= -1 && selectedEltValueId != "-1"){
|
||||
lstInputValues.push(selectedEltValue);
|
||||
}
|
||||
|
||||
if(indexId <= -1 && selectedEltValueId != "-1"){
|
||||
lstInputValuesIds.push(selectedEltValueId);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if(index > -1 && selectedEltValueId != "-1"){
|
||||
lstInputValues.splice(index, 1);
|
||||
}
|
||||
|
||||
if(indexId > -1 && selectedEltValueId != "-1"){
|
||||
lstInputValuesIds.splice(indexId, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if(lstInputValues.length > 0){
|
||||
inputElt.value = lstInputValues.join(",");
|
||||
}
|
||||
else{
|
||||
inputElt.value = "";
|
||||
}
|
||||
|
||||
if(lstInputValuesIds.length > 0){
|
||||
inputEltId.value = lstInputValuesIds.join(",");
|
||||
}
|
||||
else{
|
||||
inputEltId.value = "";
|
||||
}
|
||||
selectedElt.value = "-1";
|
||||
selectedElt.style.display = "none";
|
||||
}
|
||||
|
||||
Template.newOrgPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
@@ -608,7 +880,8 @@ Template.newOrgPopup.events({
|
||||
const orgDesc = templateInstance.find('.js-orgDesc').value.trim();
|
||||
const orgShortName = templateInstance.find('.js-orgShortName').value.trim();
|
||||
const orgWebsite = templateInstance.find('.js-orgWebsite').value.trim();
|
||||
const orgIsActive = templateInstance.find('.js-org-isactive').value.trim();
|
||||
const orgIsActive =
|
||||
templateInstance.find('.js-org-isactive').value.trim() == 'true';
|
||||
|
||||
Meteor.call(
|
||||
'setCreateOrg',
|
||||
@@ -633,9 +906,8 @@ Template.newTeamPopup.events({
|
||||
.find('.js-teamShortName')
|
||||
.value.trim();
|
||||
const teamWebsite = templateInstance.find('.js-teamWebsite').value.trim();
|
||||
const teamIsActive = templateInstance
|
||||
.find('.js-team-isactive')
|
||||
.value.trim();
|
||||
const teamIsActive =
|
||||
templateInstance.find('.js-team-isactive').value.trim() == 'true';
|
||||
|
||||
Meteor.call(
|
||||
'setCreateTeam',
|
||||
@@ -662,6 +934,34 @@ Template.newUserPopup.events({
|
||||
const importUsernames = Users.parseImportUsernames(
|
||||
templateInstance.find('.js-import-usernames').value,
|
||||
);
|
||||
const userOrgs = templateInstance.find('.js-userOrgsNewUser').value.trim();
|
||||
const userOrgsIds = templateInstance.find('.js-userOrgIdsNewUser').value.trim();
|
||||
const userTeams = templateInstance.find('.js-userteamsNewUser').value.trim();
|
||||
const userTeamsIds = templateInstance.find('.js-userteamIdsNewUser').value.trim();
|
||||
|
||||
let userTeamsList = userTeams.split(",");
|
||||
let userTeamsIdsList = userTeamsIds.split(",");
|
||||
let userTms = [];
|
||||
for(let i = 0; i < userTeamsList.length; i++){
|
||||
if(!!userTeamsIdsList[i] && !!userTeamsList[i]) {
|
||||
userTms.push({
|
||||
"teamId": userTeamsIdsList[i],
|
||||
"teamDisplayName": userTeamsList[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
let userOrgsList = userOrgs.split(",");
|
||||
let userOrgsIdsList = userOrgsIds.split(",");
|
||||
let userOrganizations = [];
|
||||
for(let i = 0; i < userOrgsList.length; i++){
|
||||
if(!!userOrgsIdsList[i] && !!userOrgsList[i]) {
|
||||
userOrganizations.push({
|
||||
"orgId": userOrgsIdsList[i],
|
||||
"orgDisplayName": userOrgsList[i],
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.call(
|
||||
'setCreateUser',
|
||||
@@ -673,6 +973,8 @@ Template.newUserPopup.events({
|
||||
isActive,
|
||||
email.toLowerCase(),
|
||||
importUsernames,
|
||||
userOrganizations,
|
||||
userTms,
|
||||
function(error) {
|
||||
const usernameMessageElement = templateInstance.$('.username-taken');
|
||||
const emailMessageElement = templateInstance.$('.email-taken');
|
||||
@@ -694,13 +996,85 @@ Template.newUserPopup.events({
|
||||
);
|
||||
Popup.close();
|
||||
},
|
||||
'click #addUserOrgNewUser'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "addOrg";
|
||||
document.getElementById("jsOrgsNewUser").style.display = 'block';
|
||||
document.getElementById("jsTeamsNewUser").style.display = 'none';
|
||||
},
|
||||
'click #removeUserOrgNewUser'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "removeOrg";
|
||||
document.getElementById("jsOrgsNewUser").style.display = 'block';
|
||||
document.getElementById("jsTeamsNewUser").style.display = 'none';
|
||||
},
|
||||
'click #addUserTeamNewUser'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "addTeam";
|
||||
document.getElementById("jsTeamsNewUser").style.display = 'block';
|
||||
document.getElementById("jsOrgsNewUser").style.display = 'none';
|
||||
},
|
||||
'click #removeUserTeamNewUser'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
userOrgsTeamsAction = "removeTeam";
|
||||
document.getElementById("jsTeamsNewUser").style.display = 'block';
|
||||
document.getElementById("jsOrgsNewUser").style.display = 'none';
|
||||
},
|
||||
'change #jsOrgsNewUser'(event) {
|
||||
event.preventDefault();
|
||||
UpdateUserOrgsOrTeamsElement(true);
|
||||
},
|
||||
'change #jsTeamsNewUser'(event) {
|
||||
event.preventDefault();
|
||||
UpdateUserOrgsOrTeamsElement(true);
|
||||
},
|
||||
});
|
||||
|
||||
Template.settingsOrgPopup.events({
|
||||
'click #deleteButton'(event) {
|
||||
event.preventDefault();
|
||||
if(Users.find({"orgs.orgId": this.orgId}).count() > 0)
|
||||
{
|
||||
let orgClassList = document.getElementById("deleteOrgWarningMessage").classList;
|
||||
if(orgClassList.contains('hide'))
|
||||
{
|
||||
orgClassList.remove('hide');
|
||||
document.getElementById("deleteOrgWarningMessage").style.color = "red";
|
||||
}
|
||||
return;
|
||||
}
|
||||
Org.remove(this.orgId);
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
|
||||
Template.settingsTeamPopup.events({
|
||||
'click #deleteButton'(event) {
|
||||
event.preventDefault();
|
||||
if(Users.find({"teams.teamId": this.teamId}).count() > 0)
|
||||
{
|
||||
let teamClassList = document.getElementById("deleteTeamWarningMessage").classList;
|
||||
if(teamClassList.contains('hide'))
|
||||
{
|
||||
teamClassList.remove('hide');
|
||||
document.getElementById("deleteTeamWarningMessage").style.color = "red";
|
||||
}
|
||||
return;
|
||||
}
|
||||
Team.remove(this.teamId);
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
|
||||
Template.settingsUserPopup.events({
|
||||
'click .impersonate-user'(event) {
|
||||
event.preventDefault();
|
||||
|
||||
Meteor.call('impersonate', this.userId, err => {
|
||||
Meteor.call('impersonate', this.userId, (err) => {
|
||||
if (!err) {
|
||||
FlowRouter.go('/');
|
||||
Meteor.connection.setUserId(this.userId);
|
||||
@@ -709,10 +1083,13 @@ Template.settingsUserPopup.events({
|
||||
},
|
||||
'click #deleteButton'(event) {
|
||||
event.preventDefault();
|
||||
Users.remove(this.userId);
|
||||
/*
|
||||
// Delete is not enabled yet, because it does leave empty user avatars
|
||||
// to boards: boards members, card members and assignees have
|
||||
// empty users. See:
|
||||
// Delete user is enabled, but you should remove user from all boards
|
||||
// before deleting user, because there is possibility of leaving empty user avatars
|
||||
// to boards. You can remove non-existing user ids manually from database,
|
||||
// if that happens.
|
||||
//. See:
|
||||
// - wekan/client/components/settings/peopleBody.jade deleteButton
|
||||
// - wekan/client/components/settings/peopleBody.js deleteButton
|
||||
// - wekan/client/components/sidebar/sidebar.js Popup.afterConfirm('removeMember'
|
||||
@@ -720,22 +1097,7 @@ Template.settingsUserPopup.events({
|
||||
// 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();
|
||||
},
|
||||
|
||||
@@ -49,3 +49,37 @@ table
|
||||
|
||||
.more-settings-user,.more-settings-team,.more-settings-org
|
||||
margin-left: 10px;
|
||||
|
||||
.js-orgs,.js-orgsNewUser
|
||||
display: none;
|
||||
|
||||
.js-teams,.js-teamsNewUser
|
||||
display: none;
|
||||
|
||||
.selectUserChkBox
|
||||
position: static !important;
|
||||
visibility: visible !important;
|
||||
left: 0 !important;
|
||||
|
||||
#divAddOrRemoveTeam
|
||||
background: green;
|
||||
display: none;
|
||||
|
||||
#addOrRemoveTeam
|
||||
background: green;
|
||||
color: white;
|
||||
|
||||
#divAddOrRemoveTeamContainer
|
||||
display: none;
|
||||
margin: auto;
|
||||
width: 50%;
|
||||
border: 3px solid green;
|
||||
padding: 10px;
|
||||
|
||||
#cancelBtn
|
||||
margin-left: 5% !important;
|
||||
background: orange;
|
||||
color: white;
|
||||
|
||||
#deleteAction
|
||||
margin-left: 5% !important;
|
||||
@@ -22,6 +22,10 @@ template(name="setting")
|
||||
a.js-setting-menu(data-id="account-setting")
|
||||
i.fa.fa-users
|
||||
| {{_ 'accounts'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="tableVisibilityMode-setting")
|
||||
i.fa.fa-eye
|
||||
| {{_ 'tableVisibilityMode'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="announcement-setting")
|
||||
i.fa.fa-bullhorn
|
||||
@@ -44,6 +48,8 @@ template(name="setting")
|
||||
+email
|
||||
else if accountSetting.get
|
||||
+accountSettings
|
||||
else if tableVisibilityModeSetting.get
|
||||
+tableVisibilityModeSettings
|
||||
else if announcementSetting.get
|
||||
+announcementSettings
|
||||
else if layoutSetting.get
|
||||
@@ -96,7 +102,7 @@ template(name='email')
|
||||
// li.smtp-form
|
||||
// .title {{_ 'smtp-username'}}
|
||||
// .form-group
|
||||
// input.wekan-form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
|
||||
// input.wekan-form-control#mail-server-u"accounts-allowUserNameChange": "Allow Username Change",sername(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
|
||||
// li.smtp-form
|
||||
// .title {{_ 'smtp-password'}}
|
||||
// .form-group
|
||||
@@ -120,6 +126,17 @@ template(name='email')
|
||||
li
|
||||
button.js-send-smtp-test-email.primary {{_ 'send-smtp-test'}}
|
||||
|
||||
template(name='tableVisibilityModeSettings')
|
||||
ul#tableVisibilityMode-setting.setting-detail
|
||||
li.tableVisibilityMode-form
|
||||
.title {{_ 'tableVisibilityMode-allowPrivateOnly'}}
|
||||
.form-group.flex
|
||||
input.wekan-form-control#accounts-allowPrivateOnly(type="radio" name="allowPrivateOnly" value="true" checked="{{#if allowPrivateOnly}}checked{{/if}}")
|
||||
span {{_ 'yes'}}
|
||||
input.wekan-form-control#accounts-allowPrivateOnly(type="radio" name="allowPrivateOnly" value="false" checked="{{#unless allowPrivateOnly}}checked{{/unless}}")
|
||||
span {{_ 'no'}}
|
||||
button.js-tableVisibilityMode-save.primary {{_ 'save'}}
|
||||
|
||||
template(name='accountSettings')
|
||||
ul#account-setting.setting-detail
|
||||
li
|
||||
@@ -163,6 +180,10 @@ template(name='announcementSettings')
|
||||
|
||||
template(name='layoutSettings')
|
||||
ul#layout-setting.setting-detail
|
||||
li.layout-form
|
||||
.title {{_ 'oidc-button-text'}}
|
||||
.form-group
|
||||
input.wekan-form-control#oidcBtnTextvalue(type="text", placeholder="" value="{{currentSetting.oidcBtnText}}")
|
||||
li.layout-form
|
||||
.title {{_ 'display-authentication-method'}}
|
||||
.form-group.flex
|
||||
@@ -173,6 +194,9 @@ template(name='layoutSettings')
|
||||
li.layout-form
|
||||
.title {{_ 'default-authentication-method'}}
|
||||
+selectAuthenticationMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod)
|
||||
li.layout-form
|
||||
.title {{_ 'wait-spinner'}}
|
||||
+selectSpinnerName(spinnerName=currentSetting.spinnerName)
|
||||
li.layout-form
|
||||
.title {{_ 'custom-product-name'}}
|
||||
.form-group
|
||||
@@ -222,3 +246,11 @@ template(name='selectAuthenticationMethod')
|
||||
option(value="{{value}}" selected) {{_ value}}
|
||||
else
|
||||
option(value="{{value}}") {{_ value}}
|
||||
|
||||
template(name='selectSpinnerName')
|
||||
select#spinnerName
|
||||
each spinner in spinners
|
||||
if isSelected spinner
|
||||
option(value="{{spinner}}" selected) {{_ spinner}}
|
||||
else
|
||||
option(value="{{spinner}}") {{_ spinner}}
|
||||
@@ -1,3 +1,5 @@
|
||||
import { ALLOWED_WAIT_SPINNERS } from '/config/const';
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
@@ -5,6 +7,7 @@ BlazeComponent.extendComponent({
|
||||
this.generalSetting = new ReactiveVar(true);
|
||||
this.emailSetting = new ReactiveVar(false);
|
||||
this.accountSetting = new ReactiveVar(false);
|
||||
this.tableVisibilityModeSetting = new ReactiveVar(false);
|
||||
this.announcementSetting = new ReactiveVar(false);
|
||||
this.layoutSetting = new ReactiveVar(false);
|
||||
this.webhookSetting = new ReactiveVar(false);
|
||||
@@ -12,6 +15,7 @@ BlazeComponent.extendComponent({
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
Meteor.subscribe('accountSettings');
|
||||
Meteor.subscribe('tableVisibilityModeSettings');
|
||||
Meteor.subscribe('announcements');
|
||||
Meteor.subscribe('globalwebhooks');
|
||||
},
|
||||
@@ -86,6 +90,7 @@ BlazeComponent.extendComponent({
|
||||
this.announcementSetting.set('announcement-setting' === targetID);
|
||||
this.layoutSetting.set('layout-setting' === targetID);
|
||||
this.webhookSetting.set('webhook-setting' === targetID);
|
||||
this.tableVisibilityModeSetting.set('tableVisibilityMode-setting' === targetID);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -194,11 +199,19 @@ BlazeComponent.extendComponent({
|
||||
)
|
||||
.val()
|
||||
.trim();
|
||||
|
||||
const oidcBtnText = $(
|
||||
'#oidcBtnTextvalue',
|
||||
)
|
||||
.val()
|
||||
.trim();
|
||||
const hideLogoChange = $('input[name=hideLogo]:checked').val() === 'true';
|
||||
const displayAuthenticationMethod =
|
||||
$('input[name=displayAuthenticationMethod]:checked').val() === 'true';
|
||||
const defaultAuthenticationMethod = $('#defaultAuthenticationMethod').val();
|
||||
|
||||
const spinnerName = $('#spinnerName').val();
|
||||
|
||||
try {
|
||||
Settings.update(Settings.findOne()._id, {
|
||||
$set: {
|
||||
@@ -213,6 +226,8 @@ BlazeComponent.extendComponent({
|
||||
displayAuthenticationMethod,
|
||||
defaultAuthenticationMethod,
|
||||
automaticLinkedUrlSchemes,
|
||||
spinnerName,
|
||||
oidcBtnText,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -312,6 +327,46 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('accountSettings');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
saveTableVisibilityChange() {
|
||||
const allowPrivateOnly =
|
||||
$('input[name=allowPrivateOnly]:checked').val() === 'true';
|
||||
TableVisibilityModeSettings.update('tableVisibilityMode-allowPrivateOnly', {
|
||||
$set: { booleanValue: allowPrivateOnly },
|
||||
});
|
||||
},
|
||||
allowPrivateOnly() {
|
||||
return TableVisibilityModeSettings.findOne('tableVisibilityMode-allowPrivateOnly').booleanValue;
|
||||
},
|
||||
allHideSystemMessages() {
|
||||
Meteor.call('setAllUsersHideSystemMessages', (err, ret) => {
|
||||
if (!err && ret) {
|
||||
if (ret === true) {
|
||||
const message = `${TAPi18n.__(
|
||||
'now-system-messages-of-all-users-are-hidden',
|
||||
)}`;
|
||||
alert(message);
|
||||
}
|
||||
} else {
|
||||
const reason = err.reason || '';
|
||||
const message = `${TAPi18n.__(err.error)}\n${reason}`;
|
||||
alert(message);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click button.js-tableVisibilityMode-save': this.saveTableVisibilityChange,
|
||||
},
|
||||
{
|
||||
'click button.js-all-hide-system-messages': this.allHideSystemMessages,
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('tableVisibilityModeSettings');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.loading = new ReactiveVar(false);
|
||||
@@ -384,3 +439,12 @@ Template.selectAuthenticationMethod.helpers({
|
||||
return Template.instance().data.authenticationMethod === match;
|
||||
},
|
||||
});
|
||||
|
||||
Template.selectSpinnerName.helpers({
|
||||
spinners() {
|
||||
return ALLOWED_WAIT_SPINNERS;
|
||||
},
|
||||
isSelected(match) {
|
||||
return Template.instance().data.spinnerName === match;
|
||||
},
|
||||
});
|
||||
@@ -12,6 +12,10 @@ template(name="settingHeaderBar")
|
||||
i.fa(class="fa-users")
|
||||
span {{_ 'people'}}
|
||||
|
||||
a.setting-header-btn.informations(href="{{pathFor 'admin-reports'}}")
|
||||
i.fa(class="fa-list")
|
||||
span {{_ 'reports'}}
|
||||
|
||||
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
|
||||
i.fa(class="fa-info-circle")
|
||||
span {{_ 'info'}}
|
||||
|
||||
@@ -5,10 +5,6 @@ template(name="sidebar")
|
||||
// title="{{showTongueTitle}}")
|
||||
// i.fa.fa-navicon
|
||||
.sidebar-shadow
|
||||
.sidebar-content.sidebar-shortcuts
|
||||
a.board-header-btn.js-shortcuts
|
||||
i.fa.fa-keyboard-o
|
||||
span {{_ 'keyboard-shortcuts' }}
|
||||
.sidebar-content.js-board-sidebar-content
|
||||
//a.hide-btn.js-hide-sidebar
|
||||
// i.fa.fa-navicon
|
||||
@@ -23,7 +19,7 @@ template(name='homeSidebar')
|
||||
hr
|
||||
+labelsWidget
|
||||
ul#cards.label-text-hidden
|
||||
a.flex.js-toggle-minicard-label-text
|
||||
a.flex.js-toggle-minicard-label-text(title="{{_ 'hide-minicard-label-text'}}")
|
||||
span {{_ 'hide-minicard-label-text'}}
|
||||
b
|
||||
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
|
||||
@@ -35,10 +31,38 @@ template(name='homeSidebar')
|
||||
+activities(mode="board")
|
||||
|
||||
template(name="membersWidget")
|
||||
if AtLeastOneOrgWasCreated
|
||||
.board-widget.board-widget-members
|
||||
h3
|
||||
i.fa.fa-users
|
||||
| {{_ 'organizations'}}
|
||||
|
||||
.board-widget-content
|
||||
+boardOrgGeneral
|
||||
.clearfix
|
||||
br
|
||||
hr
|
||||
if AtLeastOneTeamWasCreated
|
||||
.board-widget.board-widget-members
|
||||
h3
|
||||
i.fa.fa-users
|
||||
| {{_ 'teams'}}
|
||||
|
||||
.board-widget-content
|
||||
+boardTeamGeneral
|
||||
.clearfix
|
||||
br
|
||||
hr
|
||||
.board-widget.board-widget-members
|
||||
h3
|
||||
i.fa.fa-users
|
||||
| {{_ 'members'}}
|
||||
|
||||
.sidebar-shortcuts
|
||||
a.board-header-btn.js-shortcuts(title="{{_ 'keyboard-shortcuts' }}")
|
||||
i.fa.fa-keyboard-o
|
||||
span {{_ 'keyboard-shortcuts' }}
|
||||
|
||||
unless currentUser.isCommentOnly
|
||||
unless currentUser.isWorker
|
||||
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right
|
||||
@@ -49,10 +73,10 @@ template(name="membersWidget")
|
||||
+userAvatar(userId=this.userId showStatus=true)
|
||||
if isSandstorm
|
||||
if currentUser.isBoardMember
|
||||
a.member.add-member.sandstorm-powerbox-request-identity
|
||||
a.member.add-member.sandstorm-powerbox-request-identity(title="{{_ 'add-members'}}")
|
||||
i.fa.fa-plus
|
||||
else if currentUser.isBoardAdmin
|
||||
a.member.add-member.js-manage-board-members
|
||||
a.member.add-member.js-manage-board-members(title="{{_ 'add-members'}}")
|
||||
i.fa.fa-plus
|
||||
.clearfix
|
||||
if isInvited
|
||||
@@ -63,6 +87,30 @@ template(name="membersWidget")
|
||||
button.js-member-invite-accept.primary {{_ 'accept'}}
|
||||
button.js-member-invite-decline {{_ 'decline'}}
|
||||
|
||||
template(name="boardOrgGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'displayName'}}
|
||||
th
|
||||
if currentUser.isBoardAdmin
|
||||
a.member.orgOrTeamMember.add-member.js-manage-board-addOrg(title="{{_ 'add-members'}}")
|
||||
i.fa.fa-plus
|
||||
each org in currentBoard.activeOrgs
|
||||
+boardOrgRow(orgId=org.orgId)
|
||||
|
||||
template(name="boardTeamGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'displayName'}}
|
||||
th
|
||||
if currentUser.isBoardAdmin
|
||||
a.member.orgOrTeamMember.add-member.js-manage-board-addTeam(title="{{_ 'add-members'}}")
|
||||
i.fa.fa-plus
|
||||
each currentBoard.activeTeams
|
||||
+boardTeamRow(teamId=this.teamId)
|
||||
|
||||
template(name="boardChangeColorPopup")
|
||||
.board-backgrounds-list.clearfix
|
||||
each backgroundColors
|
||||
@@ -105,6 +153,14 @@ template(name="boardCardSettingsPopup")
|
||||
span
|
||||
i.fa.fa-users
|
||||
| {{_ 'members'}}
|
||||
|
||||
div.check-div
|
||||
a.flex.js-field-has-creator(class="{{#if allowsCreator}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCreator}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-user
|
||||
| {{_ 'creator'}}
|
||||
|
||||
div.check-div
|
||||
a.flex.js-field-has-assignee(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
@@ -123,12 +179,25 @@ template(name="boardCardSettingsPopup")
|
||||
span
|
||||
i.fa.fa-user-plus
|
||||
| {{_ 'requested-by'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-sorting-by-number(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-sort
|
||||
| {{_ 'card-sorting-by-number'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-labels(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-tags
|
||||
| {{_ 'labels'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-number(class="{{#if allowsCardNumber}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCardNumber}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-hashtag
|
||||
| {{_ 'card'}}
|
||||
| {{_ 'number'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-title(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
@@ -354,7 +423,7 @@ template(name="labelsWidget")
|
||||
+viewer
|
||||
= name
|
||||
if currentUser.isBoardAdmin
|
||||
a.card-label.add-label.js-add-label
|
||||
a.card-label.add-label.js-add-label(title="{{_ 'label-create'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
template(name="memberPopup")
|
||||
@@ -393,6 +462,40 @@ template(name="leaveBoardPopup")
|
||||
p {{_ 'leave-board-pop' boardTitle=board.title}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'leave-board'}}
|
||||
|
||||
template(name="addBoardOrgPopup")
|
||||
select.js-boardOrgs#jsBoardOrgs
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each value in orgsDatas
|
||||
option(value="{{value._id}}") {{_ value.orgDisplayName}}
|
||||
|
||||
template(name="removeBoardOrgPopup")
|
||||
form
|
||||
input.hide#hideOrgId(type="text" value=org._id)
|
||||
label
|
||||
| {{_ 'leave-board'}} ?
|
||||
br
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide.leaveBoardBtn#leaveBoardBtn(type="submit" value="{{_ 'leave-board'}}")
|
||||
input.primary.wide.cancelLeaveBoardBtn#cancelLeaveBoardBtn(type="submit" value="{{_ 'Cancel'}}")
|
||||
|
||||
template(name="addBoardTeamPopup")
|
||||
select.js-boardTeams#jsBoardTeams
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each value in teamsDatas
|
||||
option(value="{{value._id}}") {{_ value.teamDisplayName}}
|
||||
|
||||
template(name="removeBoardTeamPopup")
|
||||
form
|
||||
input.hide#hideTeamId(type="text" value=team._id)
|
||||
label
|
||||
| {{_ 'leave-board'}} ?
|
||||
br
|
||||
hr
|
||||
div.buttonsContainer
|
||||
input.primary.wide.leaveBoardBtn#leaveBoardTeamBtn(type="submit" value="{{_ 'leave-board'}}")
|
||||
input.primary.wide.cancelLeaveBoardBtn#cancelLeaveBoardTeamBtn(type="submit" value="{{_ 'Cancel'}}")
|
||||
|
||||
template(name="addMemberPopup")
|
||||
.js-search-member
|
||||
+esInput(index="users")
|
||||
|
||||
@@ -183,6 +183,7 @@ Template.memberPopup.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Template.boardMenuPopup.events({
|
||||
'click .js-rename-board': Popup.open('boardChangeTitle'),
|
||||
'click .js-open-rules-view'() {
|
||||
@@ -290,6 +291,42 @@ Template.leaveBoardPopup.helpers({
|
||||
return Boards.findOne(Session.get('currentBoard'));
|
||||
},
|
||||
});
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
this.findTeamsOptions = new ReactiveVar({});
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.teamPage = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
|
||||
});
|
||||
|
||||
this.autorun(() => {
|
||||
const limitTeams = this.teamPage.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('team', this.findTeamsOptions.get(), limitTeams, () => {});
|
||||
});
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
isLoading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
}).register('membersWidget');
|
||||
|
||||
Template.membersWidget.helpers({
|
||||
isInvited() {
|
||||
@@ -307,12 +344,29 @@ Template.membersWidget.helpers({
|
||||
isBoardAdmin() {
|
||||
return Meteor.user().isBoardAdmin();
|
||||
},
|
||||
AtLeastOneOrgWasCreated(){
|
||||
let orgs = Org.find({}, {sort: { createdAt: -1 }});
|
||||
if(orgs === undefined)
|
||||
return false;
|
||||
|
||||
return orgs.count() > 0;
|
||||
},
|
||||
|
||||
AtLeastOneTeamWasCreated(){
|
||||
let teams = Team.find({}, {sort: { createdAt: -1 }});
|
||||
if(teams === undefined)
|
||||
return false;
|
||||
|
||||
return teams.count() > 0;
|
||||
},
|
||||
});
|
||||
|
||||
Template.membersWidget.events({
|
||||
'click .js-member': Popup.open('member'),
|
||||
'click .js-open-board-menu': Popup.open('boardMenu'),
|
||||
'click .js-manage-board-members': Popup.open('addMember'),
|
||||
'click .js-manage-board-addOrg': Popup.open('addBoardOrg'),
|
||||
'click .js-manage-board-addTeam': Popup.open('addBoardTeam'),
|
||||
'click .js-import': Popup.open('boardImportBoard'),
|
||||
submit: this.onSubmit,
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
@@ -730,6 +784,14 @@ BlazeComponent.extendComponent({
|
||||
return this.currentBoard.allowsSubtasks;
|
||||
},
|
||||
|
||||
allowsCreator() {
|
||||
return (
|
||||
this.currentBoard.allowsCreator === null ||
|
||||
this.currentBoard.allowsCreator === undefined ||
|
||||
this.currentBoard.allowsCreator
|
||||
);
|
||||
},
|
||||
|
||||
allowsMembers() {
|
||||
return this.currentBoard.allowsMembers;
|
||||
},
|
||||
@@ -746,6 +808,10 @@ BlazeComponent.extendComponent({
|
||||
return this.currentBoard.allowsRequestedBy;
|
||||
},
|
||||
|
||||
allowsCardSortingByNumber() {
|
||||
return this.currentBoard.allowsCardSortingByNumber;
|
||||
},
|
||||
|
||||
allowsLabels() {
|
||||
return this.currentBoard.allowsLabels;
|
||||
},
|
||||
@@ -762,6 +828,10 @@ BlazeComponent.extendComponent({
|
||||
return this.currentBoard.allowsComments;
|
||||
},
|
||||
|
||||
allowsCardNumber() {
|
||||
return this.currentBoard.allowsCardNumber;
|
||||
},
|
||||
|
||||
allowsDescriptionTitle() {
|
||||
return this.currentBoard.allowsDescriptionTitle;
|
||||
},
|
||||
@@ -889,6 +959,19 @@ BlazeComponent.extendComponent({
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-creator'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCreator = !this.currentBoard.allowsCreator;
|
||||
this.currentBoard.setAllowsCreator(this.currentBoard.allowsCreator);
|
||||
$(`.js-field-has-creator ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreator,
|
||||
);
|
||||
$('.js-field-has-creator').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreator,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-members'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsMembers = !this.currentBoard.allowsMembers;
|
||||
@@ -947,6 +1030,22 @@ BlazeComponent.extendComponent({
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-card-sorting-by-number'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCardSortingByNumber = !this.currentBoard
|
||||
.allowsCardSortingByNumber;
|
||||
this.currentBoard.setAllowsCardSortingByNumber(
|
||||
this.currentBoard.allowsCardSortingByNumber,
|
||||
);
|
||||
$(`.js-field-has-card-sorting-by-number ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCardSortingByNumber,
|
||||
);
|
||||
$('.js-field-has-card-sorting-by-number').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCardSortingByNumber,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-labels'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsLabels = !this.currentBoard.allowsLabels;
|
||||
@@ -976,6 +1075,22 @@ BlazeComponent.extendComponent({
|
||||
this.currentBoard.allowsDescriptionTitle,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-card-number'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCardNumber = !this.currentBoard
|
||||
.allowsCardNumber;
|
||||
this.currentBoard.setAllowsCardNumber(
|
||||
this.currentBoard.allowsCardNumber,
|
||||
);
|
||||
$(`.js-field-has-card-number ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCardNumber,
|
||||
);
|
||||
$('.js-field-has-card-number').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCardNumber,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-description-text'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsDescriptionText = !this.currentBoard
|
||||
@@ -1127,6 +1242,346 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('addMemberPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
|
||||
});
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
isLoading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup input'() {
|
||||
this.setError('');
|
||||
},
|
||||
'change #jsBoardOrgs'() {
|
||||
let currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
let selectElt = document.getElementById("jsBoardOrgs");
|
||||
let selectedOrgId = selectElt.options[selectElt.selectedIndex].value;
|
||||
let selectedOrgDisplayName = selectElt.options[selectElt.selectedIndex].text;
|
||||
let boardOrganizations = [];
|
||||
if(currentBoard.orgs !== undefined){
|
||||
for(let i = 0; i < currentBoard.orgs.length; i++){
|
||||
boardOrganizations.push(currentBoard.orgs[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!boardOrganizations.some((org) => org.orgDisplayName == selectedOrgDisplayName)){
|
||||
boardOrganizations.push({
|
||||
"orgId": selectedOrgId,
|
||||
"orgDisplayName": selectedOrgDisplayName,
|
||||
"isActive" : true,
|
||||
})
|
||||
|
||||
if (selectedOrgId != "-1") {
|
||||
Meteor.call('setBoardOrgs', boardOrganizations, currentBoard._id);
|
||||
}
|
||||
}
|
||||
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('addBoardOrgPopup');
|
||||
|
||||
Template.addBoardOrgPopup.helpers({
|
||||
orgsDatas() {
|
||||
// return Org.find({}, {sort: { createdAt: -1 }});
|
||||
let orgs = Org.find({}, {sort: { createdAt: -1 }});
|
||||
return orgs;
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitOrgs = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('org', this.findOrgsOptions.get(), limitOrgs, () => {});
|
||||
});
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
isLoading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup input'() {
|
||||
this.setError('');
|
||||
},
|
||||
'click #leaveBoardBtn'(){
|
||||
let stringOrgId = document.getElementById('hideOrgId').value;
|
||||
let currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
let boardOrganizations = [];
|
||||
if(currentBoard.orgs !== undefined){
|
||||
for(let i = 0; i < currentBoard.orgs.length; i++){
|
||||
if(currentBoard.orgs[i].orgId != stringOrgId){
|
||||
boardOrganizations.push(currentBoard.orgs[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.call('setBoardOrgs', boardOrganizations, currentBoard._id);
|
||||
|
||||
Popup.close();
|
||||
},
|
||||
'click #cancelLeaveBoardBtn'(){
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('removeBoardOrgPopup');
|
||||
|
||||
Template.removeBoardOrgPopup.helpers({
|
||||
org() {
|
||||
return Org.findOne(this.orgId);
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
|
||||
});
|
||||
|
||||
this.findUsersOptions = new ReactiveVar({});
|
||||
this.userPage = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitUsers = this.userPage.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('people', this.findUsersOptions.get(), limitUsers, () => {});
|
||||
});
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
isLoading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup input'() {
|
||||
this.setError('');
|
||||
},
|
||||
'change #jsBoardTeams'() {
|
||||
let currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
let selectElt = document.getElementById("jsBoardTeams");
|
||||
let selectedTeamId = selectElt.options[selectElt.selectedIndex].value;
|
||||
let selectedTeamDisplayName = selectElt.options[selectElt.selectedIndex].text;
|
||||
let boardTeams = [];
|
||||
if(currentBoard.teams !== undefined){
|
||||
for(let i = 0; i < currentBoard.teams.length; i++){
|
||||
boardTeams.push(currentBoard.teams[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(!boardTeams.some((team) => team.teamDisplayName == selectedTeamDisplayName)){
|
||||
boardTeams.push({
|
||||
"teamId": selectedTeamId,
|
||||
"teamDisplayName": selectedTeamDisplayName,
|
||||
"isActive" : true,
|
||||
})
|
||||
|
||||
if (selectedTeamId != "-1") {
|
||||
let members = currentBoard.members;
|
||||
|
||||
let query = {
|
||||
"teams.teamId": { $in: boardTeams.map(t => t.teamId) },
|
||||
};
|
||||
|
||||
const boardTeamUsers = Users.find(query, {
|
||||
sort: { sort: 1 },
|
||||
});
|
||||
|
||||
if(boardTeams !== undefined && boardTeams.length > 0){
|
||||
let index;
|
||||
if(boardTeamUsers && boardTeamUsers.count() > 0){
|
||||
boardTeamUsers.forEach((u) => {
|
||||
index = members.findIndex(function(m){ return m.userId == u._id});
|
||||
if(index == -1){
|
||||
members.push({
|
||||
"isActive": true,
|
||||
"isAdmin": u.isAdmin !== undefined ? u.isAdmin : false,
|
||||
"isCommentOnly" : false,
|
||||
"isNoComments" : false,
|
||||
"userId": u._id,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.call('setBoardTeams', boardTeams, members, currentBoard._id);
|
||||
}
|
||||
}
|
||||
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('addBoardTeamPopup');
|
||||
|
||||
Template.addBoardTeamPopup.helpers({
|
||||
teamsDatas() {
|
||||
let teams = Team.find({}, {sort: { createdAt: -1 }});
|
||||
return teams;
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.findOrgsOptions = new ReactiveVar({});
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitTeams = this.page.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('team', this.findOrgsOptions.get(), limitTeams, () => {});
|
||||
});
|
||||
|
||||
this.findUsersOptions = new ReactiveVar({});
|
||||
this.userPage = new ReactiveVar(1);
|
||||
this.autorun(() => {
|
||||
const limitUsers = this.userPage.get() * Number.MAX_SAFE_INTEGER;
|
||||
this.subscribe('people', this.findUsersOptions.get(), limitUsers, () => {});
|
||||
});
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
isLoading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup input'() {
|
||||
this.setError('');
|
||||
},
|
||||
'click #leaveBoardTeamBtn'(){
|
||||
let stringTeamId = document.getElementById('hideTeamId').value;
|
||||
let currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
let boardTeams = [];
|
||||
if(currentBoard.teams !== undefined){
|
||||
for(let i = 0; i < currentBoard.teams.length; i++){
|
||||
if(currentBoard.teams[i].teamId != stringTeamId){
|
||||
boardTeams.push(currentBoard.teams[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let members = currentBoard.members;
|
||||
let query = {
|
||||
"teams.teamId": stringTeamId
|
||||
};
|
||||
|
||||
const boardTeamUsers = Users.find(query, {
|
||||
sort: { sort: 1 },
|
||||
});
|
||||
|
||||
if(currentBoard.teams !== undefined && currentBoard.teams.length > 0){
|
||||
let index;
|
||||
if(boardTeamUsers && boardTeamUsers.count() > 0){
|
||||
boardTeamUsers.forEach((u) => {
|
||||
index = members.findIndex(function(m){ return m.userId == u._id});
|
||||
if(index !== -1 && (u.isAdmin === undefined || u.isAdmin == false)){
|
||||
members.splice(index, 1);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Meteor.call('setBoardTeams', boardTeams, members, currentBoard._id);
|
||||
|
||||
Popup.close();
|
||||
},
|
||||
'click #cancelLeaveBoardTeamBtn'(){
|
||||
Popup.close();
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('removeBoardTeamPopup');
|
||||
|
||||
Template.removeBoardTeamPopup.helpers({
|
||||
team() {
|
||||
return Team.findOne(this.teamId);
|
||||
},
|
||||
});
|
||||
|
||||
Template.changePermissionsPopup.events({
|
||||
'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only, click .js-set-worker'(
|
||||
event,
|
||||
|
||||
@@ -100,13 +100,12 @@
|
||||
margin-right: 10px
|
||||
|
||||
.sidebar-shortcuts
|
||||
margin: 0
|
||||
position: absolute
|
||||
margin-left: 40%
|
||||
padding: 0
|
||||
top: auto
|
||||
text-align: center
|
||||
top: 7px
|
||||
font-size: 0.8em
|
||||
line-height: 1.6em
|
||||
vertical-align: middle
|
||||
color: darken(white, 40%)
|
||||
|
||||
.board-sidebar
|
||||
@@ -215,3 +214,13 @@
|
||||
i.fa
|
||||
padding: 8px 0px 8px 16px
|
||||
font-weight: bold
|
||||
|
||||
#jsBoardOrgs, #jsBoardTeams
|
||||
width: 90%
|
||||
|
||||
.leaveBoardBtn
|
||||
background-color: green !important
|
||||
|
||||
.cancelLeaveBoardBtn
|
||||
margin-left: 5% !important
|
||||
background-color: red !important
|
||||
Loaded 100 of 478 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user