Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1b445ad789 | ||
|
|
9baed4256a | ||
|
|
2b4df7e8c7 | ||
|
|
6e28dec712 | ||
|
|
ba9f0ca672 | ||
|
|
7261ccdc90 | ||
|
|
6fbadbe5bc | ||
|
|
26d7ba72aa | ||
|
|
44e4df2492 | ||
|
|
d8482b533a | ||
|
|
2082480ddd | ||
|
|
e8c4e394fd | ||
|
|
0c5052ebae | ||
|
|
d3b2ae1975 | ||
|
|
f4f0f489eb | ||
|
|
3368ebf067 | ||
|
|
b0ac10d94a | ||
|
|
c87a8b86ae | ||
|
|
d5d71d7097 | ||
|
|
c960a8b909 | ||
|
|
3257f78d24 | ||
|
|
a9133bf933 | ||
|
|
8e8147b5ac | ||
|
|
711f4de3d7 | ||
|
|
68998e062e | ||
|
|
f40d1f6bd5 | ||
|
|
048c3cd14d | ||
|
|
08ca353205 | ||
|
|
c83cdc9335 | ||
|
|
e91e3c076d | ||
|
|
8be7eec2ca | ||
|
|
acc4493517 | ||
|
|
ff467402c0 | ||
|
|
49d3eb5a3f | ||
|
|
889aa6d652 | ||
|
|
78e0457843 | ||
|
|
7f568faef6 | ||
|
|
be045f3156 | ||
|
|
3b5e81d514 | ||
|
|
346bdf2ca8 | ||
|
|
501289786c | ||
|
|
24ffe223be | ||
|
|
32c561d78e | ||
|
|
ff65b37336 | ||
|
|
3f698ca012 | ||
|
|
785bc2556e | ||
|
|
e198282b4d | ||
|
|
24e59c378b | ||
|
|
c1b4aae573 | ||
|
|
f5339ef97f | ||
|
|
2b53fae16f | ||
|
|
1d3466c7a0 | ||
|
|
4d8b2029d2 | ||
|
|
8ad0da2109 | ||
|
|
12827ef0a6 | ||
|
|
4c399a41f7 | ||
|
|
25968a35cc | ||
|
|
548d095223 | ||
|
|
1683bcb3e5 | ||
|
|
991843acb0 | ||
|
|
8b85437b6b | ||
|
|
6259f0de70 | ||
|
|
d86bc1d84d | ||
|
|
88bdb0815d | ||
|
|
97f64fe5e6 | ||
|
|
196fef3a1b | ||
|
|
a2d756074f | ||
|
|
b2f23d619d | ||
|
|
9d1d66b0f5 | ||
|
|
c61e44d55b | ||
|
|
76c5c283b9 | ||
|
|
2d88afb77e | ||
|
|
7fd09761cb | ||
|
|
cb53c53c2b | ||
|
|
77ff6349f6 | ||
|
|
879ad4001d | ||
|
|
e1436ab964 | ||
|
|
007bea0a4b | ||
|
|
67b76558fc | ||
|
|
f60429efdf | ||
|
|
f140e20c6f | ||
|
|
c502ab9500 | ||
|
|
425ae55422 | ||
|
|
e9006a234b | ||
|
|
ef6aa4e415 | ||
|
|
1901c3c798 | ||
|
|
6cb046f29e | ||
|
|
e7e67e300b | ||
|
|
3f948ba49b | ||
|
|
96f33e4052 | ||
|
|
68d60f4f64 | ||
|
|
f7153da83d | ||
|
|
16d53897c7 | ||
|
|
32d405bca4 | ||
|
|
2f747fc09d | ||
|
|
32d5a1d3f7 | ||
|
|
db44b8ea54 | ||
|
|
1f512c8ba1 | ||
|
|
417dc9dc42 | ||
|
|
bd66ea8acc | ||
|
|
dba9d13b00 | ||
|
|
1e034a794f | ||
|
|
a261c66f34 | ||
|
|
b94bd73d33 | ||
|
|
a9be6b17b9 | ||
|
|
ac6f8e8551 | ||
|
|
23fb2bfc7f | ||
|
|
ff1c3722a8 | ||
|
|
1712368f6a | ||
|
|
d7529bf6b5 | ||
|
|
6b145bb3cc | ||
|
|
72e905675d | ||
|
|
2fbcf7e9b6 | ||
|
|
0ade4dbf00 | ||
|
|
d70ad9d733 | ||
|
|
51a19878dd | ||
|
|
ddca6a1ad8 | ||
|
|
cac74122f2 | ||
|
|
991b2b9721 | ||
|
|
b6663acf91 | ||
|
|
7f74e72cea | ||
|
|
bd1df642fa | ||
|
|
575b0241e4 | ||
|
|
f1ed6304a4 | ||
|
|
a42d9871bd | ||
|
|
7a2ea7cace | ||
|
|
fb39811d95 | ||
|
|
78e88f4c42 | ||
|
|
db63af5f7a | ||
|
|
c3e04da796 | ||
|
|
2a59043ef1 | ||
|
|
3d76a35a68 | ||
|
|
c1733fc89c | ||
|
|
388c1bec45 | ||
|
|
a2869e9d2a | ||
|
|
3e5ff42474 | ||
|
|
9366eaf374 | ||
|
|
cb4c93a632 | ||
|
|
adaffd7189 | ||
|
|
821dc22e80 | ||
|
|
b0a71e96cc | ||
|
|
40e156992a | ||
|
|
ab031d9da1 | ||
|
|
209a76c5ce | ||
|
|
4bd74b5817 | ||
|
|
dbb1a86ca3 | ||
|
|
c066883dbd | ||
|
|
0b6b6dc7fd | ||
|
|
c546464d9f | ||
|
|
7b3e2c58e2 | ||
|
|
d6127082e9 | ||
|
|
67a5fdaf96 | ||
|
|
af9156b18a | ||
|
|
7af20fd2d9 | ||
|
|
2a5a428bc0 | ||
|
|
4b7d47465a | ||
|
|
5f4e2d8e06 | ||
|
|
f8ef8507b5 | ||
|
|
2ae143e6da | ||
|
|
38e8f52293 | ||
|
|
b143fc9297 | ||
|
|
dd10f78401 | ||
|
|
90208b774a | ||
|
|
bc35d9fe1a | ||
|
|
472d637c9f | ||
|
|
20c86613a7 | ||
|
|
5ac69ed7de | ||
|
|
0620fe5e11 | ||
|
|
44a819226f | ||
|
|
cf2cf7898a | ||
|
|
ee212b69a9 | ||
|
|
87d91560f8 | ||
|
|
bccca00aaf | ||
|
|
d6e36ed50a | ||
|
|
83f7fa768d | ||
|
|
2d49006aee | ||
|
|
c2e58dcb62 | ||
|
|
f154c5e521 | ||
|
|
eadbebb4fa | ||
|
|
40cf1c7549 | ||
|
|
9c4e305a84 | ||
|
|
167197fcda | ||
|
|
e3a40aca6f | ||
|
|
0611e0c4bd | ||
|
|
d6857693bb | ||
|
|
b5ccf7a58f | ||
|
|
bfca1822a0 | ||
|
|
30151de269 | ||
|
|
fe7c4528d7 | ||
|
|
40367995e7 | ||
|
|
b75fafc5f2 | ||
|
|
b788deb002 | ||
|
|
fa6b2e5679 | ||
|
|
70fd1ce57d | ||
|
|
97158de70f | ||
|
|
926faf0031 | ||
|
|
228996412c | ||
|
|
c9c1464c79 | ||
|
|
30c80f167c | ||
|
|
af9ca9b6c4 | ||
|
|
3e03f557cf | ||
|
|
f19dc77d2c | ||
|
|
1bad630641 | ||
|
|
8a9a82fc80 | ||
|
|
745bd7e806 | ||
|
|
cdb44da71e | ||
|
|
064a2deaaf | ||
|
|
a085ed1e1b | ||
|
|
f23448be33 | ||
|
|
a27c16e434 | ||
|
|
d5be48b905 | ||
|
|
7432af67c1 | ||
|
|
24b61cf772 | ||
|
|
cc64ef903f | ||
|
|
8e3f530217 | ||
|
|
f9b272c223 | ||
|
|
f0232fb5cb | ||
|
|
f84bad13b4 | ||
|
|
b72a68705c | ||
|
|
dd6ba152a0 | ||
|
|
cb9ced756f | ||
|
|
dbf3a48b5f | ||
|
|
b5d1799f5a | ||
|
|
d4ec0cc647 | ||
|
|
21a8c7cc45 | ||
|
|
aa691b0af1 | ||
|
|
7a75d82114 | ||
|
|
4daf69e4b6 | ||
|
|
960b33c3d9 | ||
|
|
685eb0f22c | ||
|
|
81a51c8dfc | ||
|
|
75c1dff1f8 | ||
|
|
cb24b85191 | ||
|
|
3aec8087f7 | ||
|
|
39ff51ef96 | ||
|
|
033a9482fc | ||
|
|
017017623f | ||
|
|
4b53a532bd | ||
|
|
6df296da47 | ||
|
|
9f5d04de27 | ||
|
|
c11b91d32a | ||
|
|
e266902ba9 | ||
|
|
b919eb23ab | ||
|
|
22a9e783c9 | ||
|
|
d4e75165dd | ||
|
|
73daf191ae | ||
|
|
329471e7e3 | ||
|
|
644e2c334f | ||
|
|
16d925e588 | ||
|
|
0daa6d3f7b | ||
|
|
e3b3e8b8c6 | ||
|
|
ddef1ea89c | ||
|
|
8ddf136928 | ||
|
|
893329d9c6 | ||
|
|
cb091c8a54 | ||
|
|
043f9813ef | ||
|
|
717891bee9 | ||
|
|
508f47f940 | ||
|
|
e4c0623cf7 | ||
|
|
4cf9813449 | ||
|
|
d44fb6bedd | ||
|
|
f2dd725eff | ||
|
|
3646a9c259 | ||
|
|
8c497efb46 | ||
|
|
a82aa87850 | ||
|
|
68e5909c96 | ||
|
|
4c2857b6e8 | ||
|
|
6f2275e8cb | ||
|
|
d42d7a89fb | ||
|
|
cba8b56cb5 | ||
|
|
ece009f556 | ||
|
|
53ed1f1a2c | ||
|
|
22a09f3e7d | ||
|
|
dda36f4eb3 | ||
|
|
8c6c089363 | ||
|
|
997a902ae4 | ||
|
|
defcfed272 | ||
|
|
0f1b157bda | ||
|
|
7188879567 | ||
|
|
c753d40f6c | ||
|
|
706436b638 | ||
|
|
13aab4d410 | ||
|
|
a06fd63690 | ||
|
|
07369b9784 | ||
|
|
415e28b471 | ||
|
|
f62d0530ec | ||
|
|
d12561aae9 | ||
|
|
d1ab38e57e | ||
|
|
27bc03d452 | ||
|
|
9cff76f110 | ||
|
|
a5a487caf8 | ||
|
|
9cfef8c337 | ||
|
|
46e2679f82 | ||
|
|
08383ed22d | ||
|
|
3602d59125 | ||
|
|
c72b3a870e | ||
|
|
078bab405b | ||
|
|
e57269ed57 | ||
|
|
05e0fb8fbe | ||
|
|
500ba88781 | ||
|
|
7f941840cb | ||
|
|
b4670f12a5 | ||
|
|
2a4eb0bcc2 | ||
|
|
f2b64c1aaa | ||
|
|
05b9e825bb | ||
|
|
187b4632e6 | ||
|
|
ce2b8a8d1a | ||
|
|
d3517f03f6 | ||
|
|
0583bf6df0 | ||
|
|
d446075239 | ||
|
|
e5949504b7 | ||
|
|
2ce1ba37a1 | ||
|
|
6d4ffdd8b4 | ||
|
|
8ff2e1f16a | ||
|
|
09b05ea3fb | ||
|
|
90a0478d0b | ||
|
|
ecb3a18206 | ||
|
|
e580109dd6 | ||
|
|
9561049668 | ||
|
|
d4dd646bf4 | ||
|
|
4cb25a5bcf | ||
|
|
82e90f7b94 | ||
|
|
760c008f5b | ||
|
|
54f8d4f308 | ||
|
|
0de0135619 | ||
|
|
dfdba25ea0 | ||
|
|
f61942e5cb | ||
|
|
33d4ad76ca | ||
|
|
53c8e63a09 | ||
|
|
9aa5584c9c | ||
|
|
24f66c9f88 | ||
|
|
fa548a4c32 | ||
|
|
10bc2c0d1a | ||
|
|
5188f2f2c9 | ||
|
|
1019f6272e | ||
|
|
dbd34c3254 | ||
|
|
20af78e50b | ||
|
|
96151a54fb | ||
|
|
ccf66905e7 | ||
|
|
ced56ed83f | ||
|
|
790234775f | ||
|
|
aac8933186 | ||
|
|
73edfd90a6 | ||
|
|
a168f885d9 | ||
|
|
50136fe314 | ||
|
|
6308352f90 | ||
|
|
ba5ee34d83 | ||
|
|
849f15ceee | ||
|
|
5979fc1d3d | ||
|
|
81f98e2da1 | ||
|
|
50edffee47 | ||
|
|
41330b15dc | ||
|
|
f5125b76bc | ||
|
|
ad663d2df9 | ||
|
|
9faa85a1c3 | ||
|
|
cb98b1326d | ||
|
|
e9f8e150e7 | ||
|
|
a90f648d5e | ||
|
|
8cd5f7c185 | ||
|
|
bedd3767ce | ||
|
|
63ee764a9b | ||
|
|
3dcebe8a9e | ||
|
|
232685919f | ||
|
|
b7f59db03c | ||
|
|
9e5d016017 | ||
|
|
8c8f51a84b | ||
|
|
de146f9aaf | ||
|
|
25bb0bfa22 | ||
|
|
00eeb86332 | ||
|
|
25ab20bcb4 | ||
|
|
5c588b2424 | ||
|
|
e77cda938c | ||
|
|
99793c0a12 | ||
|
|
178beee476 | ||
|
|
b4402b72ac | ||
|
|
23a35d9707 | ||
|
|
b925b8e74d | ||
|
|
6742dd0585 | ||
|
|
769b1b8110 | ||
|
|
f6040ab43c | ||
|
|
11b7ade355 | ||
|
|
7d39283aec | ||
|
|
f21afdc5f1 | ||
|
|
a864223f4a | ||
|
|
b7a74e25bc | ||
|
|
219091eb5e | ||
|
|
74a89e6610 | ||
|
|
371ce30462 | ||
|
|
1b65cbd3db | ||
|
|
b63ba110b8 | ||
|
|
5f4f447539 | ||
|
|
809c8f64f6 | ||
|
|
beaf20d256 | ||
|
|
644376a356 | ||
|
|
db757f20b3 | ||
|
|
961d9dcbdb | ||
|
|
0b971b6ddb | ||
|
|
ffdd6ff806 | ||
|
|
2b2315032d | ||
|
|
dd47d46f43 | ||
|
|
079e45eb52 | ||
|
|
55aea69948 | ||
|
|
fc5c2f40ba | ||
|
|
f599391419 | ||
|
|
ab0e1b3203 | ||
|
|
1dda8bff5e | ||
|
|
1db6efa9c8 | ||
|
|
d4774d398e | ||
|
|
04f5bda70a | ||
|
|
f11c8727d9 | ||
|
|
9e120cd44b | ||
|
|
bf42372eef | ||
|
|
5e9bf61d3f | ||
|
|
3a7ae7c5f2 | ||
|
|
be42b8d4cb | ||
|
|
28a01862d0 | ||
|
|
3b4f285fea | ||
|
|
58855ada97 | ||
|
|
5d0b23ee3f | ||
|
|
9cd980d9e6 | ||
|
|
d516ecb20c | ||
|
|
d91e0358f3 | ||
|
|
6931b88e40 | ||
|
|
d0735e1d8e | ||
|
|
506b95107c | ||
|
|
02422cc8f2 | ||
|
|
f19948f993 | ||
|
|
ebd884e654 | ||
|
|
a2866ce6f3 | ||
|
|
4c6c6ffb16 | ||
|
|
525a6defd9 | ||
|
|
1623ef65bb | ||
|
|
76bff73121 | ||
|
|
22077af137 | ||
|
|
a26f9bc1e7 | ||
|
|
56c7b3d00f | ||
|
|
fcc3560df4 | ||
|
|
f79f2733a0 | ||
|
|
4c0eb7dcc1 | ||
|
|
35677d0c55 | ||
|
|
2206c5c84c | ||
|
|
0d22f683fe | ||
|
|
001c8f2b01 | ||
|
|
463b4f2442 | ||
|
|
f437d8370e | ||
|
|
29cebc8d3d | ||
|
|
5704dd9f8b | ||
|
|
3d150b63dd | ||
|
|
7ca21d5260 | ||
|
|
111e4d8478 | ||
|
|
0aac9405ee | ||
|
|
f8b89129a3 | ||
|
|
5b8c642d8f | ||
|
|
6c1ddf58ed | ||
|
|
f32b27d2e3 | ||
|
|
288800eafc | ||
|
|
cb9c94cf9d | ||
|
|
18a1d4c5c6 | ||
|
|
ef4292b559 | ||
|
|
6a5e053da1 | ||
|
|
33caf1809a | ||
|
|
1d803d4b51 | ||
|
|
2ad318b57c | ||
|
|
5923585584 | ||
|
|
fccdffb9cc | ||
|
|
181c988706 | ||
|
|
51ac6c839e | ||
|
|
3a3666312f | ||
|
|
c433e3f80f | ||
|
|
6b86b3b6e7 | ||
|
|
d61d9994e3 | ||
|
|
a10b6fb173 | ||
|
|
f6e8e3d107 | ||
|
|
fb46a88a0f | ||
|
|
a8f1711890 | ||
|
|
d671a4bb32 | ||
|
|
cf5b962349 | ||
|
|
07f155d82e | ||
|
|
c6cea2fb4e | ||
|
|
7ee453648c | ||
|
|
b0826e2d7b | ||
|
|
bd6e4a351b | ||
|
|
209da19566 | ||
|
|
b342cfed3a | ||
|
|
a404612174 | ||
|
|
4dd66eed8e | ||
|
|
1ccacf60b2 | ||
|
|
6d88baebc7 | ||
|
|
e52cfc84b4 | ||
|
|
98003e26b1 | ||
|
|
3d4352ba0f | ||
|
|
c060f2322b | ||
|
|
734e4e5f3f | ||
|
|
b21a0caa4f | ||
|
|
c55563696e | ||
|
|
b8043d2dfc | ||
|
|
3942b584bf | ||
|
|
dce63842bb | ||
|
|
8c1630c638 | ||
|
|
f6db23b469 | ||
|
|
8c85955e6b | ||
|
|
86e3df0e5f | ||
|
|
fd805399aa | ||
|
|
6ac726e198 | ||
|
|
73480a3e1c | ||
|
|
12656ee9a1 | ||
|
|
fff11d7fc9 | ||
|
|
dba5de1882 | ||
|
|
6201809810 | ||
|
|
99d38f2d61 | ||
|
|
80e06b8ffc | ||
|
|
93e69c94a2 | ||
|
|
1f02321e27 | ||
|
|
37a53e7466 | ||
|
|
254c7fe951 | ||
|
|
02a35f94a7 | ||
|
|
39099106c6 | ||
|
|
4f54442947 | ||
|
|
1c4ce56b0f | ||
|
|
44f4a1c3bf | ||
|
|
d652eb5cee | ||
|
|
f7731f4f5e | ||
|
|
94cd2ce690 | ||
|
|
156164b5fd | ||
|
|
1bad81ca86 | ||
|
|
ff2d467d42 | ||
|
|
352e9033b6 | ||
|
|
60ffe5ab9b | ||
|
|
51c21fe639 | ||
|
|
bfabd63460 | ||
|
|
e7a03bb187 | ||
|
|
9083d5f88d | ||
|
|
e4cf94606c | ||
|
|
df4498f845 | ||
|
|
7ec7a5f27c | ||
|
|
4e21004c42 | ||
|
|
ddb8c28c38 | ||
|
|
eb8c1530a5 | ||
|
|
70623df899 | ||
|
|
6d11f3345f | ||
|
|
3941066ba5 | ||
|
|
53a020a23a | ||
|
|
2e52ff9e9d | ||
|
|
5445955a77 | ||
|
|
338e18870f | ||
|
|
6516b96ee0 | ||
|
|
0c28c5b087 | ||
|
|
b23cbbf925 | ||
|
|
4f299b72f7 | ||
|
|
ef04c2a826 | ||
|
|
b42649c777 | ||
|
|
5474099916 | ||
|
|
983a56b89b | ||
|
|
6fe7f3c553 | ||
|
|
df84a2be9a | ||
|
|
b3a752ef34 | ||
|
|
6ab5f093d5 | ||
|
|
6673b79738 | ||
|
|
053757f135 | ||
|
|
c17bef2cce | ||
|
|
36c04edb9f | ||
|
|
4f7fd3bb7b | ||
|
|
1983d3422b | ||
|
|
8cb132f492 | ||
|
|
a57806b054 | ||
|
|
25da8376ca | ||
|
|
30a3daa6af | ||
|
|
fc73dc5bbc | ||
|
|
9b43dd4fae | ||
|
|
e9f449e680 | ||
|
|
2e7a31f872 | ||
|
|
2d546627e9 | ||
|
|
f0cb948046 | ||
|
|
31f73057bf | ||
|
|
6aa7a2abef | ||
|
|
e649c79bb7 | ||
|
|
34b37116cf | ||
|
|
4e7f33b9e2 | ||
|
|
1e2582f043 | ||
|
|
63d4e0489f | ||
|
|
f1ab46d517 | ||
|
|
4608c057d5 | ||
|
|
0cb3aee803 | ||
|
|
b39458d2ee | ||
|
|
ca90220d18 | ||
|
|
45c0343f45 | ||
|
|
eb166737e3 | ||
|
|
a58ee144ac | ||
|
|
54260ca325 | ||
|
|
cb7eebaed0 | ||
|
|
6eeb708e4d | ||
|
|
1c49469b33 | ||
|
|
d18cd59c05 | ||
|
|
960cb27eef | ||
|
|
cdab6076cc | ||
|
|
be9cf34462 | ||
|
|
1e0fdf8abc | ||
|
|
2ef8803dfd | ||
|
|
1d2896886e | ||
|
|
e52351dcbf | ||
|
|
0a001d505d | ||
|
|
55072c529a | ||
|
|
66e22a2c87 | ||
|
|
07b505aa32 | ||
|
|
3c86cf854e | ||
|
|
334c15ff71 | ||
|
|
1aecf8da6b | ||
|
|
9cea76e4ef | ||
|
|
e74fb2f5b0 | ||
|
|
6c0b6ca670 | ||
|
|
9492daf9bc | ||
|
|
f346ce04f5 | ||
|
|
b465500afa | ||
|
|
adf969f6ff | ||
|
|
6462f855c9 | ||
|
|
3721742327 | ||
|
|
910771708a | ||
|
|
7ba361e2c9 | ||
|
|
cc2e0a7c7c | ||
|
|
77efcf7137 | ||
|
|
1298a07838 | ||
|
|
bcbe1aaaf5 | ||
|
|
0c351f4864 | ||
|
|
066237de08 | ||
|
|
ec3902021e | ||
|
|
6928fd71a9 | ||
|
|
035334125b | ||
|
|
70f37c55fd | ||
|
|
670ace6a8d | ||
|
|
ebaccbccca | ||
|
|
652f4e693b | ||
|
|
555d31cca6 | ||
|
|
534b20feda | ||
|
|
24f59b1855 | ||
|
|
c0df1dd4aa | ||
|
|
ba63627ebf | ||
|
|
da636ed17d | ||
|
|
4e12bcc378 | ||
|
|
6cec3b36de | ||
|
|
3e7247891d | ||
|
|
6bb2f311e2 | ||
|
|
0c5fc6d7fd | ||
|
|
8fae676551 | ||
|
|
379f1af89e | ||
|
|
5e128583ac | ||
|
|
23c27f9e07 | ||
|
|
c36509095a | ||
|
|
f85a05e454 | ||
|
|
067e4d15f3 | ||
|
|
65d1330d35 | ||
|
|
39312a075e | ||
|
|
96173ad431 | ||
|
|
c0957ce173 | ||
|
|
fdc168a476 | ||
|
|
3d76b8e1c1 | ||
|
|
1296fce72a | ||
|
|
c34b1a9ec5 | ||
|
|
13db2fd7b2 | ||
|
|
511d1973eb | ||
|
|
dfd26e4843 | ||
|
|
d2c3ecdbcd | ||
|
|
1249bef93e | ||
|
|
71b642a2ba | ||
|
|
f170c116bb | ||
|
|
4ed2f29e30 | ||
|
|
d0731a4bf4 | ||
|
|
d165733242 | ||
|
|
a91f0b5c3b | ||
|
|
cc84bf2de3 | ||
|
|
7e0bc1e33a | ||
|
|
1b94b919fe | ||
|
|
d68ad5af04 | ||
|
|
fcbbb93bb6 | ||
|
|
b3b8d3c086 | ||
|
|
676140f5c8 | ||
|
|
20757efc7e | ||
|
|
4d615057fe | ||
|
|
9bdb5aea87 | ||
|
|
d67c435132 | ||
|
|
18de911a7f | ||
|
|
39b1871e4d | ||
|
|
eecac0e37f | ||
|
|
3e0352c586 | ||
|
|
485f6b5ac2 | ||
|
|
3e715bbcc9 | ||
|
|
b881c3b908 | ||
|
|
9e29d4c815 | ||
|
|
f09d9b63de | ||
|
|
0588c2f605 | ||
|
|
b216c63c13 | ||
|
|
1f5f429fc4 | ||
|
|
3b62b5ec5d | ||
|
|
2f24dcfc7d | ||
|
|
fda4e954eb | ||
|
|
cc285afd59 | ||
|
|
b186561355 | ||
|
|
c9ca79aac8 | ||
|
|
6b4e6d0c63 | ||
|
|
c60ae13b5f | ||
|
|
4e1fedb236 | ||
|
|
3c9aa65ca3 | ||
|
|
f7446ba934 | ||
|
|
9c6d374b95 | ||
|
|
365e2e5b4b | ||
|
|
4064429047 | ||
|
|
62dd28d91c | ||
|
|
b3005f828d | ||
|
|
99e7c65907 | ||
|
|
6828ccd7f1 | ||
|
|
36447ba1c0 | ||
|
|
c694505885 | ||
|
|
807c6ce09e | ||
|
|
9fc3de8502 | ||
|
|
be00465e67 | ||
|
|
5c33a85341 | ||
|
|
e55d7e4f72 | ||
|
|
9b0eb0a9f1 | ||
|
|
53c0a52788 | ||
|
|
89b535ac0f | ||
|
|
c2eb300e21 | ||
|
|
eea077e57e | ||
|
|
f725291e14 | ||
|
|
bec1256727 | ||
|
|
9407992312 | ||
|
|
c7e02ad2ee | ||
|
|
ac12aa7ede | ||
|
|
cec5f45459 | ||
|
|
ab73afe17a | ||
|
|
dc4e93ad56 | ||
|
|
2f557ae3a5 | ||
|
|
be25e372a3 | ||
|
|
3f937764cb | ||
|
|
0b9748dff6 | ||
|
|
b9929dc682 | ||
|
|
034981cd3d | ||
|
|
79e464bf90 | ||
|
|
b015b5b724 | ||
|
|
f5515cb95f | ||
|
|
16bbd892aa | ||
|
|
32d9a2c10b | ||
|
|
9967859f42 | ||
|
|
eac0b3e7bb | ||
|
|
8177a1ed0a | ||
|
|
17308dc5f3 | ||
|
|
67301e07e2 | ||
|
|
315db00e83 | ||
|
|
692a1bc369 | ||
|
|
f76d8e47a8 | ||
|
|
6adfcb3513 | ||
|
|
bce2242528 | ||
|
|
f0597ef0c4 | ||
|
|
10aab8a733 | ||
|
|
fb75a487fc | ||
|
|
37306c8d22 | ||
|
|
4ffa8784a2 | ||
|
|
74a01691e3 | ||
|
|
49c415f023 | ||
|
|
b2e175ba8c | ||
|
|
724d26379c | ||
|
|
0a62089df0 | ||
|
|
a93de07fb9 | ||
|
|
64367a01dd | ||
|
|
5644ef66af | ||
|
|
061a13e46e | ||
|
|
dcc7b2970f | ||
|
|
d509b2608f | ||
|
|
193af893ee | ||
|
|
acd105e61b | ||
|
|
a300b73d56 | ||
|
|
5168fb7717 | ||
|
|
945ffeda34 | ||
|
|
66adc397bf | ||
|
|
82a6b4245c | ||
|
|
ae5ea46d7f | ||
|
|
b5022529ac | ||
|
|
49c471d816 | ||
|
|
445aa89e4f | ||
|
|
787941857d | ||
|
|
6a2b494713 | ||
|
|
04d7c47f4c | ||
|
|
9c94ea58b4 | ||
|
|
9f65696fcc | ||
|
|
93cc7f0232 | ||
|
|
7e4bd4a0a7 | ||
|
|
f63482b587 | ||
|
|
95b21943ee | ||
|
|
d1400f48c3 | ||
|
|
53d545eeef | ||
|
|
afeb2de412 | ||
|
|
83d6ef7301 | ||
|
|
d2e93c4927 | ||
|
|
fd67bb8e67 | ||
|
|
da6c2b5503 | ||
|
|
57d43f916f | ||
|
|
10a6dbd080 | ||
|
|
0498671cd4 | ||
|
|
b2eeff9697 | ||
|
|
a8146e61f3 | ||
|
|
6a23f73d94 | ||
|
|
b9bcb8f979 | ||
|
|
0416fbdcc4 | ||
|
|
064d125a1c | ||
|
|
92bb646977 | ||
|
|
2bb80956dd | ||
|
|
a798713919 | ||
|
|
6a0e4c9b21 | ||
|
|
dea9df2a3b | ||
|
|
09dbcf3bea | ||
|
|
5e17b01077 | ||
|
|
1189259a55 | ||
|
|
5d573a7aa1 | ||
|
|
aaae3150c4 | ||
|
|
f4eac833ed | ||
|
|
5f81b73a49 | ||
|
|
7b9aaddb5b | ||
|
|
ae5d2b7908 | ||
|
|
b0444ae338 | ||
|
|
615f66c820 | ||
|
|
bec0c4b4d0 | ||
|
|
4526845fd1 | ||
|
|
0f53220122 | ||
|
|
37817fcaf8 | ||
|
|
9e14733478 | ||
|
|
93e7c8aecf | ||
|
|
6478dd7da8 | ||
|
|
72a66c1d5b | ||
|
|
d4df405862 | ||
|
|
ccf1e8bc3c | ||
|
|
82a01edc54 | ||
|
|
9eaac52b73 | ||
|
|
edae64b1c7 | ||
|
|
171d0c8629 | ||
|
|
a69997d31e | ||
|
|
31e4400c66 | ||
|
|
05020241aa | ||
|
|
e8c24aeaf9 | ||
|
|
ddfcb235cc | ||
|
|
94fc172366 | ||
|
|
a8feb8ed32 | ||
|
|
e5c6da5a39 | ||
|
|
b8158fadfc | ||
|
|
8b32cf42cb | ||
|
|
9c5bcd7321 | ||
|
|
04f09b6042 | ||
|
|
9a509778d3 | ||
|
|
5dafea405d | ||
|
|
be97efb791 | ||
|
|
0ecbb73419 | ||
|
|
daeb06f7b7 | ||
|
|
01804daf24 | ||
|
|
bde9cc7cea | ||
|
|
6a16063f7d | ||
|
|
88fca396d4 | ||
|
|
e5cb190693 | ||
|
|
6ee6dbade5 | ||
|
|
b70252468a | ||
|
|
26c8505d9e | ||
|
|
df91d1e632 | ||
|
|
be61904a1e | ||
|
|
b7247f8d52 | ||
|
|
4191ede176 | ||
|
|
fc4d7a0bde | ||
|
|
84fd00c566 | ||
|
|
e402200b87 | ||
|
|
aede4dd9c5 | ||
|
|
9b961edb36 | ||
|
|
b7ee0173ec | ||
|
|
3e927b4e58 | ||
|
|
1c8a00943c | ||
|
|
f00797de5c | ||
|
|
b501d35b55 | ||
|
|
0e883675fc | ||
|
|
c295e47f76 | ||
|
|
fb87e4b1f2 | ||
|
|
66e56849a4 | ||
|
|
3631cd5026 | ||
|
|
485ccf4007 | ||
|
|
30a4494af2 | ||
|
|
568a1a11fd | ||
|
|
75b3d51b39 | ||
|
|
3d0bac1f49 | ||
|
|
578bdf9e67 | ||
|
|
a7f88d24a1 | ||
|
|
fa0fd5f21f | ||
|
|
dfc5537107 | ||
|
|
5b98f139d1 | ||
|
|
862239019a | ||
|
|
983649a6cb | ||
|
|
660b578ab3 | ||
|
|
594daa9cf8 | ||
|
|
ebb48f3ee8 | ||
|
|
4a2b30d08b | ||
|
|
0cee496270 | ||
|
|
2c1dadf712 | ||
|
|
6fc89a04de | ||
|
|
4994f66e9c | ||
|
|
91bab1c274 | ||
|
|
daf1a67dc2 | ||
|
|
e44c46bcd2 | ||
|
|
57cf86a79f | ||
|
|
1ef663531b | ||
|
|
becdcbd5a7 | ||
|
|
d3bdc8edbc | ||
|
|
ffc825e348 | ||
|
|
9db64a95b6 | ||
|
|
c5a707a7f5 | ||
|
|
b2d3138220 | ||
|
|
405514fd6b | ||
|
|
efa2d99bf4 | ||
|
|
8d816cdb0f | ||
|
|
918bd0befd | ||
|
|
bf2a08555b | ||
|
|
cf97123512 | ||
|
|
6aca70f0d1 | ||
|
|
963e319345 | ||
|
|
b21021501c | ||
|
|
638e2d87eb | ||
|
|
d94393c764 | ||
|
|
faa95a0f8c | ||
|
|
047e22571e | ||
|
|
ed95542b67 | ||
|
|
9c283112ed | ||
|
|
fbfe6590b7 | ||
|
|
2824873511 | ||
|
|
dc9ac5b58a | ||
|
|
ee69eb03d4 | ||
|
|
c040603786 | ||
|
|
275bb0b131 |
No files matched your search
+3
-2
@@ -14,7 +14,7 @@
|
||||
},
|
||||
"rules": {
|
||||
"strict": 0,
|
||||
"no-undef": 2,
|
||||
"no-undef": 0,
|
||||
"accessor-pairs": 2,
|
||||
"comma-dangle": [2, "always-multiline"],
|
||||
"consistent-return": 2,
|
||||
@@ -121,7 +121,8 @@
|
||||
"allowIsBoardAdmin": true,
|
||||
"allowIsBoardMember": true,
|
||||
"allowIsBoardMemberByCard": true,
|
||||
"allowIsBoardMemberNonComment": true,
|
||||
"allowIsBoardMemberCommentOnly": true,
|
||||
"allowIsBoardMemberNoComments": true,
|
||||
"Emoji": true,
|
||||
"Checklists": true,
|
||||
"Settings": true,
|
||||
|
||||
@@ -1,8 +1,15 @@
|
||||
## Issue
|
||||
|
||||
Add these issues to elsewhere:
|
||||
- LDAP: https://github.com/wekan/wekan-ldap/issues
|
||||
- Snap: https://github.com/wekan/wekan-snap/issues
|
||||
|
||||
Other Wekan issues can be added here.
|
||||
|
||||
**Server Setup Information**:
|
||||
|
||||
* Did you test in newest Wekan?:
|
||||
* For new Wekan install, did you configure root-url correctly https://github.com/wekan/wekan/wiki/Settings ?
|
||||
* Wekan version:
|
||||
* If this is about old version of Wekan, what upgrade problem you have?:
|
||||
* Operating System:
|
||||
@@ -13,6 +20,9 @@
|
||||
* ROOT_URL environment variable http(s)://(subdomain).example.com(/suburl):
|
||||
|
||||
**Problem description**:
|
||||
- *REQUIRED: Add recorded animated gif about how it works currently, and screenshot mockups how it should work*
|
||||
- *REQUIRED: Add recorded animated gif about how it works currently, and screenshot mockups how it should work. Use peek to record animgif in Linux https://github.com/phw/peek*
|
||||
- *Explain steps how to reproduce*
|
||||
- *Attach log files in .zip file)*
|
||||
- *In webbrowser, what does show Right Click / Inspect / Console ? Chrome shows more detailed info than Firefox.*
|
||||
- *If using Snap, what does show command `sudo snap logs wekan.wekan` ?*
|
||||
- *If using Docker, what does show command `sudo docker logs wekan-app` ?*
|
||||
- *If logs are very long, attach them in .zip file*
|
||||
+3
-2
@@ -4,11 +4,11 @@
|
||||
*.sublime-workspace
|
||||
tmp/
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
.vscode/
|
||||
.idea/
|
||||
.build/*
|
||||
packages/kadira-flow-router/
|
||||
packages/meteor-useraccounts-core/
|
||||
packages/
|
||||
package-lock.json
|
||||
**/parts/
|
||||
**/stage
|
||||
@@ -16,3 +16,4 @@ package-lock.json
|
||||
**/*.snap
|
||||
snap/.snapcraft/
|
||||
.idea
|
||||
.DS_Store
|
||||
+9
-5
@@ -6,7 +6,7 @@
|
||||
meteor-base@1.2.0
|
||||
|
||||
# Build system
|
||||
ecmascript@0.9.0
|
||||
ecmascript
|
||||
stylus@2.513.13
|
||||
standard-minifier-css@1.3.5
|
||||
standard-minifier-js@2.2.0
|
||||
@@ -31,6 +31,7 @@ kenton:accounts-sandstorm
|
||||
service-configuration@1.0.11
|
||||
useraccounts:unstyled
|
||||
useraccounts:flow-routing
|
||||
salleman:accounts-oidc
|
||||
|
||||
# Utilities
|
||||
check@1.2.5
|
||||
@@ -49,7 +50,6 @@ kadira:dochead
|
||||
meteorhacks:picker
|
||||
meteorhacks:subs-manager
|
||||
mquandalle:autofocus
|
||||
mquandalle:moment
|
||||
ongoworks:speakingurl
|
||||
raix:handlebar-helpers
|
||||
tap:i18n
|
||||
@@ -63,7 +63,6 @@ mousetrap:mousetrap
|
||||
mquandalle:jquery-textcomplete
|
||||
mquandalle:jquery-ui-drag-drop-sort
|
||||
mquandalle:mousetrap-bindglobal
|
||||
mquandalle:perfect-scrollbar
|
||||
peerlibrary:blaze-components@=0.15.1
|
||||
perak:markdown
|
||||
templates:tabs
|
||||
@@ -81,8 +80,13 @@ staringatlights:fast-render
|
||||
mixmax:smart-disconnect
|
||||
accounts-password@1.5.0
|
||||
cfs:gridfs
|
||||
browser-policy
|
||||
eluck:accounts-lockout
|
||||
rzymek:fullcalendar
|
||||
momentjs:moment@2.22.2
|
||||
atoy40:accounts-cas
|
||||
browser-policy-framing
|
||||
mquandalle:moment
|
||||
msavin:usercache
|
||||
wekan:wekan-ldap
|
||||
wekan:accounts-cas
|
||||
wekan-scrollbar
|
||||
mquandalle:perfect-scrollbar
|
||||
+10
-3
@@ -1,5 +1,6 @@
|
||||
3stack:presence@1.1.2
|
||||
accounts-base@1.4.0
|
||||
accounts-oauth@1.1.15
|
||||
accounts-password@1.5.0
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
@@ -9,7 +10,6 @@ aldeed:simple-schema@1.5.3
|
||||
alethes:pages@1.8.6
|
||||
allow-deny@1.1.0
|
||||
arillo:flow-router-helpers@0.5.2
|
||||
atoy40:accounts-cas@0.0.2
|
||||
audit-argument-checks@1.0.7
|
||||
autoupdate@1.3.12
|
||||
babel-compiler@6.24.7
|
||||
@@ -19,9 +19,7 @@ binary-heap@1.0.10
|
||||
blaze@2.3.2
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.3.1
|
||||
browser-policy@1.1.0
|
||||
browser-policy-common@1.0.11
|
||||
browser-policy-content@1.1.0
|
||||
browser-policy-framing@1.1.0
|
||||
caching-compiler@1.1.9
|
||||
caching-html-compiler@1.1.2
|
||||
@@ -119,8 +117,11 @@ mquandalle:jquery-ui-drag-drop-sort@0.2.0
|
||||
mquandalle:moment@1.0.1
|
||||
mquandalle:mousetrap-bindglobal@0.0.1
|
||||
mquandalle:perfect-scrollbar@0.6.5_2
|
||||
msavin:usercache@1.0.0
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@2.2.33
|
||||
oauth@1.2.1
|
||||
oauth2@1.2.0
|
||||
observe-sequence@1.0.16
|
||||
ongoworks:speakingurl@1.1.0
|
||||
ordered-dict@1.0.9
|
||||
@@ -142,6 +143,8 @@ reload@1.1.11
|
||||
retry@1.0.9
|
||||
routepolicy@1.0.12
|
||||
rzymek:fullcalendar@3.8.0
|
||||
salleman:accounts-oidc@1.0.9
|
||||
salleman:oidc@1.0.9
|
||||
service-configuration@1.0.11
|
||||
session@1.1.7
|
||||
sha@1.0.9
|
||||
@@ -176,4 +179,8 @@ useraccounts:unstyled@1.14.2
|
||||
verron:autosize@3.0.8
|
||||
webapp@1.4.0
|
||||
webapp-hashing@1.0.9
|
||||
wekan-scrollbar@3.1.3
|
||||
wekan:accounts-cas@0.1.0
|
||||
wekan:wekan-ldap@0.0.2
|
||||
yasaricli:slugify@0.0.7
|
||||
zimme:active-route@2.3.2
|
||||
+964
-1
@@ -1,4 +1,967 @@
|
||||
# v1.23 2018-07-30
|
||||
# v2.02 2019-01-22 Wekan release
|
||||
|
||||
This release adds the following new features with Apache I-CLA, thanks to bentiss:
|
||||
|
||||
- [Add per card color: Card / Hamburger menu / Set Color](https://github.com/wekan/wekan/pull/2116) with [color picker](https://github.com/wekan/wekan/pull/2117);
|
||||
- [OpenAPI and generating of REST API Docs](https://github.com/wekan/wekan/pull/1965);
|
||||
- [Allow to retrieve full export of board from the REST API](https://github.com/wekan/wekan/pull/2118) through generic authentication.
|
||||
When the board is big, retrieving individual cards is heavy for both the server and the number of requests.
|
||||
Allowing the API to directly call on export and then treat the data makes the whole process smoother.
|
||||
|
||||
and adds the following new features with Apache I-CLA, thanks to xet7 and bentiss:
|
||||
|
||||
- [Translate and add color names to IFTTT Rules dropdown](https://github.com/wekan/wekan/commit/44e4df2492b95226f1297e7f556d61b1afaab714), thanks to xet7.
|
||||
[Fix to this feature blank item](https://github.com/wekan/wekan/pull/2119), thanks to bentiss.
|
||||
|
||||
and adds these updates:
|
||||
|
||||
- Update translations. Thanks to translators.
|
||||
- Added missing translation for 'days'. Thanks to Chartman123.
|
||||
|
||||
and fixes these typos;
|
||||
|
||||
- Fix typo, changelog year to 2019. Thanks to xorander00.
|
||||
- Fix License to 2019. Thanks to ajRiverav.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v2.01 2019-01-06 Wekan release
|
||||
|
||||
Update translations. Thanks to translators.
|
||||
|
||||
# v2.00 2019-01-04 Wekan release
|
||||
|
||||
Update translations. Thanks to translators.
|
||||
|
||||
# v1.99 2019-01-04 Wekan release
|
||||
|
||||
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
|
||||
extra directories when searching. xet7 uses this a lot when developing. Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.98 2019-01-01 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Add optional Nginx reverse proxy config to docker-compose.yml and nginx directory. Thanks to MyTheValentinus.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- docker-compose.yml back to MongoDB 3.2.21 because 3.2.22 MongoDB container does not exist yet. Thanks to xet7.
|
||||
- [Mobile fixes](https://github.com/wekan/wekan/pull/2084), thanks to hupptechnologies:
|
||||
- Move home button / avatar bar from bottom to top. So at top first is home button / avatar, then others.
|
||||
- When clicking Move Card, go to correct page position. Currently it's at empty page position, and there is
|
||||
need to scroll page up to see Move Card options. It should work similarly like Copy Card, that is visible.
|
||||
- Also check that other buttons go to visible page.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.97 2018-12-26 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Upgrade to Node 8.15.0 and MongoDB 3.2.22.
|
||||
- Stacksmith: back to Meteor 1.6.x based Wekan, because Meteor 1.8.x based is currently broken.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.96 2018-12-24 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Combine all docker-compose.yml files](https://github.com/wekan/wekan/commit/3f948ba49ba7266c436ff138716bdcae9e879903).
|
||||
|
||||
and tries to fix following bugs:
|
||||
|
||||
- Revert "Improve authentication", remove login dropdown and "Default Authentication Method" that were added
|
||||
in Wekan v1.95 because login did not work with email address.
|
||||
It was later found that login did work with username, so later this could be fixed and added back.
|
||||
- Fixes to docker-compose.yml so that Wekan Meteor 1.6.x version would work.
|
||||
Most likely Meteor 1.8.x version is still broken.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.95 2018-12-21 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Improve authentication](https://github.com/wekan/wekan/pull/2065): remove login dropdown,
|
||||
and add setting `DEFAULT_AUTHENTICATION_METHOD=ldap` or
|
||||
`sudo snap set wekan default-authentication-method='ldap'`. Thanks to Akuket. Closes wekan/wekan-ldap#31
|
||||
NOTE: This was reverted in Wekan v1.96 because login did not work with email address.
|
||||
It was later found that login did work with username, so later this could be fixed and added back.
|
||||
- [Drag handles and long press on mobile when using desktop mode of mobile
|
||||
browser](https://github.com/wekan/wekan/pull/2067). Thanks to hupptechnologies.
|
||||
- Upgrade to node v8.14.1 . Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.94 2018-12-18 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Admin Panel / Layout / Custom HTML after `<body>` start, and Custom HTML before `</body>` end.
|
||||
In progress, does not work yet. Thanks to xet7.
|
||||
- Add Bitnami Stacksmith. In progress test version, that does work, but is not released yet. Thanks to j-fuentes.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.93 2018-12-16 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- In translations, only show name "Wekan" in Admin Panel Wekan version.
|
||||
Elsewhere use general descriptions for whitelabeling.
|
||||
|
||||
Thanks to GitHub user xet7 and translators for their contributions.
|
||||
|
||||
# v1.92 2018-12-16 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix [Popup class declares member name _current but use current instead](https://github.com/wekan/wekan/issues/2059). Thanks to peishaofeng.
|
||||
- Fix [Card scrollbar ignores mousewheel](https://github.com/wekan/wekan-scrollbar/commit/94a40da51627c6322afca50a5b1f4aa55c7ce7bf). Thanks to rinnaz and xet7. Closes #2058
|
||||
- Fix [favicon paths for non-suburl cases](https://github.com/wekan/wekan/commit/c1733fc89c4c73a1ab3f4054d0a9ebff7741a804). Thanks to xet7. Related #1692
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.91 2018-12-15 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Add back mquandalle:perfect-scrollbar package](https://github.com/wekan/wekan/issues/2057)
|
||||
so that Firefox and Chrome stop complaining in browser dev tools console.
|
||||
|
||||
Thanks to GitHub users uusijani and xet7 for their contributions.
|
||||
|
||||
# v1.90 2018-12-15 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Remove not working duplicate saveMailServerInfo](https://github.com/wekan/wekan/commit/ab031d9da134aa13490a26dbe97ad2d7d01d534a),
|
||||
to remove error from browser dev tools console.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.89 2018-12-15 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Admin Panel / Layout / Custom Product Name [now changes webpage title](https://github.com/wekan/wekan/commit/dbb1a86ca377e551063cc04c5189fad4aa9148c0).
|
||||
Related #1196
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.88 2018-12-14 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix: [Scrollbar used](https://github.com/wekan/wekan/issues/2056) [remote file from CDN](https://github.com/MaazAli/Meteor-Malihu-Custom-Scrollbar/blob/master/jquery.mCustomScrollbar.js#L50),
|
||||
so forked package to https://github.com/wekan/wekan-scrollbar and included
|
||||
non-minified file locally to Wekan, so that using scrollbar works without direct connection
|
||||
to Internet. Wekan should not load any external files by default, as was case before
|
||||
new scrollbar, and is again now [after this fix](https://github.com/wekan/wekan/commit/c546464d9f56117a8bf580512cd62fc1102559c3).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.87 2018-12-13 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix Reference error.
|
||||
|
||||
Thanks to GitHub user Akuket for contributions.
|
||||
|
||||
# v1.86 2018-12-13 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix [Cannot login with new LDAP account when auto-registration disabled (request invitation code)](https://github.com/wekan/wekan-ldap/issues/29);
|
||||
- Fix [Unable to create new account from LDAP](https://github.com/wekan/wekan-ldap/issues/32).
|
||||
|
||||
Thanks to GitHub user Akuket for contributions.
|
||||
|
||||
# v1.85 2018-12-09 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix [Clicking the scrollbar closes the card on Chrome](https://github.com/wekan/wekan/issues/1404)
|
||||
by changing [mquandalle:perfect-scrollbar to malihu-jquery-custom-scrollbar](https://github.com/wekan/wekan/pull/2050).
|
||||
that works also when clicking scrollbar in Chrome. Also added back required packages that were removed in PR.
|
||||
|
||||
Thanks to GitHub users hupptechnologies and xet7 for their contributions.
|
||||
|
||||
# v1.84 2018-12-07 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix 2/8: IFTTT Rule action/trigger ["Remove all members from the card"](https://github.com/wekan/wekan/issues/1972).
|
||||
|
||||
Thanks to GitHub user BurakTuran9 for contributions.
|
||||
|
||||
# v1.83 2018-12-06 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix 1/8: IFTTT Rule action/trigger [When a checklist is completed](https://github.com/wekan/wekan/issues/1972).
|
||||
And partial incomplete fix to when all of checklist is set as uncompleted. Help in fixing welcome.
|
||||
|
||||
Thanks to GitHub users BurakTuran9 and xet7 for their contributions.
|
||||
|
||||
# v1.82 2018-12-05 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Partially #2045 revert [Improve authentication](https://github.com/wekan/wekan/issues/2016),
|
||||
adding back password/LDAP dropdown, because login did now work.
|
||||
NOTE: This was added in v1.71, reverted at v1.73 because login did not work, added back at v1.79,
|
||||
and then reverted partially at v1.82 because login did not work.
|
||||
Related LDAP logout timer does not work yet.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.81 2018-12-04 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Remove extra commas `,` and add missing backslash `\`.
|
||||
Maybe after that login, logout and CORS works.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
Related #2045,
|
||||
related wekan/wekan-snap#69
|
||||
|
||||
# v1.80 2018-12-03 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Upgrade Node from v8.12 to v8.14
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Revert non-working architectures that were added at v1.79, so now Wekan is just amd64 as before.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.79 2018-12-03 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Improve authentication, removing Login password/LDAP dropdown](https://github.com/wekan/wekan/issues/2016).
|
||||
NOTE: This was added in v1.71, then reverted at v1.73 because login did not work, and after fix added back at v1.79.
|
||||
Thanks to Akuket.
|
||||
- Thanks to xet7:
|
||||
- Build snap also on i386, armhf and arm64. Ignore if it fails. More fixes will be added later.
|
||||
- Add CORS https://enable-cors.org/server_meteor.html to Standalone Wekan settings.
|
||||
- Add missing LDAP and TIMER environment variables.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Fix: Message box for deleting subtask unreachable.
|
||||
Thanks to hupptechnologies. Closes #1800
|
||||
- Fix wrong dates in ChangeLog. Thanks to kelvinhammond.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.78 2018-11-20 Wekan release
|
||||
|
||||
- Update translations (de).
|
||||
|
||||
# v1.77 2018-11-20 Wekan release
|
||||
|
||||
- Update version number. Trying to get Snap automatic review working, so that
|
||||
it would accept new Wekan release.
|
||||
|
||||
# v1.76 2018-11-20 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Add [LDAP_FULLNAME_FIELD](https://github.com/wekan/wekan-ldap/issues/10) to
|
||||
[configs](https://github.com/wekan/wekan/commit/8e3f53021775069dba125efd4b7200d0d70a1ed1)
|
||||
and other options that were not in all config files. Thanks to alkemyst and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Fix: When saving Custom Layout, save also SMTP settings. Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.75 2018-11-20 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Admin Panel / Layout: Hide Logo: Yes / No. This does hide Wekan logo on Login page and Board page. Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Snap database-list-backups command](https://github.com/wekan/wekan-snap/issues/26). Thanks to WaryWolf.
|
||||
|
||||
Thanks to above GitHub users for their contributions.
|
||||
|
||||
# v1.74.1 2018-11-18 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Full Name from LDAP server via environment variable](https://github.com/wekan/wekan-ldap/pull/18).
|
||||
|
||||
Thanks to GitHub user alkemyst for contributions.
|
||||
|
||||
# v1.74 2018-11-17 Wekan release
|
||||
|
||||
- Update version number to get this released to snap. Thanks to xet7.
|
||||
|
||||
# v1.73 2018-11-17 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Revert Improve authentication to [fix Login failure](https://github.com/wekan/wekan/issues/2004).
|
||||
NOTE: This was added in v1.71, then reverted at v1.73 because login did not work, and after fix added back at v1.79.
|
||||
|
||||
Thanks to GitHub users Broxxx3 and xet7 for their contributions.
|
||||
|
||||
# v1.72 2018-11-17 Wekan release
|
||||
|
||||
- Update translations (fi).
|
||||
|
||||
# v1.71 2018-11-17 Wekan release
|
||||
|
||||
This release adds the following new features and bugfixes:
|
||||
|
||||
- Add languages, thanks to translators:
|
||||
- Danish
|
||||
- Swahili / Kiswahili
|
||||
- Rename Recycle Bin to Archive. Thanks to xet7.
|
||||
- Update readme for clarity. Thanks to xet7.
|
||||
- [Improve authentication](https://github.com/wekan/wekan/pull/2003), thanks to Akuket:
|
||||
- Removing the select box: Now it just checks the user.authenticationMethod value to choose the authentication method.
|
||||
- Adding an option to choose the default authentication method with env var.
|
||||
- Bug fix that allowed a user to connect with the password method while his user.authenticationMethod is "ldap" for example.
|
||||
- Adding a server-side method which allows disconnecting a user after a delay defined by env vars.
|
||||
- NOTE: This was added in v1.71, then reverted at v1.73 because login did not work, and after fix added back at v1.79.
|
||||
- [Improve shell scripts](https://github.com/wekan/wekan/pull/2002). Thanks to warnerjon12.
|
||||
|
||||
Thanks to above GitHub users and translators for their contributions.
|
||||
|
||||
# v1.70 2018-11-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Auto create Custom Field to all cards. Show Custom Field Label on
|
||||
minicard](https://github.com/wekan/wekan/pull/1987).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Some fixes to Wekan import, thanks to xet7:
|
||||
- isCommentOnly and isNoComments are now optional
|
||||
- Turn off import error checking, so something is imported anyway, and import does not stop at error.
|
||||
- Now most of Sandstorm export do import to Standalone Wekan, but some of imported cards, dates etc are missing.
|
||||
- Sandstorm Import Wekan board warning messages are now translateable. But bug "Board not found" still exists.
|
||||
- LDAP: Added INTERNAL_LOG_LEVEL. Fix lint and ldap group filter options. Thanks to Akuket.
|
||||
|
||||
Thanks to above mentioned GitHub users for their contributions.
|
||||
|
||||
# v1.69 2018-11-03 Wekan release
|
||||
|
||||
- Update translations.
|
||||
|
||||
# v1.68 2018-11-03 Wekan release
|
||||
|
||||
- Update translations.
|
||||
|
||||
# v1.67 2018-11-03 Wekan release
|
||||
|
||||
This release adds the following new features to all Wekan platforms:
|
||||
|
||||
- Add Hindi language. Thanks to saurabharch.
|
||||
|
||||
and hides the following features at Sandstorm:
|
||||
|
||||
- Hide Linked Card and Linked Board on Sandstorm, because they are only
|
||||
useful when having multiple boards, and at Sandstorm
|
||||
there is only one board per grain. Thanks to ocdtrekkie and xet7. Closes #1982
|
||||
|
||||
Thanks to above mentioned GitHub users for their contributions.
|
||||
|
||||
# v1.66 2018-10-31 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- docker-compose.yml and docker-compose-build.yml, thanks to xet7:
|
||||
- Remove single quotes, because settings are quoted automatically.
|
||||
- Comment out most settings that have default values.
|
||||
- Fix typos in CHANGELOG.md, thanks to Hillside502 and loginKing.
|
||||
- [Fix typo about ldaps](https://github.com/wekan/wekan/pull/1980).
|
||||
Documentation said to set LDAP_ENCRYPTION to true if we want to use
|
||||
ldaps, but the code in wekan-ldap does not check if it is set to true,
|
||||
but if the value equals to 'ssl' instead. Thanks to imkwx.
|
||||
|
||||
Thanks to above mentioned GitHub users for their contributions.
|
||||
|
||||
# v1.65 2018-10-25 Wekan release
|
||||
|
||||
This release adds the [following new features](https://github.com/wekan/wekan/pull/1967), with Apache I-CLA:
|
||||
|
||||
- UI: list headers: show the card count smaller in grey color below list name
|
||||
- UI: lists: only output the number of cards for each swimlane
|
||||
|
||||
Thanks to GitHub user bentiss for contributions.
|
||||
|
||||
# v1.64.2 2018-10-25 Wekan Edge release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Additional fix to [Impossible to connect to LDAP if UserDN contain space(s)](https://github.com/wekan/wekan/issues/1970).
|
||||
|
||||
Thanks to GitHub users Akuket and xet7 for their contributions.
|
||||
|
||||
# v1.64.1 2018-10-25 Wekan Edge release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Impossible to connect to LDAP if UserDN contain space(s)](https://github.com/wekan/wekan/issues/1970).
|
||||
|
||||
Thanks to GitHub users Akuket and xet7 for their contributions.
|
||||
|
||||
# v1.64 2018-10-24 Wekan release
|
||||
|
||||
- Update translations.
|
||||
|
||||
# v1.63 2018-10-24 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
REST API: [Allow to remove the full list of labels/members through the API](https://github.com/wekan/wekan/pull/1968), with Apache I-CLA:
|
||||
|
||||
- [Models: Cards: an empty string in members or label deletes the list](https://github.com/wekan/wekan/commit/e5949504b7ed42ad59742d2a0aa001fe6c762873).
|
||||
There is currently no way to remove all members or all labels attached
|
||||
to a card. If an empty string is provided, we can consider as a hint to
|
||||
remove the list from the card.
|
||||
- [Models: Cards: allow singletons to be assigned to members and labelIds](https://github.com/wekan/wekan/commit/2ce1ba37a1d0a09f8b3d2a1db4c8a11d1f98caa0).
|
||||
If we need to set only one member or one label, the data provided will
|
||||
not give us an array, but the only element as a string.
|
||||
We need to detect that and convert the parameter into an array.
|
||||
|
||||
Thanks to GitHub user bentiss for contributions.
|
||||
|
||||
# v1.62 2018-10-24 Wekan release
|
||||
|
||||
- Fix missing dropdown arrow on Chrome. Thanks to xet7. Closes #1964
|
||||
|
||||
# v1.61 2018-10-24 Wekan release
|
||||
|
||||
- Fix lint error. Thanks to xet7.
|
||||
|
||||
# v1.60 2018-10-24 Wekan release
|
||||
|
||||
- Update translations.
|
||||
|
||||
# v1.59 2018-10-24 Wekan release
|
||||
|
||||
This release adds the beginning of following new features:
|
||||
|
||||
- Custom Product Name in Admin Panel / Layout. In Progress, setting does not affect change UI yet. Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Fix LDAP User Search Scope. Thanks to Vnimos and Akuket. Related #119
|
||||
- Fix Save Admin Panel SMTP password. Thanks to saurabharch and xet7. Closes #1856
|
||||
|
||||
Thanks to above mentioned GitHub users for contributions.
|
||||
|
||||
# v1.58 2018-10-23 Wekan release
|
||||
|
||||
This release adds the [following new features and fixes](https://github.com/wekan/wekan/pull/1962), with Apache I-CLA:
|
||||
|
||||
- Also export the cards created with an older wekan instance (without linked cards) (related to #1873);
|
||||
- Fix the GET customFields API that was failing;
|
||||
- Allow to directly overwrite the members of cards and boards with a PUT call (this avoids to do multiple calls to add and remove users);
|
||||
- Allow to change the swimlane of a card from the API.
|
||||
|
||||
Thanks to GitHub user bentiss for contributions.
|
||||
|
||||
# v1.57 2018-10-23 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Merge edge into stable. This brings LDAP, Rules, Role "No Comments", etc.
|
||||
- Go back to Meteor 1.6.x and MongoDB 3.2.21 that works in Snap etc.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.55.1 2018-10-16 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Automatically close the sidebar](https://github.com/wekan/wekan/pull/1954).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [LDAP: Include missing LDAP PR so that LDAP works](https://github.com/wekan/wekan-ldap/pull/6);
|
||||
- [Improve notifications](https://github.com/wekan/wekan/pull/1948);
|
||||
- [Fix deleting Custom Fields, removing broken references](https://github.com/wekan/wekan/issues/1872);
|
||||
- [Fix vertical text for swimlanes in IE11](https://github.com/wekan/wekan/issues/1798);
|
||||
- [Update broke the ability to mute notifications](https://github.com/wekan/wekan/pull/1954).
|
||||
|
||||
Thanks to GitHub users Akuket, Clement87 and tomodwyer for their contributions.
|
||||
|
||||
# v1.53.9 2018-10-11 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- docker-compose.yml in this Edge branch now works with Wekan Edge + Meteor 1.8.1-beta.0 + MongoDB 4.0.3;
|
||||
- [Snap is still broken](https://forum.snapcraft.io/t/how-to-connect-to-localhost-mongodb-in-snap-apparmor-prevents/7793/2). Please use latest Snap release on Edge branch, until this is fixed.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.8 2018-10-10 Wekan Edge release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- Try to fix Docker.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.7 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Try MongoDB 4.0.3
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.6 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add LDAP to Snap Help](https://github.com/wekan/wekan/commit/809c8f64f69721d51b7d963248a77585867fac53).
|
||||
|
||||
and tries to fix the following bugs:
|
||||
|
||||
- Try to fix snap.
|
||||
|
||||
Thanks to GitHub users Akuket and xet7 for their contributions.
|
||||
|
||||
# v1.53.5 2018-10-10 Wekan Edge relase
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- Try to fix snap.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.4 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Upgrade Hoek](https://github.com/wekan/wekan/commit/0b971b6ddb1ffc4adad6b6b09ae7f42dd376fe2c).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.3 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Upgrade](https://github.com/wekan/wekan/issues/1522) to [Meteor](https://blog.meteor.com/meteor-1-8-erases-the-debts-of-1-7-77af4c931fe3) [1.8.1-beta.0](https://github.com/meteor/meteor/issues/10216).
|
||||
with [these](https://github.com/wekan/wekan/commit/079e45eb52a0f62ddb6051bf2ea80fac8860d3d5)
|
||||
[commits](https://github.com/wekan/wekan/commit/dd47d46f4341a8c4ced05749633f783e88623e1b). So now it's possible to use MongoDB 2.6 - 4.0.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.2 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add LDAP package to Docker and Snap](https://github.com/wekan/wekan/commit/f599391419bc7422a6ead52cdefc7d380e787897).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.53.1 2018-10-10 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [LDAP](https://github.com/wekan/wekan/commit/288800eafc91d07f859c4f59588e0b646137ccb9).
|
||||
Please test and [add info about bugs](https://github.com/wekan/wekan/issues/119);
|
||||
- [Add LDAP support and authentications dropdown menu on login page](https://github.com/wekan/wekan/pull/1943);
|
||||
- [REST API: Get cards by swimlane id](https://github.com/wekan/wekan/pull/1944). Please [add docs](https://github.com/wekan/wekan/wiki/REST-API-Swimlanes).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [OpenShift: Drop default namespace value and duplicate WEKAN_SERVICE_NAME parameter.commit](https://github.com/wekan/wekan/commit/fcc3560df4dbcc418c63470776376238af4f6ddc);
|
||||
- [Fix Card URL](https://github.com/wekan/wekan/pull/1932);
|
||||
- [Add info about root-url to GitHub issue template](https://github.com/wekan/wekan/commit/4c0eb7dcc19ca9ae8c5d2d0276e0d024269de236);
|
||||
- [Feature rules: fixes and enhancements](https://github.com/wekan/wekan/pull/1936).
|
||||
|
||||
Thanks to GitHub users Akuket, Angtrim, dcmcand, lberk, maximest-pierre, InfoSec812, schulz and xet7 for their contributions.
|
||||
|
||||
# v1.52.1 2018-10-02 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- REST API: [Add member with role to board. Remove member from board](https://github.com/wekan/wekan/commit/33caf1809a459b136b671f7061f08eb5e8d5e920).
|
||||
[Docs](https://github.com/wekan/wekan/wiki/REST-API-Role). Related to [role issue](https://github.com/wekan/wekan/issues/1861).
|
||||
|
||||
and reverts previous change:
|
||||
|
||||
- OAuth2: [Revert Oidc preferred_username back to username](https://github.com/wekan/wekan/commit/33caf1809a459b136b671f7061f08eb5e8d5e920).
|
||||
This [does not fix or break anything](https://github.com/wekan/wekan/issues/1874#issuecomment-425179291),
|
||||
Oidc already works with [doorkeeper](https://github.com/doorkeeper-gem/doorkeeper-provider-app).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.51.2 2018-09-30 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [REST API: Change role of board member](https://github.com/wekan/wekan/commit/51ac6c839ecf2226b2a81b0d4f985d3b942f0938).
|
||||
Docs: https://github.com/wekan/wekan/wiki/REST-API-Role
|
||||
|
||||
Thanks to GitHub users entrptaher and xet7 for their contributions.
|
||||
|
||||
# v1.51.1 2018-09-28 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add CAS with attributes](https://github.com/wekan/wekan/commit/bd6e4a351b984b032e17c57793a70923eb17d8f5);
|
||||
- [Move Add Board button to top left, so there is no need to scroll to bottom when there is a lot of boards](https://github.com/wekan/wekan/commit/fb46a88a0f01f7f74ae6b941dd6f2060e020f09d).
|
||||
|
||||
Thanks to GitHub users ppoulard and xet7 for their contributions.
|
||||
|
||||
# v1.50.3 2018-09-23 Wekan Edge release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- [Remove "Fix Cannot setup mail server via snap variables"](https://github.com/wekan/wekan/commit/6d88baebc7e297ffdbbd5bb6971190b18f79d21f)
|
||||
to see does Wekan Snap start correctly after removing it.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.50.2 2018-09-23 Wekan Edge release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- Build Wekan and release again, to see does it work.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.50.1 2018-09-22 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Change from Node v8.12.0 prerelease to use official Node v8.12.0](https://github.com/wekan/wekan/commit/7ec7a5f27c381e90f3da6bddc3773ed87b1c1a1f).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Dockerfile Meteor install by changing tar to bsdtar](https://github.com/wekan/wekan/commit/1bad81ca86ca87c02148764cc03a3070882a8a33);
|
||||
- Add [npm-debug.log and .DS_Store](https://github.com/wekan/wekan/commit/44f4a1c3bf8033b6b658703a0ccaed5fdb183ab4) to .gitignore;
|
||||
- [Add more debug log requirements to GitHub issue template](https://github.com/wekan/wekan/commit/1c4ce56b0f18e00e01b54c7059cbbf8d3e196154);
|
||||
- [Add default Wekan Snap MongoDB bind IP 127.0.0.1](https://github.com/wekan/wekan/commit/6ac726e198933ee41c129d22a7118fcfbf4ca9a2);
|
||||
- [Fix Feature Rules](https://github.com/wekan/wekan/pull/1909);
|
||||
- [Fix Cannot setup mail server via snap variables](https://github.com/wekan/wekan/issues/1906);
|
||||
- [Try to fix OAuth2: Change oidc username to preferred_username](https://github.com/wekan/wekan/commit/734e4e5f3ff2c3dabf94c0fbfca561db066c4565).
|
||||
|
||||
Thanks to GitHub users Angtrim, maurice-schleussinger, suprovsky and xet7 for their contributions.
|
||||
|
||||
# v1.49.1 2018-09-17 Wekan Edge release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Change from Node v8.12.0 prerelease to use official Node v8.12.0.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.49 2018-09-17 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Fix lint errors.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.48 2018-09-17 Wekan release
|
||||
|
||||
This release removes the following new features:
|
||||
|
||||
- Remove IFTTT rules, until they are fixed.
|
||||
- Remove OAuth2, until it is fixed.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.47 2018-09-16 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [IFTTT Rules](https://github.com/wekan/wekan/pull/1896). Useful to automate things like
|
||||
[adding labels, members, moving card, archiving them, checking checklists etc](https://github.com/wekan/wekan/issues/1160).
|
||||
Please test and report bugs. Later colors need to be made translatable.
|
||||
|
||||
Thanks to GitHub users Angtrim and xet7 for their contributions.
|
||||
|
||||
# v1.46 2018-09-15 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Upgrade MongoDB to 3.2.21](https://github.com/wekan/wekan/commit/0cb3aee803781e4241c38a3e1e700703d063035a);
|
||||
- [Add source-map-support](https://github.com/wekan/wekan/issues/1889);
|
||||
- [Allow Announcement to be markdown](https://github.com/wekan/wekan/issues/1892).
|
||||
Note: xet7 did not yet figure out how to keep announcement on one line
|
||||
when markdown was added, so now Font Awesome icons are above and below.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Turn of http/2 in Caddyfile](https://github.com/wekan/wekan/commit/f1ab46d5178b6fb7e9c4e43628eec358026d287a)
|
||||
so that Firefox Inspect Console does not [show errors about wss](https://github.com/wekan/wekan/issues/934)
|
||||
websocket config. Chrome web console supports http/2.
|
||||
Note: If you are already using Caddy and have modified your Caddyfile, you need to edit your Caddyfile manually.
|
||||
- [Partially fix: Cannot move card from one swimline to the other if moving in the same list](https://github.com/wekan/wekan/issues/1887);
|
||||
- [Fix: Linking cards from empty board is possible and makes current board not load anymore](https://github.com/wekan/wekan/issues/1885).
|
||||
|
||||
Thanks to GitHub users andresmanelli, HLFH and xet7 for their contributions.
|
||||
|
||||
# v1.45 2018-09-09 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix lint error](https://github.com/wekan/wekan/commit/45c0343f45b4cfc06d83cf357ffb50d6fca2f23b).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.44 2018-09-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- REST API: [Add startAt/dueAt/endAt etc](https://github.com/wekan/wekan/commit/1e0fdf8abc10130ea3c50b13ae97396223ce7fa9).
|
||||
Docs at https://github.com/wekan/wekan/wiki/REST-API-Cards
|
||||
- [Fix cards export and add customFields export](https://github.com/wekan/wekan/pull/1886).
|
||||
|
||||
Thanks to GitHub users ymeramees and xet7 for their contributions.
|
||||
|
||||
# v1.43 2018-09-06 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix "No Comments" permission on Wekan and Trello import](https://github.com/wekan/wekan/commit/0a001d505d81961e6bd6715d885fffee0adb702d).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.42 2018-09-06 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- REST API: [Create board options to be modifiable](https://github.com/wekan/wekan/commit/9cea76e4efaacaebcb2e9f0690dfeb4ef6d62527),
|
||||
like permissions, public/private board - now private by default,
|
||||
and board background color.
|
||||
Docs at https://github.com/wekan/wekan/wiki/REST-API-Boards
|
||||
- [Add swimlaneId in activity. Create default swimlaneId in API](https://github.com/wekan/wekan/pull/1876).
|
||||
|
||||
Thanks to GitHub users andresmanelli and xet7 for their contributions.
|
||||
|
||||
# v1.41 2018-09-05 Wekan release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- [Try to fix Wekan Sandstorm API](https://github.com/wekan/wekan/issues/1279#issuecomment-418440401).
|
||||
|
||||
Thanks to GitHub users ocdtrekkie and xet7 for their contributions.
|
||||
|
||||
# v1.40 2018-09-04 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add permission "No comments"](https://github.com/wekan/wekan/commit/77efcf71376d3da6c19ad1a4910567263e83c0ca).
|
||||
It is like normal user, but [does not show comments and activities](https://github.com/wekan/wekan/issues/1861).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.39 2018-08-29 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Only allow ifCanModify users to add dates on cards](https://github.com/wekan/wekan/pull/1867).
|
||||
|
||||
Thanks to GitHub user rjevnikar for contributions.
|
||||
|
||||
# v1.38 2018-08-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- Add [msavin:userCache](https://github.com/msavin/userCache) to speedup Wekan.
|
||||
See [meteor forums post](https://forums.meteor.com/t/introducing-a-new-approach-to-meteor-user-this-simple-trick-can-save-you-millions-of-database-requests/45336/7).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Delete Board](https://github.com/wekan/wekan/commit/534b20fedac9162d2d316bd74eff743d636f2b3d).
|
||||
|
||||
Thanks to GitHub users msavin, rjevnikar and xet7 for their contributions.
|
||||
|
||||
# v1.37 2018-08-28 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Add Missing Index on cards.parentId since Swimlane integration
|
||||
to speedup Wekan](https://github.com/wekan/wekan/issues/1863);
|
||||
- [Update OpenShift template to add Route and parameterize](https://github.com/wekan/wekan/pull/1865);
|
||||
- [Fix typos in Wekan snap help](https://github.com/wekan/wekan/commit/0c5fc6d7fd899a6bc67a446ab43e53290d8571e4).
|
||||
|
||||
Thanks to GitHub users Clement87, InfoSec812 and xet7 for their contributions.
|
||||
|
||||
# v1.36 2018-08-25 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [OAuth2 Login on Standalone Wekan](https://github.com/wekan/wekan/wiki/OAuth2). For example, Rocket.Chat can provide OAuth2 login to Wekan.
|
||||
Also, if you have Rocket.Chat using LDAP/SAML/Google/etc for logging into Rocket.Chat, then same users can login to Wekan when
|
||||
Rocket.Chat is providing OAuth2 login to Wekan.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Move labels back to original place at minicard](https://github.com/wekan/wekan/issues/1842);
|
||||
- [Fix typos in security documentation](https://github.com/wekan/wekan/pull/1857).
|
||||
|
||||
Thanks to GitHub users hever, salleman33, tlevine and xet7 for their contributions.
|
||||
|
||||
# v1.35 2018-08-23 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
Add Caddy plugins:
|
||||
- [http.filter](https://caddyserver.com/docs/http.filter)
|
||||
for changing Wekan UI on the fly, for example custom logo,
|
||||
or changing to all different CSS file to have custom theme;
|
||||
- [http.ipfilter](https://caddyserver.com/docs/http.ipfilter)
|
||||
to block requests by ip address;
|
||||
- [http.realip](https://caddyserver.com/docs/http.realip)
|
||||
for showing real X-Forwarded-For IP to behind proxy;
|
||||
- Turn off Caddy telemetry.
|
||||
|
||||
Add configuring webhooks:
|
||||
- [Make the attributes that the webhook sends configurable](https://github.com/wekan/wekan/pull/1852).
|
||||
|
||||
Thanks to Caddy contributors, and Github users omarsy and xet7 for their contributions.
|
||||
|
||||
# v1.34 2018-08-22 Wekan release
|
||||
|
||||
This release add the following new features:
|
||||
|
||||
- [Add Favicon for pinned tab on Safari browser](https://github.com/wekan/wekan/issues/1795).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Restored SMTP settings at Admin Panel, and disabled showing password](https://github.com/wekan/wekan/issues/1790);
|
||||
- [Move color labels on minicard to bottom of minicard](https://github.com/wekan/wekan/issues/1842);
|
||||
- [Fix and improve linked cards](https://github.com/wekan/wekan/pull/1849);
|
||||
- [Allow Sandstorm to serve Wekan HTTP API](https://github.com/wekan/wekan/pull/1851);
|
||||
|
||||
Thanks to GitHub users andresmanelli, ocdtrekkie, therampagerado, woodyart and xet7 for their contributions.
|
||||
|
||||
# v1.33 2018-08-16 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Change default value of label ids](https://github.com/wekan/wekan/pull/1837).
|
||||
|
||||
Thanks to GitHub user omarsy for contributions.
|
||||
|
||||
# v1.32 2018-08-16 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Content Policy: Allow inline scripts, otherwise there is errors in browser/inspect/console](https://github.com/wekan/wekan/commit/807c6ce09e4b5d49049d343d73bbca24fa84d527);
|
||||
- [Use only framing policy, not all of content policy](https://github.com/wekan/wekan/commit/b3005f828dbf69bdf174d4bcd7654310fa9e0968);
|
||||
- [Set default matomo settings to disabled](https://github.com/wekan/wekan/commit/807c6ce09e4b5d49049d343d73bbca24fa84d527);
|
||||
- Fix [hidden](https://github.com/wekan/wekan/commit/be00465e67931f2a5655ed47f6e075ed1c589f54)
|
||||
[system](https://github.com/wekan/wekan/commit/9fc3de8502919f9aeb18c9f8ea3b0678b66ce176) [messages](https://github.com/wekan/wekan/issues/1830);
|
||||
- Fix [Requested By](https://github.com/wekan/wekan/commit/e55d7e4f72a4b425c4aca5ba04a7be1fc642649b) and
|
||||
[Assigned By](https://github.com/wekan/wekan/commit/5c33a8534186920be642be8e2ac17743a54f16db) [fields](https://github.com/wekan/wekan/issues/1830);
|
||||
- [Fix Date and Time Formats are only US in every language](https://github.com/wekan/wekan/commit/b3005f828dbf69bdf174d4bcd7654310fa9e0968).
|
||||
|
||||
Thanks to GitHub users andresmanelli and xet7 for their contributions.
|
||||
|
||||
# v1.31 2018-08-14 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Export of Board does not work on Docker](https://github.com/wekan/wekan/issues/1820).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.30 2018-08-14 Wekan release
|
||||
|
||||
This release add the following new features:
|
||||
|
||||
- [When Content Policy is enabled, allow one URL to have iframe that embeds Wekan](https://github.com/wekan/wekan/commit/b9929dc68297539a94d21950995e26e06745a263);
|
||||
- [Add option to turn off Content Policy](https://github.com/wekan/wekan/commit/b9929dc68297539a94d21950995e26e06745a263);
|
||||
- [Allow always in Wekan markdown `<img src="any-image-url-here">`](https://github.com/wekan/wekan/commit/b9929dc68297539a94d21950995e26e06745a263).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Import from Trello error 400](https://github.com/wekan/wekan/commit/2f557ae3a558c654cc6f3befff22f5ee4ea6c3d9).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.29 2018-08-12 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Revert Fix lint errors, that caused breakage](https://github.com/wekan/wekan/commit/b015b5b7240f5fb5a715843dce5d35907345eb4a).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.28 2018-08-12 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix lint errors](https://github.com/wekan/wekan/commit/f5515cb95fc93882e5e1098d6043267b9260b9d7).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.27 2018-08-12 Wekan release
|
||||
|
||||
This release add the following new features:
|
||||
|
||||
- [Linked Cards and Linked Boards](https://github.com/wekan/wekan/pull/1592).
|
||||
|
||||
Thanks to GitHub user andresmanelli for contributions.
|
||||
|
||||
# v1.26 2018-08-09 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Set WITH_API=true setting on Sandstorm, and so that export works](https://github.com/wekan/wekan/commit/a300b73d56750a1a5645767d375be60839314e84);
|
||||
- [Set Matomo blank settings on Sandstorm](https://github.com/wekan/wekan/commit/acd105e61b9dca5a78354047bbc23b0a01e71d8c).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v1.25 2018-08-09 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix showing only the cards of the current board in calendar view](https://github.com/wekan/wekan/pull/1822).
|
||||
|
||||
Thanks to GitHub user Yanonix for contributions.
|
||||
|
||||
# v1.24 2018-08-09 Wekan release
|
||||
|
||||
This release add the following new features:
|
||||
|
||||
- [Update node to v8.12.0 prerelease build](https://github.com/wekan/wekan/commit/04d7c47f4ca990311079be8dd6dc383448ee342f).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Enable Wekan API by default, so that Export Board to JSON works](https://github.com/wekan/wekan/commit/b2eeff96977592deaeb23a8171fc3b13f8c6c5dc);
|
||||
- [Fix the flagging of dates](https://github.com/wekan/wekan/pull/1814);
|
||||
- [Use new WITH_API and Matomo env variables at Dockerfile](https://github.com/wekan/wekan/issues/1820);
|
||||
- For OpenShift compliance, [change](https://github.com/wekan/wekan/commit/53d545eeef7e796bd910f7cce666686ca05de544)
|
||||
[run user](https://github.com/wekan/wekan/pull/1816)
|
||||
and [Docker internal port to 8080](https://github.com/wekan/wekan/commit/95b21943ee7a9fa5a27efe5276307febc2fbad94).
|
||||
|
||||
Thanks to GitHub users rjevnikar, tdemaret, xadagaras and xet7 for their contributions.
|
||||
|
||||
# v1.23 2018-07-30 Wekan release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
|
||||
+170
-17
@@ -10,33 +10,161 @@ ARG NPM_VERSION
|
||||
ARG FIBERS_VERSION
|
||||
ARG ARCHITECTURE
|
||||
ARG SRC_PATH
|
||||
ARG WITH_API
|
||||
ARG MATOMO_ADDRESS
|
||||
ARG MATOMO_SITE_ID
|
||||
ARG MATOMO_DO_NOT_TRACK
|
||||
ARG MATOMO_WITH_USERNAME
|
||||
ARG BROWSER_POLICY_ENABLED
|
||||
ARG TRUSTED_URL
|
||||
ARG WEBHOOKS_ATTRIBUTES
|
||||
ARG OAUTH2_ENABLED
|
||||
ARG OAUTH2_CLIENT_ID
|
||||
ARG OAUTH2_SECRET
|
||||
ARG OAUTH2_SERVER_URL
|
||||
ARG OAUTH2_AUTH_ENDPOINT
|
||||
ARG OAUTH2_USERINFO_ENDPOINT
|
||||
ARG OAUTH2_TOKEN_ENDPOINT
|
||||
ARG LDAP_ENABLE
|
||||
ARG LDAP_PORT
|
||||
ARG LDAP_HOST
|
||||
ARG LDAP_BASEDN
|
||||
ARG LDAP_LOGIN_FALLBACK
|
||||
ARG LDAP_RECONNECT
|
||||
ARG LDAP_TIMEOUT
|
||||
ARG LDAP_IDLE_TIMEOUT
|
||||
ARG LDAP_CONNECT_TIMEOUT
|
||||
ARG LDAP_AUTHENTIFICATION
|
||||
ARG LDAP_AUTHENTIFICATION_USERDN
|
||||
ARG LDAP_AUTHENTIFICATION_PASSWORD
|
||||
ARG LDAP_LOG_ENABLED
|
||||
ARG LDAP_BACKGROUND_SYNC
|
||||
ARG LDAP_BACKGROUND_SYNC_INTERVAL
|
||||
ARG LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED
|
||||
ARG LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS
|
||||
ARG LDAP_ENCRYPTION
|
||||
ARG LDAP_CA_CERT
|
||||
ARG LDAP_REJECT_UNAUTHORIZED
|
||||
ARG LDAP_USER_SEARCH_FILTER
|
||||
ARG LDAP_USER_SEARCH_SCOPE
|
||||
ARG LDAP_USER_SEARCH_FIELD
|
||||
ARG LDAP_SEARCH_PAGE_SIZE
|
||||
ARG LDAP_SEARCH_SIZE_LIMIT
|
||||
ARG LDAP_GROUP_FILTER_ENABLE
|
||||
ARG LDAP_GROUP_FILTER_OBJECTCLASS
|
||||
ARG LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE
|
||||
ARG LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE
|
||||
ARG LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT
|
||||
ARG LDAP_GROUP_FILTER_GROUP_NAME
|
||||
ARG LDAP_UNIQUE_IDENTIFIER_FIELD
|
||||
ARG LDAP_UTF8_NAMES_SLUGIFY
|
||||
ARG LDAP_USERNAME_FIELD
|
||||
ARG LDAP_FULLNAME_FIELD
|
||||
ARG LDAP_MERGE_EXISTING_USERS
|
||||
ARG LDAP_SYNC_USER_DATA
|
||||
ARG LDAP_SYNC_USER_DATA_FIELDMAP
|
||||
ARG LDAP_SYNC_GROUP_ROLES
|
||||
ARG LDAP_DEFAULT_DOMAIN
|
||||
ARG LOGOUT_WITH_TIMER
|
||||
ARG LOGOUT_IN
|
||||
ARG LOGOUT_ON_HOURS
|
||||
ARG LOGOUT_ON_MINUTES
|
||||
ARG CORS
|
||||
ARG DEFAULT_AUTHENTICATION_METHOD
|
||||
|
||||
# Set the environment variables (defaults where required)
|
||||
# DOES NOT WORK: paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
|
||||
# ENV BUILD_DEPS="paxctl"
|
||||
ENV BUILD_DEPS="apt-utils gnupg gosu wget curl bzip2 build-essential python git ca-certificates gcc-7"
|
||||
ENV NODE_VERSION ${NODE_VERSION:-v8.11.3}
|
||||
ENV METEOR_RELEASE ${METEOR_RELEASE:-1.6.0.1}
|
||||
ENV USE_EDGE ${USE_EDGE:-false}
|
||||
ENV METEOR_EDGE ${METEOR_EDGE:-1.5-beta.17}
|
||||
ENV NPM_VERSION ${NPM_VERSION:-latest}
|
||||
ENV FIBERS_VERSION ${FIBERS_VERSION:-2.0.0}
|
||||
ENV ARCHITECTURE ${ARCHITECTURE:-linux-x64}
|
||||
ENV SRC_PATH ${SRC_PATH:-./}
|
||||
ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential python python3 python3-distutils git ca-certificates gcc-7" \
|
||||
NODE_VERSION=v8.15.0 \
|
||||
METEOR_RELEASE=1.6.0.1 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
NPM_VERSION=latest \
|
||||
FIBERS_VERSION=2.0.0 \
|
||||
ARCHITECTURE=linux-x64 \
|
||||
SRC_PATH=./ \
|
||||
WITH_API=true \
|
||||
MATOMO_ADDRESS="" \
|
||||
MATOMO_SITE_ID="" \
|
||||
MATOMO_DO_NOT_TRACK=true \
|
||||
MATOMO_WITH_USERNAME=false \
|
||||
BROWSER_POLICY_ENABLED=true \
|
||||
TRUSTED_URL="" \
|
||||
WEBHOOKS_ATTRIBUTES="" \
|
||||
OAUTH2_ENABLED=false \
|
||||
OAUTH2_CLIENT_ID="" \
|
||||
OAUTH2_SECRET="" \
|
||||
OAUTH2_SERVER_URL="" \
|
||||
OAUTH2_AUTH_ENDPOINT="" \
|
||||
OAUTH2_USERINFO_ENDPOINT="" \
|
||||
OAUTH2_TOKEN_ENDPOINT="" \
|
||||
LDAP_ENABLE=false \
|
||||
LDAP_PORT=389 \
|
||||
LDAP_HOST="" \
|
||||
LDAP_BASEDN="" \
|
||||
LDAP_LOGIN_FALLBACK=false \
|
||||
LDAP_RECONNECT=true \
|
||||
LDAP_TIMEOUT=10000 \
|
||||
LDAP_IDLE_TIMEOUT=10000 \
|
||||
LDAP_CONNECT_TIMEOUT=10000 \
|
||||
LDAP_AUTHENTIFICATION=false \
|
||||
LDAP_AUTHENTIFICATION_USERDN="" \
|
||||
LDAP_AUTHENTIFICATION_PASSWORD="" \
|
||||
LDAP_LOG_ENABLED=false \
|
||||
LDAP_BACKGROUND_SYNC=false \
|
||||
LDAP_BACKGROUND_SYNC_INTERVAL=100 \
|
||||
LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false \
|
||||
LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false \
|
||||
LDAP_ENCRYPTION=false \
|
||||
LDAP_CA_CERT="" \
|
||||
LDAP_REJECT_UNAUTHORIZED=false \
|
||||
LDAP_USER_SEARCH_FILTER="" \
|
||||
LDAP_USER_SEARCH_SCOPE="" \
|
||||
LDAP_USER_SEARCH_FIELD="" \
|
||||
LDAP_SEARCH_PAGE_SIZE=0 \
|
||||
LDAP_SEARCH_SIZE_LIMIT=0 \
|
||||
LDAP_GROUP_FILTER_ENABLE=false \
|
||||
LDAP_GROUP_FILTER_OBJECTCLASS="" \
|
||||
LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE="" \
|
||||
LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE="" \
|
||||
LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT="" \
|
||||
LDAP_GROUP_FILTER_GROUP_NAME="" \
|
||||
LDAP_UNIQUE_IDENTIFIER_FIELD="" \
|
||||
LDAP_UTF8_NAMES_SLUGIFY=true \
|
||||
LDAP_USERNAME_FIELD="" \
|
||||
LDAP_FULLNAME_FIELD="" \
|
||||
LDAP_MERGE_EXISTING_USERS=false \
|
||||
LDAP_SYNC_USER_DATA=false \
|
||||
LDAP_SYNC_USER_DATA_FIELDMAP="" \
|
||||
LDAP_SYNC_GROUP_ROLES="" \
|
||||
LDAP_DEFAULT_DOMAIN="" \
|
||||
LOGOUT_WITH_TIMER=false \
|
||||
LOGOUT_IN="" \
|
||||
LOGOUT_ON_HOURS="" \
|
||||
LOGOUT_ON_MINUTES="" \
|
||||
CORS="" \
|
||||
DEFAULT_AUTHENTICATION_METHOD=""
|
||||
|
||||
# Copy the app to the image
|
||||
COPY ${SRC_PATH} /home/wekan/app
|
||||
|
||||
RUN \
|
||||
set -o xtrace && \
|
||||
# Add non-root user wekan
|
||||
useradd --user-group --system --home-dir /home/wekan wekan && \
|
||||
\
|
||||
# OS dependencies
|
||||
apt-get update -y && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \
|
||||
\
|
||||
# Meteor installer doesn't work with the default tar binary, so using bsdtar while installing.
|
||||
# https://github.com/coreos/bugs/issues/1095#issuecomment-350574389
|
||||
cp $(which tar) $(which tar)~ && \
|
||||
ln -sf $(which bsdtar) $(which tar) && \
|
||||
\
|
||||
# Download nodejs
|
||||
#wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
#wget https://nodejs.org/dist/${NODE_VERSION}/SHASUMS256.txt.asc && \
|
||||
wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
wget https://nodejs.org/dist/${NODE_VERSION}/SHASUMS256.txt.asc && \
|
||||
#---------------------------------------------------------------------------------------------
|
||||
# Node Fibers 100% CPU usage issue:
|
||||
# https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
|
||||
@@ -45,10 +173,10 @@ RUN \
|
||||
# Also see beginning of wekan/server/authentication.js
|
||||
# import Fiber from "fibers";
|
||||
# Fiber.poolSize = 1e9;
|
||||
# Download node version 8.11.1 that has fix included, node binary copied from Sandstorm
|
||||
# OLD: Download node version 8.12.0 prerelease that has fix included, => Official 8.12.0 has been released
|
||||
# Description at https://releases.wekan.team/node.txt
|
||||
wget https://releases.wekan.team/node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
echo "40e7990489c13a1ed1173d8fe03af258c6ed964b92a4bd59a0927ac5931054aa node-v8.11.3-linux-x64.tar.gz" >> SHASUMS256.txt.asc && \
|
||||
#wget https://releases.wekan.team/node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
#echo "1ed54adb8497ad8967075a0b5d03dd5d0a502be43d4a4d84e5af489c613d7795 node-v8.12.0-linux-x64.tar.gz" >> SHASUMS256.txt.asc && \
|
||||
\
|
||||
# Verify nodejs authenticity
|
||||
grep ${NODE_VERSION}-${ARCHITECTURE}.tar.gz SHASUMS256.txt.asc | shasum -a 256 -c - && \
|
||||
@@ -95,8 +223,11 @@ RUN \
|
||||
# Change user to wekan and install meteor
|
||||
cd /home/wekan/ && \
|
||||
chown wekan:wekan --recursive /home/wekan && \
|
||||
curl https://install.meteor.com -o /home/wekan/install_meteor.sh && \
|
||||
sed -i "s|RELEASE=.*|RELEASE=${METEOR_RELEASE}\"\"|g" ./install_meteor.sh && \
|
||||
curl "https://install.meteor.com" -o /home/wekan/install_meteor.sh && \
|
||||
#curl "https://install.meteor.com/?release=${METEOR_RELEASE}" -o /home/wekan/install_meteor.sh && \
|
||||
# OLD: sed -i "s|RELEASE=.*|RELEASE=${METEOR_RELEASE}\"\"|g" ./install_meteor.sh && \
|
||||
# Install Meteor forcing its progress
|
||||
sed -i 's/VERBOSITY="--silent"/VERBOSITY="--progress-bar"/' ./install_meteor.sh && \
|
||||
echo "Starting meteor ${METEOR_RELEASE} installation... \n" && \
|
||||
chown wekan:wekan /home/wekan/install_meteor.sh && \
|
||||
\
|
||||
@@ -113,10 +244,25 @@ RUN \
|
||||
cd /home/wekan/app/packages && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/flow-router.git kadira-flow-router && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/meteor-useraccounts/core.git meteor-useraccounts-core && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/meteor-accounts-cas.git && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/wekan-ldap.git && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/wekan-scrollbar.git && \
|
||||
sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' /home/wekan/app/packages/meteor-useraccounts-core/package.js && \
|
||||
cd /home/wekan/.meteor && \
|
||||
gosu wekan:wekan /home/wekan/.meteor/meteor -- help; \
|
||||
\
|
||||
# extract the OpenAPI specification
|
||||
npm install -g api2html && \
|
||||
mkdir -p /home/wekan/python && \
|
||||
chown wekan:wekan --recursive /home/wekan/python && \
|
||||
cd /home/wekan/python && \
|
||||
gosu wekan:wekan git clone --depth 1 -b master git://github.com/Kronuz/esprima-python && \
|
||||
cd /home/wekan/python/esprima-python && \
|
||||
python3 setup.py install --record files.txt && \
|
||||
cd /home/wekan/app &&\
|
||||
mkdir -p ./public/api && \
|
||||
python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml && \
|
||||
/opt/nodejs/bin/api2html -c ./public/wekan-logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml; \
|
||||
# Build app
|
||||
cd /home/wekan/app && \
|
||||
gosu wekan:wekan /home/wekan/.meteor/meteor add standard-minifier-js && \
|
||||
@@ -135,16 +281,23 @@ RUN \
|
||||
#gosu wekan:wekan npm install bcrypt && \
|
||||
mv /home/wekan/app_build/bundle /build && \
|
||||
\
|
||||
# Put back the original tar
|
||||
mv $(which tar)~ $(which tar) && \
|
||||
\
|
||||
# Cleanup
|
||||
apt-get remove --purge -y ${BUILD_DEPS} && \
|
||||
apt-get autoremove -y && \
|
||||
npm uninstall -g api2html &&\
|
||||
rm -R /var/lib/apt/lists/* && \
|
||||
rm -R /home/wekan/.meteor && \
|
||||
rm -R /home/wekan/app && \
|
||||
rm -R /home/wekan/app_build && \
|
||||
cat /home/wekan/python/esprima-python/files.txt | xargs rm -R && \
|
||||
rm -R /home/wekan/python && \
|
||||
rm /home/wekan/install_meteor.sh
|
||||
|
||||
ENV PORT=80
|
||||
ENV PORT=8080
|
||||
EXPOSE $PORT
|
||||
USER wekan
|
||||
|
||||
CMD ["node", "/build/main.js"]
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2018 The Wekan Team
|
||||
Copyright (c) 2014-2019 The Wekan Team
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
||||
@@ -1,9 +1,4 @@
|
||||
# Wekan
|
||||
|
||||
[](https://transifex.com/wekan/wekan)
|
||||
|
||||
[![Wekan Vanila Chat][vanila_badge]][vanila_chat]
|
||||
[](http://webchat.freenode.net?channels=%23wekan&uio=d4)
|
||||
# Wekan - Open Source kanban
|
||||
|
||||
[](https://github.com/wekan/wekan/graphs/contributors)
|
||||
[](https://quay.io/repository/wekan/wekan)
|
||||
@@ -15,53 +10,62 @@
|
||||
[](https://david-dm.org/wekan/wekan)
|
||||
[](https://www.openhub.net/p/wekan)
|
||||
|
||||
Please read [FAQ](https://github.com/wekan/wekan/wiki/FAQ).
|
||||
Please don't feed the trolls and spammers that are mentioned in the FAQ :)
|
||||
## [Translate Wekan at Transifex](https://transifex.com/wekan/wekan)
|
||||
|
||||
Translations to non-English languages are accepted only at [Transifex](https://transifex.com/wekan/wekan) using webbrowser.
|
||||
New English strings of new features can be added as PRs to edge branch file wekan/i18n/en.i18n.json .
|
||||
|
||||
## [Wekan feature requests and bugs](https://github.com/wekan/wekan/issues)
|
||||
|
||||
Please add most of your questions as GitHub issue: [Wekan feature requests and bugs](https://github.com/wekan/wekan/issues).
|
||||
It's better than at chat where details get lost when chat scrolls up.
|
||||
|
||||
## Chat
|
||||
|
||||
[![Wekan Vanila Chat][vanila_badge]][vanila_chat] - Most Wekan community and developers are here at #wekan chat channel.
|
||||
Use webbrowser to register, and after that you can also alternatively use mobile app Rocket.Chat by Rocket.Chat with
|
||||
address https://chat.vanila.io and same username and password.
|
||||
|
||||
[Wekan IRC FAQ](https://github.com/wekan/wekan/wiki/IRC-FAQ)
|
||||
|
||||
## FAQ
|
||||
|
||||
**NOTE**:
|
||||
- Please read the [FAQ](https://github.com/wekan/wekan/wiki/FAQ) first
|
||||
- Please don't feed the trolls and spammers that are mentioned in the FAQ :)
|
||||
|
||||
## About Wekan
|
||||
|
||||
Wekan is an completely [Open Source][open_source] and [Free software][free_software]
|
||||
collaborative kanban board application with MIT license.
|
||||
|
||||
Whether you’re maintaining a personal todo list, planning your holidays with
|
||||
some friends, or working in a team on your next revolutionary idea, Kanban
|
||||
boards are an unbeatable tool to keep your things organized. They give you a
|
||||
visual overview of the current state of your project, and make you productive by
|
||||
allowing you to focus on the few items that matter the most.
|
||||
Whether you’re maintaining a personal todo list, planning your holidays with some friends, or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool to keep your things organized. They give you a visual overview of the current state of your project, and make you productive by allowing you to focus on the few items that matter the most.
|
||||
|
||||
Wekan has real-time user interface. Not all features are implemented.
|
||||
Since Wekan is a free software, you don’t have to trust us with your data and can
|
||||
install Wekan on your own computer or server. In fact we encourage you to do
|
||||
that by providing one-click installation on various platforms.
|
||||
|
||||
[Features][features]
|
||||
|
||||
Wekan supports many [Platforms][platforms], and plan is to add more.
|
||||
|
||||
[Integrations][integrations]
|
||||
|
||||
[Team](https://github.com/wekan/wekan/wiki/Team)
|
||||
|
||||
You don’t have to trust us with your data and can install Wekan on your own
|
||||
computer or server. In fact we encourage you to do that by providing
|
||||
one-click installation on various platforms.
|
||||
- [Features][features]: Wekan has real-time user interface. Not all features are implemented, yet.
|
||||
- [Platforms][platforms]: Wekan supports many platforms and plan is to add more. This will be the first place to look if you want to **install** it, test out and learn more in depth.
|
||||
- [Integrations][integrations]: Current possible integrations and future plans.
|
||||
- [Team](https://github.com/wekan/wekan/wiki/Team): The people who spends their time and make Wekan into what it is right now.
|
||||
|
||||
## Roadmap
|
||||
|
||||
[Roadmap](https://github.com/wekan/wekan/wiki/Roadmap)
|
||||
|
||||
Upcoming Wekan App Development Platform will make possible
|
||||
many use cases. If you don't find your feature or integration in
|
||||
GitHub issues and [Features][features] or [Integrations][integrations]
|
||||
page at wiki, please add them.
|
||||
Upcoming Wekan App Development Platform will make possible many use cases. If you don't find your feature or integration in
|
||||
GitHub issues and [Features][features] or [Integrations][integrations] page at wiki, please add them.
|
||||
|
||||
We are very welcoming to new developers and teams to submit new pull
|
||||
requests to devel branch to make this Wekan App Development Platform possible
|
||||
faster. Please see [Developer Documentation][dev_docs] to get started.
|
||||
We also welcome sponsors for features, although we don't have any yet.
|
||||
By working directly with Wekan you get the benefit of active maintenance
|
||||
and new features added by growing Wekan developer community.
|
||||
We are very welcoming to new developers and teams to submit new pull requests to devel branch to make this Wekan App Development Platform possible faster. Please see [Developer Documentation][dev_docs] to get started.
|
||||
|
||||
We also welcome sponsors for features and bugfixes. By working directly with Wekan you get the benefit of active maintenance and new features added by growing Wekan developer community.
|
||||
|
||||
Actual work happens at [Wekan GitHub issues][wekan_issues].
|
||||
|
||||
See [Development links on Wekan
|
||||
wiki](https://github.com/wekan/wekan/wiki#Development)
|
||||
bottom of the page for more info.
|
||||
See [Development links on Wekan wiki](https://github.com/wekan/wekan/wiki#Development) bottom of the page for more info.
|
||||
|
||||
If you want to know what is going on exactly this moment, you can check out the [project page](https://github.com/wekan/wekan/projects/2).
|
||||
|
||||
## Demo
|
||||
|
||||
@@ -73,9 +77,16 @@ bottom of the page for more info.
|
||||
|
||||
[![Screenshot of Wekan][screenshot_wefork]][roadmap_wefork]
|
||||
|
||||
Since Wekan is a free software, you don’t have to trust us with your data and can
|
||||
install Wekan on your own computer or server. In fact we encourage you to do
|
||||
that by providing one-click installation on various platforms.
|
||||
## Stable
|
||||
|
||||
- master+devel branch. At release, devel is merged to master.
|
||||
- Receives fixes and features that have been tested at edge that they work.
|
||||
- If you want automatic updates, [use Snap](https://github.com/wekan/wekan-snap/wiki/Install).
|
||||
- If you want to test before update, [use Docker quay.io release tags](https://github.com/wekan/wekan/wiki/Docker).
|
||||
|
||||
## Edge
|
||||
|
||||
- edge branch. All new fixes and features are added to here first. [Testing Edge](https://github.com/wekan/wekan-snap/wiki/Snap-Developer-Docs).
|
||||
|
||||
## License
|
||||
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
Security is very important to us. If discover any issue regarding security, please disclose
|
||||
Security is very important to us. If you discover any issue regarding security, please disclose
|
||||
the information responsibly by sending an email to security (at) wekan.team and not by
|
||||
creating a GitHub issue. We will respond swiftly to fix verifiable security issues.
|
||||
|
||||
@@ -28,8 +28,8 @@ added to the Wekan Hall of Fame.
|
||||
|
||||
## Which domains are in scope?
|
||||
|
||||
No any public domains, because all those are donated to Wekan Open Source project,
|
||||
and we don't have any permissions to do security scans on those donated servers.
|
||||
No public domains, because all those are donated to Wekan Open Source project,
|
||||
and we don't have any permissions to do security scans on those donated servers
|
||||
|
||||
Please don't perform research that could impact other users. Secondly, please keep
|
||||
the reports short and succinct. If we fail to understand the logics of your bug, we will tell you.
|
||||
@@ -39,7 +39,7 @@ and scan it's vulnerabilities there.
|
||||
|
||||
## About Wekan versions
|
||||
|
||||
There is only 2 versions of Wekan: Standalone Wekan, and Sandstorm Wekan.
|
||||
There are only 2 versions of Wekan: Standalone Wekan, and Sandstorm Wekan.
|
||||
|
||||
### Standalone Wekan Security
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v2.02.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
userScripts:
|
||||
build: stacksmith/user-scripts/build.sh
|
||||
boot: stacksmith/user-scripts/boot.sh
|
||||
run: stacksmith/user-scripts/run.sh
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "Wekan",
|
||||
"description": "The open-source Trello-like kanban",
|
||||
"description": "The open-source kanban",
|
||||
"repository": "https://github.com/wekan/wekan",
|
||||
"logo": "https://raw.githubusercontent.com/wekan/wekan/master/meta/icons/wekan-150.png",
|
||||
"keywords": ["productivity", "tool", "team", "kanban"],
|
||||
|
||||
@@ -14,6 +14,9 @@ template(name="boardActivities")
|
||||
p.activity-desc
|
||||
+memberName(user=user)
|
||||
|
||||
if($eq activityType 'deleteAttachment')
|
||||
| {{{_ 'activity-delete-attach' cardLink}}}.
|
||||
|
||||
if($eq activityType 'addAttachment')
|
||||
| {{{_ 'activity-attached' attachmentLink cardLink}}}.
|
||||
|
||||
@@ -31,12 +34,28 @@ template(name="boardActivities")
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklist.title
|
||||
if($eq activityType 'removeChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLink}}}.
|
||||
|
||||
if($eq activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item' checkItem checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item' checkItem checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'checklistCompleted')
|
||||
| {{{_ 'activity-checklist-completed' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'checklistUncompleted')
|
||||
| {{{_ 'activity-checklist-uncompleted' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklistItem.title
|
||||
if($eq activityType 'removedChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-removed' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'archivedCard')
|
||||
| {{{_ 'activity-archived' cardLink}}}.
|
||||
@@ -89,6 +108,12 @@ template(name="boardActivities")
|
||||
if($eq activityType 'restoredCard')
|
||||
| {{{_ 'activity-sent' cardLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label' lastLabel cardLink}}}.
|
||||
|
||||
if($eq activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
|
||||
|
||||
if($eq activityType 'unjoinMember')
|
||||
if($eq user._id member._id)
|
||||
| {{{_ 'activity-unjoined' cardLink}}}.
|
||||
@@ -119,6 +144,28 @@ template(name="cardActivities")
|
||||
| {{{_ 'activity-removed' cardLabel memberLink}}}.
|
||||
if($eq activityType 'archivedCard')
|
||||
| {{_ 'activity-archived' cardLabel}}.
|
||||
|
||||
if($eq activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label-card' lastLabel }}}.
|
||||
|
||||
if($eq activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label-card' lastLabel }}}.
|
||||
|
||||
if($eq activityType 'removeChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLabel}}}.
|
||||
|
||||
if($eq activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item-card' checkItem checklist.title }}}.
|
||||
|
||||
if($eq activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item-card' checkItem checklist.title }}}.
|
||||
|
||||
if($eq activityType 'checklistCompleted')
|
||||
| {{{_ 'activity-checklist-completed-card' checklist.title }}}.
|
||||
|
||||
if($eq activityType 'checklistUncompleted')
|
||||
| {{{_ 'activity-checklist-uncompleted-card' checklist.title }}}.
|
||||
|
||||
if($eq activityType 'restoredCard')
|
||||
| {{_ 'activity-sent' cardLabel boardLabel}}.
|
||||
if($eq activityType 'moveCard')
|
||||
@@ -127,6 +174,10 @@ template(name="cardActivities")
|
||||
| {{{_ 'activity-attached' attachmentLink cardLabel}}}.
|
||||
if attachment.isImage
|
||||
img.attachment-image-preview(src=attachment.url)
|
||||
if($eq activityType 'deleteAttachment')
|
||||
| {{{_ 'activity-delete-attach' cardLabel}}}.
|
||||
if($eq activityType 'removedChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLabel}}}.
|
||||
if($eq activityType 'addChecklist')
|
||||
| {{{_ 'activity-checklist-added' cardLabel}}}.
|
||||
.activity-checklist
|
||||
|
||||
@@ -8,16 +8,24 @@ BlazeComponent.extendComponent({
|
||||
const sidebar = this.parentComponent(); // XXX for some reason not working
|
||||
sidebar.callFirstWith(null, 'resetNextPeak');
|
||||
this.autorun(() => {
|
||||
const mode = this.data().mode;
|
||||
let mode = this.data().mode;
|
||||
const capitalizedMode = Utils.capitalize(mode);
|
||||
const id = Session.get(`current${capitalizedMode}`);
|
||||
let thisId, searchId;
|
||||
if (mode === 'linkedcard' || mode === 'linkedboard') {
|
||||
thisId = Session.get('currentCard');
|
||||
searchId = Cards.findOne({_id: thisId}).linkedId;
|
||||
mode = mode.replace('linked', '');
|
||||
} else {
|
||||
thisId = Session.get(`current${capitalizedMode}`);
|
||||
searchId = thisId;
|
||||
}
|
||||
const limit = this.page.get() * activitiesPerPage;
|
||||
const user = Meteor.user();
|
||||
const hideSystem = user ? user.hasHiddenSystemMessages() : false;
|
||||
if (id === null)
|
||||
if (searchId === null)
|
||||
return;
|
||||
|
||||
this.subscribe('activities', mode, id, limit, hideSystem, () => {
|
||||
this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
|
||||
// If the sibear peak hasn't increased, that mean that there are no more
|
||||
@@ -42,6 +50,12 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
},
|
||||
|
||||
checkItem(){
|
||||
const checkItemId = this.currentData().checklistItemId;
|
||||
const checkItem = ChecklistItems.findOne({_id:checkItemId});
|
||||
return checkItem.title;
|
||||
},
|
||||
|
||||
boardLabel() {
|
||||
return TAPi18n.__('this-board');
|
||||
},
|
||||
@@ -58,6 +72,16 @@ BlazeComponent.extendComponent({
|
||||
}, card.title));
|
||||
},
|
||||
|
||||
lastLabel(){
|
||||
const lastLabelId = this.currentData().labelId;
|
||||
const lastLabel = Boards.findOne(Session.get('currentBoard')).getLabelById(lastLabelId);
|
||||
if(lastLabel.name === undefined || lastLabel.name === ''){
|
||||
return lastLabel.color;
|
||||
}else{
|
||||
return lastLabel.name;
|
||||
}
|
||||
},
|
||||
|
||||
listLabel() {
|
||||
return this.currentData().list().title;
|
||||
},
|
||||
|
||||
@@ -21,11 +21,18 @@ BlazeComponent.extendComponent({
|
||||
'submit .js-new-comment-form'(evt) {
|
||||
const input = this.getInput();
|
||||
const text = input.val().trim();
|
||||
const card = this.currentData();
|
||||
let boardId = card.boardId;
|
||||
let cardId = card._id;
|
||||
if (card.isLinkedCard()) {
|
||||
boardId = Cards.findOne(card.linkedId).boardId;
|
||||
cardId = card.linkedId;
|
||||
}
|
||||
if (text) {
|
||||
CardComments.insert({
|
||||
text,
|
||||
boardId: this.currentData().boardId,
|
||||
cardId: this.currentData()._id,
|
||||
boardId,
|
||||
cardId,
|
||||
});
|
||||
resetCommentInput(input);
|
||||
Tracker.flush();
|
||||
|
||||
@@ -37,8 +37,7 @@ BlazeComponent.extendComponent({
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
Boards.remove(currentBoard._id);
|
||||
}
|
||||
const board = this.currentData();
|
||||
Boards.remove(board._id);
|
||||
Boards.remove(this._id);
|
||||
FlowRouter.go('home');
|
||||
}),
|
||||
}];
|
||||
|
||||
@@ -147,6 +147,13 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
},
|
||||
|
||||
scrollTop(position = 0) {
|
||||
const swimlanes = this.$('.js-swimlanes');
|
||||
swimlanes && swimlanes.animate({
|
||||
scrollTop: position,
|
||||
});
|
||||
},
|
||||
|
||||
}).register('boardBody');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
|
||||
@@ -87,6 +87,10 @@ template(name="boardHeaderBar")
|
||||
if Filter.isActive
|
||||
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
|
||||
i.fa.fa-times-thin
|
||||
if currentUser.isAdmin
|
||||
a.board-header-btn.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
span {{_ 'rules'}}
|
||||
|
||||
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
|
||||
i.fa.fa-search
|
||||
@@ -290,6 +294,11 @@ template(name="boardChangeTitlePopup")
|
||||
textarea.js-board-desc= description
|
||||
input.primary.wide(type="submit" value="{{_ 'rename'}}")
|
||||
|
||||
template(name="boardCreateRulePopup")
|
||||
p {{_ 'close-board-pop'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
|
||||
|
||||
|
||||
template(name="archiveBoardPopup")
|
||||
p {{_ 'close-board-pop'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
|
||||
|
||||
@@ -108,6 +108,9 @@ BlazeComponent.extendComponent({
|
||||
'click .js-open-search-view'() {
|
||||
Sidebar.setView('search');
|
||||
},
|
||||
'click .js-open-rules-view'() {
|
||||
Modal.openWide('rulesMain');
|
||||
},
|
||||
'click .js-multiselection-activate'() {
|
||||
const currentCard = Session.get('currentCard');
|
||||
MultiSelection.activate();
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
template(name="boardList")
|
||||
.wrapper
|
||||
ul.board-list.clearfix
|
||||
li.js-add-board
|
||||
a.board-list-item.label {{_ 'add-board'}}
|
||||
each boards
|
||||
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass)
|
||||
if isInvited
|
||||
@@ -27,9 +29,6 @@ template(name="boardList")
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
|
||||
p.board-list-item-desc= description
|
||||
li.js-add-board
|
||||
a.board-list-item.label {{_ 'add-board'}}
|
||||
|
||||
|
||||
template(name="boardListHeaderBar")
|
||||
h1 {{_ 'my-boards'}}
|
||||
|
||||
@@ -57,8 +57,13 @@ Template.cardAttachmentsPopup.events({
|
||||
const card = this;
|
||||
FS.Utility.eachFile(evt, (f) => {
|
||||
const file = new FS.File(f);
|
||||
file.boardId = card.boardId;
|
||||
file.cardId = card._id;
|
||||
if (card.isLinkedCard()) {
|
||||
file.boardId = Cards.findOne(card.linkedId).boardId;
|
||||
file.cardId = card.linkedId;
|
||||
} else {
|
||||
file.boardId = card.boardId;
|
||||
file.cardId = card._id;
|
||||
}
|
||||
file.userId = Meteor.userId();
|
||||
|
||||
const attachment = Attachments.insert(file);
|
||||
|
||||
@@ -96,7 +96,7 @@ Template.dateBadge.helpers({
|
||||
(class extends DatePicker {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
this.data().receivedAt && this.date.set(moment(this.data().receivedAt));
|
||||
this.data().getReceived() && this.date.set(moment(this.data().getReceived()));
|
||||
}
|
||||
|
||||
_storeDate(date) {
|
||||
@@ -104,7 +104,7 @@ Template.dateBadge.helpers({
|
||||
}
|
||||
|
||||
_deleteDate() {
|
||||
this.card.unsetReceived();
|
||||
this.card.setReceived(null);
|
||||
}
|
||||
}).register('editCardReceivedDatePopup');
|
||||
|
||||
@@ -113,13 +113,13 @@ Template.dateBadge.helpers({
|
||||
(class extends DatePicker {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
this.data().startAt && this.date.set(moment(this.data().startAt));
|
||||
this.data().getStart() && this.date.set(moment(this.data().getStart()));
|
||||
}
|
||||
|
||||
onRendered() {
|
||||
super.onRendered();
|
||||
if (moment.isDate(this.card.receivedAt)) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.receivedAt);
|
||||
if (moment.isDate(this.card.getReceived())) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.getReceived());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -128,7 +128,7 @@ Template.dateBadge.helpers({
|
||||
}
|
||||
|
||||
_deleteDate() {
|
||||
this.card.unsetStart();
|
||||
this.card.setStart(null);
|
||||
}
|
||||
}).register('editCardStartDatePopup');
|
||||
|
||||
@@ -136,13 +136,13 @@ Template.dateBadge.helpers({
|
||||
(class extends DatePicker {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
this.data().dueAt && this.date.set(moment(this.data().dueAt));
|
||||
this.data().getDue() && this.date.set(moment(this.data().getDue()));
|
||||
}
|
||||
|
||||
onRendered() {
|
||||
super.onRendered();
|
||||
if (moment.isDate(this.card.startAt)) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt);
|
||||
if (moment.isDate(this.card.getStart())) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ Template.dateBadge.helpers({
|
||||
}
|
||||
|
||||
_deleteDate() {
|
||||
this.card.unsetDue();
|
||||
this.card.setDue(null);
|
||||
}
|
||||
}).register('editCardDueDatePopup');
|
||||
|
||||
@@ -159,13 +159,13 @@ Template.dateBadge.helpers({
|
||||
(class extends DatePicker {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
this.data().endAt && this.date.set(moment(this.data().endAt));
|
||||
this.data().getEnd() && this.date.set(moment(this.data().getEnd()));
|
||||
}
|
||||
|
||||
onRendered() {
|
||||
super.onRendered();
|
||||
if (moment.isDate(this.card.startAt)) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.startAt);
|
||||
if (moment.isDate(this.card.getStart())) {
|
||||
this.$('.js-datepicker').datepicker('setStartDate', this.card.getStart());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ Template.dateBadge.helpers({
|
||||
}
|
||||
|
||||
_deleteDate() {
|
||||
this.card.unsetEnd();
|
||||
this.card.setEnd(null);
|
||||
}
|
||||
}).register('editCardEndDatePopup');
|
||||
|
||||
@@ -213,19 +213,23 @@ class CardReceivedDate extends CardDate {
|
||||
super.onCreated();
|
||||
const self = this;
|
||||
self.autorun(() => {
|
||||
self.date.set(moment(self.data().receivedAt));
|
||||
self.date.set(moment(self.data().getReceived()));
|
||||
});
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'received-date ';
|
||||
const dueAt = this.data().dueAt;
|
||||
if (dueAt) {
|
||||
if (this.date.get().isBefore(this.now.get(), 'minute') &&
|
||||
this.now.get().isBefore(dueAt)) {
|
||||
classes += 'current';
|
||||
}
|
||||
}
|
||||
const dueAt = this.data().getDue();
|
||||
const endAt = this.data().getEnd();
|
||||
const startAt = this.data().getStart();
|
||||
const theDate = this.date.get();
|
||||
// if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged
|
||||
if (((startAt) && (theDate.isAfter(dueAt))) ||
|
||||
((endAt) && (theDate.isAfter(endAt))) ||
|
||||
((dueAt) && (theDate.isAfter(dueAt))))
|
||||
classes += 'long-overdue';
|
||||
else
|
||||
classes += 'current';
|
||||
return classes;
|
||||
}
|
||||
|
||||
@@ -246,19 +250,24 @@ class CardStartDate extends CardDate {
|
||||
super.onCreated();
|
||||
const self = this;
|
||||
self.autorun(() => {
|
||||
self.date.set(moment(self.data().startAt));
|
||||
self.date.set(moment(self.data().getStart()));
|
||||
});
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'start-date' + ' ';
|
||||
const dueAt = this.data().dueAt;
|
||||
if (dueAt) {
|
||||
if (this.date.get().isBefore(this.now.get(), 'minute') &&
|
||||
this.now.get().isBefore(dueAt)) {
|
||||
classes += 'current';
|
||||
}
|
||||
}
|
||||
const dueAt = this.data().getDue();
|
||||
const endAt = this.data().getEnd();
|
||||
const theDate = this.date.get();
|
||||
const now = this.now.get();
|
||||
// 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
|
||||
classes += 'current';
|
||||
return classes;
|
||||
}
|
||||
|
||||
@@ -279,24 +288,21 @@ class CardDueDate extends CardDate {
|
||||
super.onCreated();
|
||||
const self = this;
|
||||
self.autorun(() => {
|
||||
self.date.set(moment(self.data().dueAt));
|
||||
self.date.set(moment(self.data().getDue()));
|
||||
});
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'due-date' + ' ';
|
||||
|
||||
// if endAt exists & is < dueAt, dueAt doesn't need to be flagged
|
||||
const endAt = this.data().endAt;
|
||||
const endAt = this.data().getEnd();
|
||||
const theDate = this.date.get();
|
||||
const now = this.now.get();
|
||||
|
||||
if ((endAt !== 0) &&
|
||||
(endAt !== null) &&
|
||||
(endAt !== '') &&
|
||||
(endAt !== undefined) &&
|
||||
(theDate.isBefore(endAt)))
|
||||
// if the due date is after the end date, green - done early
|
||||
if ((endAt) && (theDate.isAfter(endAt)))
|
||||
classes += 'current';
|
||||
// if there is an end date, don't need to flag the due date
|
||||
else if (endAt)
|
||||
classes += '';
|
||||
else if (now.diff(theDate, 'days') >= 2)
|
||||
classes += 'long-overdue';
|
||||
else if (now.diff(theDate, 'minute') >= 0)
|
||||
@@ -323,22 +329,20 @@ class CardEndDate extends CardDate {
|
||||
super.onCreated();
|
||||
const self = this;
|
||||
self.autorun(() => {
|
||||
self.date.set(moment(self.data().endAt));
|
||||
self.date.set(moment(self.data().getEnd()));
|
||||
});
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'end-date' + ' ';
|
||||
const dueAt = this.data.dueAt;
|
||||
if (dueAt) {
|
||||
const diff = dueAt.diff(this.date.get(), 'days');
|
||||
if (diff >= 2)
|
||||
classes += 'long-overdue';
|
||||
else if (diff > 0)
|
||||
classes += 'due';
|
||||
else if (diff <= 0)
|
||||
classes += 'current';
|
||||
}
|
||||
const dueAt = this.data().getDue();
|
||||
const theDate = this.date.get();
|
||||
if (theDate.diff(dueAt, 'days') >= 2)
|
||||
classes += 'long-overdue';
|
||||
else if (theDate.diff(dueAt, 'days') >= 0)
|
||||
classes += 'due';
|
||||
else if (theDate.diff(dueAt, 'days') >= -2)
|
||||
classes += 'almost-due';
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,12 @@
|
||||
&.start-date
|
||||
time
|
||||
&::before
|
||||
content: "\f08b" // symbol: fa-sign-out
|
||||
content: "\f251" // symbol: fa-hourglass-start
|
||||
|
||||
&.received-date
|
||||
time
|
||||
&::before
|
||||
content: "\f251" // symbol: fa-hourglass-start
|
||||
content: "\f08b" // symbol: fa-sign-out
|
||||
|
||||
time
|
||||
&::before
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
template(name="cardDetails")
|
||||
section.card-details.js-card-details.js-perfect-scrollbar: .card-details-canvas
|
||||
.card-details-header
|
||||
.card-details-header(class='{{#if colorClass}}card-details-{{colorClass}}{{/if}}')
|
||||
+inlinedForm(classNames="js-card-details-title")
|
||||
+editCardTitleForm
|
||||
else
|
||||
@@ -10,7 +10,7 @@ template(name="cardDetails")
|
||||
h2.card-details-title.js-card-title(
|
||||
class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
|
||||
+viewer
|
||||
= title
|
||||
= getTitle
|
||||
if isWatching
|
||||
i.fa.fa-eye.card-details-watch
|
||||
.card-details-path
|
||||
@@ -19,43 +19,56 @@ template(name="cardDetails")
|
||||
a.js-parent-card(href=linkForCard) {{title}}
|
||||
// else
|
||||
{{_ 'top-level-card'}}
|
||||
unless isSandstorm
|
||||
if isLinkedCard
|
||||
h3.linked-card-location
|
||||
+viewer
|
||||
| {{getBoardTitle}} > {{getTitle}}
|
||||
|
||||
if archived
|
||||
p.warning {{_ 'card-archived'}}
|
||||
if getArchived
|
||||
if isLinkedBoard
|
||||
unless isSandstorm
|
||||
p.warning {{_ 'board-archived'}}
|
||||
else
|
||||
p.warning {{_ 'card-archived'}}
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-received
|
||||
h3.card-details-item-title {{_ 'card-received'}}
|
||||
if receivedAt
|
||||
if getReceived
|
||||
+cardReceivedDate
|
||||
else
|
||||
a.js-received-date {{_ 'add'}}
|
||||
if canModifyCard
|
||||
a.js-received-date {{_ 'add'}}
|
||||
|
||||
.card-details-item.card-details-item-start
|
||||
h3.card-details-item-title {{_ 'card-start'}}
|
||||
if startAt
|
||||
if getStart
|
||||
+cardStartDate
|
||||
else
|
||||
a.js-start-date {{_ 'add'}}
|
||||
if canModifyCard
|
||||
a.js-start-date {{_ 'add'}}
|
||||
|
||||
.card-details-item.card-details-item-due
|
||||
h3.card-details-item-title {{_ 'card-due'}}
|
||||
if dueAt
|
||||
if getDue
|
||||
+cardDueDate
|
||||
else
|
||||
a.js-due-date {{_ 'add'}}
|
||||
if canModifyCard
|
||||
a.js-due-date {{_ 'add'}}
|
||||
|
||||
.card-details-item.card-details-item-end
|
||||
h3.card-details-item-title {{_ 'card-end'}}
|
||||
if endAt
|
||||
if getEnd
|
||||
+cardEndDate
|
||||
else
|
||||
a.js-end-date {{_ 'add'}}
|
||||
if canModifyCard
|
||||
a.js-end-date {{_ 'add'}}
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-members
|
||||
h3.card-details-item-title {{_ 'members'}}
|
||||
each members
|
||||
each getMembers
|
||||
+userAvatar(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
if canModifyCard
|
||||
@@ -79,9 +92,9 @@ template(name="cardDetails")
|
||||
+cardCustomField
|
||||
|
||||
.card-details-items
|
||||
if spentTime
|
||||
if getSpentTime
|
||||
.card-details-item.card-details-item-spent
|
||||
if isOvertime
|
||||
if getIsOvertime
|
||||
h3.card-details-item-title {{_ 'overtime-hours'}}
|
||||
else
|
||||
h3.card-details-item-title {{_ 'spent-time-hours'}}
|
||||
@@ -92,15 +105,15 @@ template(name="cardDetails")
|
||||
h3.card-details-item-title {{_ 'description'}}
|
||||
+inlinedCardDescription(classNames="card-description js-card-description")
|
||||
+editor(autofocus=true)
|
||||
| {{getUnsavedValue 'cardDescription' _id description}}
|
||||
| {{getUnsavedValue 'cardDescription' _id getDescription}}
|
||||
.edit-controls.clearfix
|
||||
button.primary(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if description
|
||||
if getDescription
|
||||
+viewer
|
||||
= description
|
||||
= getDescription
|
||||
else
|
||||
| {{_ 'edit'}}
|
||||
if (hasUnsavedValue 'cardDescription' _id)
|
||||
@@ -109,10 +122,10 @@ template(name="cardDetails")
|
||||
a.js-open-inlined-form {{_ 'view-it'}}
|
||||
= ' - '
|
||||
a.js-close-inlined-form {{_ 'discard'}}
|
||||
else if description
|
||||
else if getDescription
|
||||
h3.card-details-item-title {{_ 'description'}}
|
||||
+viewer
|
||||
= description
|
||||
= getDescription
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-name
|
||||
@@ -122,14 +135,14 @@ template(name="cardDetails")
|
||||
+editCardRequesterForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if requestedBy
|
||||
if getRequestedBy
|
||||
+viewer
|
||||
= requestedBy
|
||||
= getRequestedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if requestedBy
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= requestedBy
|
||||
= getRequestedBy
|
||||
|
||||
.card-details-item.card-details-item-name
|
||||
h3.card-details-item-title {{_ 'assigned-by'}}
|
||||
@@ -138,14 +151,14 @@ template(name="cardDetails")
|
||||
+editCardAssignerForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if assignedBy
|
||||
if getAssignedBy
|
||||
+viewer
|
||||
= assignedBy
|
||||
= getAssignedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if requestedBy
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= assignedBy
|
||||
= getAssignedBy
|
||||
|
||||
hr
|
||||
+checklists(cardId = _id)
|
||||
@@ -162,36 +175,46 @@ template(name="cardDetails")
|
||||
+attachmentsGalery
|
||||
|
||||
hr
|
||||
.activity-title
|
||||
h3 {{ _ 'activity'}}
|
||||
if currentUser.isBoardMember
|
||||
.material-toggle-switch
|
||||
span.toggle-switch-title {{_ 'hide-system-messages'}}
|
||||
if hiddenSystemMessages
|
||||
input.toggle-switch(type="checkbox" id="toggleButton" checked="checked")
|
||||
else
|
||||
input.toggle-switch(type="checkbox" id="toggleButton")
|
||||
label.toggle-label(for="toggleButton")
|
||||
unless currentUser.isNoComments
|
||||
.activity-title
|
||||
h3 {{ _ 'activity'}}
|
||||
if currentUser.isBoardMember
|
||||
.material-toggle-switch
|
||||
span.toggle-switch-title {{_ 'hide-system-messages'}}
|
||||
if hiddenSystemMessages
|
||||
input.toggle-switch(type="checkbox" id="toggleButton" checked="checked")
|
||||
else
|
||||
input.toggle-switch(type="checkbox" id="toggleButton")
|
||||
label.toggle-label(for="toggleButton")
|
||||
if currentUser.isBoardMember
|
||||
+commentForm
|
||||
if isLoaded.get
|
||||
+activities(card=this mode="card")
|
||||
unless currentUser.isNoComments
|
||||
+commentForm
|
||||
unless currentUser.isNoComments
|
||||
if isLoaded.get
|
||||
if isLinkedCard
|
||||
unless isSandstorm
|
||||
+activities(card=this mode="linkedcard")
|
||||
else if isLinkedBoard
|
||||
unless isSandstorm
|
||||
+activities(card=this mode="linkedboard")
|
||||
else
|
||||
+activities(card=this mode="card")
|
||||
|
||||
template(name="editCardTitleForm")
|
||||
textarea.js-edit-card-title(rows='1' autofocus)
|
||||
= title
|
||||
= getTitle
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-submit-edit-card-title-form(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
|
||||
template(name="editCardRequesterForm")
|
||||
input.js-edit-card-requester(type='text' autofocus value=requestedBy)
|
||||
input.js-edit-card-requester(type='text' autofocus value=getRequestedBy)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-submit-edit-card-requester-form(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
|
||||
template(name="editCardAssignerForm")
|
||||
input.js-edit-card-assigner(type='text' autofocus value=assignedBy)
|
||||
input.js-edit-card-assigner(type='text' autofocus value=getAssignedBy)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-submit-edit-card-assigner-form(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
@@ -211,6 +234,7 @@ template(name="cardDetailsActionsPopup")
|
||||
li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||
li: a.js-end-date {{_ 'editCardEndDatePopup-title'}}
|
||||
li: a.js-spent-time {{_ 'editCardSpentTimePopup-title'}}
|
||||
li: a.js-set-card-color {{_ 'setCardColor-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
|
||||
@@ -230,7 +254,7 @@ template(name="moveCardPopup")
|
||||
template(name="copyCardPopup")
|
||||
label(for='copy-card-title') {{_ 'title'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= title
|
||||
= getTitle
|
||||
+boardsAndLists
|
||||
|
||||
template(name="copyChecklistToManyCardsPopup")
|
||||
@@ -241,7 +265,7 @@ template(name="copyChecklistToManyCardsPopup")
|
||||
|
||||
template(name="boardsAndLists")
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards
|
||||
select.js-select-boards(autofocus)
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
@@ -279,7 +303,7 @@ template(name="cardMorePopup")
|
||||
span {{_ 'link-card'}}
|
||||
= ' '
|
||||
i.fa.colorful(class="{{#if board.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
||||
input.inline-input(type="text" id="cardURL" readonly value="{{ absoluteUrl }}")
|
||||
input.inline-input(type="text" id="cardURL" readonly value="{{ absoluteUrl }}" autofocus="autofocus")
|
||||
button.js-copy-card-link-to-clipboard(class="btn") {{_ 'copy-card-link-to-clipboard'}}
|
||||
span.clearfix
|
||||
br
|
||||
@@ -312,7 +336,17 @@ template(name="cardMorePopup")
|
||||
span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
|
||||
a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
|
||||
|
||||
|
||||
template(name="setCardColorPopup")
|
||||
p.quiet
|
||||
span.clearfix
|
||||
label {{_ "select-color"}}
|
||||
form.edit-label
|
||||
.palette-colors: each colors
|
||||
span.card-label.palette-color.js-palette-color(class="card-details-{{color}}")
|
||||
if(isSelected color)
|
||||
i.fa.fa-check
|
||||
button.primary.confirm.js-submit {{_ 'save'}}
|
||||
button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
|
||||
|
||||
template(name="cardDeletePopup")
|
||||
p {{_ "card-delete-pop"}}
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndexData, enableClickOnTouch } = Utils;
|
||||
|
||||
let cardColors;
|
||||
Meteor.startup(() => {
|
||||
cardColors = Cards.simpleSchema()._schema.color.allowedValues;
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
@@ -22,6 +27,7 @@ BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
this.isLoaded = new ReactiveVar(false);
|
||||
this.currentColor = new ReactiveVar(this.data().color);
|
||||
const boardBody = this.parentComponent().parentComponent();
|
||||
//in Miniview parent is Board, not BoardBody.
|
||||
if (boardBody !== null) {
|
||||
@@ -69,6 +75,20 @@ BlazeComponent.extendComponent({
|
||||
if (offset) {
|
||||
bodyBoardComponent.scrollLeft(cardContainerScroll + offset);
|
||||
}
|
||||
|
||||
//Scroll top
|
||||
const cardViewStartTop = $cardView.offset().top;
|
||||
const cardContainerScrollTop = $cardContainer.scrollTop();
|
||||
let topOffset = false;
|
||||
if(cardViewStartTop < 0){
|
||||
topOffset = 0;
|
||||
} else if(cardViewStartTop - cardContainerScrollTop > 100) {
|
||||
topOffset = cardViewStartTop - cardContainerScrollTop - 100;
|
||||
}
|
||||
if(topOffset !== false) {
|
||||
bodyBoardComponent.scrollTop(topOffset);
|
||||
}
|
||||
|
||||
},
|
||||
|
||||
presentParentTask() {
|
||||
@@ -96,7 +116,12 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
if (!Utils.isMiniScreen()) this.scrollParentContainer();
|
||||
if (!Utils.isMiniScreen()) {
|
||||
Meteor.setTimeout(() => {
|
||||
$('.card-details').mCustomScrollbar({theme:'minimal-dark', setWidth: false, setLeft: 0, scrollbarPosition: 'outside', mouseWheel: true });
|
||||
this.scrollParentContainer();
|
||||
}, 500);
|
||||
}
|
||||
const $checklistsDom = this.$('.card-checklist-items');
|
||||
|
||||
$checklistsDom.sortable({
|
||||
@@ -274,7 +299,7 @@ BlazeComponent.extendComponent({
|
||||
close(isReset = false) {
|
||||
if (this.isOpen.get() && !isReset) {
|
||||
const draft = this.getValue().trim();
|
||||
if (draft !== Cards.findOne(Session.get('currentCard')).description) {
|
||||
if (draft !== Cards.findOne(Session.get('currentCard')).getDescription()) {
|
||||
UnsavedEdits.set(this._getUnsavedEditKey(), this.getValue());
|
||||
}
|
||||
}
|
||||
@@ -318,6 +343,7 @@ Template.cardDetailsActionsPopup.events({
|
||||
'click .js-move-card': Popup.open('moveCard'),
|
||||
'click .js-copy-card': Popup.open('copyCard'),
|
||||
'click .js-copy-checklist-cards': Popup.open('copyChecklistToManyCards'),
|
||||
'click .js-set-card-color': Popup.open('setCardColor'),
|
||||
'click .js-move-card-to-top' (evt) {
|
||||
evt.preventDefault();
|
||||
const minOrder = _.min(this.list().cards(this.swimlaneId).map((c) => c.sort));
|
||||
@@ -564,6 +590,37 @@ Template.copyChecklistToManyCardsPopup.events({
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentCard = this.currentData();
|
||||
this.currentColor = new ReactiveVar(this.currentCard.color);
|
||||
},
|
||||
|
||||
colors() {
|
||||
return cardColors.map((color) => ({ color, name: '' }));
|
||||
},
|
||||
|
||||
isSelected(color) {
|
||||
return this.currentColor.get() === color;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-palette-color'() {
|
||||
this.currentColor.set(this.currentData().color);
|
||||
},
|
||||
'click .js-submit' () {
|
||||
this.currentCard.setColor(this.currentColor.get());
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-remove-color'() {
|
||||
this.currentCard.setColor(null);
|
||||
Popup.close();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('setCardColorPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentCard = this.currentData();
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
@import 'nib'
|
||||
|
||||
.card-details
|
||||
padding: 0 20px
|
||||
padding: 0
|
||||
flex-shrink: 0
|
||||
flex-basis: 470px
|
||||
flex-basis: 510px
|
||||
will-change: flex-basis
|
||||
overflow-y: scroll
|
||||
overflow-x: hidden
|
||||
@@ -14,8 +14,16 @@
|
||||
box-shadow: 0 0 7px 0 darken(white, 30%)
|
||||
transition: flex-basis 0.1s
|
||||
|
||||
.mCustomScrollBox
|
||||
padding-left: 0
|
||||
|
||||
.ps-scrollbar-y-rail
|
||||
pointer-event: all
|
||||
position: absolute;
|
||||
|
||||
.card-details-canvas
|
||||
width: 470px
|
||||
padding-left: 20px;
|
||||
|
||||
.card-details-header
|
||||
margin: 0 -20px 5px
|
||||
@@ -47,6 +55,12 @@
|
||||
margin: 7px 0 0
|
||||
padding: 0
|
||||
|
||||
.linked-card-location
|
||||
font-style: italic
|
||||
font-size: 1em
|
||||
margin-bottom: 0
|
||||
& p
|
||||
margin-bottom: 0
|
||||
|
||||
form.inlined-form
|
||||
margin-top: 5px
|
||||
@@ -126,3 +140,80 @@ input[type="submit"].attachment-add-link-submit
|
||||
|
||||
.card-details-menu
|
||||
margin-right: 10px
|
||||
|
||||
card-details-color(background, color...)
|
||||
background: background !important
|
||||
if color
|
||||
color: color //overwrite text for better visibility
|
||||
|
||||
.card-details-green
|
||||
card-details-color(#3cb500, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-yellow
|
||||
card-details-color(#fad900)
|
||||
|
||||
.card-details-orange
|
||||
card-details-color(#ff9f19)
|
||||
|
||||
.card-details-red
|
||||
card-details-color(#eb4646, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-purple
|
||||
card-details-color(#a632db, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-blue
|
||||
card-details-color(#0079bf, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-pink
|
||||
card-details-color(#ff78cb)
|
||||
|
||||
.card-details-sky
|
||||
card-details-color(#00c2e0, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-black
|
||||
card-details-color(#4d4d4d, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-lime
|
||||
card-details-color(#51e898)
|
||||
|
||||
.card-details-silver
|
||||
card-details-color(#c0c0c0)
|
||||
|
||||
.card-details-peachpuff
|
||||
card-details-color(#ffdab9)
|
||||
|
||||
.card-details-crimson
|
||||
card-details-color(#dc143c, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-plum
|
||||
card-details-color(#dda0dd)
|
||||
|
||||
.card-details-darkgreen
|
||||
card-details-color(#006400, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-slateblue
|
||||
card-details-color(#6a5acd, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-magenta
|
||||
card-details-color(#ff00ff, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-gold
|
||||
card-details-color(#ffd700)
|
||||
|
||||
.card-details-navy
|
||||
card-details-color(#000080, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-gray
|
||||
card-details-color(#808080, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-saddlebrown
|
||||
card-details-color(#8b4513, #ffffff) //White text for better visibility
|
||||
|
||||
.card-details-paleturquoise
|
||||
card-details-color(#afeeee)
|
||||
|
||||
.card-details-mistyrose
|
||||
card-details-color(#ffe4e1)
|
||||
|
||||
.card-details-indigo
|
||||
card-details-color(#4b0082, #ffffff) //White text for better visibility
|
||||
@@ -3,10 +3,10 @@ template(name="editCardSpentTime")
|
||||
form.edit-time
|
||||
.fields
|
||||
label(for="time") {{_ 'time'}}
|
||||
input.js-time-field#time(type="number" step="0.01" name="time" value="{{card.spentTime}}" placeholder=timeFormat autofocus)
|
||||
input.js-time-field#time(type="number" step="0.01" name="time" value="{{card.getSpentTime}}" placeholder=timeFormat autofocus)
|
||||
label(for="overtime") {{_ 'overtime'}}
|
||||
a.js-toggle-overtime
|
||||
.materialCheckBox#overtime(class="{{#if card.isOvertime}}is-checked{{/if}}" name="overtime")
|
||||
.materialCheckBox#overtime(class="{{#if getIsOvertime}}is-checked{{/if}}" name="overtime")
|
||||
|
||||
if error.get
|
||||
.warning {{_ error.get}}
|
||||
@@ -15,8 +15,8 @@ template(name="editCardSpentTime")
|
||||
|
||||
template(name="timeBadge")
|
||||
if canModifyCard
|
||||
a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||
a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if getIsOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||
| {{showTime}}
|
||||
else
|
||||
a.card-time(title="{{showTitle}}" class="{{#if isOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||
a.card-time(title="{{showTitle}}" class="{{#if getIsOvertime}}card-label-red{{else}}card-label-green{{/if}}")
|
||||
| {{showTime}}
|
||||
@@ -7,17 +7,17 @@ BlazeComponent.extendComponent({
|
||||
this.card = this.data();
|
||||
},
|
||||
toggleOvertime() {
|
||||
this.card.isOvertime = !this.card.isOvertime;
|
||||
this.card.setIsOvertime(!this.card.getIsOvertime());
|
||||
$('#overtime .materialCheckBox').toggleClass('is-checked');
|
||||
|
||||
$('#overtime').toggleClass('is-checked');
|
||||
},
|
||||
storeTime(spentTime, isOvertime) {
|
||||
this.card.setSpentTime(spentTime);
|
||||
this.card.setOvertime(isOvertime);
|
||||
this.card.setIsOvertime(isOvertime);
|
||||
},
|
||||
deleteTime() {
|
||||
this.card.unsetSpentTime();
|
||||
this.card.setSpentTime(null);
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
@@ -26,7 +26,7 @@ BlazeComponent.extendComponent({
|
||||
evt.preventDefault();
|
||||
|
||||
const spentTime = parseFloat(evt.target.time.value);
|
||||
const isOvertime = this.card.isOvertime;
|
||||
const isOvertime = this.card.getIsOvertime();
|
||||
|
||||
if (spentTime >= 0) {
|
||||
this.storeTime(spentTime, isOvertime);
|
||||
@@ -55,17 +55,14 @@ BlazeComponent.extendComponent({
|
||||
self.time = ReactiveVar();
|
||||
},
|
||||
showTitle() {
|
||||
if (this.data().isOvertime) {
|
||||
return `${TAPi18n.__('overtime')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||
if (this.data().getIsOvertime()) {
|
||||
return `${TAPi18n.__('overtime')} ${this.data().getSpentTime()} ${TAPi18n.__('hours')}`;
|
||||
} else {
|
||||
return `${TAPi18n.__('card-spent')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||
return `${TAPi18n.__('card-spent')} ${this.data().getSpentTime()} ${TAPi18n.__('hours')}`;
|
||||
}
|
||||
},
|
||||
showTime() {
|
||||
return this.data().spentTime;
|
||||
},
|
||||
isOvertime() {
|
||||
return this.data().isOvertime;
|
||||
return this.data().getSpentTime();
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
|
||||
@@ -74,8 +74,10 @@ BlazeComponent.extendComponent({
|
||||
event.preventDefault();
|
||||
const textarea = this.find('textarea.js-add-checklist-item');
|
||||
const title = textarea.value.trim();
|
||||
const cardId = this.currentData().cardId;
|
||||
let cardId = this.currentData().cardId;
|
||||
const card = Cards.findOne(cardId);
|
||||
if (card.isLinked())
|
||||
cardId = card.linkedId;
|
||||
|
||||
if (title) {
|
||||
Checklists.insert({
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
template(name="minicard")
|
||||
.minicard
|
||||
.minicard(
|
||||
class="{{#if isLinkedCard}}linked-card{{/if}}"
|
||||
class="{{#if isLinkedBoard}}linked-board{{/if}}"
|
||||
class="minicard-{{colorClass}}")
|
||||
if cover
|
||||
.minicard-cover(style="background-image: url('{{cover.url}}');")
|
||||
if labels
|
||||
@@ -7,14 +10,24 @@ template(name="minicard")
|
||||
each labels
|
||||
.minicard-label(class="card-label-{{color}}" title="{{name}}")
|
||||
.minicard-title
|
||||
.handle
|
||||
.fa.fa-arrows
|
||||
if $eq 'prefix-with-full-path' currentBoard.presentParentTask
|
||||
.parent-prefix
|
||||
| {{ parentString ' > ' }}
|
||||
if $eq 'prefix-with-parent' currentBoard.presentParentTask
|
||||
.parent-prefix
|
||||
| {{ parentCardName }}
|
||||
if isLinkedBoard
|
||||
a.js-linked-link
|
||||
span.linked-icon.fa.fa-folder
|
||||
else if isLinkedCard
|
||||
a.js-linked-link
|
||||
span.linked-icon.fa.fa-id-card
|
||||
if getArchived
|
||||
span.linked-icon.linked-archived.fa.fa-archive
|
||||
+viewer
|
||||
| {{ title }}
|
||||
= getTitle
|
||||
if $eq 'subtext-with-full-path' currentBoard.presentParentTask
|
||||
.parent-subtext
|
||||
| {{ parentString ' > ' }}
|
||||
@@ -23,23 +36,19 @@ template(name="minicard")
|
||||
| {{ parentCardName }}
|
||||
|
||||
.dates
|
||||
if receivedAt
|
||||
unless startAt
|
||||
unless dueAt
|
||||
unless endAt
|
||||
if getReceived
|
||||
unless getStart
|
||||
unless getDue
|
||||
unless getEnd
|
||||
.date
|
||||
+minicardReceivedDate
|
||||
if startAt
|
||||
if getStart
|
||||
.date
|
||||
+minicardStartDate
|
||||
if dueAt
|
||||
unless endAt
|
||||
.date
|
||||
+minicardDueDate
|
||||
if endAt
|
||||
if getDue
|
||||
.date
|
||||
+minicardEndDate
|
||||
if spentTime
|
||||
+minicardDueDate
|
||||
if getSpentTime
|
||||
.date
|
||||
+cardSpentTime
|
||||
|
||||
@@ -47,24 +56,26 @@ template(name="minicard")
|
||||
each customFieldsWD
|
||||
if definition.showOnCard
|
||||
.minicard-custom-field
|
||||
.minicard-custom-field-item
|
||||
= definition.name
|
||||
if definition.showLabelOnMiniCard
|
||||
.minicard-custom-field-item
|
||||
= definition.name
|
||||
.minicard-custom-field-item
|
||||
+viewer
|
||||
= trueValue
|
||||
|
||||
if members
|
||||
if getMembers
|
||||
.minicard-members.js-minicard-members
|
||||
each members
|
||||
each getMembers
|
||||
+userAvatar(userId=this)
|
||||
|
||||
.badges
|
||||
if comments.count
|
||||
.badge(title="{{_ 'card-comments-title' comments.count }}")
|
||||
span.badge-icon.fa.fa-comment-o.badge-comment
|
||||
span.badge-text= comments.count
|
||||
if description
|
||||
.badge.badge-state-image-only(title=description)
|
||||
unless currentUser.isNoComments
|
||||
if comments.count
|
||||
.badge(title="{{_ 'card-comments-title' comments.count }}")
|
||||
span.badge-icon.fa.fa-comment-o.badge-comment
|
||||
span.badge-text= comments.count
|
||||
if getDescription
|
||||
.badge.badge-state-image-only(title=getDescription)
|
||||
span.badge-icon.fa.fa-align-left
|
||||
if attachments.count
|
||||
.badge
|
||||
|
||||
@@ -3,7 +3,22 @@
|
||||
// });
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentColor = new ReactiveVar(this.data().color);
|
||||
},
|
||||
|
||||
template() {
|
||||
return 'minicard';
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-linked-link' () {
|
||||
if (this.data().isLinkedCard())
|
||||
Utils.goCardId(this.data().linkedId);
|
||||
else if (this.data().isLinkedBoard())
|
||||
Utils.goBoardId(this.data().linkedId);
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('minicard');
|
||||
@@ -44,6 +44,16 @@
|
||||
transition: transform 0.2s,
|
||||
border-radius 0.2s
|
||||
|
||||
&.linked-board
|
||||
&.linked-card
|
||||
.linked-icon
|
||||
display: inline-block
|
||||
margin-right: 11px
|
||||
vertical-align: baseline
|
||||
font-size: 0.9em
|
||||
.linked-archived
|
||||
color: #937760
|
||||
|
||||
.is-selected &
|
||||
transform: translateX(11px)
|
||||
border-bottom-right-radius: 0
|
||||
@@ -84,9 +94,24 @@
|
||||
.minicard-custom-field-item
|
||||
max-width:50%;
|
||||
flex-grow:1;
|
||||
.handle
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
right: 5px;
|
||||
top: 5px;
|
||||
display:none;
|
||||
@media only screen and (max-width: 1199px) {
|
||||
display:block;
|
||||
}
|
||||
.fa-arrows
|
||||
font-size:20px;
|
||||
color: #ccc;
|
||||
.minicard-title
|
||||
p:last-child
|
||||
margin-bottom: 0
|
||||
.viewer
|
||||
display: inline-block
|
||||
.dates
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -177,3 +202,86 @@
|
||||
border-top-right-radius: 0
|
||||
z-index: 15
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.15)
|
||||
|
||||
minicard-color(background, color...)
|
||||
background-color: background
|
||||
if color
|
||||
color: color //overwrite text for better visibility
|
||||
&:hover:not(.minicard-composer),
|
||||
.is-selected &,
|
||||
.draggable-hover-card &
|
||||
background: darken(background, 3%)
|
||||
.draggable-hover-card &
|
||||
background: darken(background, 7%)
|
||||
|
||||
.minicard-green
|
||||
minicard-color(#3cb500, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-yellow
|
||||
minicard-color(#fad900)
|
||||
|
||||
.minicard-orange
|
||||
minicard-color(#ff9f19)
|
||||
|
||||
.minicard-red
|
||||
minicard-color(#eb4646, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-purple
|
||||
minicard-color(#a632db, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-blue
|
||||
minicard-color(#0079bf, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-pink
|
||||
minicard-color(#ff78cb)
|
||||
|
||||
.minicard-sky
|
||||
minicard-color(#00c2e0, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-black
|
||||
minicard-color(#4d4d4d, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-lime
|
||||
minicard-color(#51e898)
|
||||
|
||||
.minicard-silver
|
||||
minicard-color(#c0c0c0)
|
||||
|
||||
.minicard-peachpuff
|
||||
minicard-color(#ffdab9)
|
||||
|
||||
.minicard-crimson
|
||||
minicard-color(#dc143c, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-plum
|
||||
minicard-color(#dda0dd)
|
||||
|
||||
.minicard-darkgreen
|
||||
minicard-color(#006400, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-slateblue
|
||||
minicard-color(#6a5acd, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-magenta
|
||||
minicard-color(#ff00ff, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-gold
|
||||
minicard-color(#ffd700)
|
||||
|
||||
.minicard-navy
|
||||
minicard-color(#000080, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-gray
|
||||
minicard-color(#808080, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-saddlebrown
|
||||
minicard-color(#8b4513, #ffffff) //White text for better visibility
|
||||
|
||||
.minicard-paleturquoise
|
||||
minicard-color(#afeeee)
|
||||
|
||||
.minicard-mistyrose
|
||||
minicard-color(#ffe4e1)
|
||||
|
||||
.minicard-indigo
|
||||
minicard-color(#4b0082, #ffffff) //White text for better visibility
|
||||
@@ -29,6 +29,7 @@ BlazeComponent.extendComponent({
|
||||
boardId: targetBoard._id,
|
||||
sort: sortIndex,
|
||||
swimlaneId,
|
||||
type: 'cardType-card',
|
||||
});
|
||||
|
||||
// In case the filter is active we need to add the newly inserted card in
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
@import 'nib'
|
||||
|
||||
select,
|
||||
textarea,
|
||||
input:not([type=file]),
|
||||
button
|
||||
box-sizing: border-box
|
||||
-webkit-appearance: none
|
||||
background-color: #ebebeb
|
||||
border: 1px solid #ccc
|
||||
border-radius: 3px
|
||||
@@ -225,9 +225,12 @@ textarea
|
||||
|
||||
.edit-controls,
|
||||
.add-controls
|
||||
display: flex
|
||||
align-items: baseline
|
||||
margin-top: 0
|
||||
|
||||
button[type=submit]
|
||||
input[type=button]
|
||||
float: left
|
||||
height: 32px
|
||||
margin-top: -2px
|
||||
|
||||
@@ -12,11 +12,11 @@ template(name="import")
|
||||
|
||||
template(name="importTextarea")
|
||||
form
|
||||
p: label(for='import-textarea') {{_ instruction}}
|
||||
p: label(for='import-textarea') {{_ instruction}} {{_ 'import-board-instruction-about-errors'}}
|
||||
textarea.js-import-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus)
|
||||
| {{jsonText}}
|
||||
if isSandstorm
|
||||
h1.warning DANGER !!! THIS DESTROYS YOUR IMPORTED DATA, CAUSES BOARD NOT FOUND ERROR WHEN YOU OPEN THIS GRAIN AGAIN https://github.com/wekan/wekan/issues/1430
|
||||
h1.warning {{_ 'import-sandstorm-backup-warning'}}
|
||||
p.warning {{_ 'import-sandstorm-warning'}}
|
||||
input.primary.wide(type="submit" value="{{_ 'import'}}")
|
||||
|
||||
|
||||
@@ -26,6 +26,13 @@ BlazeComponent.extendComponent({
|
||||
|
||||
const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
||||
const $cards = this.$('.js-minicards');
|
||||
|
||||
if(window.matchMedia('(max-width: 1199px)').matches) {
|
||||
$( '.js-minicards' ).sortable({
|
||||
handle: '.handle',
|
||||
});
|
||||
}
|
||||
|
||||
$cards.sortable({
|
||||
connectWith: '.js-minicards:not(.js-list-full)',
|
||||
tolerance: 'pointer',
|
||||
@@ -47,6 +54,7 @@ BlazeComponent.extendComponent({
|
||||
items: itemsSelector,
|
||||
placeholder: 'minicard-wrapper placeholder',
|
||||
start(evt, ui) {
|
||||
ui.helper.css('z-index', 1000);
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
boardComponent.setIsDragging(true);
|
||||
|
||||
@@ -187,3 +187,14 @@
|
||||
padding: 7px
|
||||
top: -@padding
|
||||
right: 17px
|
||||
|
||||
.link-board-wrapper
|
||||
display: flex
|
||||
align-items: baseline
|
||||
|
||||
.js-link-board
|
||||
margin-left: 15px
|
||||
|
||||
.search-card-results
|
||||
max-height: 250px
|
||||
overflow: hidden
|
||||
@@ -34,8 +34,62 @@ template(name="addCardForm")
|
||||
|
||||
.add-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'add'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
unless isSandstorm
|
||||
span.quiet
|
||||
| {{_ 'or'}}
|
||||
a.js-link {{_ 'link'}}
|
||||
span.quiet
|
||||
|
|
||||
| /
|
||||
a.js-search {{_ 'search'}}
|
||||
|
||||
template(name="autocompleteLabelLine")
|
||||
.minicard-label(class="card-label-{{colorName}}" title=labelName)
|
||||
span(class="{{#if hasNoName}}quiet{{/if}}")= labelName
|
||||
|
||||
template(name="linkCardPopup")
|
||||
label {{_ 'boards'}}:
|
||||
.link-board-wrapper
|
||||
select.js-select-boards
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
input.primary.confirm.js-link-board(type="button" value="{{_ 'link'}}")
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
each swimlanes
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each lists
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'cards'}}:
|
||||
select.js-select-cards
|
||||
each cards
|
||||
option(value="{{getId}}") {{getTitle}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
unless isSandstorm
|
||||
input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
|
||||
|
||||
template(name="searchCardPopup")
|
||||
label {{_ 'boards'}}:
|
||||
.link-board-wrapper
|
||||
select.js-select-boards
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
form.js-search-term-form
|
||||
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
|
||||
.list-body.js-perfect-scrollbar.search-card-results
|
||||
.minicards.clearfix.js-minicards
|
||||
each results
|
||||
a.minicard-wrapper.js-minicard
|
||||
+minicard(this)
|
||||
@@ -1,3 +1,5 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.PerfectScrollbar];
|
||||
@@ -55,7 +57,10 @@ BlazeComponent.extendComponent({
|
||||
boardId: boardId._id,
|
||||
sort: sortIndex,
|
||||
swimlaneId,
|
||||
type: 'cardType-card',
|
||||
});
|
||||
|
||||
|
||||
// In case the filter is active we need to add the newly inserted card in
|
||||
// the list of exceptions -- cards that are not filtered. Otherwise the
|
||||
// card will disappear instantly.
|
||||
@@ -149,6 +154,14 @@ BlazeComponent.extendComponent({
|
||||
this.labels = new ReactiveVar([]);
|
||||
this.members = new ReactiveVar([]);
|
||||
this.customFields = new ReactiveVar([]);
|
||||
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
arr = [];
|
||||
_.forEach(Boards.findOne(currentBoardId).customFields().fetch(), function(field){
|
||||
if(field.automaticallyOnCard)
|
||||
arr.push({_id: field._id, value: null});
|
||||
});
|
||||
this.customFields.set(arr);
|
||||
},
|
||||
|
||||
reset() {
|
||||
@@ -197,6 +210,8 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{
|
||||
keydown: this.pressKey,
|
||||
'click .js-link': Popup.open('linkCard'),
|
||||
'click .js-search': Popup.open('searchCard'),
|
||||
}];
|
||||
},
|
||||
|
||||
@@ -268,3 +283,226 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
},
|
||||
}).register('addCardForm');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
// Prefetch first non-current board id
|
||||
const boardId = Boards.findOne({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {$ne: Session.get('currentBoard')},
|
||||
}, {
|
||||
sort: ['title'],
|
||||
})._id;
|
||||
// Subscribe to this board
|
||||
subManager.subscribe('board', boardId);
|
||||
this.selectedBoardId = new ReactiveVar(boardId);
|
||||
this.selectedSwimlaneId = new ReactiveVar('');
|
||||
this.selectedListId = new ReactiveVar('');
|
||||
|
||||
this.boardId = Session.get('currentBoard');
|
||||
// In order to get current board info
|
||||
subManager.subscribe('board', this.boardId);
|
||||
this.board = Boards.findOne(this.boardId);
|
||||
// List where to insert card
|
||||
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
|
||||
this.listId = Blaze.getData(list[0])._id;
|
||||
// Swimlane where to insert card
|
||||
const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
|
||||
this.swimlaneId = '';
|
||||
const boardView = Meteor.user().profile.boardView;
|
||||
if (boardView === 'board-view-swimlanes')
|
||||
this.swimlaneId = Blaze.getData(swimlane[0])._id;
|
||||
else if (boardView === 'board-view-lists')
|
||||
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
|
||||
},
|
||||
|
||||
boards() {
|
||||
const boards = Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {$ne: Session.get('currentBoard')},
|
||||
}, {
|
||||
sort: ['title'],
|
||||
});
|
||||
return boards;
|
||||
},
|
||||
|
||||
swimlanes() {
|
||||
if (!this.selectedBoardId) {
|
||||
return [];
|
||||
}
|
||||
const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()});
|
||||
if (swimlanes.count())
|
||||
this.selectedSwimlaneId.set(swimlanes.fetch()[0]._id);
|
||||
return swimlanes;
|
||||
},
|
||||
|
||||
lists() {
|
||||
if (!this.selectedBoardId) {
|
||||
return [];
|
||||
}
|
||||
const lists = Lists.find({boardId: this.selectedBoardId.get()});
|
||||
if (lists.count())
|
||||
this.selectedListId.set(lists.fetch()[0]._id);
|
||||
return lists;
|
||||
},
|
||||
|
||||
cards() {
|
||||
if (!this.board) {
|
||||
return [];
|
||||
}
|
||||
const ownCardsIds = this.board.cards().map((card) => { return card.linkedId || card._id; });
|
||||
return Cards.find({
|
||||
boardId: this.selectedBoardId.get(),
|
||||
swimlaneId: this.selectedSwimlaneId.get(),
|
||||
listId: this.selectedListId.get(),
|
||||
archived: false,
|
||||
linkedId: {$nin: ownCardsIds},
|
||||
_id: {$nin: ownCardsIds},
|
||||
});
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'change .js-select-boards'(evt) {
|
||||
subManager.subscribe('board', $(evt.currentTarget).val());
|
||||
this.selectedBoardId.set($(evt.currentTarget).val());
|
||||
},
|
||||
'change .js-select-swimlanes'(evt) {
|
||||
this.selectedSwimlaneId.set($(evt.currentTarget).val());
|
||||
},
|
||||
'change .js-select-lists'(evt) {
|
||||
this.selectedListId.set($(evt.currentTarget).val());
|
||||
},
|
||||
'click .js-done' (evt) {
|
||||
// LINK CARD
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
const linkedId = $('.js-select-cards option:selected').val();
|
||||
if (!linkedId) {
|
||||
Popup.close();
|
||||
return;
|
||||
}
|
||||
const _id = Cards.insert({
|
||||
title: $('.js-select-cards option:selected').text(), //dummy
|
||||
listId: this.listId,
|
||||
swimlaneId: this.swimlaneId,
|
||||
boardId: this.boardId,
|
||||
sort: Lists.findOne(this.listId).cards().count(),
|
||||
type: 'cardType-linkedCard',
|
||||
linkedId,
|
||||
});
|
||||
Filter.addException(_id);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-link-board' (evt) {
|
||||
//LINK BOARD
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
const impBoardId = $('.js-select-boards option:selected').val();
|
||||
if (!impBoardId || Cards.findOne({linkedId: impBoardId, archived: false})) {
|
||||
Popup.close();
|
||||
return;
|
||||
}
|
||||
const _id = Cards.insert({
|
||||
title: $('.js-select-boards option:selected').text(), //dummy
|
||||
listId: this.listId,
|
||||
swimlaneId: this.swimlaneId,
|
||||
boardId: this.boardId,
|
||||
sort: Lists.findOne(this.listId).cards().count(),
|
||||
type: 'cardType-linkedBoard',
|
||||
linkedId: impBoardId,
|
||||
});
|
||||
Filter.addException(_id);
|
||||
Popup.close();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('linkCardPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.PerfectScrollbar];
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
// Prefetch first non-current board id
|
||||
let board = Boards.findOne({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {$ne: Session.get('currentBoard')},
|
||||
});
|
||||
if (!board) {
|
||||
Popup.close();
|
||||
return;
|
||||
}
|
||||
const boardId = board._id;
|
||||
// Subscribe to this board
|
||||
subManager.subscribe('board', boardId);
|
||||
this.selectedBoardId = new ReactiveVar(boardId);
|
||||
|
||||
this.boardId = Session.get('currentBoard');
|
||||
// In order to get current board info
|
||||
subManager.subscribe('board', this.boardId);
|
||||
board = Boards.findOne(this.boardId);
|
||||
// List where to insert card
|
||||
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
|
||||
this.listId = Blaze.getData(list[0])._id;
|
||||
// Swimlane where to insert card
|
||||
const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
|
||||
this.swimlaneId = '';
|
||||
if (board.view === 'board-view-swimlanes')
|
||||
this.swimlaneId = Blaze.getData(swimlane[0])._id;
|
||||
else
|
||||
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
|
||||
this.term = new ReactiveVar('');
|
||||
},
|
||||
|
||||
boards() {
|
||||
const boards = Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {$ne: Session.get('currentBoard')},
|
||||
}, {
|
||||
sort: ['title'],
|
||||
});
|
||||
return boards;
|
||||
},
|
||||
|
||||
results() {
|
||||
if (!this.selectedBoardId) {
|
||||
return [];
|
||||
}
|
||||
const board = Boards.findOne(this.selectedBoardId.get());
|
||||
return board.searchCards(this.term.get(), false);
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'change .js-select-boards'(evt) {
|
||||
subManager.subscribe('board', $(evt.currentTarget).val());
|
||||
this.selectedBoardId.set($(evt.currentTarget).val());
|
||||
},
|
||||
'submit .js-search-term-form'(evt) {
|
||||
evt.preventDefault();
|
||||
this.term.set(evt.target.searchTerm.value);
|
||||
},
|
||||
'click .js-minicard'(evt) {
|
||||
// LINK CARD
|
||||
const card = Blaze.getData(evt.currentTarget);
|
||||
const _id = Cards.insert({
|
||||
title: card.title, //dummy
|
||||
listId: this.listId,
|
||||
swimlaneId: this.swimlaneId,
|
||||
boardId: this.boardId,
|
||||
sort: Lists.findOne(this.listId).cards().count(),
|
||||
type: 'cardType-linkedCard',
|
||||
linkedId: card.linkedId || card._id,
|
||||
});
|
||||
Filter.addException(_id);
|
||||
Popup.close();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('searchCardPopup');
|
||||
@@ -15,9 +15,8 @@ template(name="listHeader")
|
||||
|/#{wipLimit.value})
|
||||
|
||||
if showCardsCountForList cards.count
|
||||
= cards.count
|
||||
span
|
||||
| {{_ 'cards-count'}}
|
||||
|
|
||||
p.quiet.small {{cardsCount}} {{_ 'cards-count'}}
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
if isWatching
|
||||
|
||||
@@ -22,6 +22,16 @@ BlazeComponent.extendComponent({
|
||||
return Meteor.user().getLimitToShowCardsCount();
|
||||
},
|
||||
|
||||
cardsCount() {
|
||||
const list = Template.currentData();
|
||||
let swimlaneId = '';
|
||||
const boardView = Meteor.user().profile.boardView;
|
||||
if (boardView === 'board-view-swimlanes')
|
||||
swimlaneId = this.parentComponent().parentComponent().data()._id;
|
||||
|
||||
return list.cards(swimlaneId).count();
|
||||
},
|
||||
|
||||
reachedWipLimit() {
|
||||
const list = Template.currentData();
|
||||
return list.getWipLimit('enabled') && list.getWipLimit('value') <= list.cards().count();
|
||||
|
||||
@@ -38,7 +38,10 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
||||
const view = this;
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const knowedUsers = currentBoard.members.map((member) => {
|
||||
member.username = Users.findOne(member.userId).username;
|
||||
const u = Users.findOne(member.userId);
|
||||
if(u){
|
||||
member.username = u.username;
|
||||
}
|
||||
return member;
|
||||
});
|
||||
const mentionRegex = /\B@([\w.]*)/gi;
|
||||
|
||||
@@ -47,6 +47,7 @@ template(name="header")
|
||||
+Template.dynamic(template=headerBar)
|
||||
|
||||
unless hideLogo
|
||||
|
||||
//-
|
||||
On sandstorm, the logo shouldn't be clickable, because we only have one
|
||||
page/document on it, and we don't want to see the home page containing
|
||||
@@ -55,8 +56,9 @@ template(name="header")
|
||||
.wekan-logo
|
||||
img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
|
||||
else
|
||||
a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
|
||||
img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
|
||||
unless currentSetting.hideLogo
|
||||
a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
|
||||
img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
|
||||
|
||||
if appIsOffline
|
||||
+offlineWarning
|
||||
@@ -66,7 +68,8 @@ template(name="header")
|
||||
.announcement
|
||||
p
|
||||
i.fa.fa-bullhorn
|
||||
| #{announcement}
|
||||
+viewer
|
||||
| #{announcement}
|
||||
i.fa.fa-times-circle.js-close-announcement
|
||||
|
||||
template(name="offlineWarning")
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
Meteor.subscribe('user-admin');
|
||||
Meteor.subscribe('boards');
|
||||
Meteor.subscribe('setting');
|
||||
|
||||
Template.header.helpers({
|
||||
wrappedHeader() {
|
||||
return !Session.get('currentBoard');
|
||||
},
|
||||
|
||||
currentSetting() {
|
||||
return Settings.findOne();
|
||||
},
|
||||
|
||||
hideLogo() {
|
||||
return Utils.isMiniScreen() && Session.get('currentBoard');
|
||||
},
|
||||
|
||||
@@ -188,8 +188,6 @@
|
||||
width: 100%
|
||||
padding: 10px 0px
|
||||
z-index: 30
|
||||
position: absolute
|
||||
bottom: 0px
|
||||
|
||||
ul
|
||||
width: calc(100% - 60px)
|
||||
|
||||
@@ -7,16 +7,23 @@ head
|
||||
where the application is deployed with a path prefix, but it seems to be
|
||||
difficult to do that cleanly with Blaze -- at least without adding extra
|
||||
packages.
|
||||
link(rel="shortcut icon" href="/wekan-favicon.png")
|
||||
link(rel="apple-touch-icon" href="/wekan-favicon.png")
|
||||
link(rel="manifest" href="/wekan-manifest.json")
|
||||
link(rel="shortcut icon" href="/public/wekan-favicon.png")
|
||||
link(rel="apple-touch-icon" href="/public/wekan-favicon.png")
|
||||
link(rel="mask-icon" href="/public/wekan-150.svg")
|
||||
link(rel="manifest" href="/public/wekan-manifest.json")
|
||||
|
||||
template(name="userFormsLayout")
|
||||
section.auth-layout
|
||||
h1.at-form-landing-logo
|
||||
img(src="{{pathFor '/wekan-logo.png'}}" alt="Wekan")
|
||||
unless currentSetting.hideLogo
|
||||
h1.at-form-landing-logo
|
||||
img(src="{{pathFor '/wekan-logo.png'}}" alt="Wekan")
|
||||
if currentSetting.hideLogo
|
||||
h1
|
||||
br
|
||||
br
|
||||
section.auth-dialog
|
||||
+Template.dynamic(template=content)
|
||||
+connectionMethod
|
||||
if isCas
|
||||
.at-form
|
||||
button#cas(class='at-btn submit' type='submit') {{casSignInLabel}}
|
||||
@@ -31,15 +38,24 @@ template(name="userFormsLayout")
|
||||
template(name="defaultLayout")
|
||||
+header
|
||||
#content
|
||||
| {{{afterBodyStart}}}
|
||||
+Template.dynamic(template=content)
|
||||
| {{{beforeBodyEnd}}}
|
||||
if (Modal.isOpen)
|
||||
#modal
|
||||
.overlay
|
||||
.modal-content
|
||||
a.modal-close-btn.js-close-modal
|
||||
i.fa.fa-times-thin
|
||||
+Template.dynamic(template=Modal.getHeaderName)
|
||||
+Template.dynamic(template=Modal.getTemplateName)
|
||||
if (Modal.isWide)
|
||||
.modal-content-wide.modal-container
|
||||
a.modal-close-btn.js-close-modal
|
||||
i.fa.fa-times-thin
|
||||
+Template.dynamic(template=Modal.getHeaderName)
|
||||
+Template.dynamic(template=Modal.getTemplateName)
|
||||
else
|
||||
.modal-content.modal-container
|
||||
a.modal-close-btn.js-close-modal
|
||||
i.fa.fa-times-thin
|
||||
+Template.dynamic(template=Modal.getHeaderName)
|
||||
+Template.dynamic(template=Modal.getTemplateName)
|
||||
|
||||
template(name="notFound")
|
||||
+message(label='page-not-found')
|
||||
|
||||
@@ -6,7 +6,29 @@ const i18nTagToT9n = (i18nTag) => {
|
||||
return i18nTag;
|
||||
};
|
||||
|
||||
const validator = {
|
||||
set(obj, prop, value) {
|
||||
if (prop === 'state' && value !== 'signIn') {
|
||||
$('.at-form-authentication').hide();
|
||||
} else if (prop === 'state' && value === 'signIn') {
|
||||
$('.at-form-authentication').show();
|
||||
}
|
||||
// The default behavior to store the value
|
||||
obj[prop] = value;
|
||||
// Indicate success
|
||||
return true;
|
||||
},
|
||||
};
|
||||
|
||||
Template.userFormsLayout.onCreated(() => {
|
||||
Meteor.subscribe('setting');
|
||||
|
||||
});
|
||||
|
||||
Template.userFormsLayout.onRendered(() => {
|
||||
|
||||
AccountsTemplates.state.form.keys = new Proxy(AccountsTemplates.state.form.keys, validator);
|
||||
|
||||
const i18nTag = navigator.language;
|
||||
if (i18nTag) {
|
||||
T9n.setLanguage(i18nTagToT9n(i18nTag));
|
||||
@@ -15,6 +37,20 @@ Template.userFormsLayout.onRendered(() => {
|
||||
});
|
||||
|
||||
Template.userFormsLayout.helpers({
|
||||
|
||||
currentSetting() {
|
||||
return Settings.findOne();
|
||||
},
|
||||
|
||||
|
||||
afterBodyStart() {
|
||||
return currentSetting.customHTMLafterBodyStart;
|
||||
},
|
||||
|
||||
beforeBodyEnd() {
|
||||
return currentSetting.customHTMLbeforeBodyEnd;
|
||||
},
|
||||
|
||||
languages() {
|
||||
return _.map(TAPi18n.getLanguages(), (lang, code) => {
|
||||
const tag = code;
|
||||
@@ -39,7 +75,7 @@ Template.userFormsLayout.helpers({
|
||||
const curLang = T9n.getLanguage() || 'en';
|
||||
return t9nTag === curLang;
|
||||
},
|
||||
|
||||
/*
|
||||
isCas() {
|
||||
return Meteor.settings.public &&
|
||||
Meteor.settings.public.cas &&
|
||||
@@ -49,6 +85,7 @@ Template.userFormsLayout.helpers({
|
||||
casSignInLabel() {
|
||||
return TAPi18n.__('casSignIn', {}, T9n.getLanguage() || 'en');
|
||||
},
|
||||
*/
|
||||
});
|
||||
|
||||
Template.userFormsLayout.events({
|
||||
@@ -64,6 +101,44 @@ Template.userFormsLayout.events({
|
||||
}
|
||||
});
|
||||
},
|
||||
'click #at-btn'(event) {
|
||||
/* All authentication method can be managed/called here.
|
||||
!! DON'T FORGET to correctly fill the fields of the user during its creation if necessary authenticationMethod : String !!
|
||||
*/
|
||||
const authenticationMethodSelected = $('.select-authentication').val();
|
||||
// Local account
|
||||
if (authenticationMethodSelected === 'password') {
|
||||
return;
|
||||
}
|
||||
|
||||
// Stop submit #at-pwd-form
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
const email = $('#at-field-username_and_email').val();
|
||||
const password = $('#at-field-password').val();
|
||||
|
||||
// Ldap account
|
||||
if (authenticationMethodSelected === 'ldap') {
|
||||
// Check if the user can use the ldap connection
|
||||
Meteor.subscribe('user-authenticationMethod', email, {
|
||||
onReady() {
|
||||
const user = Users.findOne();
|
||||
if (user === undefined || user.authenticationMethod === 'ldap') {
|
||||
// Use the ldap connection package
|
||||
Meteor.loginWithLDAP(email, password, function(error) {
|
||||
if (!error) {
|
||||
// Connection
|
||||
return FlowRouter.go('/');
|
||||
}
|
||||
return error;
|
||||
});
|
||||
}
|
||||
return this.stop();
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.defaultLayout.events({
|
||||
|
||||
@@ -61,6 +61,23 @@ body
|
||||
display: block
|
||||
float: right
|
||||
font-size: 24px
|
||||
|
||||
.modal-content-wide
|
||||
width: 800px
|
||||
min-height: 0px
|
||||
margin: 42px auto
|
||||
padding: 12px
|
||||
border-radius: 4px
|
||||
background: darken(white, 13%)
|
||||
z-index: 110
|
||||
|
||||
h2
|
||||
margin-bottom: 25px
|
||||
|
||||
.modal-close-btn
|
||||
display: block
|
||||
float: right
|
||||
font-size: 24px
|
||||
|
||||
h1
|
||||
font-size: 22px
|
||||
@@ -368,8 +385,8 @@ a
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
#content
|
||||
margin: 1px 0px 49px 0px
|
||||
height: calc(100% - 96px)
|
||||
margin: 1px 0px 0px 0px
|
||||
height: calc(100% - 0px)
|
||||
|
||||
> .wrapper
|
||||
margin-top: 0px
|
||||
|
||||
Vendored
BIN
Binary file not shown.
@@ -0,0 +1,72 @@
|
||||
template(name="boardActions")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-move-card-to'}}
|
||||
div.trigger-dropdown
|
||||
select(id="move-gen-action")
|
||||
option(value="top") {{_'r-top-of'}}
|
||||
option(value="bottom") {{_'r-bottom-of'}}
|
||||
div.trigger-text
|
||||
| {{_'r-its-list'}}
|
||||
div.trigger-button.js-add-gen-move-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-move-card-to'}}
|
||||
div.trigger-dropdown
|
||||
select(id="move-spec-action")
|
||||
option(value="top") {{_'r-top-of'}}
|
||||
option(value="bottom") {{_'r-bottom-of'}}
|
||||
div.trigger-text
|
||||
| {{_'r-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="listName",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-spec-move-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="arch-action")
|
||||
option(value="archive") {{_'r-archive'}}
|
||||
option(value="unarchive") {{_'r-unarchive'}}
|
||||
div.trigger-text
|
||||
| {{_'r-card'}}
|
||||
div.trigger-button.js-add-arch-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-add-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="swimlane-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-swimlane-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-create-card'}}
|
||||
div.trigger-dropdown
|
||||
input(id="card-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-in-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="list-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-in-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="swimlane-name2",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-create-card-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,168 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-create-card-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const cardName = this.find('#card-name').value;
|
||||
const listName = this.find('#list-name').value;
|
||||
const swimlaneName = this.find('#swimlane-name2').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'createCard',
|
||||
swimlaneName,
|
||||
cardName,
|
||||
listName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
|
||||
},
|
||||
'click .js-add-swimlane-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const swimlaneName = this.find('#swimlane-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'addSwimlane',
|
||||
swimlaneName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
|
||||
},
|
||||
'click .js-add-spec-move-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#move-spec-action').value;
|
||||
const listTitle = this.find('#listName').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'top') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToTop',
|
||||
listTitle,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'bottom') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToBottom',
|
||||
listTitle,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-gen-move-action' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const boardId = Session.get('currentBoard');
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#move-gen-action').value;
|
||||
if (actionSelected === 'top') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToTop',
|
||||
'listTitle': '*',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'bottom') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToBottom',
|
||||
'listTitle': '*',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-arch-action' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const boardId = Session.get('currentBoard');
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#arch-action').value;
|
||||
if (actionSelected === 'archive') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'archive',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'unarchive') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'unarchive',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('boardActions');
|
||||
/* eslint-no-undef */
|
||||
@@ -0,0 +1,70 @@
|
||||
template(name="cardActions")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="label-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
div.trigger-text
|
||||
| {{{_'r-label'}}}
|
||||
div.trigger-dropdown
|
||||
select(id="label-id")
|
||||
each labels
|
||||
option(value="#{_id}")
|
||||
= name
|
||||
div.trigger-button.js-add-label-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="member-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
div.trigger-text
|
||||
| {{{_'r-member'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="member-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-button.js-add-member-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-remove-all'}}}
|
||||
div.trigger-button.js-add-removeall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-set-color'}}}
|
||||
div.trigger-dropdown
|
||||
select(id="color-action")
|
||||
option(value="white") {{{_'color-white'}}}
|
||||
option(value="green") {{{_'color-green'}}}
|
||||
option(value="yellow") {{{_'color-yellow'}}}
|
||||
option(value="orange") {{{_'color-orange'}}}
|
||||
option(value="red") {{{_'color-red'}}}
|
||||
option(value="purple") {{{_'color-purple'}}}
|
||||
option(value="blue") {{{_'color-blue'}}}
|
||||
option(value="sky") {{{_'color-sky'}}}
|
||||
option(value="lime") {{{_'color-lime'}}}
|
||||
option(value="pink") {{{_'color-pink'}}}
|
||||
option(value="black") {{{_'color-black'}}}
|
||||
option(value="silver") {{{_'color-silver'}}}
|
||||
option(value="peachpuff") {{{_'color-peachpuff'}}}
|
||||
option(value="crimson") {{{_'color-crimson'}}}
|
||||
option(value="plum") {{{_'color-plum'}}}
|
||||
option(value="darkgreen") {{{_'color-darkgreen'}}}
|
||||
option(value="slateblue") {{{_'color-slateblue'}}}
|
||||
option(value="magenta") {{{_'color-magenta'}}}
|
||||
option(value="gold") {{{_'color-gold'}}}
|
||||
option(value="navy") {{{_'color-navy'}}}
|
||||
option(value="gray") {{{_'color-gray'}}}
|
||||
option(value="saddlebrown") {{{_'color-saddlebrown'}}}
|
||||
option(value="paleturquoise") {{{_'color-paleturquoise'}}}
|
||||
option(value="mistyrose") {{{_'color-mistyrose'}}}
|
||||
option(value="indigo") {{{_'color-indigo'}}}
|
||||
div.trigger-button.js-set-color-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
@@ -0,0 +1,138 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
},
|
||||
|
||||
labels() {
|
||||
const labels = Boards.findOne(Session.get('currentBoard')).labels;
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
if (labels[i].name === '' || labels[i].name === undefined) {
|
||||
labels[i].name = labels[i].color.toUpperCase();
|
||||
}
|
||||
}
|
||||
return labels;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-add-label-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#label-action').value;
|
||||
const labelId = this.find('#label-id').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'add') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'addLabel',
|
||||
labelId,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'remove') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'removeLabel',
|
||||
labelId,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
'click .js-add-member-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#member-action').value;
|
||||
const username = this.find('#member-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'add') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'addMember',
|
||||
username,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'remove') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'removeMember',
|
||||
username,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-removeall-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const boardId = Session.get('currentBoard');
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'removeMember',
|
||||
'username': '*',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
},
|
||||
'click .js-set-color-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const selectedColor = this.find('#color-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'setColor',
|
||||
selectedColor,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('cardActions');
|
||||
@@ -0,0 +1,70 @@
|
||||
template(name="checklistActions")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-action")
|
||||
option(value="add") {{{_'r-add'}}}
|
||||
option(value="remove") {{{_'r-remove'}}}
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-button.js-add-checklist-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="checkall-action")
|
||||
option(value="check") {{{_'r-check-all'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck-all'}}}
|
||||
div.trigger-text
|
||||
| {{{_'r-items-check'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name2",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-button.js-add-checkall-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-dropdown
|
||||
select(id="check-item-action")
|
||||
option(value="check") {{{_'r-check'}}}
|
||||
option(value="uncheck") {{{_'r-uncheck'}}}
|
||||
div.trigger-text
|
||||
| {{{_'r-item'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checkitem-name",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-of-checklist'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-button.js-add-check-item-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-add-checklist'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-name-3",type=text,placeholder="{{{_'r-name'}}}")
|
||||
div.trigger-text
|
||||
| {{{_'r-with-items'}}}
|
||||
div.trigger-dropdown
|
||||
input(id="checklist-items",type=text,placeholder="{{{_'r-items-list'}}}")
|
||||
div.trigger-button.js-add-checklist-items-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-checklist-note'}}}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,151 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-add-checklist-items-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const checklistName = this.find('#checklist-name-3').value;
|
||||
const checklistItems = this.find('#checklist-items').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'addChecklistWithItems',
|
||||
checklistName,
|
||||
checklistItems,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
|
||||
},
|
||||
'click .js-add-checklist-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#check-action').value;
|
||||
const checklistName = this.find('#checklist-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'add') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'addChecklist',
|
||||
checklistName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'remove') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'removeChecklist',
|
||||
checklistName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
|
||||
},
|
||||
'click .js-add-checkall-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#checkall-action').value;
|
||||
const checklistName = this.find('#checklist-name2').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'check') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'checkAll',
|
||||
checklistName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'uncheck') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'uncheckAll',
|
||||
checklistName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-check-item-action' (event) {
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const checkItemName = this.find('#checkitem-name');
|
||||
const checklistName = this.find('#checklist-name3');
|
||||
const actionSelected = this.find('#check-item-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'check') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'checkItem',
|
||||
checklistName,
|
||||
checkItemName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'uncheck') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'uncheckItem',
|
||||
checklistName,
|
||||
checkItemName,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('checklistActions');
|
||||
@@ -0,0 +1,11 @@
|
||||
template(name="mailActions")
|
||||
div.trigger-item.trigger-item-mail
|
||||
div.trigger-content.trigger-content-mail
|
||||
div.trigger-text.trigger-text-email
|
||||
| {{_'r-send-email'}}
|
||||
div.trigger-dropdown-mail
|
||||
input(id="email-to",type=text,placeholder="{{_'r-to'}}")
|
||||
input(id="email-subject",type=text,placeholder="{{_'r-subject'}}")
|
||||
textarea(id="email-msg")
|
||||
div.trigger-button.trigger-button-email.js-mail-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
@@ -0,0 +1,35 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-mail-action' (event) {
|
||||
const emailTo = this.find('#email-to').value;
|
||||
const emailSubject = this.find('#email-subject').value;
|
||||
const emailMsg = this.find('#email-msg').value;
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const boardId = Session.get('currentBoard');
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'sendEmail',
|
||||
emailTo,
|
||||
emailSubject,
|
||||
emailMsg,
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
title: ruleName,
|
||||
triggerId,
|
||||
actionId,
|
||||
boardId,
|
||||
});
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('mailActions');
|
||||
@@ -0,0 +1,20 @@
|
||||
template(name="ruleDetails")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule-details' }}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-main-body
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
= trigger
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
= action
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
@@ -0,0 +1,38 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
this.subscribe('allTriggers');
|
||||
this.subscribe('allActions');
|
||||
|
||||
},
|
||||
|
||||
trigger() {
|
||||
const ruleId = this.data().ruleId;
|
||||
const rule = Rules.findOne({
|
||||
_id: ruleId.get(),
|
||||
});
|
||||
const trigger = Triggers.findOne({
|
||||
_id: rule.triggerId,
|
||||
});
|
||||
const desc = trigger.description();
|
||||
const upperdesc = desc.charAt(0).toUpperCase() + desc.substr(1);
|
||||
return upperdesc;
|
||||
},
|
||||
action() {
|
||||
const ruleId = this.data().ruleId;
|
||||
const rule = Rules.findOne({
|
||||
_id: ruleId.get(),
|
||||
});
|
||||
const action = Actions.findOne({
|
||||
_id: rule.actionId,
|
||||
});
|
||||
const desc = action.description();
|
||||
const upperdesc = desc.charAt(0).toUpperCase() + desc.substr(1);
|
||||
return upperdesc;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{}];
|
||||
},
|
||||
|
||||
}).register('ruleDetails');
|
||||
@@ -0,0 +1,181 @@
|
||||
.rules-list
|
||||
overflow:hidden
|
||||
overflow-y:scroll
|
||||
max-height: 400px
|
||||
.rules-lists-item
|
||||
display: block
|
||||
position: relative
|
||||
overflow: auto
|
||||
p
|
||||
display: inline-block
|
||||
float: left
|
||||
margin: revert
|
||||
.hide-element
|
||||
display:none !important
|
||||
.user-details
|
||||
display:inline-block
|
||||
.rules-btns-group
|
||||
position: absolute
|
||||
right: 0
|
||||
top: 50%
|
||||
transform: translateY(-50%)
|
||||
button
|
||||
margin: auto
|
||||
.rules-add
|
||||
display: block
|
||||
overflow: auto
|
||||
margin-top: 15px
|
||||
margin-bottom: 5px
|
||||
input
|
||||
display: inline-block
|
||||
float: right
|
||||
margin: auto
|
||||
margin-right: 10px
|
||||
button
|
||||
display: inline-block
|
||||
float: right
|
||||
margin: auto
|
||||
.rules-back
|
||||
display: block
|
||||
overflow: auto
|
||||
margin-top: 15px
|
||||
margin-bottom: 5px
|
||||
button
|
||||
display: inline-block
|
||||
float: right
|
||||
margin: auto
|
||||
margin-right:14px
|
||||
|
||||
.flex
|
||||
display: -webkit-box
|
||||
display: -moz-box
|
||||
display: -webkit-flex
|
||||
display: -moz-flex
|
||||
display: -ms-flexbox
|
||||
display: flex
|
||||
|
||||
|
||||
|
||||
.triggers-content
|
||||
color: #727479
|
||||
background: #dedede
|
||||
.triggers-body
|
||||
display flex
|
||||
padding-top 15px
|
||||
height 100%
|
||||
|
||||
.triggers-side-menu
|
||||
background-color: #f7f7f7
|
||||
border: 1px solid #f0f0f0
|
||||
border-radius: 4px
|
||||
height: intrinsic
|
||||
box-shadow: inset -1px -1px 3px rgba(0,0,0,.05)
|
||||
|
||||
ul
|
||||
|
||||
li
|
||||
margin: 0.1rem 0.2rem;
|
||||
width:50px
|
||||
height:50px
|
||||
text-align:center
|
||||
font-size: 25px
|
||||
position: relative
|
||||
|
||||
i
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
box-shadow: none
|
||||
transform: translate(-50%,-50%);
|
||||
|
||||
|
||||
&.active
|
||||
background #fff
|
||||
box-shadow 0 1px 2px rgba(0,0,0,0.15);
|
||||
|
||||
&:hover
|
||||
background #fff
|
||||
box-shadow 0 1px 2px rgba(0,0,0,0.15);
|
||||
a
|
||||
@extends .flex
|
||||
padding: 1rem 0 1rem 1rem
|
||||
width: 100% - 5rem
|
||||
|
||||
|
||||
span
|
||||
font-size: 13px
|
||||
.triggers-main-body
|
||||
padding: 0.1em 1em
|
||||
width:100%
|
||||
.trigger-item
|
||||
overflow:auto
|
||||
padding:10px
|
||||
height:40px
|
||||
margin-bottom:5px
|
||||
border-radius: 3px
|
||||
position: relative
|
||||
background-color: white
|
||||
.trigger-content
|
||||
position:absolute
|
||||
top:50%
|
||||
transform: translateY(-50%)
|
||||
left:10px
|
||||
.trigger-text
|
||||
font-size: 16px
|
||||
display:inline-block
|
||||
.trigger-inline-button
|
||||
font-size: 16px
|
||||
display: inline;
|
||||
padding: 6px;
|
||||
border: 1px solid #eee
|
||||
border-radius: 4px
|
||||
box-shadow: inset -1px -1px 3px rgba(0,0,0,.05)
|
||||
&:hover, &.is-active
|
||||
box-shadow: 0 0 0 2px darken(white, 60%) inset
|
||||
.trigger-text.trigger-text-email
|
||||
margin-left: 5px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
.trigger-dropdown
|
||||
display:inline-block
|
||||
select
|
||||
width:auto
|
||||
height:30px
|
||||
margin:0px
|
||||
margin-left:5px
|
||||
input
|
||||
display: inline-block
|
||||
width: 80px;
|
||||
margin: 0;
|
||||
.trigger-content-mail
|
||||
left:20px
|
||||
right:100px
|
||||
.trigger-button
|
||||
position:absolute
|
||||
top:50%
|
||||
transform: translateY(-50%)
|
||||
width:30px
|
||||
height:30px
|
||||
border: 1px solid #eee
|
||||
border-radius: 4px
|
||||
box-shadow: inset -1px -1px 3px rgba(0,0,0,.05)
|
||||
text-align:center
|
||||
font-size: 20px
|
||||
right:10px
|
||||
i
|
||||
position: absolute
|
||||
top: 50%
|
||||
left: 50%
|
||||
box-shadow: none
|
||||
transform: translate(-50%,-50%)
|
||||
&:hover, &.is-active
|
||||
box-shadow: 0 0 0 2px darken(white, 60%) inset
|
||||
.trigger-button.trigger-button-email
|
||||
top:30px
|
||||
.trigger-button.trigger-button-person
|
||||
right:-40px
|
||||
.trigger-item.trigger-item-mail
|
||||
height:300px
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
template(name="rulesActions")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-action'}}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
ul
|
||||
li.active.js-set-board-actions
|
||||
i.fa.fa-columns
|
||||
li.js-set-card-actions
|
||||
i.fa.fa-sticky-note
|
||||
li.js-set-checklist-actions
|
||||
i.fa.fa-check
|
||||
li.js-set-mail-actions
|
||||
i.fa.fa-at
|
||||
.triggers-main-body
|
||||
if ($eq currentActions.get 'board')
|
||||
+boardActions(ruleName=data.ruleName triggerVar=data.triggerVar)
|
||||
else if ($eq currentActions.get 'card')
|
||||
+cardActions(ruleName=data.ruleName triggerVar=data.triggerVar)
|
||||
else if ($eq currentActions.get 'checklist')
|
||||
+checklistActions(ruleName=data.ruleName triggerVar=data.triggerVar)
|
||||
else if ($eq currentActions.get 'mail')
|
||||
+mailActions(ruleName=data.ruleName triggerVar=data.triggerVar)
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
@@ -0,0 +1,58 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentActions = new ReactiveVar('board');
|
||||
},
|
||||
|
||||
setBoardActions() {
|
||||
this.currentActions.set('board');
|
||||
$('.js-set-card-actions').removeClass('active');
|
||||
$('.js-set-board-actions').addClass('active');
|
||||
$('.js-set-checklist-actions').removeClass('active');
|
||||
$('.js-set-mail-actions').removeClass('active');
|
||||
},
|
||||
setCardActions() {
|
||||
this.currentActions.set('card');
|
||||
$('.js-set-card-actions').addClass('active');
|
||||
$('.js-set-board-actions').removeClass('active');
|
||||
$('.js-set-checklist-actions').removeClass('active');
|
||||
$('.js-set-mail-actions').removeClass('active');
|
||||
},
|
||||
setChecklistActions() {
|
||||
this.currentActions.set('checklist');
|
||||
$('.js-set-card-actions').removeClass('active');
|
||||
$('.js-set-board-actions').removeClass('active');
|
||||
$('.js-set-checklist-actions').addClass('active');
|
||||
$('.js-set-mail-actions').removeClass('active');
|
||||
},
|
||||
setMailActions() {
|
||||
this.currentActions.set('mail');
|
||||
$('.js-set-card-actions').removeClass('active');
|
||||
$('.js-set-board-actions').removeClass('active');
|
||||
$('.js-set-checklist-actions').removeClass('active');
|
||||
$('.js-set-mail-actions').addClass('active');
|
||||
},
|
||||
|
||||
rules() {
|
||||
return Rules.find({});
|
||||
},
|
||||
|
||||
name() {
|
||||
// console.log(this.data());
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-set-board-actions'(){
|
||||
this.setBoardActions();
|
||||
},
|
||||
'click .js-set-card-actions'() {
|
||||
this.setCardActions();
|
||||
},
|
||||
'click .js-set-mail-actions'() {
|
||||
this.setMailActions();
|
||||
},
|
||||
'click .js-set-checklist-actions'() {
|
||||
this.setChecklistActions();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('rulesActions');
|
||||
@@ -0,0 +1,27 @@
|
||||
template(name="rulesList")
|
||||
.rules
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-board-rules' }}}
|
||||
|
||||
ul.rules-list
|
||||
each rules
|
||||
li.rules-lists-item
|
||||
p
|
||||
= title
|
||||
div.rules-btns-group
|
||||
button.js-goto-details
|
||||
i.fa.fa-eye
|
||||
| {{{_ 'r-view-rule'}}}
|
||||
if currentUser.isAdmin
|
||||
button.js-delete-rule
|
||||
i.fa.fa-trash-o
|
||||
| {{{_ 'r-delete-rule'}}}
|
||||
else
|
||||
li.no-items-message {{{_ 'r-no-rules' }}}
|
||||
if currentUser.isAdmin
|
||||
div.rules-add
|
||||
button.js-goto-trigger
|
||||
i.fa.fa-plus
|
||||
| {{{_ 'r-add-rule'}}}
|
||||
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
|
||||
@@ -0,0 +1,15 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
},
|
||||
|
||||
rules() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return Rules.find({
|
||||
boardId,
|
||||
});
|
||||
},
|
||||
events() {
|
||||
return [{}];
|
||||
},
|
||||
}).register('rulesList');
|
||||
@@ -0,0 +1,9 @@
|
||||
template(name="rulesMain")
|
||||
if($eq rulesCurrentTab.get 'rulesList')
|
||||
+rulesList
|
||||
if($eq rulesCurrentTab.get 'trigger')
|
||||
+rulesTriggers(ruleName=ruleName triggerVar=triggerVar)
|
||||
if($eq rulesCurrentTab.get 'action')
|
||||
+rulesActions(ruleName=ruleName triggerVar=triggerVar)
|
||||
if($eq rulesCurrentTab.get 'ruleDetails')
|
||||
+ruleDetails(ruleId=ruleId)
|
||||
@@ -0,0 +1,97 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.rulesCurrentTab = new ReactiveVar('rulesList');
|
||||
this.ruleName = new ReactiveVar('');
|
||||
this.triggerVar = new ReactiveVar();
|
||||
this.ruleId = new ReactiveVar();
|
||||
},
|
||||
|
||||
setTrigger() {
|
||||
this.rulesCurrentTab.set('trigger');
|
||||
},
|
||||
sanitizeObject(obj){
|
||||
Object.keys(obj).forEach((key) => {
|
||||
if(obj[key] === '' || obj[key] === undefined){
|
||||
obj[key] = '*';
|
||||
}}
|
||||
);
|
||||
},
|
||||
setRulesList() {
|
||||
this.rulesCurrentTab.set('rulesList');
|
||||
},
|
||||
|
||||
setAction() {
|
||||
this.rulesCurrentTab.set('action');
|
||||
},
|
||||
|
||||
setRuleDetails() {
|
||||
this.rulesCurrentTab.set('ruleDetails');
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-delete-rule' () {
|
||||
const rule = this.currentData();
|
||||
Rules.remove(rule._id);
|
||||
Actions.remove(rule.actionId);
|
||||
Triggers.remove(rule.triggerId);
|
||||
|
||||
},
|
||||
'click .js-goto-trigger' (event) {
|
||||
event.preventDefault();
|
||||
const ruleTitle = this.find('#ruleTitle').value;
|
||||
if(ruleTitle !== undefined && ruleTitle !== ''){
|
||||
this.find('#ruleTitle').value = '';
|
||||
this.ruleName.set(ruleTitle);
|
||||
this.setTrigger();
|
||||
}
|
||||
},
|
||||
'click .js-goto-action' (event) {
|
||||
event.preventDefault();
|
||||
// Add user to the trigger
|
||||
const username = $(event.currentTarget.offsetParent).find('.user-name').val();
|
||||
let trigger = this.triggerVar.get();
|
||||
trigger.userId = '*';
|
||||
if(username !== undefined ){
|
||||
const userFound = Users.findOne({username});
|
||||
if(userFound !== undefined){
|
||||
trigger.userId = userFound._id;
|
||||
this.triggerVar.set(trigger);
|
||||
}
|
||||
}
|
||||
// Sanitize trigger
|
||||
trigger = this.triggerVar.get();
|
||||
this.sanitizeObject(trigger);
|
||||
this.triggerVar.set(trigger);
|
||||
this.setAction();
|
||||
},
|
||||
'click .js-show-user-field' (event) {
|
||||
event.preventDefault();
|
||||
$(event.currentTarget.offsetParent).find('.user-details').removeClass('hide-element');
|
||||
},
|
||||
'click .js-goto-rules' (event) {
|
||||
event.preventDefault();
|
||||
this.setRulesList();
|
||||
},
|
||||
'click .js-goback' (event) {
|
||||
event.preventDefault();
|
||||
if(this.rulesCurrentTab.get() === 'trigger' || this.rulesCurrentTab.get() === 'ruleDetails' ){
|
||||
this.setRulesList();
|
||||
}
|
||||
if(this.rulesCurrentTab.get() === 'action'){
|
||||
this.setTrigger();
|
||||
}
|
||||
},
|
||||
'click .js-goto-details' (event) {
|
||||
event.preventDefault();
|
||||
const rule = this.currentData();
|
||||
this.ruleId.set(rule._id);
|
||||
this.setRuleDetails();
|
||||
},
|
||||
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('rulesMain');
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
template(name="rulesTriggers")
|
||||
h2
|
||||
i.fa.fa-magic
|
||||
| {{{_ 'r-rule' }}} "#{data.ruleName.get}" - {{{_ 'r-add-trigger'}}}
|
||||
.triggers-content
|
||||
.triggers-body
|
||||
.triggers-side-menu
|
||||
ul
|
||||
li.active.js-set-board-triggers
|
||||
i.fa.fa-columns
|
||||
li.js-set-card-triggers
|
||||
i.fa.fa-sticky-note
|
||||
li.js-set-checklist-triggers
|
||||
i.fa.fa-check
|
||||
.triggers-main-body
|
||||
if showBoardTrigger.get
|
||||
+boardTriggers
|
||||
else if showCardTrigger.get
|
||||
+cardTriggers
|
||||
else if showChecklistTrigger.get
|
||||
+checklistTriggers
|
||||
div.rules-back
|
||||
button.js-goback
|
||||
i.fa.fa-chevron-left
|
||||
| {{{_ 'back'}}}
|
||||
@@ -0,0 +1,53 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.showBoardTrigger = new ReactiveVar(true);
|
||||
this.showCardTrigger = new ReactiveVar(false);
|
||||
this.showChecklistTrigger = new ReactiveVar(false);
|
||||
},
|
||||
|
||||
setBoardTriggers() {
|
||||
this.showBoardTrigger.set(true);
|
||||
this.showCardTrigger.set(false);
|
||||
this.showChecklistTrigger.set(false);
|
||||
$('.js-set-card-triggers').removeClass('active');
|
||||
$('.js-set-board-triggers').addClass('active');
|
||||
$('.js-set-checklist-triggers').removeClass('active');
|
||||
},
|
||||
setCardTriggers() {
|
||||
this.showBoardTrigger.set(false);
|
||||
this.showCardTrigger.set(true);
|
||||
this.showChecklistTrigger.set(false);
|
||||
$('.js-set-card-triggers').addClass('active');
|
||||
$('.js-set-board-triggers').removeClass('active');
|
||||
$('.js-set-checklist-triggers').removeClass('active');
|
||||
},
|
||||
setChecklistTriggers() {
|
||||
this.showBoardTrigger.set(false);
|
||||
this.showCardTrigger.set(false);
|
||||
this.showChecklistTrigger.set(true);
|
||||
$('.js-set-card-triggers').removeClass('active');
|
||||
$('.js-set-board-triggers').removeClass('active');
|
||||
$('.js-set-checklist-triggers').addClass('active');
|
||||
},
|
||||
|
||||
rules() {
|
||||
return Rules.find({});
|
||||
},
|
||||
|
||||
name() {
|
||||
// console.log(this.data());
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-set-board-triggers' () {
|
||||
this.setBoardTriggers();
|
||||
},
|
||||
'click .js-set-card-triggers' () {
|
||||
this.setCardTriggers();
|
||||
},
|
||||
'click .js-set-checklist-triggers' () {
|
||||
this.setChecklistTriggers();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('rulesTriggers');
|
||||
@@ -0,0 +1,117 @@
|
||||
template(name="boardTriggers")
|
||||
div.trigger-item#trigger-two
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-card'}}
|
||||
div.trigger-inline-button.js-open-card-title-popup
|
||||
i.fa.fa-filter
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-text
|
||||
| {{_'r-added-to'}}
|
||||
div.trigger-text
|
||||
| {{_'r-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="create-list-name",type=text,placeholder="{{_'r-list-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-in-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="create-swimlane-name",type=text,placeholder="{{_'r-swimlane-name'}}")
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-create-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item#trigger-three
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-card'}}
|
||||
div.trigger-inline-button.js-open-card-title-popup
|
||||
i.fa.fa-filter
|
||||
div.trigger-text
|
||||
| {{_'r-is-moved'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-moved-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item#trigger-four
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-card'}}
|
||||
div.trigger-inline-button.js-open-card-title-popup
|
||||
i.fa.fa-filter
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="move-action")
|
||||
option(value="moved-to") {{_'r-moved-to'}}
|
||||
option(value="moved-from") {{_'r-moved-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="move-list-name",type=text,placeholder="{{_'r-list-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-in-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="create-swimlane-name",type=text,placeholder="{{_'r-swimlane-name'}}")
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-moved-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item#trigger-five
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-card'}}
|
||||
div.trigger-inline-button.js-open-card-title-popup
|
||||
i.fa.fa-filter
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="arch-action")
|
||||
option(value="archived") {{_'r-archived'}}
|
||||
option(value="unarchived") {{_'r-unarchived'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-arch-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{{_'r-board-note'}}}
|
||||
|
||||
template(name="boardCardTitlePopup")
|
||||
form
|
||||
label
|
||||
| Card Title Filter
|
||||
input.js-card-filter-name(type="text" value=title autofocus)
|
||||
input.js-card-filter-button.primary.wide(type="submit" value="{{_ 'set-filter'}}")
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.provaVar = new ReactiveVar('');
|
||||
this.currentPopupTriggerId = 'def';
|
||||
this.cardTitleFilters = {};
|
||||
},
|
||||
setNameFilter(name){
|
||||
this.cardTitleFilters[this.currentPopupTriggerId] = name;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-open-card-title-popup'(event){
|
||||
const funct = Popup.open('boardCardTitle');
|
||||
const divId = $(event.currentTarget.parentNode.parentNode).attr('id');
|
||||
//console.log('current popup');
|
||||
//console.log(this.currentPopupTriggerId);
|
||||
this.currentPopupTriggerId = divId;
|
||||
funct.call(this, event);
|
||||
},
|
||||
'click .js-add-create-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const listName = this.find('#create-list-name').value;
|
||||
const swimlaneName = this.find('#create-swimlane-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const divId = $(event.currentTarget.parentNode).attr('id');
|
||||
const cardTitle = this.cardTitleFilters[divId];
|
||||
// move to generic funciont
|
||||
datas.triggerVar.set({
|
||||
activityType: 'createCard',
|
||||
boardId,
|
||||
cardTitle,
|
||||
swimlaneName,
|
||||
listName,
|
||||
desc,
|
||||
});
|
||||
},
|
||||
'click .js-add-moved-trigger' (event) {
|
||||
const datas = this.data();
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const swimlaneName = this.find('#create-swimlane-name').value;
|
||||
const actionSelected = this.find('#move-action').value;
|
||||
const listName = this.find('#move-list-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'moved-to') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'moveCard',
|
||||
boardId,
|
||||
listName,
|
||||
swimlaneName,
|
||||
'oldListName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'moved-from') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'moveCard',
|
||||
boardId,
|
||||
swimlaneName,
|
||||
'listName': '*',
|
||||
'oldListName': listName,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-gen-moved-trigger' (event){
|
||||
const datas = this.data();
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const boardId = Session.get('currentBoard');
|
||||
|
||||
datas.triggerVar.set({
|
||||
'activityType': 'moveCard',
|
||||
boardId,
|
||||
'swimlaneName': '*',
|
||||
'listName':'*',
|
||||
'oldListName': '*',
|
||||
desc,
|
||||
});
|
||||
},
|
||||
'click .js-add-arc-trigger' (event) {
|
||||
const datas = this.data();
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const actionSelected = this.find('#arch-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'archived') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'archivedCard',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'unarchived') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'restoredCard',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('boardTriggers');
|
||||
|
||||
|
||||
Template.boardCardTitlePopup.events({
|
||||
submit(evt, tpl) {
|
||||
const title = tpl.$('.js-card-filter-name').val().trim();
|
||||
Popup.getOpenerComponent().setNameFilter(title);
|
||||
evt.preventDefault();
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,114 @@
|
||||
template(name="cardTriggers")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-label-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="label-action")
|
||||
option(value="added") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-label-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-the-label-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="spec-label")
|
||||
each labels
|
||||
option(value="#{_id}" style="background-color: #{name}")
|
||||
= translatedname
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="spec-label-action")
|
||||
option(value="added") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-spec-label-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-member'}}
|
||||
div.trigger-dropdown
|
||||
select(id="gen-member-action")
|
||||
option(value="added") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-member-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-the-member'}}
|
||||
div.trigger-dropdown
|
||||
input(id="spec-member",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="spec-member-action")
|
||||
option(value="added") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-spec-member-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-attach'}}
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="attach-action")
|
||||
option(value="added") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-attachment-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
@@ -0,0 +1,131 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
},
|
||||
labels() {
|
||||
const labels = Boards.findOne(Session.get('currentBoard')).labels;
|
||||
for (let i = 0; i < labels.length; i++) {
|
||||
if (labels[i].name === '' || labels[i].name === undefined) {
|
||||
labels[i].name = labels[i].color;
|
||||
labels[i].translatedname = `${TAPi18n.__(`color-${ labels[i].color}`)}`;
|
||||
} else {
|
||||
labels[i].translatedname = labels[i].name;
|
||||
}
|
||||
}
|
||||
return labels;
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-add-gen-label-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#label-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'added') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'addedLabel',
|
||||
boardId,
|
||||
'labelId': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'removedLabel',
|
||||
boardId,
|
||||
'labelId': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-spec-label-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#spec-label-action').value;
|
||||
const labelId = this.find('#spec-label').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'added') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'addedLabel',
|
||||
boardId,
|
||||
labelId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'removedLabel',
|
||||
boardId,
|
||||
labelId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-gen-member-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#gen-member-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'added') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'joinMember',
|
||||
boardId,
|
||||
'username': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'unjoinMember',
|
||||
boardId,
|
||||
'username': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-spec-member-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#spec-member-action').value;
|
||||
const username = this.find('#spec-member').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'added') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'joinMember',
|
||||
boardId,
|
||||
username,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'unjoinMember',
|
||||
boardId,
|
||||
username,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-attachment-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#attach-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'added') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'addAttachment',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'deleteAttachment',
|
||||
boardId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('cardTriggers');
|
||||
@@ -0,0 +1,125 @@
|
||||
template(name="checklistTriggers")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-checklist'}}
|
||||
div.trigger-dropdown
|
||||
select(id="gen-check-action")
|
||||
option(value="created") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-check-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-the-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="check-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="spec-check-action")
|
||||
option(value="created") {{_'r-added-to'}}
|
||||
option(value="removed") {{_'r-removed-from'}}
|
||||
div.trigger-text
|
||||
| {{_'r-a-card'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-spec-check-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-checklist'}}
|
||||
div.trigger-dropdown
|
||||
select(id="gen-comp-check-action")
|
||||
option(value="completed") {{_'r-completed'}}
|
||||
option(value="uncompleted") {{_'r-made-incomplete'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-comp-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-the-checklist'}}
|
||||
div.trigger-dropdown
|
||||
input(id="spec-comp-check-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="spec-comp-check-action")
|
||||
option(value="completed") {{_'r-completed'}}
|
||||
option(value="uncompleted") {{_'r-made-incomplete'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-spec-comp-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-a-item'}}
|
||||
div.trigger-dropdown
|
||||
select(id="check-item-gen-action")
|
||||
option(value="checked") {{_'r-checked'}}
|
||||
option(value="unchecked") {{_'r-unchecked'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-gen-check-item-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
| {{_'r-when-the-item'}}
|
||||
div.trigger-dropdown
|
||||
input(id="check-item-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-is'}}
|
||||
div.trigger-dropdown
|
||||
select(id="check-item-spec-action")
|
||||
option(value="checked") {{_'r-checked'}}
|
||||
option(value="unchecked") {{_'r-unchecked'}}
|
||||
div.trigger-button.trigger-button-person.js-show-user-field
|
||||
i.fa.fa-user
|
||||
div.user-details.hide-element
|
||||
div.trigger-text
|
||||
| {{_'r-by'}}
|
||||
div.trigger-dropdown
|
||||
input(class="user-name",type=text,placeholder="{{_'username'}}")
|
||||
div.trigger-button.js-add-spec-check-item-trigger.js-goto-action
|
||||
i.fa.fa-plus
|
||||
@@ -0,0 +1,146 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.subscribe('allRules');
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-add-gen-check-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#gen-check-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'created') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'addChecklist',
|
||||
boardId,
|
||||
'checklistName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'removeChecklist',
|
||||
boardId,
|
||||
'checklistName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-spec-check-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#spec-check-action').value;
|
||||
const checklistId = this.find('#check-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'created') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'addChecklist',
|
||||
boardId,
|
||||
'checklistName': checklistId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'removed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'removeChecklist',
|
||||
boardId,
|
||||
'checklistName': checklistId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-gen-comp-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#gen-comp-check-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'completed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'completeChecklist',
|
||||
boardId,
|
||||
'checklistName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'uncompleted') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'uncompleteChecklist',
|
||||
boardId,
|
||||
'checklistName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-spec-comp-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#spec-comp-check-action').value;
|
||||
const checklistId = this.find('#spec-comp-check-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'completed') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'completeChecklist',
|
||||
boardId,
|
||||
'checklistName': checklistId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'uncompleted') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'uncompleteChecklist',
|
||||
boardId,
|
||||
'checklistName': checklistId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-gen-check-item-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#check-item-gen-action').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'checked') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'checkedItem',
|
||||
boardId,
|
||||
'checklistItemName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'unchecked') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'uncheckedItem',
|
||||
boardId,
|
||||
'checklistItemName': '*',
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-add-spec-check-item-trigger' (event) {
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
const datas = this.data();
|
||||
const actionSelected = this.find('#check-item-spec-action').value;
|
||||
const checklistItemId = this.find('#check-item-name').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
if (actionSelected === 'checked') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'checkedItem',
|
||||
boardId,
|
||||
'checklistItemName': checklistItemId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
if (actionSelected === 'unchecked') {
|
||||
datas.triggerVar.set({
|
||||
activityType: 'uncheckedItem',
|
||||
boardId,
|
||||
'checklistItemName': checklistItemId,
|
||||
desc,
|
||||
});
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
|
||||
}).register('checklistTriggers');
|
||||
@@ -0,0 +1,6 @@
|
||||
template(name='connectionMethod')
|
||||
div.at-form-authentication
|
||||
label {{_ 'authentication-method'}}
|
||||
select.select-authentication
|
||||
each authentications
|
||||
option(value="{{value}}") {{_ value}}
|
||||
@@ -0,0 +1,34 @@
|
||||
Template.connectionMethod.onCreated(function() {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
|
||||
Meteor.call('getAuthenticationsEnabled', (_, result) => {
|
||||
if (result) {
|
||||
// TODO : add a management of different languages
|
||||
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
|
||||
this.authenticationMethods.set([
|
||||
{value: 'password'},
|
||||
// Gets only the authentication methods availables
|
||||
...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})),
|
||||
]);
|
||||
}
|
||||
|
||||
// If only the default authentication available, hides the select boxe
|
||||
const content = $('.at-form-authentication');
|
||||
if (!(this.authenticationMethods.get().length > 1)) {
|
||||
content.hide();
|
||||
} else {
|
||||
content.show();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.connectionMethod.onRendered(() => {
|
||||
// Moves the select boxe in the first place of the at-pwd-form div
|
||||
$('.at-form-authentication').detach().prependTo('.at-pwd-form');
|
||||
});
|
||||
|
||||
Template.connectionMethod.helpers({
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
});
|
||||
@@ -17,7 +17,7 @@ template(name='statistics')
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'Wekan_version'}}
|
||||
th Wekan {{_ 'info'}}
|
||||
td {{statistics.version}}
|
||||
tr
|
||||
th {{_ 'Node_version'}}
|
||||
|
||||
@@ -27,6 +27,7 @@ template(name="peopleGeneral")
|
||||
th {{_ 'verified'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
th {{_ 'authentication-method'}}
|
||||
th
|
||||
each user in peopleList
|
||||
+peopleRow(userId=user._id)
|
||||
@@ -52,6 +53,7 @@ template(name="peopleRow")
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
td {{_ userData.authenticationMethod }}
|
||||
td
|
||||
a.edit-user
|
||||
| {{_ 'edit'}}
|
||||
@@ -66,12 +68,18 @@ template(name="editUserPopup")
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
| {{_ 'error-username-taken'}}
|
||||
input.js-profile-username(type="text" value=user.username)
|
||||
if isLdap
|
||||
input.js-profile-username(type="text" value=user.username readonly)
|
||||
else
|
||||
input.js-profile-username(type="text" value=user.username)
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
| {{_ 'error-email-taken'}}
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}")
|
||||
if isLdap
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
|
||||
else
|
||||
input.js-profile-email(type="email" value="{{user.emails.[0].address}}")
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
@@ -82,9 +90,17 @@ template(name="editUserPopup")
|
||||
select.select-active.js-profile-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{user.loginDisabled}}") {{_ 'no'}}
|
||||
label
|
||||
| {{_ 'authentication-type'}}
|
||||
select.select-authenticationMethod.js-authenticationMethod
|
||||
each authentications
|
||||
if isSelected value
|
||||
option(value="{{value}}" selected) {{_ value}}
|
||||
else
|
||||
option(value="{{value}}") {{_ value}}
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
input.js-profile-password(type="password")
|
||||
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -62,10 +62,39 @@ Template.peopleRow.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.editUserPopup.onCreated(function() {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
|
||||
Meteor.call('getAuthenticationsEnabled', (_, result) => {
|
||||
if (result) {
|
||||
// TODO : add a management of different languages
|
||||
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
|
||||
this.authenticationMethods.set([
|
||||
{value: 'password'},
|
||||
// Gets only the authentication methods availables
|
||||
...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})),
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.editUserPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
isSelected(match) {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === match;
|
||||
},
|
||||
isLdap() {
|
||||
const userId = Template.instance().data.userId;
|
||||
const selected = Users.findOne(userId).authenticationMethod;
|
||||
return selected === 'ldap';
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -91,6 +120,7 @@ Template.editUserPopup.events({
|
||||
const isAdmin = tpl.find('.js-profile-isadmin').value.trim();
|
||||
const isActive = tpl.find('.js-profile-isactive').value.trim();
|
||||
const email = tpl.find('.js-profile-email').value.trim();
|
||||
const authentication = tpl.find('.js-authenticationMethod').value.trim();
|
||||
|
||||
const isChangePassword = password.length > 0;
|
||||
const isChangeUserName = username !== user.username;
|
||||
@@ -101,6 +131,7 @@ Template.editUserPopup.events({
|
||||
'profile.fullname': fullname,
|
||||
'isAdmin': isAdmin === 'true',
|
||||
'loginDisabled': isActive === 'true',
|
||||
'authenticationMethod': authentication,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -16,6 +16,8 @@ template(name="setting")
|
||||
a.js-setting-menu(data-id="account-setting") {{_ 'accounts'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="announcement-setting") {{_ 'admin-announcement'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="layout-setting") {{_ 'layout'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
@@ -27,6 +29,8 @@ template(name="setting")
|
||||
+accountSettings
|
||||
else if announcementSetting.get
|
||||
+announcementSettings
|
||||
else if layoutSetting.get
|
||||
+layoutSettings
|
||||
|
||||
template(name="general")
|
||||
ul#registration-setting.setting-detail
|
||||
@@ -55,6 +59,40 @@ template(name="general")
|
||||
|
||||
template(name='email')
|
||||
ul#email-setting.setting-detail
|
||||
li.smtp-form
|
||||
.title {{_ 'smtp-host'}}
|
||||
.description {{_ 'smtp-host-description'}}
|
||||
.form-group
|
||||
input.form-control#mail-server-host(type="text", placeholder="smtp.domain.com" value="{{currentSetting.mailServer.host}}")
|
||||
li.smtp-form
|
||||
.title {{_ 'smtp-port'}}
|
||||
.description {{_ 'smtp-port-description'}}
|
||||
.form-group
|
||||
input.form-control#mail-server-port(type="text", placeholder="25" value="{{currentSetting.mailServer.port}}")
|
||||
li.smtp-form
|
||||
.title {{_ 'smtp-username'}}
|
||||
.form-group
|
||||
input.form-control#mail-server-username(type="text", placeholder="{{_ 'username'}}" value="{{currentSetting.mailServer.username}}")
|
||||
li.smtp-form
|
||||
.title {{_ 'smtp-password'}}
|
||||
.form-group
|
||||
input.form-control#mail-server-password(type="password", placeholder="{{_ 'password'}}" value="{{currentSetting.mailServer.password}}")
|
||||
li.smtp-form
|
||||
.title {{_ 'smtp-tls'}}
|
||||
.form-group
|
||||
a.flex.js-toggle-tls
|
||||
.materialCheckBox#mail-server-tls(class="{{#if currentSetting.mailServer.enableTLS}}is-checked{{/if}}")
|
||||
|
||||
span {{_ 'smtp-tls-description'}}
|
||||
|
||||
li.smtp-form
|
||||
.title {{_ 'send-from'}}
|
||||
.form-group
|
||||
input.form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
|
||||
|
||||
li
|
||||
button.js-save.primary {{_ 'save'}}
|
||||
|
||||
li
|
||||
button.js-send-smtp-test-email.primary {{_ 'send-smtp-test'}}
|
||||
|
||||
@@ -93,3 +131,25 @@ template(name='announcementSettings')
|
||||
textarea#admin-announcement.form-control= currentSetting.body
|
||||
li
|
||||
button.js-announcement-save.primary {{_ 'save'}}
|
||||
|
||||
template(name='layoutSettings')
|
||||
ul#layout-setting.setting-detail
|
||||
li.layout-form
|
||||
.title {{_ 'hide-logo'}}
|
||||
.form-group.flex
|
||||
input.form-control#hide-logo(type="radio" name="hideLogo" value="true" checked="{{#if currentSetting.hideLogo}}checked{{/if}}")
|
||||
span {{_ 'yes'}}
|
||||
input.form-control#hide-logo(type="radio" name="hideLogo" value="false" checked="{{#unless currentSetting.hideLogo}}checked{{/unless}}")
|
||||
span {{_ 'no'}}
|
||||
li.layout-form
|
||||
.title {{_ 'custom-product-name'}}
|
||||
.form-group
|
||||
input.form-control#product-name(type="text", placeholder="Wekan" value="{{currentSetting.productName}}")
|
||||
li.layout-form
|
||||
.title {{_ 'add-custom-html-after-body-start'}}
|
||||
textarea#customHTMLafterBodyStart.form-control= currentSetting.customHTMLafterBodyStart
|
||||
li.layout-form
|
||||
.title {{_ 'add-custom-html-before-body-end'}}
|
||||
textarea#customHTMLbeforeBodyEnd.form-control= currentSetting.customHTMLbeforeBodyEnd
|
||||
li
|
||||
button.js-save-layout.primary {{_ 'save'}}
|
||||
@@ -6,6 +6,7 @@ BlazeComponent.extendComponent({
|
||||
this.emailSetting = new ReactiveVar(false);
|
||||
this.accountSetting = new ReactiveVar(false);
|
||||
this.announcementSetting = new ReactiveVar(false);
|
||||
this.layoutSetting = new ReactiveVar(false);
|
||||
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
@@ -20,7 +21,7 @@ BlazeComponent.extendComponent({
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
/*
|
||||
|
||||
checkField(selector) {
|
||||
const value = $(selector).val();
|
||||
if (!value || value.trim() === '') {
|
||||
@@ -30,7 +31,7 @@ BlazeComponent.extendComponent({
|
||||
return value;
|
||||
}
|
||||
},
|
||||
*/
|
||||
|
||||
currentSetting() {
|
||||
return Settings.findOne();
|
||||
},
|
||||
@@ -55,11 +56,12 @@ BlazeComponent.extendComponent({
|
||||
$('.invite-people').slideDown();
|
||||
}
|
||||
},
|
||||
/*
|
||||
toggleTLS() {
|
||||
$('#mail-server-tls').toggleClass('is-checked');
|
||||
},
|
||||
*/
|
||||
toggleHideLogo() {
|
||||
$('#hide-logo').toggleClass('is-checked');
|
||||
},
|
||||
switchMenu(event) {
|
||||
const target = $(event.target);
|
||||
if (!target.hasClass('active')) {
|
||||
@@ -70,6 +72,7 @@ BlazeComponent.extendComponent({
|
||||
this.emailSetting.set('email-setting' === targetID);
|
||||
this.accountSetting.set('account-setting' === targetID);
|
||||
this.announcementSetting.set('announcement-setting' === targetID);
|
||||
this.layoutSetting.set('layout-setting' === targetID);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -101,13 +104,11 @@ BlazeComponent.extendComponent({
|
||||
// if (!err) {
|
||||
// TODO - show more info to user
|
||||
// }
|
||||
|
||||
this.setLoading(false);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
saveMailServerInfo() {
|
||||
this.setLoading(true);
|
||||
$('li').removeClass('has-error');
|
||||
@@ -132,7 +133,36 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
|
||||
},
|
||||
*/
|
||||
|
||||
saveLayout() {
|
||||
this.setLoading(true);
|
||||
$('li').removeClass('has-error');
|
||||
|
||||
const productName = $('#product-name').val().trim();
|
||||
const hideLogoChange = ($('input[name=hideLogo]:checked').val() === 'true');
|
||||
const customHTMLafterBodyStart = $('#customHTMLafterBodyStart').val().trim();
|
||||
const customHTMLbeforeBodyEnd = $('#customHTMLbeforeBodyEnd').val().trim();
|
||||
|
||||
try {
|
||||
|
||||
Settings.update(Settings.findOne()._id, {
|
||||
$set: {
|
||||
productName,
|
||||
hideLogo: hideLogoChange,
|
||||
customHTMLafterBodyStart,
|
||||
customHTMLbeforeBodyEnd,
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
return;
|
||||
} finally {
|
||||
this.setLoading(false);
|
||||
}
|
||||
|
||||
DocHead.setTitle(productName);
|
||||
|
||||
},
|
||||
|
||||
sendSMTPTestEmail() {
|
||||
Meteor.call('sendSMTPTestEmail', (err, ret) => {
|
||||
if (!err && ret) { /* eslint-disable no-console */
|
||||
@@ -152,16 +182,14 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{
|
||||
'click a.js-toggle-registration': this.toggleRegistration,
|
||||
/*
|
||||
'click a.js-toggle-tls': this.toggleTLS,
|
||||
*/
|
||||
'click a.js-setting-menu': this.switchMenu,
|
||||
'click a.js-toggle-board-choose': this.checkBoard,
|
||||
'click button.js-email-invite': this.inviteThroughEmail,
|
||||
/*
|
||||
'click button.js-save': this.saveMailServerInfo,
|
||||
*/
|
||||
'click button.js-send-smtp-test-email': this.sendSMTPTestEmail,
|
||||
'click a.js-toggle-hide-logo': this.toggleHideLogo,
|
||||
'click button.js-save-layout': this.saveLayout,
|
||||
}];
|
||||
},
|
||||
}).register('setting');
|
||||
|
||||
@@ -66,7 +66,8 @@
|
||||
padding: 0 0.5rem
|
||||
|
||||
.admin-announcement,
|
||||
.invite-people
|
||||
.invite-people,
|
||||
.layout
|
||||
padding-left 20px;
|
||||
li
|
||||
min-width: 500px;
|
||||
|
||||
@@ -23,10 +23,11 @@ template(name='homeSidebar')
|
||||
hr
|
||||
+labelsWidget
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-comments-o
|
||||
| {{_ 'activities'}}
|
||||
+activities(mode="board")
|
||||
unless currentUser.isNoComments
|
||||
h3
|
||||
i.fa.fa-comments-o
|
||||
| {{_ 'activities'}}
|
||||
+activities(mode="board")
|
||||
|
||||
template(name="membersWidget")
|
||||
.board-widget.board-widget-members
|
||||
@@ -145,6 +146,12 @@ template(name="changePermissionsPopup")
|
||||
if isNormal
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'normal-desc'}}
|
||||
li
|
||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-no-comments{{/if}}")
|
||||
| {{_ 'no-comments'}}
|
||||
if isNoComments
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'no-comments-desc'}}
|
||||
li
|
||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-comment-only{{/if}}")
|
||||
| {{_ 'comment-only'}}
|
||||
|
||||
@@ -16,8 +16,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
onCreated() {
|
||||
const initOpen = Utils.isMiniScreen() ? false : (!Session.get('currentCard'));
|
||||
this._isOpen = new ReactiveVar(initOpen);
|
||||
this._isOpen = new ReactiveVar(false);
|
||||
this._view = new ReactiveVar(defaultView);
|
||||
Sidebar = this;
|
||||
},
|
||||
@@ -126,8 +125,11 @@ Template.memberPopup.helpers({
|
||||
if(type === 'normal'){
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const commentOnly = currentBoard.hasCommentOnly(this.userId);
|
||||
const noComments = currentBoard.hasNoComments(this.userId);
|
||||
if(commentOnly){
|
||||
return TAPi18n.__('comment-only').toLowerCase();
|
||||
} else if(noComments) {
|
||||
return TAPi18n.__('no-comments').toLowerCase();
|
||||
} else {
|
||||
return TAPi18n.__(type).toLowerCase();
|
||||
}
|
||||
@@ -324,12 +326,13 @@ BlazeComponent.extendComponent({
|
||||
}).register('addMemberPopup');
|
||||
|
||||
Template.changePermissionsPopup.events({
|
||||
'click .js-set-admin, click .js-set-normal, click .js-set-comment-only'(event) {
|
||||
'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only'(event) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const memberId = this.userId;
|
||||
const isAdmin = $(event.currentTarget).hasClass('js-set-admin');
|
||||
const isCommentOnly = $(event.currentTarget).hasClass('js-set-comment-only');
|
||||
currentBoard.setMemberPermission(memberId, isAdmin, isCommentOnly);
|
||||
const isNoComments = $(event.currentTarget).hasClass('js-set-no-comments');
|
||||
currentBoard.setMemberPermission(memberId, isAdmin, isNoComments, isCommentOnly);
|
||||
Popup.back(1);
|
||||
},
|
||||
});
|
||||
@@ -342,7 +345,12 @@ Template.changePermissionsPopup.helpers({
|
||||
|
||||
isNormal() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return !currentBoard.hasAdmin(this.userId) && !currentBoard.hasCommentOnly(this.userId);
|
||||
return !currentBoard.hasAdmin(this.userId) && !currentBoard.hasNoComments(this.userId) && !currentBoard.hasCommentOnly(this.userId);
|
||||
},
|
||||
|
||||
isNoComments() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return !currentBoard.hasAdmin(this.userId) && currentBoard.hasNoComments(this.userId);
|
||||
},
|
||||
|
||||
isCommentOnly() {
|
||||
|
||||
@@ -41,6 +41,16 @@ template(name="createCustomFieldPopup")
|
||||
.materialCheckBox(class="{{#if showOnCard}}is-checked{{/if}}")
|
||||
|
||||
span {{_ 'show-field-on-card'}}
|
||||
a.flex.js-field-automatically-on-card(class="{{#if automaticallyOnCard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if automaticallyOnCard}}is-checked{{/if}}")
|
||||
|
||||
span {{_ 'automatically-field-on-card'}}
|
||||
|
||||
a.flex.js-field-showLabel-on-card(class="{{#if showLabelOnMiniCard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if showLabelOnMiniCard}}is-checked{{/if}}")
|
||||
|
||||
span {{_ 'showLabel-field-on-card'}}
|
||||
|
||||
button.primary.wide.left(type="button")
|
||||
| {{_ 'save'}}
|
||||
if _id
|
||||
|
||||
@@ -83,6 +83,22 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
|
||||
$target.find('.materialCheckBox').toggleClass('is-checked');
|
||||
$target.toggleClass('is-checked');
|
||||
},
|
||||
'click .js-field-automatically-on-card'(evt) {
|
||||
let $target = $(evt.target);
|
||||
if(!$target.hasClass('js-field-automatically-on-card')){
|
||||
$target = $target.parent();
|
||||
}
|
||||
$target.find('.materialCheckBox').toggleClass('is-checked');
|
||||
$target.toggleClass('is-checked');
|
||||
},
|
||||
'click .js-field-showLabel-on-card'(evt) {
|
||||
let $target = $(evt.target);
|
||||
if(!$target.hasClass('js-field-showLabel-on-card')){
|
||||
$target = $target.parent();
|
||||
}
|
||||
$target.find('.materialCheckBox').toggleClass('is-checked');
|
||||
$target.toggleClass('is-checked');
|
||||
},
|
||||
'click .primary'(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -92,6 +108,8 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
|
||||
type: this.type.get(),
|
||||
settings: this.getSettings(),
|
||||
showOnCard: this.find('.js-field-show-on-card.is-checked') !== null,
|
||||
showLabelOnMiniCard: this.find('.js-field-showLabel-on-card.is-checked') !== null,
|
||||
automaticallyOnCard: this.find('.js-field-automatically-on-card.is-checked') !== null,
|
||||
};
|
||||
|
||||
// insert or update
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
border-bottom: 1px solid #CCC
|
||||
|
||||
.swimlane-header
|
||||
-ms-writing-mode: tb-rl;
|
||||
writing-mode: vertical-rl;
|
||||
transform: rotate(180deg);
|
||||
font-size: 14px;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
template(name="userAvatar")
|
||||
a.member.js-member(title="{{userData.profile.fullname}} ({{userData.username}})")
|
||||
if userData.profile.avatarUrl
|
||||
img.avatar.avatar-image(src=userData.profile.avatarUrl)
|
||||
img.avatar.avatar-image(src="{{userData.profile.avatarUrl}}")
|
||||
else
|
||||
+userAvatarInitials(userId=userData._id)
|
||||
|
||||
|
||||
@@ -134,8 +134,9 @@ BlazeComponent.extendComponent({
|
||||
|
||||
Template.cardMembersPopup.helpers({
|
||||
isCardMember() {
|
||||
const cardId = Template.parentData()._id;
|
||||
const cardMembers = Cards.findOne(cardId).members || [];
|
||||
const card = Template.parentData();
|
||||
const cardMembers = card.getMembers();
|
||||
|
||||
return _.contains(cardMembers, this.userId);
|
||||
},
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ template(name="memberMenuPopup")
|
||||
li: a.js-change-avatar {{_ 'edit-avatar'}}
|
||||
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
|
||||
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
|
||||
li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
|
||||
if currentUser.isAdmin
|
||||
li: a.js-go-setting(href="{{pathFor 'setting'}}") {{_ 'admin-panel'}}
|
||||
hr
|
||||
@@ -50,23 +49,6 @@ template(name="editProfilePopup")
|
||||
input.js-profile-email(type="email" value="{{emails.[0].address}}" readonly)
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="editNotificationPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-toggle-tag-notify-watch
|
||||
i.fa.fa-eye.colorful
|
||||
| {{_ 'watching'}}
|
||||
if hasTag "notify-watch"
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'notify-watch'}}
|
||||
li
|
||||
a.js-toggle-tag-notify-participate
|
||||
i.fa.fa-bell.colorful
|
||||
| {{_ 'tracking'}}
|
||||
if hasTag "notify-participate"
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'notify-participate'}}
|
||||
|
||||
template(name="changePasswordPopup")
|
||||
+atForm(state='changePwd')
|
||||
|
||||
|
||||
@@ -9,7 +9,6 @@ Template.memberMenuPopup.events({
|
||||
'click .js-change-avatar': Popup.open('changeAvatar'),
|
||||
'click .js-change-password': Popup.open('changePassword'),
|
||||
'click .js-change-language': Popup.open('changeLanguage'),
|
||||
'click .js-edit-notification': Popup.open('editNotification'),
|
||||
'click .js-logout'(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -89,25 +88,6 @@ Template.editProfilePopup.events({
|
||||
},
|
||||
});
|
||||
|
||||
Template.editNotificationPopup.helpers({
|
||||
hasTag(tag) {
|
||||
const user = Meteor.user();
|
||||
return user && user.hasTag(tag);
|
||||
},
|
||||
});
|
||||
|
||||
// we defined github like rules, see: https://github.com/settings/notifications
|
||||
Template.editNotificationPopup.events({
|
||||
'click .js-toggle-tag-notify-participate'() {
|
||||
const user = Meteor.user();
|
||||
if (user) user.toggleTag('notify-participate');
|
||||
},
|
||||
'click .js-toggle-tag-notify-watch'() {
|
||||
const user = Meteor.user();
|
||||
if (user) user.toggleTag('notify-watch');
|
||||
},
|
||||
});
|
||||
|
||||
// XXX For some reason the useraccounts autofocus isnt working in this case.
|
||||
// See https://github.com/meteor-useraccounts/core/issues/384
|
||||
Template.changePasswordPopup.onRendered(function () {
|
||||
|
||||
+108
-48
@@ -3,7 +3,6 @@
|
||||
// RangeFilter, dateFilter, etc.). We then define a global `Filter` object whose
|
||||
// goal is to filter complete documents by using the local filters for each
|
||||
// fields.
|
||||
|
||||
function showFilterSidebar() {
|
||||
Sidebar.setView('filter');
|
||||
}
|
||||
@@ -64,7 +63,9 @@ class SetFilter {
|
||||
|
||||
_getMongoSelector() {
|
||||
this._dep.depend();
|
||||
return { $in: this._selectedElements };
|
||||
return {
|
||||
$in: this._selectedElements,
|
||||
};
|
||||
}
|
||||
|
||||
_getEmptySelector() {
|
||||
@@ -75,7 +76,9 @@ class SetFilter {
|
||||
includeEmpty = true;
|
||||
}
|
||||
});
|
||||
return includeEmpty ? { $eq: [] } : null;
|
||||
return includeEmpty ? {
|
||||
$eq: [],
|
||||
} : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +122,7 @@ class AdvancedFilter {
|
||||
current += char;
|
||||
continue;
|
||||
}
|
||||
if (char === '/'){
|
||||
if (char === '/') {
|
||||
string = !string;
|
||||
if (string) regex = true;
|
||||
current += char;
|
||||
@@ -135,7 +138,11 @@ class AdvancedFilter {
|
||||
continue;
|
||||
}
|
||||
if (char === ' ' && !string) {
|
||||
commands.push({ 'cmd': current, 'string': wasString, regex});
|
||||
commands.push({
|
||||
'cmd': current,
|
||||
'string': wasString,
|
||||
regex,
|
||||
});
|
||||
wasString = false;
|
||||
current = '';
|
||||
continue;
|
||||
@@ -143,25 +150,29 @@ class AdvancedFilter {
|
||||
current += char;
|
||||
}
|
||||
if (current !== '') {
|
||||
commands.push({ 'cmd': current, 'string': wasString, regex});
|
||||
commands.push({
|
||||
'cmd': current,
|
||||
'string': wasString,
|
||||
regex,
|
||||
});
|
||||
}
|
||||
return commands;
|
||||
}
|
||||
|
||||
_fieldNameToId(field) {
|
||||
const found = CustomFields.findOne({ 'name': field });
|
||||
const found = CustomFields.findOne({
|
||||
'name': field,
|
||||
});
|
||||
return found._id;
|
||||
}
|
||||
|
||||
_fieldValueToId(field, value)
|
||||
{
|
||||
const found = CustomFields.findOne({ 'name': field });
|
||||
if (found.settings.dropdownItems && found.settings.dropdownItems.length > 0)
|
||||
{
|
||||
for (let i = 0; i < found.settings.dropdownItems.length; i++)
|
||||
{
|
||||
if (found.settings.dropdownItems[i].name === value)
|
||||
{
|
||||
_fieldValueToId(field, value) {
|
||||
const found = CustomFields.findOne({
|
||||
'name': field,
|
||||
});
|
||||
if (found.settings.dropdownItems && found.settings.dropdownItems.length > 0) {
|
||||
for (let i = 0; i < found.settings.dropdownItems.length; i++) {
|
||||
if (found.settings.dropdownItems[i].name === value) {
|
||||
return found.settings.dropdownItems[i]._id;
|
||||
}
|
||||
}
|
||||
@@ -173,10 +184,15 @@ class AdvancedFilter {
|
||||
try {
|
||||
//let changed = false;
|
||||
this._processSubCommands(commands);
|
||||
} catch (e) {
|
||||
return this._lastValide;
|
||||
}
|
||||
catch (e) { return this._lastValide; }
|
||||
this._lastValide = { $or: commands };
|
||||
return { $or: commands };
|
||||
this._lastValide = {
|
||||
$or: commands,
|
||||
};
|
||||
return {
|
||||
$or: commands,
|
||||
};
|
||||
}
|
||||
|
||||
_processSubCommands(commands) {
|
||||
@@ -232,19 +248,24 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
if (commands[i + 1].regex)
|
||||
{
|
||||
if (commands[i + 1].regex) {
|
||||
const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
||||
let regex = null;
|
||||
if (match.length > 2)
|
||||
regex = new RegExp(match[1], match[2]);
|
||||
else
|
||||
regex = new RegExp(match[1]);
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': regex };
|
||||
}
|
||||
else
|
||||
{
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': {$in: [this._fieldValueToId(field, str), parseInt(str, 10)]} };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': regex,
|
||||
};
|
||||
} else {
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$in: [this._fieldValueToId(field, str), parseInt(str, 10)],
|
||||
},
|
||||
};
|
||||
}
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
@@ -257,19 +278,28 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
if (commands[i + 1].regex)
|
||||
{
|
||||
if (commands[i + 1].regex) {
|
||||
const match = str.match(new RegExp('^/(.*?)/([gimy]*)$'));
|
||||
let regex = null;
|
||||
if (match.length > 2)
|
||||
regex = new RegExp(match[1], match[2]);
|
||||
else
|
||||
regex = new RegExp(match[1]);
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $not: regex } };
|
||||
}
|
||||
else
|
||||
{
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $not: {$in: [this._fieldValueToId(field, str), parseInt(str, 10)]} } };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$not: regex,
|
||||
},
|
||||
};
|
||||
} else {
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$not: {
|
||||
$in: [this._fieldValueToId(field, str), parseInt(str, 10)],
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
@@ -284,7 +314,12 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $gt: parseInt(str, 10) } };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$gt: parseInt(str, 10),
|
||||
},
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
@@ -299,7 +334,12 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $gte: parseInt(str, 10) } };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$gte: parseInt(str, 10),
|
||||
},
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
@@ -313,7 +353,12 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $lt: parseInt(str, 10) } };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$lt: parseInt(str, 10),
|
||||
},
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
@@ -328,14 +373,18 @@ class AdvancedFilter {
|
||||
{
|
||||
const field = commands[i - 1].cmd;
|
||||
const str = commands[i + 1].cmd;
|
||||
commands[i] = { 'customFields._id': this._fieldNameToId(field), 'customFields.value': { $lte: parseInt(str, 10) } };
|
||||
commands[i] = {
|
||||
'customFields._id': this._fieldNameToId(field),
|
||||
'customFields.value': {
|
||||
$lte: parseInt(str, 10),
|
||||
},
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -353,7 +402,9 @@ class AdvancedFilter {
|
||||
{
|
||||
const op1 = commands[i - 1];
|
||||
const op2 = commands[i + 1];
|
||||
commands[i] = { $or: [op1, op2] };
|
||||
commands[i] = {
|
||||
$or: [op1, op2],
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
@@ -368,27 +419,29 @@ class AdvancedFilter {
|
||||
{
|
||||
const op1 = commands[i - 1];
|
||||
const op2 = commands[i + 1];
|
||||
commands[i] = { $and: [op1, op2] };
|
||||
commands[i] = {
|
||||
$and: [op1, op2],
|
||||
};
|
||||
commands.splice(i - 1, 1);
|
||||
commands.splice(i, 1);
|
||||
//changed = true;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
case 'not':
|
||||
case 'Not':
|
||||
case 'NOT':
|
||||
case '!':
|
||||
{
|
||||
const op1 = commands[i + 1];
|
||||
commands[i] = { $not: op1 };
|
||||
commands[i] = {
|
||||
$not: op1,
|
||||
};
|
||||
commands.splice(i + 1, 1);
|
||||
//changed = true;
|
||||
i--;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,8 +494,7 @@ Filter = {
|
||||
if (filter._isActive()) {
|
||||
if (filter.subField !== '') {
|
||||
filterSelector[`${fieldName}.${filter.subField}`] = filter._getMongoSelector();
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
filterSelector[fieldName] = filter._getMongoSelector();
|
||||
}
|
||||
emptySelector[fieldName] = filter._getEmptySelector();
|
||||
@@ -452,7 +504,11 @@ Filter = {
|
||||
}
|
||||
});
|
||||
|
||||
const exceptionsSelector = { _id: { $in: this._exceptions } };
|
||||
const exceptionsSelector = {
|
||||
_id: {
|
||||
$in: this._exceptions,
|
||||
},
|
||||
};
|
||||
this._exceptionsDep.depend();
|
||||
|
||||
const selectors = [exceptionsSelector];
|
||||
@@ -463,7 +519,9 @@ Filter = {
|
||||
if (includeEmptySelectors) selectors.push(emptySelector);
|
||||
if (this.advanced._isActive()) selectors.push(this.advanced._getMongoSelector());
|
||||
|
||||
return { $or: selectors };
|
||||
return {
|
||||
$or: selectors,
|
||||
};
|
||||
},
|
||||
|
||||
mongoSelector(additionalSelector) {
|
||||
@@ -471,7 +529,9 @@ Filter = {
|
||||
if (_.isUndefined(additionalSelector))
|
||||
return filterSelector;
|
||||
else
|
||||
return { $and: [filterSelector, additionalSelector] };
|
||||
return {
|
||||
$and: [filterSelector, additionalSelector],
|
||||
};
|
||||
},
|
||||
|
||||
reset() {
|
||||
|
||||
+13
-1
@@ -4,6 +4,7 @@ window.Modal = new class {
|
||||
constructor() {
|
||||
this._currentModal = new ReactiveVar(closedValue);
|
||||
this._onCloseGoTo = '';
|
||||
this._isWideModal = false;
|
||||
}
|
||||
|
||||
getHeaderName() {
|
||||
@@ -20,6 +21,10 @@ window.Modal = new class {
|
||||
return this.getTemplateName() !== closedValue;
|
||||
}
|
||||
|
||||
isWide(){
|
||||
return this._isWideModal;
|
||||
}
|
||||
|
||||
close() {
|
||||
this._currentModal.set(closedValue);
|
||||
if (this._onCloseGoTo) {
|
||||
@@ -27,9 +32,16 @@ window.Modal = new class {
|
||||
}
|
||||
}
|
||||
|
||||
openWide(modalName, { header = '', onCloseGoTo = ''} = {}) {
|
||||
this._currentModal.set({ header, modalName });
|
||||
this._onCloseGoTo = onCloseGoTo;
|
||||
this._isWideModal = true;
|
||||
}
|
||||
|
||||
open(modalName, { header = '', onCloseGoTo = ''} = {}) {
|
||||
this._currentModal.set({ header, modalName });
|
||||
this._onCloseGoTo = onCloseGoTo;
|
||||
|
||||
}
|
||||
}();
|
||||
|
||||
@@ -38,5 +50,5 @@ Blaze.registerHelper('Modal', Modal);
|
||||
EscapeActions.register('modalWindow',
|
||||
() => Modal.close(),
|
||||
() => Modal.isOpen(),
|
||||
{ noClickEscapeOn: '.modal-content' }
|
||||
{ noClickEscapeOn: '.modal-container' }
|
||||
);
|
||||
+4
-6
@@ -4,9 +4,9 @@ window.Popup = new class {
|
||||
this.template = Template.popup;
|
||||
|
||||
// We only want to display one popup at a time and we keep the view object
|
||||
// in this `Popup._current` variable. If there is no popup currently opened
|
||||
// in this `Popup.current` variable. If there is no popup currently opened
|
||||
// the value is `null`.
|
||||
this._current = null;
|
||||
this.current = null;
|
||||
|
||||
// It's possible to open a sub-popup B from a popup A. In that case we keep
|
||||
// the data of popup A so we can return back to it. Every time we open a new
|
||||
@@ -27,11 +27,9 @@ window.Popup = new class {
|
||||
open(name) {
|
||||
const self = this;
|
||||
const popupName = `${name}Popup`;
|
||||
|
||||
function clickFromPopup(evt) {
|
||||
return $(evt.target).closest('.js-pop-over').length !== 0;
|
||||
}
|
||||
|
||||
return function(evt) {
|
||||
// If a popup is already opened, clicking again on the opener element
|
||||
// should close it -- and interrupt the current `open` function.
|
||||
@@ -57,7 +55,6 @@ window.Popup = new class {
|
||||
self._stack = [];
|
||||
openerElement = evt.currentTarget;
|
||||
}
|
||||
|
||||
$(openerElement).addClass('is-active');
|
||||
evt.preventDefault();
|
||||
|
||||
@@ -139,6 +136,7 @@ window.Popup = new class {
|
||||
const openerElement = this._getTopStack().openerElement;
|
||||
$(openerElement).removeClass('is-active');
|
||||
|
||||
|
||||
this._stack = [];
|
||||
}
|
||||
}
|
||||
@@ -200,7 +198,7 @@ escapeActions.forEach((actionName) => {
|
||||
() => Popup[actionName](),
|
||||
() => Popup.isOpen(),
|
||||
{
|
||||
noClickEscapeOn: '.js-pop-over',
|
||||
noClickEscapeOn: '.js-pop-over,.js-open-card-title-popup',
|
||||
enabledOnClick: actionName === 'close',
|
||||
}
|
||||
);
|
||||
|
||||
+55
-4
@@ -39,11 +39,11 @@ Utils = {
|
||||
if (!prevData && !nextData) {
|
||||
base = 0;
|
||||
increment = 1;
|
||||
// If we drop the card in the first position
|
||||
// If we drop the card in the first position
|
||||
} else if (!prevData) {
|
||||
base = nextData.sort - 1;
|
||||
increment = -1;
|
||||
// If we drop the card in the last position
|
||||
// If we drop the card in the last position
|
||||
} else if (!nextData) {
|
||||
base = prevData.sort + 1;
|
||||
increment = 1;
|
||||
@@ -71,11 +71,11 @@ Utils = {
|
||||
if (!prevCardDomElement && !nextCardDomElement) {
|
||||
base = 0;
|
||||
increment = 1;
|
||||
// If we drop the card in the first position
|
||||
// If we drop the card in the first position
|
||||
} else if (!prevCardDomElement) {
|
||||
base = Blaze.getData(nextCardDomElement).sort - 1;
|
||||
increment = -1;
|
||||
// If we drop the card in the last position
|
||||
// If we drop the card in the last position
|
||||
} else if (!nextCardDomElement) {
|
||||
base = Blaze.getData(prevCardDomElement).sort + 1;
|
||||
increment = 1;
|
||||
@@ -145,6 +145,26 @@ Utils = {
|
||||
});
|
||||
},
|
||||
|
||||
manageCustomUI(){
|
||||
Meteor.call('getCustomUI', (err, data) => {
|
||||
if (err && err.error[0] === 'var-not-exist'){
|
||||
Session.set('customUI', false); // siteId || address server not defined
|
||||
}
|
||||
if (!err){
|
||||
Utils.setCustomUI(data);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
setCustomUI(data){
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (currentBoard) {
|
||||
DocHead.setTitle(`${currentBoard.title } - ${ data.productName}`);
|
||||
} else {
|
||||
DocHead.setTitle(`${data.productName}`);
|
||||
}
|
||||
},
|
||||
|
||||
setMatomo(data){
|
||||
window._paq = window._paq || [];
|
||||
window._paq.push(['setDoNotTrack', data.doNotTrack]);
|
||||
@@ -189,6 +209,37 @@ Utils = {
|
||||
window._paq.push(['trackPageView']);
|
||||
}
|
||||
},
|
||||
|
||||
getTriggerActionDesc(event, tempInstance) {
|
||||
const jqueryEl = tempInstance.$(event.currentTarget.parentNode);
|
||||
const triggerEls = jqueryEl.find('.trigger-content').children();
|
||||
let finalString = '';
|
||||
for (let i = 0; i < triggerEls.length; i++) {
|
||||
const element = tempInstance.$(triggerEls[i]);
|
||||
if (element.hasClass('trigger-text')) {
|
||||
finalString += element.text().toLowerCase();
|
||||
} else if (element.hasClass('user-details')) {
|
||||
let username = element.find('input').val();
|
||||
if(username === undefined || username === ''){
|
||||
username = '*';
|
||||
}
|
||||
finalString += `${element.find('.trigger-text').text().toLowerCase() } ${ username}`;
|
||||
} else if (element.find('select').length > 0) {
|
||||
finalString += element.find('select option:selected').text().toLowerCase();
|
||||
} else if (element.find('input').length > 0) {
|
||||
let inputvalue = element.find('input').val();
|
||||
if(inputvalue === undefined || inputvalue === ''){
|
||||
inputvalue = '*';
|
||||
}
|
||||
finalString += inputvalue;
|
||||
}
|
||||
// Add space
|
||||
if (i !== length - 1) {
|
||||
finalString += ' ';
|
||||
}
|
||||
}
|
||||
return finalString;
|
||||
},
|
||||
};
|
||||
|
||||
// A simple tracker dependency that we invalidate every time the window is
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
module.exports.models = {
|
||||
connection: 'mongodb',
|
||||
migrate: 'safe',
|
||||
};
|
||||
+16
-11
@@ -14,6 +14,7 @@ FlowRouter.route('/', {
|
||||
Filter.reset();
|
||||
EscapeActions.executeAll();
|
||||
|
||||
Utils.manageCustomUI();
|
||||
Utils.manageMatomo();
|
||||
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
@@ -40,6 +41,7 @@ FlowRouter.route('/b/:id/:slug', {
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
}
|
||||
|
||||
Utils.manageCustomUI();
|
||||
Utils.manageMatomo();
|
||||
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
@@ -57,6 +59,7 @@ FlowRouter.route('/b/:boardId/:slug/:cardId', {
|
||||
Session.set('currentBoard', params.boardId);
|
||||
Session.set('currentCard', params.cardId);
|
||||
|
||||
Utils.manageCustomUI();
|
||||
Utils.manageMatomo();
|
||||
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
@@ -122,6 +125,7 @@ FlowRouter.route('/setting', {
|
||||
},
|
||||
],
|
||||
action() {
|
||||
Utils.manageCustomUI();
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
headerBar: 'settingHeaderBar',
|
||||
content: 'setting',
|
||||
@@ -199,20 +203,21 @@ _.each(redirections, (newPath, oldPath) => {
|
||||
// using the `kadira:dochead` package. Currently we only use it to display the
|
||||
// board title if we are in a board page (see #364) but we may want to support
|
||||
// some <meta> tags in the future.
|
||||
const appTitle = 'Wekan';
|
||||
//const appTitle = Utils.manageCustomUI();
|
||||
|
||||
// XXX The `Meteor.startup` should not be necessary -- we don't need to wait for
|
||||
// the complete DOM to be ready to call `DocHead.setTitle`. But the problem is
|
||||
// that the global variable `Boards` is undefined when this file loads so we
|
||||
// wait a bit until hopefully all files are loaded. This will be fixed in a
|
||||
// clean way once Meteor will support ES6 modules -- hopefully in Meteor 1.3.
|
||||
Meteor.isClient && Meteor.startup(() => {
|
||||
Tracker.autorun(() => {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const titleStack = [appTitle];
|
||||
if (currentBoard) {
|
||||
titleStack.push(currentBoard.title);
|
||||
}
|
||||
DocHead.setTitle(titleStack.reverse().join(' - '));
|
||||
});
|
||||
});
|
||||
//Meteor.isClient && Meteor.startup(() => {
|
||||
// Tracker.autorun(() => {
|
||||
|
||||
// const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
// const titleStack = [appTitle];
|
||||
// if (currentBoard) {
|
||||
// titleStack.push(currentBoard.title);
|
||||
// }
|
||||
// DocHead.setTitle(titleStack.reverse().join(' - '));
|
||||
// });
|
||||
//});
|
||||
+484
-15
@@ -1,9 +1,101 @@
|
||||
version: '2'
|
||||
|
||||
# Note: Do not add single quotes '' to variables. Having spaces still works without quotes where required.
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# ==== CREATING USERS AND LOGGING IN TO WEKAN ====
|
||||
# https://github.com/wekan/wekan/wiki/Adding-users
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# ==== FORGOT PASSWORD ====
|
||||
# https://github.com/wekan/wekan/wiki/Forgot-Password
|
||||
#---------------------------------------------------------------------------------------------------------
|
||||
# ==== Upgrading Wekan to new version =====
|
||||
# 1) Stop Wekan:
|
||||
# docker-compose stop
|
||||
# 2) Download new version:
|
||||
# docker-compose pull wekan
|
||||
# 3) If you have more networks for VPN etc as described at bottom of
|
||||
# this config, download for them too:
|
||||
# docker-compose pull wekan2
|
||||
# 4) Start Wekan:
|
||||
# docker-compose start
|
||||
#----------------------------------------------------------------------------------
|
||||
# ==== OPTIONAL: DEDICATED DOCKER USER ====
|
||||
# 1) Optionally create a dedicated user for Wekan, for example:
|
||||
# sudo useradd -d /home/wekan -m -s /bin/bash wekan
|
||||
# 2) Add this user to the docker group, then logout+login or reboot:
|
||||
# sudo usermod -aG docker wekan
|
||||
# 3) Then login as user wekan.
|
||||
# 4) Create this file /home/wekan/docker-compose.yml with your modifications.
|
||||
#----------------------------------------------------------------------------------
|
||||
# ==== RUN DOCKER AS SERVICE ====
|
||||
# 1a) Running Docker as service, on Systemd like Debian 9, Ubuntu 16.04, CentOS 7:
|
||||
# sudo systemctl enable docker
|
||||
# sudo systemctl start docker
|
||||
# 1b) Running Docker as service, on init.d like Debian 8, Ubuntu 14.04, CentOS 6:
|
||||
# sudo update-rc.d docker defaults
|
||||
# sudo service docker start
|
||||
# ----------------------------------------------------------------------------------
|
||||
# ==== USAGE OF THIS docker-compose.yml ====
|
||||
# 1) For seeing does Wekan work, try this and check with your webbroser:
|
||||
# docker-compose up
|
||||
# 2) Stop Wekan and start Wekan in background:
|
||||
# docker-compose stop
|
||||
# docker-compose up -d
|
||||
# 3) See running Docker containers:
|
||||
# docker ps
|
||||
# 4) Stop Docker containers:
|
||||
# docker-compose stop
|
||||
# ----------------------------------------------------------------------------------
|
||||
# ===== INSIDE DOCKER CONTAINERS, AND BACKUP/RESTORE ====
|
||||
# https://github.com/wekan/wekan/wiki/Backup
|
||||
# If really necessary, repair MongoDB: https://github.com/wekan/wekan-mongodb/issues/6#issuecomment-424004116
|
||||
# 1) Going inside containers:
|
||||
# a) Wekan app, does not contain data
|
||||
# docker exec -it wekan-app bash
|
||||
# b) MongoDB, contains all data
|
||||
# docker exec -it wekan-db bash
|
||||
# 2) Copying database to outside of container:
|
||||
# docker exec -it wekan-db bash
|
||||
# cd /data
|
||||
# mongodump
|
||||
# exit
|
||||
# docker cp wekan-db:/data/dump .
|
||||
# 3) Restoring database
|
||||
# # 1) Stop wekan
|
||||
# docker stop wekan-app
|
||||
# # 2) Go inside database container
|
||||
# docker exec -it wekan-db bash
|
||||
# # 3) and data directory
|
||||
# cd /data
|
||||
# # 4) Remove previos dump
|
||||
# rm -rf dump
|
||||
# # 5) Exit db container
|
||||
# exit
|
||||
# # 6) Copy dump to inside docker container
|
||||
# docker cp dump wekan-db:/data/
|
||||
# # 7) Go inside database container
|
||||
# docker exec -it wekan-db bash
|
||||
# # 8) and data directory
|
||||
# cd /data
|
||||
# # 9) Restore
|
||||
# mongorestore --drop
|
||||
# # 10) Exit db container
|
||||
# exit
|
||||
# # 11) Start wekan
|
||||
# docker start wekan-app
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
services:
|
||||
|
||||
wekandb:
|
||||
image: mongo:3.2.20
|
||||
#-------------------------------------------------------------------------------------
|
||||
# ==== MONGODB AND METEOR VERSION ====
|
||||
# a) CURRENTLY BROKEN: For Wekan Meteor 1.8.x version at meteor-1.8 branch, use mongo 4.x
|
||||
# image: mongo:4.0.4
|
||||
# b) For Wekan Meteor 1.6.x version at master/devel/edge branches.
|
||||
# Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
|
||||
image: mongo:3.2.21
|
||||
#-------------------------------------------------------------------------------------
|
||||
container_name: wekan-db
|
||||
restart: always
|
||||
command: mongod --smallfiles --oplogSize 128
|
||||
@@ -16,31 +108,408 @@ services:
|
||||
- wekan-db-dump:/dump
|
||||
|
||||
wekan:
|
||||
#-------------------------------------------------------------------------------------
|
||||
# ==== MONGODB AND METEOR VERSION ====
|
||||
# a) CURRENTLY BROKEN: For Wekan Meteor 1.8.x version at meteor-1.8 branch,
|
||||
# using https://quay.io/wekan/wekan automatic builds
|
||||
# image: quay.io/wekan/wekan:meteor-1.8
|
||||
# b) For Wekan Meteor 1.6.x version at master/devel/edge branches.
|
||||
# Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
|
||||
image: quay.io/wekan/wekan
|
||||
# c) Using specific Meteor 1.6.x version tag:
|
||||
# image: quay.io/wekan/wekan:v1.95
|
||||
# c) Using Docker Hub automatic builds https://hub.docker.com/r/wekanteam/wekan
|
||||
# image: wekanteam/wekan:meteor-1.8
|
||||
# image: wekanteam/wekan:v1.95
|
||||
#-------------------------------------------------------------------------------------
|
||||
container_name: wekan-app
|
||||
restart: always
|
||||
networks:
|
||||
- wekan-tier
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile
|
||||
args:
|
||||
- NODE_VERSION=${NODE_VERSION}
|
||||
- METEOR_RELEASE=${METEOR_RELEASE}
|
||||
- NPM_VERSION=${NPM_VERSION}
|
||||
- ARCHITECTURE=${ARCHITECTURE}
|
||||
- SRC_PATH=${SRC_PATH}
|
||||
- METEOR_EDGE=${METEOR_EDGE}
|
||||
- USE_EDGE=${USE_EDGE}
|
||||
#-------------------------------------------------------------------------------------
|
||||
# ==== BUILD wekan-app DOCKER CONTAINER FROM SOURCE, if you uncomment these ====
|
||||
# ==== and use commands: docker-compose up -d --build
|
||||
#build:
|
||||
# context: .
|
||||
# dockerfile: Dockerfile
|
||||
# args:
|
||||
# - NODE_VERSION=${NODE_VERSION}
|
||||
# - METEOR_RELEASE=${METEOR_RELEASE}
|
||||
# - NPM_VERSION=${NPM_VERSION}
|
||||
# - ARCHITECTURE=${ARCHITECTURE}
|
||||
# - SRC_PATH=${SRC_PATH}
|
||||
# - METEOR_EDGE=${METEOR_EDGE}
|
||||
# - USE_EDGE=${USE_EDGE}
|
||||
#-------------------------------------------------------------------------------------
|
||||
ports:
|
||||
- 80:80
|
||||
# Docker outsideport:insideport. Do not add anything extra here.
|
||||
# For example, if you want to have wekan on port 3001,
|
||||
# use 3001:8080 . Do not add any extra address etc here, that way it does not work.
|
||||
# remove port mapping if you use nginx reverse proxy, port 8080 is already exposed to wekan-tier network
|
||||
- 80:8080
|
||||
environment:
|
||||
- MONGO_URL=mongodb://wekandb:27017/wekan
|
||||
- ROOT_URL=http://localhost
|
||||
- WITH_API=false
|
||||
#---------------------------------------------------------------
|
||||
# ==== ROOT_URL SETTING ====
|
||||
# Change ROOT_URL to your real Wekan URL, for example:
|
||||
# If you have Caddy/Nginx/Apache providing SSL
|
||||
# - https://example.com
|
||||
# - https://boards.example.com
|
||||
# This can be problematic with avatars https://github.com/wekan/wekan/issues/1776
|
||||
# - https://example.com/wekan
|
||||
# If without https, can be only wekan node, no need for Caddy/Nginx/Apache if you don't need them
|
||||
# - http://example.com
|
||||
# - http://boards.example.com
|
||||
# - http://192.168.1.100 <=== using at local LAN
|
||||
- ROOT_URL=http://localhost # <=== using only at same laptop/desktop where Wekan is installed
|
||||
#---------------------------------------------------------------
|
||||
# ==== EMAIL SETTINGS ====
|
||||
# Email settings are required in both MAIL_URL and Admin Panel,
|
||||
# see https://github.com/wekan/wekan/wiki/Troubleshooting-Mail
|
||||
# For SSL in email, change smtp:// to smtps://
|
||||
# NOTE: Special characters need to be url-encoded in MAIL_URL.
|
||||
# You can encode those characters for example at: https://www.urlencoder.org
|
||||
- MAIL_URL=smtp://user:pass@mailserver.example.com:25/
|
||||
- MAIL_FROM='Example Wekan Support <support@example.com>'
|
||||
#---------------------------------------------------------------
|
||||
# ==== OPTIONAL: MONGO OPLOG SETTINGS =====
|
||||
# https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-378343587
|
||||
# We've fixed our CPU usage problem today with an environment
|
||||
# change around Wekan. I wasn't aware during implementation
|
||||
# that if you're using more than 1 instance of Wekan
|
||||
# (or any MeteorJS based tool) you're supposed to set
|
||||
# MONGO_OPLOG_URL as an environment variable.
|
||||
# Without setting it, Meteor will perform a pull-and-diff
|
||||
# update of it's dataset. With it, Meteor will update from
|
||||
# the OPLOG. See here
|
||||
# https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908
|
||||
# After setting
|
||||
# MONGO_OPLOG_URL=mongodb://<username>:<password>@<mongoDbURL>/local?authSource=admin&replicaSet=rsWekan
|
||||
# the CPU usage for all Wekan instances dropped to an average
|
||||
# of less than 10% with only occasional spikes to high usage
|
||||
# (I guess when someone is doing a lot of work)
|
||||
# - MONGO_OPLOG_URL=mongodb://<username>:<password>@<mongoDbURL>/local?authSource=admin&replicaSet=rsWekan
|
||||
#---------------------------------------------------------------
|
||||
# ==== OPTIONAL: KADIRA PERFORMANCE MONITORING FOR METEOR ====
|
||||
# https://github.com/smeijer/kadira
|
||||
# https://blog.meteor.com/kadira-apm-is-now-open-source-490469ffc85f
|
||||
# - export KADIRA_OPTIONS_ENDPOINT=http://127.0.0.1:11011
|
||||
#---------------------------------------------------------------
|
||||
# ==== OPTIONAL: LOGS AND STATS ====
|
||||
# https://github.com/wekan/wekan/wiki/Logs
|
||||
#
|
||||
# Daily export of Wekan changes as JSON to Logstash and ElasticSearch / Kibana (ELK)
|
||||
# https://github.com/wekan/wekan-logstash
|
||||
#
|
||||
# Statistics Python script for Wekan Dashboard
|
||||
# https://github.com/wekan/wekan-stats
|
||||
#
|
||||
# Console, file, and zulip logger on database changes https://github.com/wekan/wekan/pull/1010
|
||||
# with fix to replace console.log by winston logger https://github.com/wekan/wekan/pull/1033
|
||||
# but there could be bug https://github.com/wekan/wekan/issues/1094
|
||||
#
|
||||
# There is Feature Request: Logging date and time of all activity with summary reports,
|
||||
# and requesting reason for changing card to other column https://github.com/wekan/wekan/issues/1598
|
||||
#---------------------------------------------------------------
|
||||
# ==== WEKAN API AND EXPORT BOARD ====
|
||||
# Wekan Export Board works when WITH_API=true.
|
||||
# https://github.com/wekan/wekan/wiki/REST-API
|
||||
# https://github.com/wekan/wekan-gogs
|
||||
# If you disable Wekan API with false, Export Board does not work.
|
||||
- WITH_API=true
|
||||
#-----------------------------------------------------------------
|
||||
# ==== CORS =====
|
||||
# CORS: Set Access-Control-Allow-Origin header. Example: *
|
||||
#- CORS=*
|
||||
#-----------------------------------------------------------------
|
||||
# ==== MATOMO INTEGRATION ====
|
||||
# Optional: Integration with Matomo https://matomo.org that is installed to your server
|
||||
# The address of the server where Matomo is hosted.
|
||||
# example: - MATOMO_ADDRESS=https://example.com/matomo
|
||||
#- MATOMO_ADDRESS=
|
||||
# The value of the site ID given in Matomo server for Wekan
|
||||
# example: - MATOMO_SITE_ID=12345
|
||||
#- MATOMO_SITE_ID=
|
||||
# The option do not track which enables users to not be tracked by matomo
|
||||
# example: - MATOMO_DO_NOT_TRACK=false
|
||||
#- MATOMO_DO_NOT_TRACK=
|
||||
# The option that allows matomo to retrieve the username:
|
||||
# example: MATOMO_WITH_USERNAME=true
|
||||
#- MATOMO_WITH_USERNAME=false
|
||||
#-----------------------------------------------------------------
|
||||
# ==== BROWSER POLICY AND TRUSTED IFRAME URL ====
|
||||
# Enable browser policy and allow one trusted URL that can have iframe that has Wekan embedded inside.
|
||||
# Setting this to false is not recommended, it also disables all other browser policy protections
|
||||
# and allows all iframing etc. See wekan/server/policy.js
|
||||
- BROWSER_POLICY_ENABLED=true
|
||||
# When browser policy is enabled, HTML code at this Trusted URL can have iframe that embeds Wekan inside.
|
||||
#- TRUSTED_URL=
|
||||
#-----------------------------------------------------------------
|
||||
# ==== OUTGOING WEBHOOKS ====
|
||||
# What to send to Outgoing Webhook, or leave out. Example, that includes all that are default: cardId,listId,oldListId,boardId,comment,user,card,commentId .
|
||||
# example: WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
|
||||
#- WEBHOOKS_ATTRIBUTES=
|
||||
#-----------------------------------------------------------------
|
||||
# ==== OAUTH2 ONLY WITH OIDC AND DOORKEEPER AS INDENTITY PROVIDER
|
||||
# https://github.com/wekan/wekan/issues/1874
|
||||
# https://github.com/wekan/wekan/wiki/OAuth2
|
||||
# Enable the OAuth2 connection
|
||||
# example: OAUTH2_ENABLED=true
|
||||
#- OAUTH2_ENABLED=false
|
||||
# OAuth2 docs: https://github.com/wekan/wekan/wiki/OAuth2
|
||||
# OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345
|
||||
# example: OAUTH2_CLIENT_ID=abcde12345
|
||||
#- OAUTH2_CLIENT_ID=
|
||||
# OAuth2 Secret, for example from Rocket.Chat: Example: 54321abcde
|
||||
# example: OAUTH2_SECRET=54321abcde
|
||||
#- OAUTH2_SECRET=
|
||||
# OAuth2 Server URL, for example Rocket.Chat. Example: https://chat.example.com
|
||||
# example: OAUTH2_SERVER_URL=https://chat.example.com
|
||||
#- OAUTH2_SERVER_URL=
|
||||
# OAuth2 Authorization Endpoint. Example: /oauth/authorize
|
||||
# example: OAUTH2_AUTH_ENDPOINT=/oauth/authorize
|
||||
#- OAUTH2_AUTH_ENDPOINT=
|
||||
# OAuth2 Userinfo Endpoint. Example: /oauth/userinfo
|
||||
# example: OAUTH2_USERINFO_ENDPOINT=/oauth/userinfo
|
||||
#- OAUTH2_USERINFO_ENDPOINT=
|
||||
# OAuth2 Token Endpoint. Example: /oauth/token
|
||||
# example: OAUTH2_TOKEN_ENDPOINT=/oauth/token
|
||||
#- OAUTH2_TOKEN_ENDPOINT=
|
||||
#-----------------------------------------------------------------
|
||||
# ==== LDAP ====
|
||||
# https://github.com/wekan/wekan/wiki/LDAP
|
||||
# For Snap settings see https://github.com/wekan/wekan-snap/wiki/Supported-settings-keys
|
||||
# Most settings work both on Snap and Docker below.
|
||||
# Note: Do not add single quotes '' to variables. Having spaces still works without quotes where required.
|
||||
#
|
||||
# DEFAULT_AUTHENTICATION_METHOD : The default authentication method used if a user does not exist to create and authenticate. Can be set as ldap.
|
||||
# example : DEFAULT_AUTHENTICATION_METHOD=ldap
|
||||
#- DEFAULT_AUTHENTICATION_METHOD=
|
||||
#
|
||||
# LDAP_ENABLE : Enable or not the connection by the LDAP
|
||||
# example : LDAP_ENABLE=true
|
||||
#- LDAP_ENABLE=false
|
||||
#
|
||||
# LDAP_PORT : The port of the LDAP server
|
||||
# example : LDAP_PORT=389
|
||||
#- LDAP_PORT=389
|
||||
#
|
||||
# LDAP_HOST : The host server for the LDAP server
|
||||
# example : LDAP_HOST=localhost
|
||||
#- LDAP_HOST=
|
||||
#
|
||||
# LDAP_BASEDN : The base DN for the LDAP Tree
|
||||
# example : LDAP_BASEDN=ou=user,dc=example,dc=org
|
||||
#- LDAP_BASEDN=
|
||||
#
|
||||
# LDAP_LOGIN_FALLBACK : Fallback on the default authentication method
|
||||
# example : LDAP_LOGIN_FALLBACK=true
|
||||
#- LDAP_LOGIN_FALLBACK=false
|
||||
#
|
||||
# LDAP_RECONNECT : Reconnect to the server if the connection is lost
|
||||
# example : LDAP_RECONNECT=false
|
||||
#- LDAP_RECONNECT=true
|
||||
#
|
||||
# LDAP_TIMEOUT : Overall timeout, in milliseconds
|
||||
# example : LDAP_TIMEOUT=12345
|
||||
#- LDAP_TIMEOUT=10000
|
||||
#
|
||||
# LDAP_IDLE_TIMEOUT : Specifies the timeout for idle LDAP connections in milliseconds
|
||||
# example : LDAP_IDLE_TIMEOUT=12345
|
||||
#- LDAP_IDLE_TIMEOUT=10000
|
||||
#
|
||||
# LDAP_CONNECT_TIMEOUT : Connection timeout, in milliseconds
|
||||
# example : LDAP_CONNECT_TIMEOUT=12345
|
||||
#- LDAP_CONNECT_TIMEOUT=10000
|
||||
#
|
||||
# LDAP_AUTHENTIFICATION : If the LDAP needs a user account to search
|
||||
# example : LDAP_AUTHENTIFICATION=true
|
||||
#- LDAP_AUTHENTIFICATION=false
|
||||
#
|
||||
# LDAP_AUTHENTIFICATION_USERDN : The search user DN
|
||||
# example : LDAP_AUTHENTIFICATION_USERDN=cn=admin,dc=example,dc=org
|
||||
#- LDAP_AUTHENTIFICATION_USERDN=
|
||||
#
|
||||
# LDAP_AUTHENTIFICATION_PASSWORD : The password for the search user
|
||||
# example : AUTHENTIFICATION_PASSWORD=admin
|
||||
#- LDAP_AUTHENTIFICATION_PASSWORD=
|
||||
#
|
||||
# LDAP_LOG_ENABLED : Enable logs for the module
|
||||
# example : LDAP_LOG_ENABLED=true
|
||||
#- LDAP_LOG_ENABLED=false
|
||||
#
|
||||
# LDAP_BACKGROUND_SYNC : If the sync of the users should be done in the background
|
||||
# example : LDAP_BACKGROUND_SYNC=true
|
||||
#- LDAP_BACKGROUND_SYNC=false
|
||||
#
|
||||
# LDAP_BACKGROUND_SYNC_INTERVAL : At which interval does the background task sync in milliseconds
|
||||
# example : LDAP_BACKGROUND_SYNC_INTERVAL=12345
|
||||
#- LDAP_BACKGROUND_SYNC_INTERVAL=100
|
||||
#
|
||||
# LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED :
|
||||
# example : LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=true
|
||||
#- LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false
|
||||
#
|
||||
# LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS :
|
||||
# example : LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=true
|
||||
#- LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false
|
||||
#
|
||||
# LDAP_ENCRYPTION : If using LDAPS
|
||||
# example : LDAP_ENCRYPTION=ssl
|
||||
#- LDAP_ENCRYPTION=false
|
||||
#
|
||||
# LDAP_CA_CERT : The certification for the LDAPS server. Certificate needs to be included in this docker-compose.yml file.
|
||||
# example : LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+zCCA+OgAwIBAgIkAhwR/6TVLmdRY6hHxvUFWc0+Enmu/Hu6cj+G2FIdAgIC...-----END CERTIFICATE-----
|
||||
#- LDAP_CA_CERT=
|
||||
#
|
||||
# LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate
|
||||
# example : LDAP_REJECT_UNAUTHORIZED=true
|
||||
#- LDAP_REJECT_UNAUTHORIZED=false
|
||||
#
|
||||
# LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
|
||||
# example : LDAP_USER_SEARCH_FILTER=
|
||||
#- LDAP_USER_SEARCH_FILTER=
|
||||
#
|
||||
# LDAP_USER_SEARCH_SCOPE : base (search only in the provided DN), one (search only in the provided DN and one level deep), or sub (search the whole subtree)
|
||||
# example : LDAP_USER_SEARCH_SCOPE=one
|
||||
#- LDAP_USER_SEARCH_SCOPE=
|
||||
#
|
||||
# LDAP_USER_SEARCH_FIELD : Which field is used to find the user
|
||||
# example : LDAP_USER_SEARCH_FIELD=uid
|
||||
#- LDAP_USER_SEARCH_FIELD=
|
||||
#
|
||||
# LDAP_SEARCH_PAGE_SIZE : Used for pagination (0=unlimited)
|
||||
# example : LDAP_SEARCH_PAGE_SIZE=12345
|
||||
#- LDAP_SEARCH_PAGE_SIZE=0
|
||||
#
|
||||
# LDAP_SEARCH_SIZE_LIMIT : The limit number of entries (0=unlimited)
|
||||
# example : LDAP_SEARCH_SIZE_LIMIT=12345
|
||||
#- LDAP_SEARCH_SIZE_LIMIT=0
|
||||
#
|
||||
# LDAP_GROUP_FILTER_ENABLE : Enable group filtering
|
||||
# example : LDAP_GROUP_FILTER_ENABLE=true
|
||||
#- LDAP_GROUP_FILTER_ENABLE=false
|
||||
#
|
||||
# LDAP_GROUP_FILTER_OBJECTCLASS : The object class for filtering
|
||||
# example : LDAP_GROUP_FILTER_OBJECTCLASS=group
|
||||
#- LDAP_GROUP_FILTER_OBJECTCLASS=
|
||||
#
|
||||
# LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE :
|
||||
# example :
|
||||
#- LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=
|
||||
#
|
||||
# LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE :
|
||||
# example :
|
||||
#- LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=
|
||||
#
|
||||
# LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT :
|
||||
# example :
|
||||
#- LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=
|
||||
#
|
||||
# LDAP_GROUP_FILTER_GROUP_NAME :
|
||||
# example :
|
||||
#- LDAP_GROUP_FILTER_GROUP_NAME=
|
||||
#
|
||||
# LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier)
|
||||
# example : LDAP_UNIQUE_IDENTIFIER_FIELD=guid
|
||||
#- LDAP_UNIQUE_IDENTIFIER_FIELD=
|
||||
#
|
||||
# LDAP_UTF8_NAMES_SLUGIFY : Convert the username to utf8
|
||||
# example : LDAP_UTF8_NAMES_SLUGIFY=false
|
||||
#- LDAP_UTF8_NAMES_SLUGIFY=true
|
||||
#
|
||||
# LDAP_USERNAME_FIELD : Which field contains the ldap username
|
||||
# example : LDAP_USERNAME_FIELD=username
|
||||
#- LDAP_USERNAME_FIELD=
|
||||
#
|
||||
# LDAP_FULLNAME_FIELD : Which field contains the ldap fullname
|
||||
# example : LDAP_FULLNAME_FIELD=fullname
|
||||
#- LDAP_FULLNAME_FIELD=
|
||||
#
|
||||
# LDAP_MERGE_EXISTING_USERS :
|
||||
# example : LDAP_MERGE_EXISTING_USERS=true
|
||||
#- LDAP_MERGE_EXISTING_USERS=false
|
||||
#-----------------------------------------------------------------
|
||||
# LDAP_SYNC_USER_DATA :
|
||||
# example : LDAP_SYNC_USER_DATA=true
|
||||
#- LDAP_SYNC_USER_DATA=false
|
||||
#
|
||||
# LDAP_SYNC_USER_DATA_FIELDMAP :
|
||||
# example : LDAP_SYNC_USER_DATA_FIELDMAP={"cn":"name", "mail":"email"}
|
||||
#- LDAP_SYNC_USER_DATA_FIELDMAP=
|
||||
#
|
||||
# LDAP_SYNC_GROUP_ROLES :
|
||||
# example :
|
||||
#- LDAP_SYNC_GROUP_ROLES=
|
||||
#
|
||||
# LDAP_DEFAULT_DOMAIN : The default domain of the ldap it is used to create email if the field is not map correctly with the LDAP_SYNC_USER_DATA_FIELDMAP
|
||||
# example :
|
||||
#- LDAP_DEFAULT_DOMAIN=
|
||||
#---------------------------------------------------------------------
|
||||
# ==== LOGOUT TIMER, probably does not work yet ====
|
||||
# LOGOUT_WITH_TIMER : Enables or not the option logout with timer
|
||||
# example : LOGOUT_WITH_TIMER=true
|
||||
#- LOGOUT_WITH_TIMER=
|
||||
#
|
||||
# LOGOUT_IN : The number of days
|
||||
# example : LOGOUT_IN=1
|
||||
#- LOGOUT_IN=
|
||||
#
|
||||
# LOGOUT_ON_HOURS : The number of hours
|
||||
# example : LOGOUT_ON_HOURS=9
|
||||
#- LOGOUT_ON_HOURS=
|
||||
#
|
||||
# LOGOUT_ON_MINUTES : The number of minutes
|
||||
# example : LOGOUT_ON_MINUTES=55
|
||||
#- LOGOUT_ON_MINUTES=
|
||||
#-------------------------------------------------------------------
|
||||
|
||||
depends_on:
|
||||
- wekandb
|
||||
|
||||
#---------------------------------------------------------------------------------
|
||||
# ==== OPTIONAL: SHARE DATABASE TO OFFICE LAN AND REMOTE VPN ====
|
||||
# When using Wekan both at office LAN and remote VPN:
|
||||
# 1) Have above Wekan docker container config with LAN IP address
|
||||
# 2) Copy all of above wekan container config below, look above of this part above and all config below it,
|
||||
# before above depends_on: part:
|
||||
#
|
||||
# wekan:
|
||||
# #-------------------------------------------------------------------------------------
|
||||
# # ==== MONGODB AND METEOR VERSION ====
|
||||
# # a) For Wekan Meteor 1.8.x version at meteor-1.8 branch, .....
|
||||
#
|
||||
#
|
||||
# and change name to different name like wekan2 or wekanvpn, and change ROOT_URL to server VPN IP
|
||||
# address.
|
||||
# 3) This way both Wekan containers can use same MongoDB database
|
||||
# and see the same Wekan boards.
|
||||
# 4) You could also add 3rd Wekan container for 3rd network etc.
|
||||
# EXAMPLE:
|
||||
# wekan2:
|
||||
# ....COPY CONFIG FROM ABOVE TO HERE...
|
||||
# environment:
|
||||
# - ROOT_URL='http://10.10.10.10'
|
||||
# ...COPY CONFIG FROM ABOVE TO HERE...
|
||||
#---------------------------------------------------------------------------------
|
||||
|
||||
# OPTIONAL NGINX CONFIG FOR REVERSE PROXY
|
||||
# nginx:
|
||||
# image: nginx
|
||||
# container_name: nginx
|
||||
# restart: always
|
||||
# networks:
|
||||
# - wekan-tier
|
||||
# depends_on:
|
||||
# - wekan
|
||||
# ports:
|
||||
# - 80:80
|
||||
# - 443:443
|
||||
# volumes:
|
||||
# - ./nginx/ssl:/etc/nginx/ssl/
|
||||
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf
|
||||
|
||||
|
||||
volumes:
|
||||
wekan-db:
|
||||
driver: local
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Find text from all subdirectories
|
||||
# and ignore all temporary directories:
|
||||
# - node-modules = installed node modules
|
||||
# - .build = Wekan bundle that is combined from source. Do not edit these, these are deleted and recreated.
|
||||
# - .meteor = Meteor version, packages etc at .meteor/local
|
||||
# - .git = git history
|
||||
|
||||
# If less or more that 1 parameter, show usage.
|
||||
if (( $# != 1 )); then
|
||||
echo 'Usage: ./find.sh text-to-find'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
find . | grep -v node_modules | grep -v .build | grep -v .meteor | grep -v .git | xargs grep --no-messages $1 | less
|
||||
+218
-62
@@ -1,20 +1,20 @@
|
||||
{
|
||||
"accept": "اقبلboard",
|
||||
"act-activity-notify": "[Wekan] اشعار عن نشاط",
|
||||
"act-addAttachment": "ربط __attachment__ الى __card__",
|
||||
"act-addSubtask": "added subtask __checklist__ to __card__",
|
||||
"act-addChecklist": "added checklist __checklist__ to __card__",
|
||||
"act-addChecklistItem": "added __checklistItem__ to checklist __checklist__ on __card__",
|
||||
"act-addComment": "علق على __comment__ : __card__",
|
||||
"act-createBoard": "احدث __board__",
|
||||
"act-createCard": "اضاف __card__ الى __list__",
|
||||
"act-createCustomField": "created custom field __customField__",
|
||||
"act-createList": "اضاف __list__ الى __board__",
|
||||
"accept": "قبول",
|
||||
"act-activity-notify": "اشعارات النشاط",
|
||||
"act-addAttachment": "ربط __المرفق__ الى __بطاقة__",
|
||||
"act-addSubtask": "تمة اضافة فرع المهمة __ قائمة التدقيق __ الى __ بطاقة",
|
||||
"act-addChecklist": "تمة اضافة قائمة التدقيق __ قائمة التدقيق __ الى __ بطاقة",
|
||||
"act-addChecklistItem": "تمة اضافة عنصر قائمة التدقيق __الى قائمة التدقيق __ قائمة التدقيق __ في __ بطاقة",
|
||||
"act-addComment": "علق على __بطاقة__ : __تعليق__",
|
||||
"act-createBoard": "احدث __لوحة__",
|
||||
"act-createCard": "تمة اضافة __بطاقة__ الى __قائمة__",
|
||||
"act-createCustomField": "احدث حقل مخصص __ حقل مخصص__",
|
||||
"act-createList": "اضاف __قائمة__ الى __لوحة__",
|
||||
"act-addBoardMember": "اضاف __member__ الى __board__",
|
||||
"act-archivedBoard": "__board__ moved to Recycle Bin",
|
||||
"act-archivedCard": "__card__ moved to Recycle Bin",
|
||||
"act-archivedList": "__list__ moved to Recycle Bin",
|
||||
"act-archivedSwimlane": "__swimlane__ moved to Recycle Bin",
|
||||
"act-archivedBoard": "__ لوح __ انتقل إلى الأرشيف",
|
||||
"act-archivedCard": "__ بطاقة __ انتقلت إلى الأرشيف",
|
||||
"act-archivedList": "__ القائمة __ انتقلت إلى الأرشيف",
|
||||
"act-archivedSwimlane": "__خط السباحة__انتقل إلى الأرشيف",
|
||||
"act-importBoard": "إستورد __board__",
|
||||
"act-importCard": "إستورد __card__",
|
||||
"act-importList": "إستورد __list__",
|
||||
@@ -23,16 +23,16 @@
|
||||
"act-removeBoardMember": "أزال __member__ من __board__",
|
||||
"act-restoredCard": "أعاد __card__ إلى __board__",
|
||||
"act-unjoinMember": "أزال __member__ من __card__",
|
||||
"act-withBoardTitle": "[Wekan] __board__",
|
||||
"act-withBoardTitle": "__لوح__",
|
||||
"act-withCardTitle": "[__board__] __card__",
|
||||
"actions": "الإجراءات",
|
||||
"activities": "الأنشطة",
|
||||
"activity": "النشاط",
|
||||
"activity-added": "تمت إضافة %s ل %s",
|
||||
"activity-archived": "%s moved to Recycle Bin",
|
||||
"activity-archived": "%s انتقل الى الارشيف",
|
||||
"activity-attached": "إرفاق %s ل %s",
|
||||
"activity-created": "أنشأ %s",
|
||||
"activity-customfield-created": "created custom field %s",
|
||||
"activity-customfield-created": "%s احدت حقل مخصص",
|
||||
"activity-excluded": "استبعاد %s عن %s",
|
||||
"activity-imported": "imported %s into %s from %s",
|
||||
"activity-imported-board": "imported %s from %s",
|
||||
@@ -42,10 +42,20 @@
|
||||
"activity-removed": "حذف %s إلى %s",
|
||||
"activity-sent": "إرسال %s إلى %s",
|
||||
"activity-unjoined": "غادر %s",
|
||||
"activity-subtask-added": "added subtask to %s",
|
||||
"activity-subtask-added": "تم اضافة مهمة فرعية الى %s",
|
||||
"activity-checked-item": "تحقق %s في قائمة التحقق %s من %s",
|
||||
"activity-unchecked-item": "ازالة تحقق %s من قائمة التحقق %s من %s",
|
||||
"activity-checklist-added": "أضاف قائمة تحقق إلى %s",
|
||||
"activity-checklist-item-added": "added checklist item to '%s' in %s",
|
||||
"activity-checklist-removed": "ازالة قائمة التحقق من %s",
|
||||
"activity-checklist-completed": "تم انجاز قائمة التحقق %s من %s",
|
||||
"activity-checklist-uncompleted": "لم يتم انجاز قائمة التحقق %s من %s",
|
||||
"activity-checklist-item-added": "تم اضافة عنصر قائمة التحقق الى '%s' في %s",
|
||||
"activity-checklist-item-removed": "تم ازالة عنصر قائمة التحقق الى '%s' في %s",
|
||||
"add": "أضف",
|
||||
"activity-checked-item-card": "checked %s in checklist %s",
|
||||
"activity-unchecked-item-card": "unchecked %s in checklist %s",
|
||||
"activity-checklist-completed-card": "completed the checklist %s",
|
||||
"activity-checklist-uncompleted-card": "uncompleted the checklist %s",
|
||||
"add-attachment": "إضافة مرفق",
|
||||
"add-board": "إضافة لوحة",
|
||||
"add-card": "إضافة بطاقة",
|
||||
@@ -68,20 +78,20 @@
|
||||
"and-n-other-card": "And __count__ other بطاقة",
|
||||
"and-n-other-card_plural": "And __count__ other بطاقات",
|
||||
"apply": "طبق",
|
||||
"app-is-offline": "يتمّ تحميل ويكان، يرجى الانتظار. سيؤدي تحديث الصفحة إلى فقدان البيانات. إذا لم يتم تحميل ويكان، يرجى التحقق من أن خادم ويكان لم يتوقف. ",
|
||||
"archive": "Move to Recycle Bin",
|
||||
"archive-all": "Move All to Recycle Bin",
|
||||
"archive-board": "Move Board to Recycle Bin",
|
||||
"archive-card": "Move Card to Recycle Bin",
|
||||
"archive-list": "Move List to Recycle Bin",
|
||||
"archive-swimlane": "Move Swimlane to Recycle Bin",
|
||||
"archive-selection": "Move selection to Recycle Bin",
|
||||
"archiveBoardPopup-title": "Move Board to Recycle Bin?",
|
||||
"archived-items": "Recycle Bin",
|
||||
"archived-boards": "Boards in Recycle Bin",
|
||||
"app-is-offline": "Loading, please wait. Refreshing the page will cause data loss. If loading does not work, please check that server has not stopped.",
|
||||
"archive": "نقل الى الارشيف",
|
||||
"archive-all": "نقل الكل الى الارشيف",
|
||||
"archive-board": "نقل اللوح الى الارشيف",
|
||||
"archive-card": "نقل البطاقة الى الارشيف",
|
||||
"archive-list": "نقل القائمة الى الارشيف",
|
||||
"archive-swimlane": "نقل خط السباحة الى الارشيف",
|
||||
"archive-selection": "نقل التحديد إلى الأرشيف",
|
||||
"archiveBoardPopup-title": "نقل الوح إلى الأرشيف",
|
||||
"archived-items": "أرشيف",
|
||||
"archived-boards": "الالواح في الأرشيف",
|
||||
"restore-board": "استعادة اللوحة",
|
||||
"no-archived-boards": "No Boards in Recycle Bin.",
|
||||
"archives": "Recycle Bin",
|
||||
"no-archived-boards": "لا توجد لوحات في الأرشيف.",
|
||||
"archives": "أرشيف",
|
||||
"assign-member": "تعيين عضو",
|
||||
"attached": "أُرفق)",
|
||||
"attachment": "مرفق",
|
||||
@@ -102,22 +112,23 @@
|
||||
"boardChangeWatchPopup-title": "تغيير المتابعة",
|
||||
"boardMenuPopup-title": "قائمة اللوحة",
|
||||
"boards": "لوحات",
|
||||
"board-view": "Board View",
|
||||
"board-view-cal": "Calendar",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view": "عرض اللوحات",
|
||||
"board-view-cal": "التقويم",
|
||||
"board-view-swimlanes": "خطوط السباحة",
|
||||
"board-view-lists": "القائمات",
|
||||
"bucket-example": "مثل « todo list » على سبيل المثال",
|
||||
"cancel": "إلغاء",
|
||||
"card-archived": "This card is moved to Recycle Bin.",
|
||||
"card-archived": "البطاقة منقولة الى الارشيف",
|
||||
"board-archived": "اللوحات منقولة الى الارشيف",
|
||||
"card-comments-title": "%s تعليقات لهذه البطاقة",
|
||||
"card-delete-notice": "هذا حذف أبديّ . سوف تفقد كل الإجراءات المنوطة بهذه البطاقة",
|
||||
"card-delete-pop": "سيتم إزالة جميع الإجراءات من تبعات النشاط، وأنك لن تكون قادرا على إعادة فتح البطاقة. لا يوجد التراجع.",
|
||||
"card-delete-suggest-archive": "You can move a card to Recycle Bin to remove it from the board and preserve the activity.",
|
||||
"card-delete-suggest-archive": "يمكنك نقل بطاقة إلى الأرشيف لإزالتها من اللوحة والمحافظة على النشاط.",
|
||||
"card-due": "مستحق",
|
||||
"card-due-on": "مستحق في",
|
||||
"card-spent": "Spent Time",
|
||||
"card-spent": "امضى وقتا",
|
||||
"card-edit-attachments": "تعديل المرفقات",
|
||||
"card-edit-custom-fields": "Edit custom fields",
|
||||
"card-edit-custom-fields": "تعديل الحقل المعدل",
|
||||
"card-edit-labels": "تعديل العلامات",
|
||||
"card-edit-members": "تعديل الأعضاء",
|
||||
"card-labels-title": "تعديل علامات البطاقة.",
|
||||
@@ -125,8 +136,8 @@
|
||||
"card-start": "بداية",
|
||||
"card-start-on": "يبدأ في",
|
||||
"cardAttachmentsPopup-title": "إرفاق من",
|
||||
"cardCustomField-datePopup-title": "Change date",
|
||||
"cardCustomFieldsPopup-title": "Edit custom fields",
|
||||
"cardCustomField-datePopup-title": "تغير التاريخ",
|
||||
"cardCustomFieldsPopup-title": "تعديل الحقل المعدل",
|
||||
"cardDeletePopup-title": "حذف البطاقة ?",
|
||||
"cardDetailsActionsPopup-title": "إجراءات على البطاقة",
|
||||
"cardLabelsPopup-title": "علامات",
|
||||
@@ -134,7 +145,10 @@
|
||||
"cardMorePopup-title": "المزيد",
|
||||
"cards": "بطاقات",
|
||||
"cards-count": "بطاقات",
|
||||
"casSignIn": "Sign In with CAS",
|
||||
"casSignIn": "تسجيل الدخول مع CAS",
|
||||
"cardType-card": "بطاقة",
|
||||
"cardType-linkedCard": "البطاقة المرتبطة",
|
||||
"cardType-linkedBoard": "Linked Board",
|
||||
"change": "Change",
|
||||
"change-avatar": "تعديل الصورة الشخصية",
|
||||
"change-password": "تغيير كلمة المرور",
|
||||
@@ -152,25 +166,45 @@
|
||||
"clipboard": "Clipboard or drag & drop",
|
||||
"close": "غلق",
|
||||
"close-board": "غلق اللوحة",
|
||||
"close-board-pop": "You will be able to restore the board by clicking the “Recycle Bin” button from the home header.",
|
||||
"close-board-pop": "You will be able to restore the board by clicking the “Archive” button from the home header.",
|
||||
"color-black": "black",
|
||||
"color-blue": "blue",
|
||||
"color-crimson": "crimson",
|
||||
"color-darkgreen": "darkgreen",
|
||||
"color-gold": "gold",
|
||||
"color-gray": "gray",
|
||||
"color-green": "green",
|
||||
"color-indigo": "indigo",
|
||||
"color-lime": "lime",
|
||||
"color-magenta": "magenta",
|
||||
"color-mistyrose": "mistyrose",
|
||||
"color-navy": "navy",
|
||||
"color-orange": "orange",
|
||||
"color-paleturquoise": "paleturquoise",
|
||||
"color-peachpuff": "peachpuff",
|
||||
"color-pink": "pink",
|
||||
"color-plum": "plum",
|
||||
"color-purple": "purple",
|
||||
"color-red": "red",
|
||||
"color-saddlebrown": "saddlebrown",
|
||||
"color-silver": "silver",
|
||||
"color-sky": "sky",
|
||||
"color-slateblue": "slateblue",
|
||||
"color-white": "white",
|
||||
"color-yellow": "yellow",
|
||||
"unset-color": "Unset",
|
||||
"comment": "تعليق",
|
||||
"comment-placeholder": "أكتب تعليق",
|
||||
"comment-only": "التعليق فقط",
|
||||
"comment-only-desc": "يمكن التعليق على بطاقات فقط.",
|
||||
"no-comments": "No comments",
|
||||
"no-comments-desc": "Can not see comments and activities.",
|
||||
"computer": "حاسوب",
|
||||
"confirm-subtask-delete-dialog": "Are you sure you want to delete subtask?",
|
||||
"confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?",
|
||||
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
|
||||
"linkCardPopup-title": "ربط البطاقة",
|
||||
"searchCardPopup-title": "Search Card",
|
||||
"copyCardPopup-title": "نسخ البطاقة",
|
||||
"copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
|
||||
"copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
|
||||
@@ -261,21 +295,24 @@
|
||||
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
|
||||
"home": "الرئيسية",
|
||||
"import": "Import",
|
||||
"link": "Link",
|
||||
"import-board": "استيراد لوحة",
|
||||
"import-board-c": "استيراد لوحة",
|
||||
"import-board-title-trello": "Import board from Trello",
|
||||
"import-board-title-wekan": "استيراد لوحة من ويكان",
|
||||
"import-board-title-wekan": "Import board from previous export",
|
||||
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
|
||||
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
|
||||
"from-trello": "من تريلو",
|
||||
"from-wekan": "من ويكان",
|
||||
"from-wekan": "From previous export",
|
||||
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
|
||||
"import-board-instruction-wekan": "في لوحة ويكان الخاصة بك، انتقل إلى 'القائمة'، ثم 'تصدير اللوحة'، ونسخ النص في الملف الذي تم تنزيله.",
|
||||
"import-board-instruction-wekan": "In your board, go to 'Menu', then 'Export board', and copy the text in the downloaded file.",
|
||||
"import-board-instruction-about-errors": "If you get errors when importing board, sometimes importing still works, and board is at All Boards page.",
|
||||
"import-json-placeholder": "Paste your valid JSON data here",
|
||||
"import-map-members": "رسم خريطة الأعضاء",
|
||||
"import-members-map": "Your imported board has some members. Please map the members you want to import to Wekan users",
|
||||
"import-members-map": "Your imported board has some members. Please map the members you want to import to your users",
|
||||
"import-show-user-mapping": "Review members mapping",
|
||||
"import-user-select": "Pick the Wekan user you want to use as this member",
|
||||
"importMapMembersAddPopup-title": "حدّد عضو ويكان",
|
||||
"import-user-select": "Pick your existing user you want to use as this member",
|
||||
"importMapMembersAddPopup-title": "Select member",
|
||||
"info": "الإصدار",
|
||||
"initials": "أولية",
|
||||
"invalid-date": "تاريخ غير صالح",
|
||||
@@ -294,8 +331,8 @@
|
||||
"leave-board-pop": "Are you sure you want to leave __boardTitle__? You will be removed from all cards on this board.",
|
||||
"leaveBoardPopup-title": "مغادرة اللوحة ؟",
|
||||
"link-card": "ربط هذه البطاقة",
|
||||
"list-archive-cards": "Move all cards in this list to Recycle Bin",
|
||||
"list-archive-cards-pop": "This will remove all the cards in this list from the board. To view cards in Recycle Bin and bring them back to the board, click “Menu” > “Recycle Bin”.",
|
||||
"list-archive-cards": "Move all cards in this list to Archive",
|
||||
"list-archive-cards-pop": "This will remove all the cards in this list from the board. To view cards in Archive and bring them back to the board, click “Menu” > “Archive”.",
|
||||
"list-move-cards": "نقل بطاقات هذه القائمة",
|
||||
"list-select-cards": "تحديد بطاقات هذه القائمة",
|
||||
"listActionPopup-title": "قائمة الإجراءات",
|
||||
@@ -304,9 +341,9 @@
|
||||
"listMorePopup-title": "المزيد",
|
||||
"link-list": "رابط إلى هذه القائمة",
|
||||
"list-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the list. There is no undo.",
|
||||
"list-delete-suggest-archive": "You can move a list to Recycle Bin to remove it from the board and preserve the activity.",
|
||||
"list-delete-suggest-archive": "You can move a list to Archive to remove it from the board and preserve the activity.",
|
||||
"lists": "القائمات",
|
||||
"swimlanes": "Swimlanes",
|
||||
"swimlanes": "خطوط السباحة",
|
||||
"log-out": "تسجيل الخروج",
|
||||
"log-in": "تسجيل الدخول",
|
||||
"loginPopup-title": "تسجيل الدخول",
|
||||
@@ -324,9 +361,9 @@
|
||||
"muted-info": "You will never be notified of any changes in this board",
|
||||
"my-boards": "لوحاتي",
|
||||
"name": "اسم",
|
||||
"no-archived-cards": "No cards in Recycle Bin.",
|
||||
"no-archived-lists": "No lists in Recycle Bin.",
|
||||
"no-archived-swimlanes": "No swimlanes in Recycle Bin.",
|
||||
"no-archived-cards": "No cards in Archive.",
|
||||
"no-archived-lists": "No lists in Archive.",
|
||||
"no-archived-swimlanes": "No swimlanes in Archive.",
|
||||
"no-results": "لا توجد نتائج",
|
||||
"normal": "عادي",
|
||||
"normal-desc": "يمكن مشاهدة و تعديل البطاقات. لا يمكن تغيير إعدادات الضبط.",
|
||||
@@ -362,6 +399,7 @@
|
||||
"restore": "استعادة",
|
||||
"save": "حفظ",
|
||||
"search": "بحث",
|
||||
"rules": "Rules",
|
||||
"search-cards": "Search from card titles and descriptions on this board",
|
||||
"search-example": "Text to search for?",
|
||||
"select-color": "اختيار اللون",
|
||||
@@ -405,7 +443,7 @@
|
||||
"uploaded-avatar": "تم رفع الصورة الشخصية",
|
||||
"username": "اسم المستخدم",
|
||||
"view-it": "شاهدها",
|
||||
"warn-list-archived": "warning: this card is in an list at Recycle Bin",
|
||||
"warn-list-archived": "warning: this card is in an list at Archive",
|
||||
"watch": "مُشاهد",
|
||||
"watching": "مشاهدة",
|
||||
"watching-info": "You will be notified of any change in this board",
|
||||
@@ -438,16 +476,16 @@
|
||||
"send-smtp-test": "Send a test email to yourself",
|
||||
"invitation-code": "رمز الدعوة",
|
||||
"email-invite-register-subject": "__inviter__ أرسل دعوة لك",
|
||||
"email-invite-register-text": "Dear __user__,\n\n__inviter__ invites you to Wekan for collaborations.\n\nPlease follow the link below:\n__url__\n\nAnd your invitation code is: __icode__\n\nThanks.",
|
||||
"email-smtp-test-subject": "SMTP Test Email From Wekan",
|
||||
"email-invite-register-text": "Dear __user__,\n\n__inviter__ invites you to kanban board for collaborations.\n\nPlease follow the link below:\n__url__\n\nAnd your invitation code is: __icode__\n\nThanks.",
|
||||
"email-smtp-test-subject": "SMTP Test Email",
|
||||
"email-smtp-test-text": "You have successfully sent an email",
|
||||
"error-invitation-code-not-exist": "رمز الدعوة غير موجود",
|
||||
"error-notAuthorized": "أنتَ لا تملك الصلاحيات لرؤية هذه الصفحة.",
|
||||
"outgoing-webhooks": "الويبهوك الصادرة",
|
||||
"outgoingWebhooksPopup-title": "الويبهوك الصادرة",
|
||||
"boardCardTitlePopup-title": "Card Title Filter",
|
||||
"new-outgoing-webhook": "ويبهوك جديدة ",
|
||||
"no-name": "(غير معروف)",
|
||||
"Wekan_version": "إصدار ويكان",
|
||||
"Node_version": "إصدار النود",
|
||||
"OS_Arch": "معمارية نظام التشغيل",
|
||||
"OS_Cpus": "استهلاك وحدة المعالجة المركزية لنظام التشغيل",
|
||||
@@ -458,10 +496,13 @@
|
||||
"OS_Totalmem": "الذاكرة الكلية لنظام التشغيل",
|
||||
"OS_Type": "نوع نظام التشغيل",
|
||||
"OS_Uptime": "مدة تشغيل نظام التشغيل",
|
||||
"days": "days",
|
||||
"hours": "الساعات",
|
||||
"minutes": "الدقائق",
|
||||
"seconds": "الثواني",
|
||||
"show-field-on-card": "Show this field on card",
|
||||
"automatically-field-on-card": "Auto create field to all cards",
|
||||
"showLabel-field-on-card": "Show field label on minicard",
|
||||
"yes": "نعم",
|
||||
"no": "لا",
|
||||
"accounts": "الحسابات",
|
||||
@@ -476,6 +517,7 @@
|
||||
"card-end-on": "Ends on",
|
||||
"editCardReceivedDatePopup-title": "Change received date",
|
||||
"editCardEndDatePopup-title": "Change end date",
|
||||
"setCardColor-title": "Set color",
|
||||
"assigned-by": "Assigned By",
|
||||
"requested-by": "Requested By",
|
||||
"board-delete-notice": "Deleting is permanent. You will lose all lists, cards and actions associated with this board.",
|
||||
@@ -498,5 +540,119 @@
|
||||
"change-card-parent": "Change card's parent",
|
||||
"parent-card": "Parent card",
|
||||
"source-board": "Source board",
|
||||
"no-parent": "Don't show parent"
|
||||
"no-parent": "Don't show parent",
|
||||
"activity-added-label": "added label '%s' to %s",
|
||||
"activity-removed-label": "removed label '%s' from %s",
|
||||
"activity-delete-attach": "deleted an attachment from %s",
|
||||
"activity-added-label-card": "added label '%s'",
|
||||
"activity-removed-label-card": "removed label '%s'",
|
||||
"activity-delete-attach-card": "deleted an attachment",
|
||||
"r-rule": "Rule",
|
||||
"r-add-trigger": "Add trigger",
|
||||
"r-add-action": "Add action",
|
||||
"r-board-rules": "Board rules",
|
||||
"r-add-rule": "Add rule",
|
||||
"r-view-rule": "View rule",
|
||||
"r-delete-rule": "Delete rule",
|
||||
"r-new-rule-name": "New rule title",
|
||||
"r-no-rules": "No rules",
|
||||
"r-when-a-card": "When a card",
|
||||
"r-is": "is",
|
||||
"r-is-moved": "is moved",
|
||||
"r-added-to": "added to",
|
||||
"r-removed-from": "Removed from",
|
||||
"r-the-board": "the board",
|
||||
"r-list": "list",
|
||||
"set-filter": "Set Filter",
|
||||
"r-moved-to": "Moved to",
|
||||
"r-moved-from": "Moved from",
|
||||
"r-archived": "Moved to Archive",
|
||||
"r-unarchived": "Restored from Archive",
|
||||
"r-a-card": "a card",
|
||||
"r-when-a-label-is": "When a label is",
|
||||
"r-when-the-label-is": "When the label is",
|
||||
"r-list-name": "list name",
|
||||
"r-when-a-member": "When a member is",
|
||||
"r-when-the-member": "When the member",
|
||||
"r-name": "name",
|
||||
"r-when-a-attach": "When an attachment",
|
||||
"r-when-a-checklist": "When a checklist is",
|
||||
"r-when-the-checklist": "When the checklist",
|
||||
"r-completed": "Completed",
|
||||
"r-made-incomplete": "Made incomplete",
|
||||
"r-when-a-item": "When a checklist item is",
|
||||
"r-when-the-item": "When the checklist item",
|
||||
"r-checked": "Checked",
|
||||
"r-unchecked": "Unchecked",
|
||||
"r-move-card-to": "Move card to",
|
||||
"r-top-of": "Top of",
|
||||
"r-bottom-of": "Bottom of",
|
||||
"r-its-list": "its list",
|
||||
"r-archive": "نقل الى الارشيف",
|
||||
"r-unarchive": "Restore from Archive",
|
||||
"r-card": "card",
|
||||
"r-add": "أضف",
|
||||
"r-remove": "Remove",
|
||||
"r-label": "label",
|
||||
"r-member": "member",
|
||||
"r-remove-all": "Remove all members from the card",
|
||||
"r-set-color": "Set color to",
|
||||
"r-checklist": "checklist",
|
||||
"r-check-all": "Check all",
|
||||
"r-uncheck-all": "Uncheck all",
|
||||
"r-items-check": "items of checklist",
|
||||
"r-check": "Check",
|
||||
"r-uncheck": "Uncheck",
|
||||
"r-item": "item",
|
||||
"r-of-checklist": "of checklist",
|
||||
"r-send-email": "Send an email",
|
||||
"r-to": "to",
|
||||
"r-subject": "subject",
|
||||
"r-rule-details": "Rule details",
|
||||
"r-d-move-to-top-gen": "Move card to top of its list",
|
||||
"r-d-move-to-top-spec": "Move card to top of list",
|
||||
"r-d-move-to-bottom-gen": "Move card to bottom of its list",
|
||||
"r-d-move-to-bottom-spec": "Move card to bottom of list",
|
||||
"r-d-send-email": "Send email",
|
||||
"r-d-send-email-to": "to",
|
||||
"r-d-send-email-subject": "subject",
|
||||
"r-d-send-email-message": "message",
|
||||
"r-d-archive": "Move card to Archive",
|
||||
"r-d-unarchive": "Restore card from Archive",
|
||||
"r-d-add-label": "Add label",
|
||||
"r-d-remove-label": "Remove label",
|
||||
"r-create-card": "Create new card",
|
||||
"r-in-list": "in list",
|
||||
"r-in-swimlane": "in swimlane",
|
||||
"r-d-add-member": "Add member",
|
||||
"r-d-remove-member": "Remove member",
|
||||
"r-d-remove-all-member": "Remove all member",
|
||||
"r-d-check-all": "Check all items of a list",
|
||||
"r-d-uncheck-all": "Uncheck all items of a list",
|
||||
"r-d-check-one": "Check item",
|
||||
"r-d-uncheck-one": "Uncheck item",
|
||||
"r-d-check-of-list": "of checklist",
|
||||
"r-d-add-checklist": "Add checklist",
|
||||
"r-d-remove-checklist": "Remove checklist",
|
||||
"r-by": "by",
|
||||
"r-add-checklist": "Add checklist",
|
||||
"r-with-items": "with items",
|
||||
"r-items-list": "item1,item2,item3",
|
||||
"r-add-swimlane": "Add swimlane",
|
||||
"r-swimlane-name": "swimlane name",
|
||||
"r-board-note": "Note: leave a field empty to match every possible value.",
|
||||
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
|
||||
"r-when-a-card-is-moved": "When a card is moved to another list",
|
||||
"ldap": "LDAP",
|
||||
"oauth2": "OAuth2",
|
||||
"cas": "CAS",
|
||||
"authentication-method": "Authentication method",
|
||||
"authentication-type": "Authentication type",
|
||||
"custom-product-name": "Custom Product Name",
|
||||
"layout": "Layout",
|
||||
"hide-logo": "Hide Logo",
|
||||
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
|
||||
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
|
||||
"error-undefined": "Something went wrong",
|
||||
"error-ldap-login": "An error occurred while trying to login"
|
||||
}
|
||||
Loaded 100 of 234 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user