Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83848dbee2 | ||
|
|
cb099d1093 | ||
|
|
89a8a6f5e3 | ||
|
|
22923d08af | ||
|
|
57ccfcde63 | ||
|
|
75693d16e2 | ||
|
|
454523dd47 | ||
|
|
bb37d8fa96 | ||
|
|
f470323ee7 | ||
|
|
c62a2ee11f | ||
|
|
5b0f7f8aef | ||
|
|
0495e61c28 | ||
|
|
c1c3421006 | ||
|
|
3ce90e9766 | ||
|
|
293718d90c | ||
|
|
4b53b0c90a | ||
|
|
98103bb2f7 | ||
|
|
e5b003f5ab | ||
|
|
9a1b1a5bed | ||
|
|
990af4e5c2 | ||
|
|
f7a9bafe4c | ||
|
|
ac7d44f8a8 | ||
|
|
ed8471be9b | ||
|
|
65beb89944 | ||
|
|
663d8e3c34 | ||
|
|
128a356b92 | ||
|
|
2092b429db | ||
|
|
58e5e9b308 | ||
|
|
338fb5304d | ||
|
|
9e62584b26 | ||
|
|
5849ffbb53 | ||
|
|
a58bffbb3e | ||
|
|
a8ae6adbc2 | ||
|
|
946dcf0b0a | ||
|
|
1ca9e96f35 | ||
|
|
b475127c53 | ||
|
|
bbca361aeb | ||
|
|
f96e21f462 | ||
|
|
1be8e5625f | ||
|
|
9084158aec | ||
|
|
d454fa7dd7 | ||
|
|
b6d3e79548 | ||
|
|
a23d93391b | ||
|
|
a033c35a34 | ||
|
|
48cd551a69 | ||
|
|
8d2839f0c3 | ||
|
|
284fac043b | ||
|
|
bd239351fd | ||
|
|
37c94622e4 | ||
|
|
c4fa9010f3 | ||
|
|
843381a36c | ||
|
|
59ba2111e8 | ||
|
|
1efa66b58c | ||
|
|
dc8c9053c2 | ||
|
|
0a16147470 | ||
|
|
373e9782dc | ||
|
|
951a0db380 | ||
|
|
c0d33d97f2 | ||
|
|
5bdb392258 | ||
|
|
a48630ffcf | ||
|
|
fe1941008c | ||
|
|
190aa36a51 | ||
|
|
468f4de0cf | ||
|
|
93215be2cf | ||
|
|
ab2884cae0 | ||
|
|
5f374b2fd2 | ||
|
|
636e1657f6 | ||
|
|
2001c01b4d | ||
|
|
a9166d877f | ||
|
|
435501fb8e | ||
|
|
fd47e10e52 | ||
|
|
e3bd1c4d23 | ||
|
|
f7b72a1a80 | ||
|
|
31f25bcddb | ||
|
|
1ec5e90706 | ||
|
|
20d6ea85d4 | ||
|
|
7498dba32c | ||
|
|
d374cd2f81 | ||
|
|
ffbd3ccc2a | ||
|
|
ad1a181f6d | ||
|
|
fcd83ea7bd | ||
|
|
07fc296762 | ||
|
|
62fca18fea | ||
|
|
af82a80b2b | ||
|
|
9966c19f94 | ||
|
|
ff320f7b3a | ||
|
|
9c9694bcd1 | ||
|
|
fcd7097aba | ||
|
|
19089e8930 | ||
|
|
f7920da0cf | ||
|
|
d7ea73ff82 | ||
|
|
e077c85d00 | ||
|
|
3665a9131c | ||
|
|
f7fe44fcdf | ||
|
|
a533caa944 | ||
|
|
26f66f3cf0 | ||
|
|
2e449e9e78 | ||
|
|
e30f6515c6 | ||
|
|
11e9811f82 | ||
|
|
df5be82840 | ||
|
|
599c83e0da | ||
|
|
c0dbb79ac9 | ||
|
|
0375c551f3 | ||
|
|
ee0f42eeb1 | ||
|
|
7f4b382d2f | ||
|
|
96d81768bc | ||
|
|
cd012954e9 | ||
|
|
3b202c284a | ||
|
|
8da1dd524d | ||
|
|
cfaeb43f1f | ||
|
|
25e0c38ad8 | ||
|
|
756fbd0f4c | ||
|
|
55a53e2655 | ||
|
|
29461cb110 | ||
|
|
a30f61d72f | ||
|
|
056843d66c | ||
|
|
69e4ad48bf | ||
|
|
3588f4324c | ||
|
|
71decc370d | ||
|
|
3171af613a | ||
|
|
11b8e12ede | ||
|
|
69aeee536d | ||
|
|
ab6a7c2dd6 | ||
|
|
0a5af2b719 | ||
|
|
ecd77c8704 | ||
|
|
c5019e620a | ||
|
|
257ed56db3 | ||
|
|
edc2459ff8 | ||
|
|
36a2aa355e | ||
|
|
cea8101574 | ||
|
|
3cb356eb1d | ||
|
|
b3d3158863 | ||
|
|
f795edc640 | ||
|
|
c1ddaaa475 | ||
|
|
2dc71e97a7 | ||
|
|
92122f0fa2 | ||
|
|
ce1fd00517 | ||
|
|
5871a478e1 | ||
|
|
fcebb2a537 | ||
|
|
b267015d8c | ||
|
|
842c8b83d2 | ||
|
|
9705118ca2 | ||
|
|
326b4c5350 | ||
|
|
f3ed6ee6f6 | ||
|
|
60c6f4f5af | ||
|
|
3c1cd85f6f | ||
|
|
bb9d5cb694 | ||
|
|
669c2f3861 | ||
|
|
6a93a93d0b | ||
|
|
c3fe70e094 | ||
|
|
79ae90825e | ||
|
|
b0f0bf4a24 | ||
|
|
9dba6ff6fd | ||
|
|
d77afe3e2e | ||
|
|
ec0a8449ba | ||
|
|
9df3e3d26b | ||
|
|
73401a5d74 | ||
|
|
653f2b1ac8 | ||
|
|
2cd4caa76a | ||
|
|
000b267eaf | ||
|
|
5953fb8a44 | ||
|
|
3414cb84ad | ||
|
|
42bc905c16 | ||
|
|
d94f11c778 | ||
|
|
fcd5fda751 | ||
|
|
66bfb1cdc8 | ||
|
|
69dfa1033f | ||
|
|
94b8bba324 | ||
|
|
5dd8c9829d | ||
|
|
e0e6f06a83 | ||
|
|
8322500e47 | ||
|
|
ff9ca755f3 | ||
|
|
d3c110cd8f | ||
|
|
f6fb05d3f4 | ||
|
|
8102ee5b4f | ||
|
|
3c60df4fcd | ||
|
|
23cba8a43f | ||
|
|
65c081acc0 | ||
|
|
735907977d | ||
|
|
9d7ff75d3f | ||
|
|
1ef5b8efe1 | ||
|
|
f3d6aa9e09 | ||
|
|
fd430d3405 | ||
|
|
0ce4171d33 | ||
|
|
7df5679c0c | ||
|
|
1616dd1b74 | ||
|
|
081c1fdf83 | ||
|
|
9444624f19 | ||
|
|
abd1d322f2 | ||
|
|
d19083bb89 | ||
|
|
7ddaa12520 | ||
|
|
3b8c76a32e | ||
|
|
7f4401f3a2 | ||
|
|
188341cf50 | ||
|
|
af119ff7c0 | ||
|
|
7b04f14e3c | ||
|
|
a14f4ffee2 | ||
|
|
2d7d9b5d9f | ||
|
|
ecb8c88233 | ||
|
|
91e738bd32 | ||
|
|
ec0bbe9e14 | ||
|
|
6e25ef73b0 | ||
|
|
d2ce41694f | ||
|
|
b2c9d47b0f | ||
|
|
52aa22f36a | ||
|
|
bc6217854a | ||
|
|
d79bb1a81c | ||
|
|
fb220fe918 | ||
|
|
89ccef84be | ||
|
|
6622dbb56b | ||
|
|
7963171058 | ||
|
|
ee2a43dd5b | ||
|
|
690a5b9703 | ||
|
|
f33be3e243 | ||
|
|
4eaf92d17e | ||
|
|
1baa4b2fa4 | ||
|
|
6210c00f95 | ||
|
|
8b6a2eade3 | ||
|
|
f7ef629dba | ||
|
|
0f0a93cabf | ||
|
|
e5193870fc | ||
|
|
428465d361 | ||
|
|
37b2771a9d | ||
|
|
ccb14beb83 | ||
|
|
17bb464107 | ||
|
|
cd4062c9f1 | ||
|
|
22158b4941 | ||
|
|
bdf252b6e2 | ||
|
|
2347fbae17 | ||
|
|
9e3e63f494 | ||
|
|
ba2d9b89dc | ||
|
|
62d000cd67 | ||
|
|
0c15048bdd | ||
|
|
74877fd10d | ||
|
|
c3e67510c8 | ||
|
|
4fad48e7ac | ||
|
|
0f567a8e9c | ||
|
|
0d976aaf0f | ||
|
|
f115e33f66 | ||
|
|
6e8a84eaa7 | ||
|
|
eb9d417a27 | ||
|
|
8dd6255ebf | ||
|
|
7a943f99e3 | ||
|
|
415fafe7f6 | ||
|
|
462b8023eb | ||
|
|
8f2bebeeef | ||
|
|
e08f9686d8 | ||
|
|
bd127af916 | ||
|
|
d235a00b11 | ||
|
|
8dc9856ed8 | ||
|
|
ca1da1adc2 | ||
|
|
4c0b262c7b | ||
|
|
4ac9048d80 | ||
|
|
fb83a5164d | ||
|
|
a05292bd91 | ||
|
|
f4e0d92296 | ||
|
|
9e0142b885 | ||
|
|
5f30c6ecca | ||
|
|
7214e4bb2f | ||
|
|
fd7a140429 | ||
|
|
07954c0f6d | ||
|
|
a282a38ecd | ||
|
|
1f830cc5e3 | ||
|
|
96b560eb00 | ||
|
|
6ce5ea9ca5 | ||
|
|
9ed730284d | ||
|
|
10427a9beb | ||
|
|
ddcdcb6e08 | ||
|
|
7afea1809f | ||
|
|
1790b99fe0 | ||
|
|
d5d661b131 | ||
|
|
8a28e988e9 | ||
|
|
d1d8e0b935 | ||
|
|
84d60b5908 | ||
|
|
245d262705 | ||
|
|
c686cadfef | ||
|
|
26405c011f | ||
|
|
ba9e163dd5 | ||
|
|
7c403053e3 | ||
|
|
c52233cacf | ||
|
|
d6a5cb534d | ||
|
|
e2f768c6a0 | ||
|
|
4c5eda0ae5 | ||
|
|
670cc99b8f | ||
|
|
847843e51d | ||
|
|
9261371c51 | ||
|
|
233554a3d6 | ||
|
|
fa281e3f5f | ||
|
|
fcf7c02c69 | ||
|
|
3a391d5539 | ||
|
|
22e369804b | ||
|
|
3dc326db6a | ||
|
|
b3eab212ae | ||
|
|
6d9d183674 | ||
|
|
54036fd7a3 | ||
|
|
c72792e4ed | ||
|
|
c3e2ee1db8 | ||
|
|
5d8462ca11 | ||
|
|
7e4b42e9b3 | ||
|
|
c609096700 | ||
|
|
79fa5f89f3 | ||
|
|
f224934ae0 | ||
|
|
c31d7455f7 | ||
|
|
596dd87862 | ||
|
|
c048ce89f1 | ||
|
|
44559b52a6 | ||
|
|
162b15c0cd | ||
|
|
3756b7b0fc | ||
|
|
332f12ce28 | ||
|
|
d31d5fd47a | ||
|
|
83efd5b872 | ||
|
|
c2fd03e113 | ||
|
|
dffe3d5ade | ||
|
|
d7cefc0042 | ||
|
|
33b7622897 | ||
|
|
eb8083097f | ||
|
|
80c0c80a6a | ||
|
|
e28f3692ca | ||
|
|
6bcc1cfc62 | ||
|
|
990003ee0f | ||
|
|
60929fb200 | ||
|
|
45c78a05e2 | ||
|
|
cf045e3c34 | ||
|
|
6575312e74 | ||
|
|
ee22364354 | ||
|
|
a64dbc4a9b | ||
|
|
ebff813f99 | ||
|
|
674d45a81c | ||
|
|
b03c9b9879 | ||
|
|
7f8f6bf3db | ||
|
|
4ffe9438e0 | ||
|
|
fbf97d31a0 | ||
|
|
0c5d6c2ade | ||
|
|
00737fa015 | ||
|
|
0c9343ad88 | ||
|
|
f31d007177 | ||
|
|
932a273ba0 | ||
|
|
9ea35b7188 | ||
|
|
d76387aed2 | ||
|
|
77a4341621 | ||
|
|
e162fe3c0f | ||
|
|
f3e7646cfa | ||
|
|
552fa32b87 | ||
|
|
8a4f5ed6e3 | ||
|
|
c8cef7551f | ||
|
|
9c46c6c962 | ||
|
|
01818a99b9 | ||
|
|
70fb1c4650 | ||
|
|
5c743f12a1 | ||
|
|
5b9e8cce14 | ||
|
|
06afa1ae35 | ||
|
|
a84db59898 | ||
|
|
9441fb29c9 | ||
|
|
7dae37eeac | ||
|
|
90fd3286a8 | ||
|
|
996fdc2bda | ||
|
|
6dba4ccd4d | ||
|
|
b592e8ad14 | ||
|
|
d38071457c | ||
|
|
eec3c301bc | ||
|
|
dfd0b21947 | ||
|
|
6d93e9ffb0 | ||
|
|
99be745f02 | ||
|
|
62e43c0832 | ||
|
|
eceaac7998 | ||
|
|
c01335ee29 | ||
|
|
9353d785ea | ||
|
|
0ea96fca3f | ||
|
|
75c5eeb046 | ||
|
|
9f30eeae61 | ||
|
|
6fc992e6d7 | ||
|
|
622292e40e | ||
|
|
22e43e6591 | ||
|
|
13d8e75c05 | ||
|
|
8ae9cb97f7 | ||
|
|
b4c3e02b75 | ||
|
|
ffb8b72b69 | ||
|
|
309c1d08ff | ||
|
|
ce4f158976 | ||
|
|
5a37ba0d9f | ||
|
|
59f4daf91e | ||
|
|
fa1d8cd5ef | ||
|
|
e3b7f85cc3 | ||
|
|
3bead1bf78 | ||
|
|
1f6545e411 | ||
|
|
29d54f46aa | ||
|
|
2d12a4f404 | ||
|
|
ba3c3f8289 | ||
|
|
6eef4043ca | ||
|
|
999cdb2bb9 | ||
|
|
cc5435c780 | ||
|
|
e015e4245e | ||
|
|
c17f26f6ba | ||
|
|
fdd1aad80d | ||
|
|
8bf3f300ad | ||
|
|
99455b2728 | ||
|
|
1a232c7bbb | ||
|
|
d3d73e9cdd | ||
|
|
0c34cb97a7 | ||
|
|
0df3e7a3c0 | ||
|
|
29a08e5568 | ||
|
|
09808840cd | ||
|
|
c5e36d9160 | ||
|
|
aa1646ad45 | ||
|
|
c2173e073e | ||
|
|
81d00a9471 | ||
|
|
e8cfed1f7b | ||
|
|
28c78fdfef | ||
|
|
d48043c7ee | ||
|
|
dd1a8ade5e | ||
|
|
d9705a0ec4 | ||
|
|
58fbe8e6f2 | ||
|
|
5c1ace7293 | ||
|
|
0321d9770c | ||
|
|
6a2b6ef3c0 | ||
|
|
01507576b1 | ||
|
|
94a6d9ae2f | ||
|
|
64fe808a4a | ||
|
|
a493c314db | ||
|
|
d1670ee4c1 | ||
|
|
2edced5467 | ||
|
|
509b640588 | ||
|
|
624c5aa9b2 | ||
|
|
c5540ddcbd | ||
|
|
b105f0e2e7 | ||
|
|
99703035d7 | ||
|
|
b92cde23aa | ||
|
|
21f76bcacc | ||
|
|
0d7c1501ce | ||
|
|
97a23011da | ||
|
|
93d8a3f88a | ||
|
|
624719974e | ||
|
|
c290d63048 | ||
|
|
b55756216e | ||
|
|
77d23df87f | ||
|
|
3ab33ed826 | ||
|
|
8f1f7a1d56 | ||
|
|
4eccfb6c25 | ||
|
|
a5daf5dc29 | ||
|
|
6a89914873 | ||
|
|
5532a0071a | ||
|
|
46d7a33575 | ||
|
|
2f0609db64 | ||
|
|
f16687fa94 | ||
|
|
dc82582391 | ||
|
|
ff7b001b00 | ||
|
|
33cea11393 | ||
|
|
10cb2db94f | ||
|
|
c346743234 | ||
|
|
6ba1fc5ba1 | ||
|
|
de2acaec68 | ||
|
|
fb060ed2c5 | ||
|
|
c84187bdad | ||
|
|
ad607c1291 | ||
|
|
b9be17360f | ||
|
|
23ff08382a | ||
|
|
b34c62bbc7 | ||
|
|
e85d6d6c5e | ||
|
|
8daa5b4848 | ||
|
|
273784b9e4 | ||
|
|
f77da76c68 | ||
|
|
214fe6a61f | ||
|
|
38d1a424d0 | ||
|
|
e4c08f6933 | ||
|
|
3bee5ad7fe | ||
|
|
296520f9ac | ||
|
|
c865bfe497 | ||
|
|
089dbf0cf6 | ||
|
|
527c430307 | ||
|
|
de4ae2dc74 | ||
|
|
bab02bf8fa | ||
|
|
23a9ba0ef6 | ||
|
|
c3804dc0fa | ||
|
|
08bab70dbe | ||
|
|
ed4c749cea | ||
|
|
d6ef4a8266 | ||
|
|
1d3e2ffadd | ||
|
|
0074317bd3 | ||
|
|
26aa9a4ac4 | ||
|
|
e587964e82 | ||
|
|
61dce8e65d | ||
|
|
c18ded23a3 | ||
|
|
ff5e88fca3 | ||
|
|
8df9e681ed | ||
|
|
443c3a7ac6 | ||
|
|
c8cbb7697d | ||
|
|
d213d37dab | ||
|
|
a003161fa7 | ||
|
|
51fd053119 | ||
|
|
740c705748 | ||
|
|
a1d0672739 | ||
|
|
7d3fed56ae | ||
|
|
a0cccb736c | ||
|
|
6ec14ee52b | ||
|
|
4b995e88ba | ||
|
|
2ae0dc315f | ||
|
|
a88ac6113e | ||
|
|
42ca385a36 | ||
|
|
e6a866cb9e | ||
|
|
8680d7727b | ||
|
|
d8169138e5 | ||
|
|
6bb2302f81 | ||
|
|
90d904e10d | ||
|
|
9e075fb2da | ||
|
|
222c071925 | ||
|
|
0e3620c776 | ||
|
|
de1ca1d12a | ||
|
|
196f959f1d | ||
|
|
a918d36533 | ||
|
|
e03f2102de | ||
|
|
4a20208d95 | ||
|
|
0e43a5561b | ||
|
|
c9c650664f | ||
|
|
aa1876f94c | ||
|
|
109cd08151 | ||
|
|
9940d635b4 | ||
|
|
dcd4a2f1e3 | ||
|
|
75f15f1be2 | ||
|
|
bbe37cfad8 | ||
|
|
f883757552 | ||
|
|
eb945f26a3 | ||
|
|
a62c8eb5a0 | ||
|
|
f0b7f34928 | ||
|
|
c4fd729b34 | ||
|
|
ee94735922 | ||
|
|
deef0855d5 | ||
|
|
61ee107c27 | ||
|
|
fb79c8786a | ||
|
|
b503ba1144 | ||
|
|
860ae6f38d | ||
|
|
415343bbd0 | ||
|
|
1dd66fdac2 | ||
|
|
d4d20d2a43 | ||
|
|
f7a1c4896b | ||
|
|
cb4a679050 | ||
|
|
6addc3c217 | ||
|
|
d0d2406186 | ||
|
|
2c8876aa2e | ||
|
|
d974311d9b | ||
|
|
802dc94363 | ||
|
|
3fa969eb26 | ||
|
|
c3cccfc66e | ||
|
|
28eca2a11f | ||
|
|
6e5d9f9bb6 | ||
|
|
57d6180a7a | ||
|
|
5f697eac05 | ||
|
|
e97c2c7bf0 | ||
|
|
20ba743f9b | ||
|
|
6921452a7d | ||
|
|
43a58c92ac | ||
|
|
b8ddef1a23 | ||
|
|
fdf25a274f | ||
|
|
0bbfa632f7 | ||
|
|
f98d640e1e | ||
|
|
fcdc1637fc | ||
|
|
cf8e1da383 | ||
|
|
eb55b978aa | ||
|
|
a410dc50bb | ||
|
|
2f69e65dc0 | ||
|
|
5ef24437a3 | ||
|
|
7a6babe878 | ||
|
|
f9245727a6 | ||
|
|
9bfdc1932f | ||
|
|
59a76ed144 | ||
|
|
68897a77dc | ||
|
|
b7c7b93640 | ||
|
|
1442fd637a | ||
|
|
f2ca520a69 | ||
|
|
f3f845dde8 | ||
|
|
a9ca17426b | ||
|
|
3bb8431827 | ||
|
|
fb8330353c | ||
|
|
1ee11e1cfd | ||
|
|
ce98c86fb3 | ||
|
|
95c11415e2 | ||
|
|
5aa3b405fa | ||
|
|
3a1859eb31 | ||
|
|
a38b4c6a83 | ||
|
|
7c16e07f7d | ||
|
|
5d12423b9d | ||
|
|
a3d4a94890 | ||
|
|
eb9b809175 | ||
|
|
17cf8ded07 | ||
|
|
181af6f250 | ||
|
|
2e845a5134 | ||
|
|
255df20da0 | ||
|
|
bc4ea6fd9a | ||
|
|
6ff0cf91e2 | ||
|
|
d4537af3b4 | ||
|
|
e3d2d6b292 | ||
|
|
e041f55254 | ||
|
|
ba9f4fa7b7 | ||
|
|
01bbc089da | ||
|
|
491a352792 | ||
|
|
8d37a0418a | ||
|
|
1048718f0b | ||
|
|
4ad4c6ea22 | ||
|
|
ad09630d4e | ||
|
|
a579125a1f | ||
|
|
ee938c0423 | ||
|
|
5bc95511e5 | ||
|
|
f566022aa4 | ||
|
|
ddc21046b9 | ||
|
|
51206cb108 | ||
|
|
200d49d369 | ||
|
|
55023171af | ||
|
|
decb31ffa4 | ||
|
|
ecb4863c39 | ||
|
|
31c7ada591 | ||
|
|
b4ec609fe0 | ||
|
|
d55c952289 | ||
|
|
afc002d81a | ||
|
|
06644d9c71 | ||
|
|
a4dfdd4fd1 | ||
|
|
e21b3e6bb2 | ||
|
|
777b65b1f7 | ||
|
|
80a13be3e2 | ||
|
|
27340ec8f7 | ||
|
|
84d40bd3e3 | ||
|
|
fe5ea60847 | ||
|
|
4d4c127b99 | ||
|
|
c99a950979 | ||
|
|
a2d7e2cb74 | ||
|
|
1b40c42cab | ||
|
|
2740f8c31e | ||
|
|
7d52a29620 | ||
|
|
93f08eb9c7 | ||
|
|
1cc104e07e | ||
|
|
36b642be09 | ||
|
|
0554d576d5 | ||
|
|
f1488436b8 | ||
|
|
5665c755cb | ||
|
|
061d91ae7c | ||
|
|
a96ece2c11 | ||
|
|
1e7e9d2715 | ||
|
|
783dfc7495 | ||
|
|
c31f2d6a6c | ||
|
|
41bb5d51ab | ||
|
|
f3467dab4a | ||
|
|
4586be46f7 | ||
|
|
1f5d806a65 | ||
|
|
723d9b4eae | ||
|
|
719c5404f3 | ||
|
|
cb4f3ce52c | ||
|
|
2bd971a9b1 | ||
|
|
7a0467c8c5 | ||
|
|
6f5bbaf871 | ||
|
|
6a10257fd7 | ||
|
|
57219df16a | ||
|
|
06fdfd98b0 | ||
|
|
6a7d7d04b1 | ||
|
|
6b99d28768 | ||
|
|
6d90c03225 | ||
|
|
800b8bb6bd | ||
|
|
8ad704ca0a | ||
|
|
dca36b59a2 | ||
|
|
e407eb9a8b | ||
|
|
3085230b13 | ||
|
|
d7c8f5242f | ||
|
|
417bce5a01 | ||
|
|
c0f67eb99b | ||
|
|
7e0bcacf91 | ||
|
|
d85dc181d6 | ||
|
|
7984890cab | ||
|
|
a9d4538d53 | ||
|
|
bda15daa78 | ||
|
|
f521b7949a | ||
|
|
f9f529e53f | ||
|
|
979a2025ef | ||
|
|
b24212d70a | ||
|
|
a56e0b6d4a | ||
|
|
7c9b194bb6 | ||
|
|
28cce312a8 | ||
|
|
1a5fe93500 | ||
|
|
5d24d3de2a | ||
|
|
66da6362c8 | ||
|
|
b0487e4dbc | ||
|
|
2b9bc5d046 | ||
|
|
01928bfe5a | ||
|
|
0b0ceb4c0e | ||
|
|
5c1662a7c1 | ||
|
|
96c79f78cc | ||
|
|
82d553721c | ||
|
|
fe2163a546 | ||
|
|
7b4970a8d9 | ||
|
|
74f5628622 | ||
|
|
1eaada0feb | ||
|
|
d2b1a837e6 | ||
|
|
f34ef01de9 | ||
|
|
567aa89bd2 | ||
|
|
4fdcc144d5 | ||
|
|
dc547c38d1 | ||
|
|
048f7e0566 | ||
|
|
0e33c44831 | ||
|
|
b0657ae5f5 | ||
|
|
f96a6b2286 | ||
|
|
d2d0ef2889 | ||
|
|
c02988c515 | ||
|
|
b5836ab0ff | ||
|
|
698e773e3a | ||
|
|
604146b294 | ||
|
|
e48198353f | ||
|
|
12ec92a0b5 | ||
|
|
25ce99958c | ||
|
|
3140067330 | ||
|
|
b0dea10a38 | ||
|
|
2267dd0fd7 | ||
|
|
57f9c1df69 | ||
|
|
f3f15f83b0 | ||
|
|
aed3e64972 | ||
|
|
e2ee005a5f | ||
|
|
bea876efd8 | ||
|
|
0b72eeaf9d | ||
|
|
81e0d4e382 | ||
|
|
52619ef622 | ||
|
|
6357d2fa8b | ||
|
|
67f5a1326b | ||
|
|
8bd71a4cc1 | ||
|
|
3d4a7512f1 | ||
|
|
2302453b36 | ||
|
|
753cc2e1e2 | ||
|
|
7f8a334e12 | ||
|
|
9513053816 | ||
|
|
4ab2c0d815 | ||
|
|
e1176f1e30 | ||
|
|
069ca6df5e | ||
|
|
6e4a082411 | ||
|
|
992f9b70fe | ||
|
|
55cbf7d4de | ||
|
|
769bab6582 | ||
|
|
6b5a610d01 | ||
|
|
04fb2ae52c | ||
|
|
2778c336bf | ||
|
|
eb83a9fb62 | ||
|
|
f6a70a28cb | ||
|
|
a21892b84f | ||
|
|
246f1dd3ac | ||
|
|
710eb75f3e | ||
|
|
afa5ec360f | ||
|
|
c649c87d16 | ||
|
|
c26317eddf | ||
|
|
510708d0e1 | ||
|
|
19a71c0d92 | ||
|
|
6fe4f00c44 | ||
|
|
2d595da6a6 | ||
|
|
8f075ec1a2 | ||
|
|
1aea465a23 | ||
|
|
b25436e1bf | ||
|
|
f89c37c1fd | ||
|
|
c7b53becf3 | ||
|
|
0e6cfdbb2a | ||
|
|
0d5e829c56 | ||
|
|
e66c99499f | ||
|
|
429e2f9992 | ||
|
|
bcd42ad958 | ||
|
|
24290b66a3 | ||
|
|
d31b4cd2d9 | ||
|
|
3f4c285551 | ||
|
|
cbcf10a02b | ||
|
|
cac82e4330 | ||
|
|
61b2c91ffe | ||
|
|
d461580749 | ||
|
|
b5197fa673 | ||
|
|
13d7378dc5 | ||
|
|
e9ad9b5be2 | ||
|
|
c5b83c04c1 | ||
|
|
2c94254ec3 | ||
|
|
4159aa0929 | ||
|
|
0e5a6a9e9e | ||
|
|
29f65be1e0 | ||
|
|
cbbdf8442d | ||
|
|
a26db7f3c8 | ||
|
|
99d6bd4415 | ||
|
|
9ccffe5342 | ||
|
|
6ec217a5e2 | ||
|
|
160205f139 | ||
|
|
afc30226ac | ||
|
|
e8a661e0ea | ||
|
|
2c1509686d | ||
|
|
95f1772280 | ||
|
|
3a99eb9c9f | ||
|
|
1e52523505 | ||
|
|
592d0d8e4e | ||
|
|
b0367491b9 | ||
|
|
f682de9690 | ||
|
|
5854805bdc | ||
|
|
e03c69ab8f | ||
|
|
1ba0f912f1 | ||
|
|
0fe247070a | ||
|
|
aca2692214 | ||
|
|
a538c14976 | ||
|
|
60495e4765 | ||
|
|
0f5dba14cb | ||
|
|
5c42394279 | ||
|
|
02a841b468 | ||
|
|
e7a58c764d | ||
|
|
c5381d30ed | ||
|
|
b94083e43f | ||
|
|
ef0c729b27 | ||
|
|
8937f18423 | ||
|
|
f2a8a5d910 | ||
|
|
2356ad8fec | ||
|
|
1f80f96735 | ||
|
|
974825bbcf | ||
|
|
6c9725a8c9 | ||
|
|
db9fc3cde1 | ||
|
|
06bcb7adaa | ||
|
|
7d4015e043 | ||
|
|
2c4daae051 | ||
|
|
01f907897a | ||
|
|
9787ab4d51 | ||
|
|
868587c409 | ||
|
|
741a7887bd | ||
|
|
aff4655134 | ||
|
|
9d74a76ca2 | ||
|
|
a8c578ac35 | ||
|
|
015d0fa12d | ||
|
|
cc7475573c | ||
|
|
3c0df2dd64 | ||
|
|
f0f27d1b95 | ||
|
|
5ef594a7d3 | ||
|
|
289eaf5ad2 | ||
|
|
d94848e4e1 | ||
|
|
865bb9063a | ||
|
|
8e3b287c41 | ||
|
|
793a62048b | ||
|
|
834ffc7811 | ||
|
|
594b908c26 | ||
|
|
6df910f2ea | ||
|
|
b0e67bc961 | ||
|
|
86e2744c24 | ||
|
|
e560a0bc9d | ||
|
|
728535a0e9 | ||
|
|
ba0b91f141 | ||
|
|
3e7517e29d | ||
|
|
8b6b065462 | ||
|
|
04577cfdf3 | ||
|
|
9ae03f3056 | ||
|
|
32d9c3d714 | ||
|
|
de98230db3 | ||
|
|
060f11758d | ||
|
|
974fca2171 | ||
|
|
b858b7d341 | ||
|
|
848d3e076e | ||
|
|
59b8d35386 | ||
|
|
70233865d7 | ||
|
|
37effd8324 | ||
|
|
82d289e899 | ||
|
|
732914c71f | ||
|
|
d934401379 | ||
|
|
d8cc8167de | ||
|
|
beb59414c7 | ||
|
|
e796f6d195 | ||
|
|
f2b4ccd043 | ||
|
|
3ed496cef6 | ||
|
|
aa459f0142 | ||
|
|
47a0fe1d03 | ||
|
|
c9c6682299 | ||
|
|
b61034048f | ||
|
|
ebb7d38a6a | ||
|
|
80d73b9910 | ||
|
|
b98411a441 | ||
|
|
2522398233 | ||
|
|
183142a8b4 | ||
|
|
9b9b208169 | ||
|
|
a9dde296bf | ||
|
|
cdddf42847 | ||
|
|
b08dccf7d4 | ||
|
|
9b64215b64 | ||
|
|
19ddf42859 | ||
|
|
83d14b910c | ||
|
|
b5c22e2a8a | ||
|
|
012ee672d3 | ||
|
|
ed22866231 | ||
|
|
d0d28749f1 | ||
|
|
f4b4c6d1ee | ||
|
|
9b5c283892 | ||
|
|
58b0be8211 | ||
|
|
fb1b61eda6 | ||
|
|
19cb92bd88 | ||
|
|
3d45c9610f | ||
|
|
76f6f8caa4 | ||
|
|
9481264283 | ||
|
|
54f3cf9429 | ||
|
|
9a6b4278d3 | ||
|
|
8ade0988eb | ||
|
|
c3505d13bd | ||
|
|
060278f9b8 | ||
|
|
a1c0401cb4 | ||
|
|
f0cc185a47 | ||
|
|
bee9bf2226 | ||
|
|
3b6c1baff3 | ||
|
|
89537700e3 | ||
|
|
59c3cd3956 | ||
|
|
fc9c27d150 | ||
|
|
e33156dcc4 | ||
|
|
15b428893f | ||
|
|
de5589a987 | ||
|
|
5b0da6cb3a | ||
|
|
390830cba5 | ||
|
|
9ed806a86c | ||
|
|
28c348342d | ||
|
|
6877836ad6 | ||
|
|
132a348486 | ||
|
|
3507eed620 | ||
|
|
371a2dc84d | ||
|
|
200cc1d97a | ||
|
|
dda8ff9796 | ||
|
|
0333d4b75b | ||
|
|
1ed7756d6c | ||
|
|
8de6461cf7 | ||
|
|
fe94ab0dde | ||
|
|
0092a73e86 | ||
|
|
0e7c79bd1a | ||
|
|
e3fab53806 | ||
|
|
058aabff68 | ||
|
|
4ff906bd7b | ||
|
|
25b26657da | ||
|
|
c59891d44b | ||
|
|
cb99fc582e | ||
|
|
066593f9c3 | ||
|
|
1e8d9f02f3 | ||
|
|
95e2025ff9 | ||
|
|
ef6f2e8d62 | ||
|
|
1bdc28bf9c | ||
|
|
452901d3b1 | ||
|
|
158f19b67c | ||
|
|
fa928956c2 | ||
|
|
609a8894ec | ||
|
|
adc6a45185 | ||
|
|
a472986d0e | ||
|
|
5be30a2cd8 | ||
|
|
6147bfac82 | ||
|
|
0cf0f20f9d | ||
|
|
e285632d9e | ||
|
|
89e36ab9aa | ||
|
|
ada9478ed7 | ||
|
|
70ca6fdec9 | ||
|
|
ffd704b0cf | ||
|
|
1c3551201a | ||
|
|
c0ddc89f21 | ||
|
|
b5271e5346 | ||
|
|
548172949a | ||
|
|
d9c0825d5f |
No files matched your search
+9
-4
@@ -28,7 +28,7 @@
|
||||
"no-unneeded-ternary": 2,
|
||||
"radix": 2,
|
||||
"semi": [2, "always"],
|
||||
"camelcase": 2,
|
||||
"camelcase": [2, {"properties": "never"}],
|
||||
"comma-spacing": 2,
|
||||
"comma-style": 2,
|
||||
"eol-last": 2,
|
||||
@@ -52,7 +52,6 @@
|
||||
"prefer-const": 2,
|
||||
"prefer-spread": 2,
|
||||
"prefer-template": 2,
|
||||
"no-console": 0,
|
||||
"no-unused-vars" : "warn"
|
||||
},
|
||||
"globals": {
|
||||
@@ -125,7 +124,13 @@
|
||||
"Checklists": true,
|
||||
"Settings": true,
|
||||
"InvitationCodes": true,
|
||||
"Winston":true,
|
||||
"JsonRoutes": true
|
||||
"JsonRoutes": true,
|
||||
"Authentication": true,
|
||||
"Integrations": true,
|
||||
"HTTP": true,
|
||||
"AccountSettings": true,
|
||||
"Announcements": true,
|
||||
"Swimlanes": true,
|
||||
"Npm": true
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
## Issue
|
||||
**Impacted version**: xxxx
|
||||
|
||||
**Server Setup Information**:
|
||||
|
||||
* Operating System:
|
||||
* Deployment Method(tar/sandstorm/snap/docker/etc /http frontend (nginx, httpd, ...)):
|
||||
* Node Version:
|
||||
* MongoDB Version:
|
||||
* ROOT_URL environment variable (Is there a subfolder?):
|
||||
|
||||
**Problem description**:
|
||||
- *be as explicit as you can*
|
||||
- *describe the problem and its symptoms*
|
||||
- *explain how to reproduce*
|
||||
- *attach whatever information that can help understanding the context (screen capture, log files)*
|
||||
+10
-1
@@ -5,4 +5,13 @@
|
||||
tmp/
|
||||
node_modules/
|
||||
.vscode/
|
||||
.build/*
|
||||
.idea/
|
||||
.build/*
|
||||
packages/kadira-flow-router/
|
||||
packages/meteor-useraccounts-core/
|
||||
package-lock.json
|
||||
**/parts/
|
||||
**/stage
|
||||
**/prime
|
||||
**/*.snap
|
||||
snap/.snapcraft/
|
||||
@@ -1,3 +0,0 @@
|
||||
[submodule "packages/kadira:flow-router"]
|
||||
path = packages/kadira:flow-router
|
||||
url = https://github.com/wekan/flow-router.git
|
||||
@@ -15,3 +15,4 @@ notices-for-facebook-graph-api-2
|
||||
1.4.0-remove-old-dev-bundle-link
|
||||
1.4.1-add-shell-server-package
|
||||
1.4.3-split-account-service-packages
|
||||
1.5-add-dynamic-import-package
|
||||
+21
-16
@@ -3,13 +3,13 @@
|
||||
# 'meteor add' and 'meteor remove' will edit this file for you,
|
||||
# but you can also edit it by hand.
|
||||
|
||||
meteor-base@1.0.4
|
||||
meteor-base@1.2.0
|
||||
|
||||
# Build system
|
||||
ecmascript@0.7.2
|
||||
stylus@2.513.9
|
||||
standard-minifier-css@1.3.4
|
||||
standard-minifier-js@2.0.0
|
||||
ecmascript@0.9.0
|
||||
stylus@2.513.13
|
||||
standard-minifier-css@1.3.5
|
||||
standard-minifier-js@2.2.0
|
||||
mquandalle:jade
|
||||
|
||||
# Polyfills
|
||||
@@ -17,32 +17,28 @@ es5-shim@4.6.15
|
||||
|
||||
# Collections
|
||||
aldeed:collection2
|
||||
cfs:gridfs
|
||||
cfs:standard-packages
|
||||
cottz:publish-relations
|
||||
dburles:collection-helpers
|
||||
idmontie:migrations
|
||||
matb33:collection-hooks
|
||||
matteodem:easy-search
|
||||
mongo@1.1.16
|
||||
mongo@1.3.1
|
||||
mquandalle:collection-mutations
|
||||
|
||||
# Account system
|
||||
accounts-password@1.3.5
|
||||
kenton:accounts-sandstorm
|
||||
service-configuration@1.0.11
|
||||
useraccounts:core
|
||||
useraccounts:unstyled
|
||||
useraccounts:flow-routing
|
||||
email@1.2.0
|
||||
|
||||
# Utilities
|
||||
check@1.2.5
|
||||
jquery@1.11.10
|
||||
random@1.0.10
|
||||
reactive-dict@1.1.8
|
||||
reactive-dict@1.2.0
|
||||
session@1.1.7
|
||||
tracker@1.1.2
|
||||
tracker@1.1.3
|
||||
underscore@1.0.10
|
||||
3stack:presence
|
||||
alethes:pages
|
||||
@@ -50,7 +46,6 @@ arillo:flow-router-helpers
|
||||
audit-argument-checks@1.0.7
|
||||
kadira:blaze-layout
|
||||
kadira:dochead
|
||||
meteorhacks:fast-render
|
||||
meteorhacks:picker
|
||||
meteorhacks:subs-manager
|
||||
mquandalle:autofocus
|
||||
@@ -58,6 +53,7 @@ mquandalle:moment
|
||||
ongoworks:speakingurl
|
||||
raix:handlebar-helpers
|
||||
tap:i18n
|
||||
http@1.3.0
|
||||
|
||||
# UI components
|
||||
blaze
|
||||
@@ -70,10 +66,19 @@ mquandalle:mousetrap-bindglobal
|
||||
mquandalle:perfect-scrollbar
|
||||
peerlibrary:blaze-components@=0.15.1
|
||||
perak:markdown
|
||||
seriousm:emoji-continued
|
||||
templates:tabs
|
||||
verron:autosize
|
||||
simple:json-routes
|
||||
rajit:bootstrap3-datepicker
|
||||
kadira:flow-router
|
||||
shell-server@0.2.3
|
||||
shell-server@0.3.0
|
||||
simple:rest-accounts-password
|
||||
useraccounts:core
|
||||
email@1.2.3
|
||||
horka:swipebox
|
||||
dynamic-import@0.2.0
|
||||
staringatlights:fast-render
|
||||
staringatlights:flow-router
|
||||
|
||||
mixmax:smart-disconnect
|
||||
accounts-password@1.5.0
|
||||
cfs:gridfs
|
||||
+1
-1
@@ -1 +1 @@
|
||||
METEOR@1.4.4.1
|
||||
METEOR@1.6.0.1
|
||||
+58
-47
@@ -1,23 +1,23 @@
|
||||
3stack:presence@1.0.5
|
||||
accounts-base@1.2.16
|
||||
accounts-password@1.3.5
|
||||
3stack:presence@1.1.2
|
||||
accounts-base@1.4.0
|
||||
accounts-password@1.5.0
|
||||
aldeed:collection2@2.10.0
|
||||
aldeed:collection2-core@1.2.0
|
||||
aldeed:schema-deny@1.1.0
|
||||
aldeed:schema-index@1.1.1
|
||||
aldeed:simple-schema@1.5.3
|
||||
alethes:pages@1.8.6
|
||||
allow-deny@1.0.5
|
||||
allow-deny@1.1.0
|
||||
arillo:flow-router-helpers@0.5.2
|
||||
audit-argument-checks@1.0.7
|
||||
autoupdate@1.3.12
|
||||
babel-compiler@6.18.2
|
||||
babel-runtime@1.0.1
|
||||
babel-compiler@6.24.7
|
||||
babel-runtime@1.1.1
|
||||
base64@1.0.10
|
||||
binary-heap@1.0.10
|
||||
blaze@2.3.2
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.0.11
|
||||
boilerplate-generator@1.3.1
|
||||
caching-compiler@1.1.9
|
||||
caching-html-compiler@1.1.2
|
||||
callback-hook@1.0.10
|
||||
@@ -27,7 +27,7 @@ cfs:collection@0.5.5
|
||||
cfs:collection-filters@0.2.4
|
||||
cfs:data-man@0.0.6
|
||||
cfs:file@0.1.17
|
||||
cfs:gridfs@0.0.33
|
||||
cfs:gridfs@0.0.34
|
||||
cfs:http-methods@0.0.32
|
||||
cfs:http-publish@0.0.13
|
||||
cfs:power-queue@0.9.11
|
||||
@@ -40,61 +40,66 @@ cfs:upload-http@0.0.20
|
||||
cfs:worker@0.1.4
|
||||
check@1.2.5
|
||||
chuangbo:cookie@1.1.0
|
||||
coffeescript@1.12.3_1
|
||||
cottz:publish-relations@2.0.7
|
||||
coffeescript@1.12.7_3
|
||||
coffeescript-compiler@1.12.7_3
|
||||
cottz:publish-relations@2.0.8
|
||||
dburles:collection-helpers@1.1.0
|
||||
ddp@1.2.5
|
||||
ddp-client@1.3.4
|
||||
ddp-common@1.2.8
|
||||
ddp@1.4.0
|
||||
ddp-client@2.2.0
|
||||
ddp-common@1.3.0
|
||||
ddp-rate-limiter@1.0.7
|
||||
ddp-server@1.3.14
|
||||
ddp-server@2.1.1
|
||||
deps@1.0.12
|
||||
diff-sequence@1.0.7
|
||||
ecmascript@0.7.3
|
||||
ecmascript-runtime@0.3.15
|
||||
ejson@1.0.13
|
||||
email@1.2.1
|
||||
dynamic-import@0.2.1
|
||||
ecmascript@0.9.0
|
||||
ecmascript-runtime@0.5.0
|
||||
ecmascript-runtime-client@0.5.0
|
||||
ecmascript-runtime-server@0.5.0
|
||||
ejson@1.1.0
|
||||
email@1.2.3
|
||||
es5-shim@4.6.15
|
||||
fastclick@1.0.13
|
||||
fortawesome:fontawesome@4.7.0
|
||||
geojson-utils@1.0.10
|
||||
horka:swipebox@1.0.2
|
||||
hot-code-push@1.0.4
|
||||
html-tools@1.0.11
|
||||
htmljs@1.0.11
|
||||
http@1.2.12
|
||||
http@1.3.0
|
||||
id-map@1.0.9
|
||||
idmontie:migrations@1.0.3
|
||||
jquery@1.11.10
|
||||
kadira:blaze-layout@2.3.0
|
||||
kadira:dochead@1.5.0
|
||||
kadira:flow-router@2.12.1
|
||||
kenton:accounts-sandstorm@0.6.0
|
||||
kenton:accounts-sandstorm@0.7.0
|
||||
launch-screen@1.1.1
|
||||
livedata@1.0.18
|
||||
localstorage@1.0.12
|
||||
logging@1.1.17
|
||||
localstorage@1.2.0
|
||||
logging@1.1.19
|
||||
matb33:collection-hooks@0.8.4
|
||||
matteodem:easy-search@1.6.4
|
||||
mdg:validation-error@0.5.1
|
||||
meteor@1.6.1
|
||||
meteor-base@1.0.4
|
||||
meteor@1.8.2
|
||||
meteor-base@1.2.0
|
||||
meteor-platform@1.2.6
|
||||
meteorhacks:aggregate@1.3.0
|
||||
meteorhacks:collection-utils@1.2.0
|
||||
meteorhacks:fast-render@2.16.0
|
||||
meteorhacks:inject-data@2.0.0
|
||||
meteorhacks:meteorx@1.4.1
|
||||
meteorhacks:picker@1.0.3
|
||||
meteorhacks:subs-manager@1.6.4
|
||||
meteorspark:util@0.2.0
|
||||
minifier-css@1.2.16
|
||||
minifier-js@2.0.0
|
||||
minifier-js@2.2.2
|
||||
minifiers@1.1.8-faster-rebuild.0
|
||||
minimongo@1.0.21
|
||||
minimongo@1.4.3
|
||||
mixmax:smart-disconnect@0.0.4
|
||||
mobile-status-bar@1.0.14
|
||||
modules@0.8.2
|
||||
modules-runtime@0.7.10
|
||||
mongo@1.1.16
|
||||
modules@0.11.0
|
||||
modules-runtime@0.9.1
|
||||
mongo@1.3.1
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.6
|
||||
mongo-livedata@1.0.12
|
||||
mousetrap:mousetrap@1.4.6_1
|
||||
@@ -107,48 +112,54 @@ 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
|
||||
npm-bcrypt@0.9.2
|
||||
npm-mongo@2.2.24
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@2.2.33
|
||||
observe-sequence@1.0.16
|
||||
ongoworks:speakingurl@1.1.0
|
||||
ordered-dict@1.0.9
|
||||
peerlibrary:assert@0.2.5
|
||||
peerlibrary:base-component@0.16.0
|
||||
peerlibrary:blaze-components@0.15.1
|
||||
peerlibrary:computed-field@0.6.1
|
||||
peerlibrary:computed-field@0.7.0
|
||||
peerlibrary:reactive-field@0.3.0
|
||||
perak:markdown@1.0.5
|
||||
promise@0.8.8
|
||||
promise@0.10.0
|
||||
raix:eventemitter@0.1.3
|
||||
raix:handlebar-helpers@0.2.5
|
||||
rajit:bootstrap3-datepicker@1.6.4
|
||||
rajit:bootstrap3-datepicker@1.7.1
|
||||
random@1.0.10
|
||||
rate-limit@1.0.8
|
||||
reactive-dict@1.1.8
|
||||
reactive-dict@1.2.0
|
||||
reactive-var@1.0.11
|
||||
reload@1.1.11
|
||||
retry@1.0.9
|
||||
routepolicy@1.0.12
|
||||
seriousm:emoji-continued@1.4.0
|
||||
service-configuration@1.0.11
|
||||
session@1.1.7
|
||||
sha@1.0.9
|
||||
shell-server@0.2.3
|
||||
shell-server@0.3.1
|
||||
simple:authenticate-user-by-token@1.0.1
|
||||
simple:json-routes@2.1.0
|
||||
softwarerero:accounts-t9n@1.3.9
|
||||
simple:rest-accounts-password@1.1.2
|
||||
simple:rest-bearer-token-parser@1.0.1
|
||||
simple:rest-json-error-handler@1.0.1
|
||||
softwarerero:accounts-t9n@1.3.11
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.2
|
||||
spacebars-compiler@1.1.3
|
||||
srp@1.0.10
|
||||
standard-minifier-css@1.3.4
|
||||
standard-minifier-js@2.0.0
|
||||
stylus@2.513.9
|
||||
standard-minifier-css@1.3.5
|
||||
standard-minifier-js@2.2.3
|
||||
staringatlights:fast-render@2.16.5
|
||||
staringatlights:flow-router@2.12.2
|
||||
staringatlights:inject-data@2.0.5
|
||||
stylus@2.513.13
|
||||
tap:i18n@1.8.2
|
||||
templates:tabs@2.3.0
|
||||
templating@1.3.2
|
||||
templating-compiler@1.3.2
|
||||
templating-compiler@1.3.3
|
||||
templating-runtime@1.3.2
|
||||
templating-tools@1.1.2
|
||||
tracker@1.1.2
|
||||
tracker@1.1.3
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.1.0
|
||||
@@ -156,6 +167,6 @@ useraccounts:core@1.14.2
|
||||
useraccounts:flow-routing@1.14.2
|
||||
useraccounts:unstyled@1.14.2
|
||||
verron:autosize@3.0.8
|
||||
webapp@1.3.15
|
||||
webapp@1.4.0
|
||||
webapp-hashing@1.0.9
|
||||
zimme:active-route@2.3.2
|
||||
+3
-3
@@ -2,9 +2,9 @@ dist: trusty
|
||||
sudo: required
|
||||
|
||||
env:
|
||||
TRAVIS_DOCKER_COMPOSE_VERSION: 1.12.0
|
||||
TRAVIS_NODE_VERSION: 4.8.1
|
||||
TRAVIS_NPM_VERSION: 4.4.4
|
||||
TRAVIS_DOCKER_COMPOSE_VERSION: 1.17.0
|
||||
TRAVIS_NODE_VERSION: 8.9.3
|
||||
TRAVIS_NPM_VERSION: 5.5.1
|
||||
|
||||
before_install:
|
||||
- sudo apt-get update -y
|
||||
|
||||
+1
-1
@@ -39,7 +39,7 @@ host = https://www.transifex.com
|
||||
# tap:i18n requires us to use `-` separator in the language identifiers whereas
|
||||
# Transifex uses a `_` separator, without an option to customize it on one side
|
||||
# or the other, so we need to do a Manual mapping.
|
||||
lang_map = es_ES:es-ES, fa_IR:fa, fi_FI:fi, hu_HU:hu, pt_BR:pt-BR, ro_RO:ro, zh_CN:zh-CN, zh_TW:zh-TW
|
||||
lang_map = bg_BG:bg, en_GB:en-GB, es_AR:es-AR, el_GR:el, fi_FI:fi, hu_HU:hu, id_ID:id, mn_MN:mn, no:nb, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, zh_CN:zh-CN, zh_TW:zh-TW
|
||||
|
||||
[wekan.application]
|
||||
file_filter = i18n/<lang>.i18n.json
|
||||
|
||||
+722
-5
@@ -1,3 +1,720 @@
|
||||
# v0.78 2018-03-17 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Allow swimlanes reordering](https://github.com/wekan/wekan/commit/37c94622e476f50bf2387bc8b140454d66200e78);
|
||||
- [Import missing card fields: isOvertime, startAt and spentTime](https://github.com/wekan/wekan/commit/b475127c53031fa498da139a7d16f3e54d43b90d);
|
||||
- [Lists view is the default view when creating boards](https://github.com/wekan/wekan/commit/1ca9e96f35389c0eec2290e8e1207801ee25f907);
|
||||
- [Enabled import at Sandtorm. Keep there big DANGER warning about data loss bug.](https://github.com/wekan/wekan/commit/22923d08af4f1a63ded1d92fe6918436b598592b);
|
||||
- [Add language: Armenian](https://github.com/wekan/wekan/commit/75693d16e2a0f3d201c1036ab06e6d40eb1c0adc).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix lint errors related to sandstorm](https://github.com/wekan/wekan/commit/0a16147470246c8f49bb918f5ddc7bb2e54fba14);
|
||||
- [Add Swimlanes to globals](https://github.com/wekan/wekan/commit/373e9782dcf87a9c1169b5d1f8175ce14e4898c9);
|
||||
- [Fix lint errors related to trello creator](https://github.com/wekan/wekan/commit/951a0db380d60f3d948ae38d50b85a54983a51de);
|
||||
- [Fix lint errors related to language names](https://github.com/wekan/wekan/commit/c0d33d97f2c8d4e9371a03d4ad3022df3ed64d3d);
|
||||
- [Avoid swimlane title overlap](https://github.com/wekan/wekan/commit/c4fa9010f34966b633c7bf7e46ad49fc101127c9);
|
||||
- [Fix scrollbar inside list and outer scroll](https://github.com/wekan/wekan/commit/a033c35a3411902b9bf8f62a40cd68f641e573d3);
|
||||
- [Remove list max-height 350px](https://github.com/wekan/wekan/commit/b6d3e79548d1e88c93fa2965a936595176a95565);
|
||||
- [Snap: Adding network hooks for configure hook to fix security denials](https://github.com/wekan/wekan/commit/9084158aece8a642dc49bf7ecc2196bf9d1af63e);
|
||||
- [Snap: Fixing problem when mongodb was not started at install/refresh](https://github.com/wekan/wekan/commit/1be8e5625fd20797910009a8221ca706fd52ab11);
|
||||
- [Fix Add Card Button dissapearing when dragging](https://github.com/wekan/wekan/commit/58e5e9b308113e5a8af5166328a68a0aafcc2558);
|
||||
- [Fix Scrollbar near top of screen when using internet explorer on Win7](https://github.com/wekan/wekan/commit/128a356b9222fa0ed824b477c2d0e1e6a0368021);
|
||||
- [Fix scroll when dragging elements. Remove scrollbars from swimlanes.](https://github.com/wekan/wekan/commit/ed8471be9b79243b016a275e5b11a6912717fbb9);
|
||||
- [Partial fix for scroll bar inside cardDetails](https://github.com/wekan/wekan/commit/ac7d44f8a8d809cd94ed5ef3640473f34c72403b);
|
||||
- [Fix swimlane header rotation on Google Chrome. After this change both Firefox 58 and Google Chrome 64
|
||||
have properly rotated swimlane header.](https://github.com/wekan/wekan/commit/9a1b1a5bedbe44827de109731a3c3b1a07790d3e);
|
||||
- [Fix card copy and move with swimlanes](https://github.com/wekan/wekan/commit/4b53b0c90a57593c0fe2d808d2298e85f488bfa9).
|
||||
- [Fix scroll board when opening cardDetails](https://github.com/wekan/wekan/commit/454523dd4744b2bccb6805dad59abd664fdacb31);
|
||||
- [Fix swimlane info not displayed in activities](https://github.com/wekan/wekan/commit/bb37d8fa964c0d03721a664387e74300fde09eef);
|
||||
- [Fix sandstorm default swimlane creation](https://github.com/wekan/wekan/commit/f470323ee746c4e79f07d166d511867408194eb6);
|
||||
- [Extend lists to bottom of frame in lists view](https://github.com/wekan/wekan/commit/c62a2ee11febf7f98456c97dc3973509b4bfe119);
|
||||
- [Fix drag and drop issues when re-enter board](https://github.com/wekan/wekan/commit/5b0f7f8aef115b202aaff6bc25bb514426dc2009).
|
||||
|
||||
Thanks to GitHub users andresmanelli, GhassenRjab, kubiko, lumatijev, lunatic4ever and xet7 for their contributions.
|
||||
|
||||
# v0.77 2018-02-23 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Search from card titles and descriptions on this board](https://github.com/wekan/wekan/pull/1503).
|
||||
- Add Bulgarian language.
|
||||
|
||||
and adds the following [Snap updates](https://github.com/wekan/wekan/pull/1495):
|
||||
|
||||
- Cleanup of snap helper scripts
|
||||
- Cleanup and snapctl settings handling
|
||||
- Fix for snap store auto review refusal
|
||||
- Adding support for automatic restart of services when setting(s) are changed.
|
||||
No need to call systemctl restart anymore
|
||||
- Fixing snap set functionality
|
||||
- Adding optional caddy service support (by default caddy service is disabled),
|
||||
it can be enabled by calling: snap set wekan caddy-enabled=true
|
||||
- [Service life cycle improvements](https://github.com/wekan/wekan/pull/1495)
|
||||
- [Wekan help text changes and tweaks](https://github.com/wekan/wekan/pull/1495).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix: card-shadow no longer covered the page if you scroll down](https://github.com/wekan/wekan/pull/1496).
|
||||
|
||||
Thanks to GitHub users GhassenRjab, kubiko and stefano-pogliani for their contributions.
|
||||
|
||||
# v0.76 2018-02-21 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add swimlaneId to POST /api/boards/:boardId/lists/:listId/cards route](https://github.com/wekan/wekan/commit/ee0f42eeb1b10107bd8fc38cdefbdbc4f3fde108);
|
||||
- [Added path to capnp.js to make Wekan work on Sandstorm](https://github.com/wekan/wekan/commit/11e9811f82858a3d98036e142b0da69d867adebc).
|
||||
|
||||
Known bugs:
|
||||
|
||||
- [Disabled Import temporarily on Sandstorm because of data loss bug](https://github.com/wekan/wekan/commit/e30f6515c623de7a48f25e0b2fc75313ae5d187c);
|
||||
- [Swimlane not visible at Sandstorm](https://github.com/wekan/wekan/issues/1494).
|
||||
|
||||
Thanks to GitHub users couscous3 and xet7 for their contributions.
|
||||
|
||||
# v0.75 2018-02-16 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Checklist templates](https://github.com/wekan/wekan/pull/1470);
|
||||
- Added [Finnish language changelog](https://github.com/wekan/wekan/tree/devel/meta/t9n-changelog)
|
||||
and [more Finnish traslations](https://github.com/wekan/wekan/blob/devel/sandstorm-pkgdef.capnp)
|
||||
to Sandstorm.
|
||||
|
||||
Thanks to GitHub users erikturk and xet7 for their contributions.
|
||||
|
||||
# v0.74 2018-02-13 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Remove Emoji support, so MAC addresses etc show correctly](https://github.com/wekan/wekan/commit/056843d66c361594d5d4478cfe86e2e405333b91).
|
||||
NOTE: You can still add Unicode Emojis, this only removes broken autoconversion to Emojis.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.73 2018-02-08 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Ubuntu snap build](https://github.com/wekan/wekan/pull/1469).
|
||||
|
||||
Thanks to GitHub user kubiko for contributions.
|
||||
|
||||
# v0.72 2018-02-07 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix card sorting](https://github.com/wekan/wekan/pull/1465);
|
||||
- [Fix import Trello board without swimlanes](https://github.com/wekan/wekan/commit/5871a478e1280818f12fcb7250b7cbccf6907cf0);
|
||||
- [Fix swimlane move parameters](https://github.com/wekan/wekan/commit/fcebb2a5373d6dea41b98b530c176cbee31bee4b).
|
||||
|
||||
Thanks to GitHub users andresmanelli and ViViDboarder for their contributions.
|
||||
|
||||
# v0.71 2018-02-03 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Welcome board is not editable: Added default swimlane to Welcome board](https://github.com/wekan/wekan/commit/9df3e3d26bffb2268cdcc7fa768eda60e4f0975c);
|
||||
- [Fix Import Wekan board with swimlanes](https://github.com/wekan/wekan/commit/ec0a8449ba98aea708e484d386e5a209e2be8fff).
|
||||
|
||||
Thanks to GitHub user andresmanelli for contributions.
|
||||
|
||||
# v0.70 2018-02-02 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add ability to edit swimlane name](https://github.com/wekan/wekan/commit/3414cb84ad8ac800e23bbda6ce12822f40d1bd19);
|
||||
- [Add swimlane popup menu and archive icon](https://github.com/wekan/wekan/commit/5953fb8a44a3582ed0d8816ffb32a5b7f41f50a3).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Two empty columns in swimlane view](https://github.com/wekan/wekan/issues/1459).
|
||||
|
||||
Thanks to GitHub user andresmanelli for contributions.
|
||||
|
||||
# v0.69 2018-02-01 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix swimlanes card details bug](https://github.com/wekan/wekan/commit/f6fb05d3f49c656e9890351f5d7c0827bf2605c1);
|
||||
- [Workaround to avoid swimlanes drag bug](https://github.com/wekan/wekan/commit/d3c110cd8f3ad16a4ced5520c27ab542cc79b548);
|
||||
- [Fix swimlanes details view in lists only mode](https://github.com/wekan/wekan/commit/ff9ca755f338e3c45a1bd726dfbce1c607f2ff4c).
|
||||
- [Fix typo in issue template](https://github.com/wekan/wekan/pull/1451).
|
||||
|
||||
Thanks to GitHub users andresmanelli and d-Rickyy-b for their contributions.
|
||||
|
||||
# v0.68 2018-01-30 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Partial fix: Trello board import fails because of missing "Swimlane id"](https://github.com/wekan/wekan/issues/1442), still needs some work.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.67 2018-01-28 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Fix Igbo language name at menu](https://github.com/wekan/wekan/commit/9d7ff75d3fed1285273245fbe6f6a757b6180039).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.66 2018-01-28 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Fix Dockerfile for Debian](https://github.com/wekan/wekan/pull/1439).
|
||||
|
||||
Thanks to GitHub user soohwa for contributions.
|
||||
|
||||
# v0.65 2018-01-28 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Swimlanes, part 1](https://github.com/wekan/wekan/issues/955);
|
||||
* Added new language: Igbo.
|
||||
|
||||
Thanks to GitHub user andresmanelli for contributions.
|
||||
|
||||
# v0.64 2018-01-22 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Different icons for start and due date](https://github.com/wekan/wekan/pull/1420).
|
||||
* Added new languages: Mongolian and Portuguese;
|
||||
* Upgraded to Meteor 1.6.0.1, Node 8.9.3, NPM 5.5.1 and fibers 2.0.0.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix for dragging into scrolled-down list](https://github.com/wekan/wekan/pull/1424).
|
||||
* [Fix double slash bug on snap](https://github.com/wekan/wekan/issues/962#issuecomment-357785748).
|
||||
|
||||
Thanks to GitHub users dpoznyak, mmarschall and xet7 for their contributions.
|
||||
|
||||
# v0.63 2017-12-20 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Auto update card cover with new image uploaded via drag&drop](https://github.com/wekan/wekan/pull/1401);
|
||||
* Update to Node 4.8.7.
|
||||
|
||||
Thanks to GitHub users thuanpq and xet7 for their contributions.
|
||||
|
||||
# v0.62 2017-12-12 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* Added missing packages to build script.
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.61 2017-12-12 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Change password of any user in Standalone Wekan Admin Panel](https://github.com/wekan/wekan/pull/1372);
|
||||
* [Performance optimization: Move more global subscriptions to template subscription](https://github.com/wekan/wekan/pull/1373);
|
||||
* [Auto update card cover with latest uploaded image attachment](https://github.com/wekan/wekan/pull/1387);
|
||||
* [Always display attachment section for uploading file quickly](https://github.com/wekan/wekan/pull/1391);
|
||||
* [Make it easier to see the Add Card button at top of list](https://github.com/wekan/wekan/pull/1392);
|
||||
* [Add mixmax:smart-disconnect to lower CPU usage when browser tab is not selected](https://github.com/wekan/wekan-mongodb/issues/2);
|
||||
* Update tranlations. Add Latvian language;
|
||||
* Update to Node 4.8.6 and MongoDB 3.2.18.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Bug on not being able to see Admin Panel if not having access to Board List](https://github.com/wekan/wekan/pull/1371);
|
||||
* [Bug on not able to see member avatar on sidebar activity](https://github.com/wekan/wekan/pull/1380);
|
||||
* [Don't open swipebox on update card cover / download file / delete file](https://github.com/wekan/wekan/pull/1386);
|
||||
* [Boards subscription should be placed at header for all other component can be used](https://github.com/wekan/wekan/pull/1381);
|
||||
* [Bug on long url of attachment in card activity log](https://github.com/wekan/wekan/pull/1388).
|
||||
|
||||
Thanks to GitHub users mfshiu, thuanpq and xet7 for their contributions.
|
||||
Thanks to translators for their translations.
|
||||
|
||||
# v0.60 2017-11-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add SMTP test email button to Standalone Wekan Admin Panel](https://github.com/wekan/wekan/pull/1359);
|
||||
* [Optimize for mobile web, show single list per page with navigate bar](https://github.com/wekan/wekan/pull/1365).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [User with comment only permissions can remove another user from a card](https://github.com/wekan/wekan/pull/1352);
|
||||
* [Frequent Subscriptions problem that make Excessive CPU usage](https://github.com/wekan/wekan/pull/1363).
|
||||
|
||||
Thanks to GitHub users floatinghotpot, mfshiu and nztqa for their contributions.
|
||||
|
||||
# v0.59 2017-11-23 Wekan release.
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Remove incomplete logger fix](https://github.com/wekan/wekan/pull/1352).
|
||||
|
||||
Thanks to GitHub user pierreozoux for contributions.
|
||||
|
||||
# v0.58 2017-11-23 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* Updated translations.
|
||||
|
||||
Thanks to all translators.
|
||||
|
||||
# v0.57 2017-11-23 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Gogs Integration](https://github.com/wekan/wekan-gogs) as separate project. Please test and submit issues and pull requests to that project.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix Winston logger](https://github.com/wekan/wekan/pull/1350).
|
||||
|
||||
Thanks to GitHub users andresmanelli and pierreozoux for their contributions.
|
||||
|
||||
# v0.56 2017-11-21 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Copy/Move cards to other board in Standalone Wekan](https://github.com/wekan/wekan/pull/1330);
|
||||
* [Spent time/Overtime on card](https://github.com/wekan/wekan/pull/1344);
|
||||
* New translation: Greek.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Board list with long-description boards not visible](https://github.com/wekan/wekan/pull/1346);
|
||||
* [Remove erroneous minicard title whitespace](https://github.com/wekan/wekan/pull/1347);
|
||||
* [Fix title editing with shift key at card details](https://github.com/wekan/wekan/pull/1348).
|
||||
|
||||
Thanks to GitHub users couscous3, GhassenRjab, thuanpq and xet7 for their contributions.
|
||||
|
||||
# v0.55 2017-11-19 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Markdown in card/minicard/checlist titles and checklist items. Next line: Shift+Enter. Submit: Enter.](https://github.com/wekan/wekan/pull/1334);
|
||||
* [User Admin to Admin Panel: List users. Change: is user admin, name, fullname, email address, is user active. Not changing password yet.](https://github.com/wekan/wekan/pull/1325);
|
||||
* [REST API better error output](https://github.com/wekan/wekan/pull/1323).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Emoji detection breaks MAC addresses](https://github.com/wekan/wekan/issues/1248); - this has not yet fixed all cases.
|
||||
* [Codeblocks should not be scanned for emoji](https://github.com/wekan/wekan/issues/643);
|
||||
* [Whitespace trimming breaks Markdown code block indentation](https://github.com/wekan/wekan/issues/1288):
|
||||
* [Helper to list boards for user](https://github.com/wekan/wekan/pull/1327);
|
||||
* [Error after sending invitation and joining board: Exception while invoking method 'login' TypeError: Cannot read property 'loginDisabled' of undefined](https://github.com/wekan/wekan/issues/1331);
|
||||
* [Invitation /sign-up page did not show input for invitation code](https://github.com/wekan/wekan/commit/99be745f0299b32a8a7b30204b43bff7fd5ba638).
|
||||
|
||||
Thanks to Github users brooksbecton, milesibastos, nztqa, soohwa, thuanpq and xet7 for their contributions.
|
||||
|
||||
# v0.54 2017-11-02 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Soft WIP Limit](https://github.com/wekan/wekan/pull/1319).
|
||||
|
||||
Thanks to GitHub users amadilsons and xet7 for their contributions.
|
||||
|
||||
# v0.53 2017-11-02 Wekan release
|
||||
|
||||
(This was canceled, it had some missing version numbers).
|
||||
|
||||
# v0.52 2017-10-31 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Permit editing WIP limit](https://github.com/wekan/wekan/pull/1312);
|
||||
* [Image attachment resize on smaller screens and swipebox](https://github.com/wekan/wekan/pull/1315);
|
||||
* [Add iPhone favicon for Wekan](https://github.com/wekan/wekan/issues/1317).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Members do not get included on board import from Wekan](https://github.com/wekan/wekan/pull/1316).
|
||||
|
||||
Thanks to GitHub users brooksbecton, guillaumebriday, nztqa, ocdtrekkie and Tentoe for their contributions.
|
||||
|
||||
# v0.51 2017-10-25 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [REST API: Disable and enable user login. Take ownership boards of a user. List boards of user.](https://github.com/wekan/wekan/pull/1296);
|
||||
* [Add translation: Spanish of Argentina](https://github.com/wekan/wekan/commit/b105f0e2e72c49a2f1ba3f6c87532a5418192386);
|
||||
* [Add more languages to Roboto font](https://github.com/wekan/wekan/issues/1299).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Segfault on Alpine Linux](https://github.com/wekan/wekan/issues/1303);
|
||||
* [Change invitation link from sign-in to sign-up](https://github.com/wekan/wekan/issues/1300);
|
||||
* [User with comment only permission can add cards](https://github.com/wekan/wekan/issues/1301).
|
||||
|
||||
Thanks to GitHub users chromas-cro, soohwa, wenerme and xet7 for their contributions.
|
||||
|
||||
# v0.50 2017-10-10 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Fix and update translations](https://github.com/wekan/wekan/issues/1286).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.49 2017-10-09 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [When WIP limit in use, hide also add card + button at top of list](https://github.com/wekan/wekan/commit/a5daf5dc29278b82e133fbe4db09a91ffc0c0d3b).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.48 2017-10-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [WIP Limits](https://github.com/wekan/wekan/pull/1278);
|
||||
* [REST API: Create user despite disabling registration](https://github.com/wekan/wekan/issues/1232);
|
||||
* [User can leave board on Standalone Wekan](https://github.com/wekan/wekan/pull/1283).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Admin announcement can be viewed without signing in](https://github.com/wekan/wekan/issues/1281).
|
||||
|
||||
Thanks to GitHub users amadilsons, nztqa and soohwa for their contributions.
|
||||
|
||||
# v0.47 2017-10-04 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Use theme color for Slider for Comments only](https://github.com/wekan/wekan/pull/1275).
|
||||
|
||||
Thanks to GitHub user nztqa for contributions.
|
||||
|
||||
# v0.46 2017-10-03 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Webhook parameters and response order](https://github.com/wekan/wekan/pull/1263).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* SECURITY FIX: [Meteor allow/deny](https://blog.meteor.com/meteor-allow-deny-vulnerability-disclosure-baf398f47b25) fixed
|
||||
[here](https://github.com/wekan/wekan/commit/c3804dc0fad0817285460d86dc1b3bdc96361f49);
|
||||
* [Fix: Slider for Comments only does not work correctly with over 21 activities](https://github.com/wekan/wekan/pull/1247).
|
||||
|
||||
Thanks to GitHub users andresmanelli and nztqa for their contributions.
|
||||
|
||||
# v0.45 2017-10-01 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Slider for Comments only in activity feed](https://github.com/wekan/wekan/issues/1247);
|
||||
* [Site Wide Announcement](https://github.com/wekan/wekan/pull/1260).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Data inconsistency when copying card](https://github.com/wekan/wekan/pull/1246). Note: There is no feature for copying card attachment yet;
|
||||
* [Hide create label from normal users, because only board admin can create labels](https://github.com/wekan/wekan/pull/1261).
|
||||
|
||||
Thanks to GitHub user nztqa for contributions.
|
||||
|
||||
# v0.44 2017-09-30 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Confirm popup appears before Checklist Delete](https://github.com/wekan/wekan/pull/1257).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix errors when importing from Trello](https://github.com/wekan/wekan/pull/1259).
|
||||
|
||||
Thanks to GitHub users amadilsons and GhassenRjab for their contributions.
|
||||
|
||||
# v0.43 2017-09-25 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Add emojis back, because removing them broke local dev Sandstorm](https://github.com/wekan/wekan/issues/1248).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.42 2017-09-25 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Remove emoji support, because it breaks MAC addresses, urls, code etc](https://github.com/wekan/wekan/issues/1248).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.41 2017-09-25 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Can't create user and login after install. Reverting REST API: Create user despite disabling registration](https://github.com/wekan/wekan/issues/1249).
|
||||
|
||||
Thanks to GitHub user xet7 for contributions.
|
||||
|
||||
# v0.40 2017-09-25 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add translations (en/de/fi) for email notifications regarding checklists and checklist
|
||||
items](https://github.com/wekan/wekan/pull/1238);
|
||||
* [Added plus button to add card on top of the list](https://github.com/wekan/wekan/pull/1244);
|
||||
* [REST API: Create user despite disabling registration](https://github.com/wekan/wekan/issues/1232).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Checklist items are lost when moving items to another checklist](https://github.com/wekan/wekan/pull/1240);
|
||||
* [Keep state of checklist items when moved to another checklist](https://github.com/wekan/wekan/pull/1242).
|
||||
|
||||
Thanks to GitHub users GhassenRjab, mario-orlicky, soohwa, umbertooo and xet7 for their contributions.
|
||||
|
||||
# v0.39 2017-09-18 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Import checklist sort attributes from Wekan and Trello](https://github.com/wekan/wekan/pull/1226).
|
||||
|
||||
Thanks to GitHub user GhassenRjab for contributions.
|
||||
|
||||
# v0.38 2017-09-14 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Reorder checklists. Move checklist item to another checklist.](https://github.com/wekan/wekan/pull/1215);
|
||||
* [Card title is now pre-filled in copy card dialog](https://github.com/wekan/wekan/pull/1214).
|
||||
|
||||
Thanks to GitHub user frmwrk123 for contributions.
|
||||
|
||||
# v0.37 2017-09-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Copy card within one board](https://github.com/wekan/wekan/pull/1204).
|
||||
|
||||
Thanks to GitHub user frmwrk123 for contributions.
|
||||
|
||||
# v0.36 2017-09-02 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Import attachments related activities from Wekan and
|
||||
Trello](https://github.com/wekan/wekan/pull/1202).
|
||||
|
||||
Thanks to GitHub user GhassenRjab for contributions.
|
||||
|
||||
# v0.35 2017-09-02 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add more than one Outgoing Webhook](https://github.com/wekan/wekan/pull/1199).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix errors caused by checklist items activities](https://github.com/wekan/wekan/pull/1200).
|
||||
|
||||
Thanks to GitHub users andresmanelli, GhassenRjab and nztqa for contributions.
|
||||
|
||||
# v0.34 2017-08-30 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Import Trello and Wekan board times of creation of activities](https://github.com/wekan/wekan/pull/1187);
|
||||
* Newest Wekan is available at Sandstorm App Market.
|
||||
|
||||
Known issues:
|
||||
|
||||
* [Attachment creation times are not imported to Trello and Wekan](https://github.com/wekan/wekan/issues/1157).
|
||||
- This is fixed in v0.36.
|
||||
|
||||
Thanks to GitHub user GhassenRjab for contributions.
|
||||
|
||||
# v0.33 2017-08-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add Bounties and Commercial Support to wiki](https://github.com/wekan/wekan/wiki);
|
||||
* [Add display Wekan version number and runtime
|
||||
environment to Admin Panel](https://github.com/wekan/wekan/pull/1156);
|
||||
* [Change Email address](https://github.com/wekan/wekan/pull/1161);
|
||||
* [Ubuntu snap: Use version scriptlet](https://github.com/wekan/wekan/pull/1164);
|
||||
* [Gogs integration part 1](https://github.com/wekan/wekan/pull/1189);
|
||||
* [Add web manifest so Wekan can be used like standalone app on Desktop
|
||||
with Chrome or Firefox](https://github.com/wekan/wekan/pull/1184);
|
||||
* [Copy card link to clipboard](https://github.com/wekan/wekan/issues/1188);
|
||||
* [Usernames can now include dots (.)](https://github.com/wekan/wekan/pull/1194).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix Squeezed tickbox in Card](https://github.com/wekan/wekan/pull/1171);
|
||||
* [Percent-encode SMTP password to prevent URI malformed
|
||||
errors](https://github.com/wekan/wekan/pull/1190);
|
||||
* [Fix Wekan Import Export on Standalone and Sandstorm](https://github.com/wekan/wekan/pull/1197).
|
||||
|
||||
Thanks to GitHub users andresmanelli, danhawkes, GhassenRjab, jonasob, kubiko, nztqa,
|
||||
pkuhner and xet7 for their contributions.
|
||||
|
||||
# v0.32 2017-07-30 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add dwrensha's Sandstorm patch to Wekan so it does not need to be maintained
|
||||
separately](https://github.com/wekan/wekan/commit/bda15daa78556223117a5846941aafd1212f14d3).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [FIX SECURITY ISSUE Files accessible without authentication](https://github.com/wekan/wekan/issues/1105);
|
||||
* [Fix showing card activity history in IE11](https://github.com/wekan/wekan/pull/1152).
|
||||
|
||||
Thanks to GitHub users dwrensha, GhassenRjab and nztqa for their contributions.
|
||||
|
||||
# v0.31 2017-07-30 Wekan release
|
||||
|
||||
* This was broken, having lint errors.
|
||||
|
||||
# v0.30 2017-07-27 Wekan release
|
||||
|
||||
SECURITY ISSUE [Files accessible without authentication](https://github.com/wekan/wekan/issues/1105)
|
||||
IS NOT FIXED YET.
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [More screenshots at Features page](https://github.com/wekan/wekan/wiki/Features);
|
||||
* [Export and import boards in Sandstorm](https://github.com/wekan/wekan/pull/1144);
|
||||
* [GitHub Issue template](https://github.com/wekan/wekan/pull/1146);
|
||||
* [Add checklist items to activity log](https://github.com/wekan/wekan/pull/1148).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Double shashes on ROOT_URL](https://github.com/wekan/wekan/issues/962).
|
||||
|
||||
Thanks to GitHub users GhassenRjab, nztqa and xet7 for their contributions.
|
||||
|
||||
# v0.29 2017-07-21 Wekan release
|
||||
|
||||
SECURITY ISSUE [Files accessible without authentication](https://github.com/wekan/wekan/issues/1105)
|
||||
IS NOT FIXED YET.
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Export and import attachments as base64 encoded files](https://github.com/wekan/wekan/pull/1134);
|
||||
* [Export and import checklists](https://github.com/wekan/wekan/pull/1140).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Activity user messed up when creating a card using the REST-API](https://github.com/wekan/wekan/pull/1116).
|
||||
|
||||
Thanks to GitHub users GhassenRjab and zarnifoulette for their contributions.
|
||||
|
||||
# v0.28 2017-07-15 Wekan release
|
||||
|
||||
SECURITY ISSUE [Files accessible without authentication](https://github.com/wekan/wekan/issues/1105)
|
||||
IS NOT FIXED YET.
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [REST API: Add PUT method to update a card](https://github.com/wekan/wekan/pull/1095) and
|
||||
[related fix](https://github.com/wekan/wekan/pull/1097);
|
||||
* [When finished input of checklist item, open new checklist
|
||||
item](https://github.com/wekan/wekan/pull/1099);
|
||||
* [Improve UI design of checklist items](https://github.com/wekan/wekan/pull/1108);
|
||||
* [Import Wekan board](https://github.com/wekan/wekan/pull/1117);
|
||||
* [Outgoing Webhooks](https://github.com/wekan/wekan/pull/1119);
|
||||
* [Wekan wiki now has menu with categories](https://github.com/wekan/wekan/wiki).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [SECURITY: Upgrade Node.js, MongoDB and Debian on Docker and Ubuntu snap edge](https://github.com/wekan/wekan/pull/1132);
|
||||
* [Possible to add empty item to checklist](https://github.com/wekan/wekan/pull/1107);
|
||||
* [Double-slash issue](https://github.com/wekan/wekan/pull/1114);
|
||||
* [Node.js crash when adding new user to board](https://github.com/wekan/wekan/issues/1131).
|
||||
|
||||
Thanks to GitHub users GhassenRjab, johnleeming, jtickle, nztqa, xet7 and zarnifoulette
|
||||
for their contributions.
|
||||
|
||||
# v0.27 2017-06-28 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Snapcraft build support from source](https://github.com/wekan/wekan/pull/1091).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix incorrect attachment link with subfolder in the url](https://github.com/wekan/wekan/pull/1086);
|
||||
* [Fix link to card](https://github.com/wekan/wekan/pull/1087);
|
||||
* [Fix duplicate id generation](https://github.com/wekan/wekan/pull/1093).
|
||||
|
||||
Thanks to GitHub users kubiko and nztqa for their contributions.
|
||||
|
||||
# v0.26 2017-06-26 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
* [Fix admin panel route for subfolder](https://github.com/wekan/wekan/pull/1084);
|
||||
* [Fix i18n route for subfolder](https://github.com/wekan/wekan/pull/1085).
|
||||
|
||||
Thanks to GitHub user nztqa for contributions.
|
||||
|
||||
# v0.25 2017-06-24 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Import due date from Trello](https://github.com/wekan/wekan/pull/1082).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix importing Trello board: Attribute correct members to their
|
||||
comments](https://github.com/wekan/wekan/pull/1080);
|
||||
* [Fix Case-sensitive email handling](https://github.com/wekan/wekan/issues/675);
|
||||
* [Use fibers 1.0.15 because 2.0.0 is broken](https://github.com/wekan/wekan/commit/86e2744c24149c0eacf725b68a186d0bcfae5100);
|
||||
* [Remove git submodules, so that git clone of Wekan repo works now on Windows](https://github.com/wekan/wekan/issues/977).
|
||||
|
||||
Thanks to GitHub users GhassenRjab, nztqa and xet7 for their contributions.
|
||||
|
||||
# v0.24 2017-06-21 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Change the way to delete a list (card-like)](https://github.com/wekan/wekan/pull/1050), fixes
|
||||
[missing undo button](https://github.com/wekan/wekan/issues/1023);
|
||||
* [When deleting list, delete list's cards too](https://github.com/wekan/wekan/pull/1054);
|
||||
* [Re-enable Export Wekan Board](https://github.com/wekan/wekan/pull/1059);
|
||||
* [Sort languages by their translated names](https://github.com/wekan/wekan/pull/1070);
|
||||
* [Add Breton language name](https://github.com/wekan/wekan/pull/1071).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [Fix Admin Panel link available to all users, only link is hidden](https://github.com/wekan/wekan/pull/1076);
|
||||
* [Fix IE 11 drag board to scroll](https://github.com/wekan/wekan/pull/1052);
|
||||
* [Fix Export Wekan board](https://github.com/wekan/wekan/pull/1067);
|
||||
* [Fix "W" shortcut binding](https://github.com/wekan/wekan/pull/1066);
|
||||
* [Fix login url in invitation email](https://github.com/wekan/wekan/issues/993);
|
||||
* [Edit card description with invalid markdown](https://github.com/wekan/wekan/pull/1073);
|
||||
* [Fix filter reset on moving between starred boards](https://github.com/wekan/wekan/pull/1074).
|
||||
|
||||
Thanks to GitHub users BaobabCoder, GhassenRjab, nebulade, nztqa and xet7
|
||||
for their contributions.
|
||||
|
||||
# v0.23 2017-05-21 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
* [Add checklist and card comment to REST API](https://github.com/wekan/wekan/pull/1033);
|
||||
* [Add token authentication to REST API](https://github.com/wekan/wekan/pull/1033), this fixes
|
||||
[Security flaws introduced by REST API](https://github.com/wekan/wekan/issues/1032);
|
||||
* [Authorization improvements etc to REST API](https://github.com/wekan/wekan/pull/1041);
|
||||
* [IE 11 support in unicode filename downloads](https://github.com/wekan/wekan/issues/1031).
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
* [When Wekan starts, there's "here1 false" messages in
|
||||
console](https://github.com/wekan/wekan/issues/1028);
|
||||
* [IE11 problem when closing cards, sidebar etc](https://github.com/wekan/wekan/pull/1042).
|
||||
|
||||
Thanks to GitHub users huneau, mayjs and nztqa for their contributions.
|
||||
|
||||
# v0.22 2017-05-07 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
@@ -82,12 +799,12 @@ and fixes the following bugs:
|
||||
exists valid admin panel data MAIL_URL is not set.
|
||||
MAIL_FROM was ignored. Same behaviour, env variable has bigger priority
|
||||
than database configuration.
|
||||
On both cases, althrought environment variable is set, updating admin-panel
|
||||
On both cases, althought environment variable is set, updating admin-panel
|
||||
mail settings will load new info and ignore the environment variable;
|
||||
* Dockerfile fix for local packages;
|
||||
* Don't send emails if missing smtp host;
|
||||
* Remove invitation code if email sending failed;
|
||||
* Show customized error msg while invitaion code is wrong during registration;
|
||||
* Show customized error msg while invitation code is wrong during registration;
|
||||
* Fix "internal error" while registration is done;
|
||||
* Fix "cannot access disableRegistration of undefined" error;
|
||||
* Add high available server for getting the gpg keys - suppose it should lead
|
||||
@@ -96,7 +813,7 @@ and fixes the following bugs:
|
||||
requests need further review before merging into devel;
|
||||
* Use navigator language by default instead of English.
|
||||
|
||||
Thanks to GitHub users JamborJan, lkisme, rhelsing, Serubi, stephenmoloney,
|
||||
Thanks to GitHub users JamborJan, lkisme, rhelsing, Serubin, stephenmoloney,
|
||||
umbertooo and Zokormazo for their contributions.
|
||||
|
||||
# v0.17 2017-03-25 Wekan release
|
||||
@@ -192,7 +909,7 @@ and adds the following new features:
|
||||
```
|
||||
1) Disable Self-Registration and invite users
|
||||
2) SMTP settings.
|
||||
|
||||
|
||||
Adding Admin user in mongo cli:
|
||||
1) Use database that has wekan data, for example:
|
||||
use admin;
|
||||
@@ -373,7 +1090,7 @@ performance and security. It also features the following improvements:
|
||||
password, to change the password, or to enable email confirmation (all of
|
||||
which were previously impossible);
|
||||
* Avatar customization, including the possibility to upload images and to choose
|
||||
one from Gravatar or the user initials (on Sandstrom we use the avatar exposed
|
||||
one from Gravatar or the user initials (on Sandstorm we use the avatar exposed
|
||||
by Sandstorm);
|
||||
* Cards multi-selection to facilitate batch actions such as moving all the cards
|
||||
of selection, or attaching a label or a member to them;
|
||||
|
||||
+40
-35
@@ -1,4 +1,4 @@
|
||||
FROM debian:8.7
|
||||
FROM debian:buster-slim
|
||||
MAINTAINER wekan
|
||||
|
||||
# Declare Arguments
|
||||
@@ -7,17 +7,19 @@ ARG METEOR_RELEASE
|
||||
ARG METEOR_EDGE
|
||||
ARG USE_EDGE
|
||||
ARG NPM_VERSION
|
||||
ARG FIBERS_VERSION
|
||||
ARG ARCHITECTURE
|
||||
ARG SRC_PATH
|
||||
|
||||
# Set the environment variables (defaults where required)
|
||||
ENV BUILD_DEPS="wget curl bzip2 build-essential python git ca-certificates gcc-4.9"
|
||||
ENV GOSU_VERSION=1.10
|
||||
ENV NODE_VERSION ${NODE_VERSION:-v4.8.1}
|
||||
ENV METEOR_RELEASE ${METEOR_RELEASE:-1.4.4.1}
|
||||
# paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
|
||||
ENV BUILD_DEPS="apt-utils gnupg gosu wget curl bzip2 build-essential python git ca-certificates gcc-7 paxctl"
|
||||
ENV NODE_VERSION ${NODE_VERSION:-v8.9.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:-4.5.0}
|
||||
ENV NPM_VERSION ${NPM_VERSION:-5.5.1}
|
||||
ENV FIBERS_VERSION ${FIBERS_VERSION:-2.0.0}
|
||||
ENV ARCHITECTURE ${ARCHITECTURE:-linux-x64}
|
||||
ENV SRC_PATH ${SRC_PATH:-./}
|
||||
|
||||
@@ -29,17 +31,7 @@ RUN \
|
||||
useradd --user-group --system --home-dir /home/wekan wekan && \
|
||||
\
|
||||
# OS dependencies
|
||||
apt-get update -y && apt-get dist-upgrade -y && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \
|
||||
\
|
||||
# Gosu installation
|
||||
GOSU_ARCHITECTURE="$(dpkg --print-architecture | awk -F- '{ print $NF }')" && \
|
||||
wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${GOSU_ARCHITECTURE}" && \
|
||||
wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/${GOSU_VERSION}/gosu-${GOSU_ARCHITECTURE}.asc" && \
|
||||
export GNUPGHOME="$(mktemp -d)" && \
|
||||
gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 && \
|
||||
gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu && \
|
||||
rm -R "$GNUPGHOME" /usr/local/bin/gosu.asc && \
|
||||
chmod +x /usr/local/bin/gosu && \
|
||||
apt-get update -y && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \
|
||||
\
|
||||
# Download nodejs
|
||||
wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
@@ -48,7 +40,7 @@ RUN \
|
||||
# Verify nodejs authenticity
|
||||
grep ${NODE_VERSION}-${ARCHITECTURE}.tar.gz SHASUMS256.txt.asc | shasum -a 256 -c - && \
|
||||
export GNUPGHOME="$(mktemp -d)" && \
|
||||
|
||||
\
|
||||
# Try other key servers if ha.pool.sks-keyservers.net is unreachable
|
||||
# Code from https://github.com/chorrell/docker-node/commit/2b673e17547c34f17f24553db02beefbac98d23c
|
||||
# gpg keys listed at https://github.com/nodejs/node#release-team
|
||||
@@ -67,7 +59,10 @@ RUN \
|
||||
gpg --keyserver keyserver.pgp.com --recv-keys "$key" ; \
|
||||
done && \
|
||||
gpg --verify SHASUMS256.txt.asc && \
|
||||
rm -R "$GNUPGHOME" SHASUMS256.txt.asc && \
|
||||
# Ignore socket files then delete files then delete directories
|
||||
find "$GNUPGHOME" -type f | xargs rm -f && \
|
||||
find "$GNUPGHOME" -type d | xargs rm -fR && \
|
||||
rm -f SHASUMS256.txt.asc && \
|
||||
\
|
||||
# Install Node
|
||||
tar xvzf node-${NODE_VERSION}-${ARCHITECTURE}.tar.gz && \
|
||||
@@ -76,42 +71,52 @@ RUN \
|
||||
ln -s /opt/nodejs/bin/node /usr/bin/node && \
|
||||
ln -s /opt/nodejs/bin/npm /usr/bin/npm && \
|
||||
\
|
||||
# paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
|
||||
paxctl -mC `which node` && \
|
||||
\
|
||||
# Install Node dependencies
|
||||
npm install -g npm@${NPM_VERSION} && \
|
||||
npm install -g node-gyp && \
|
||||
npm install -g fibers && \
|
||||
npm install -g fibers@${FIBERS_VERSION} && \
|
||||
\
|
||||
# Change user to wekan and install meteor
|
||||
cd /home/wekan/ && \
|
||||
chown wekan:wekan --recursive /home/wekan && \
|
||||
curl https://install.meteor.com -o ./install_meteor.sh && \
|
||||
curl https://install.meteor.com -o /home/wekan/install_meteor.sh && \
|
||||
sed -i "s|RELEASE=.*|RELEASE=${METEOR_RELEASE}\"\"|g" ./install_meteor.sh && \
|
||||
echo "Starting meteor ${METEOR_RELEASE} installation... \n" && \
|
||||
chown wekan:wekan ./install_meteor.sh && \
|
||||
chown wekan:wekan /home/wekan/install_meteor.sh && \
|
||||
\
|
||||
# Check if opting for a release candidate instead of major release
|
||||
if [ "$USE_EDGE" = false ]; then \
|
||||
gosu wekan:wekan sh ./install_meteor.sh; \
|
||||
gosu wekan:wekan sh /home/wekan/install_meteor.sh; \
|
||||
else \
|
||||
gosu wekan:wekan git clone --recursive git://github.com/meteor/meteor.git /home/wekan/.meteor && \
|
||||
cd /home/wekan/.meteor && \
|
||||
gosu wekan:wekan git checkout release/METEOR@${METEOR_EDGE} && \
|
||||
gosu wekan /home/wekan/.meteor/meteor -- help; \
|
||||
fi && \
|
||||
gosu wekan:wekan git clone --recursive --depth 1 -b release/METEOR@${METEOR_EDGE} git://github.com/meteor/meteor.git /home/wekan/.meteor; \
|
||||
fi; \
|
||||
\
|
||||
# Get additional packages
|
||||
mkdir -p /home/wekan/app/packages && \
|
||||
chown wekan:wekan --recursive /home/wekan && \
|
||||
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 && \
|
||||
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; \
|
||||
\
|
||||
# Build app
|
||||
cd /home/wekan/app && \
|
||||
gosu wekan /home/wekan/.meteor/meteor add standard-minifier-js && \
|
||||
gosu wekan /home/wekan/.meteor/meteor npm install && \
|
||||
gosu wekan /home/wekan/.meteor/meteor build --directory /home/wekan/app_build && \
|
||||
gosu wekan:wekan /home/wekan/.meteor/meteor add standard-minifier-js && \
|
||||
gosu wekan:wekan /home/wekan/.meteor/meteor npm install && \
|
||||
gosu wekan:wekan /home/wekan/.meteor/meteor build --directory /home/wekan/app_build && \
|
||||
cp /home/wekan/app/fix-download-unicode/cfs_access-point.txt /home/wekan/app_build/bundle/programs/server/packages/cfs_access-point.js && \
|
||||
chown wekan:wekan /home/wekan/app_build/bundle/programs/server/packages/cfs_access-point.js && \
|
||||
gosu wekan sed -i "s|build\/Release\/bson|browser_build\/bson|g" /home/wekan/app_build/bundle/programs/server/npm/node_modules/meteor/cfs_gridfs/node_modules/mongodb/node_modules/bson/ext/index.js && \
|
||||
cd /home/wekan/app_build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt && \
|
||||
gosu wekan rm -rf node_modules/bcrypt && \
|
||||
gosu wekan npm install bcrypt && \
|
||||
gosu wekan:wekan rm -rf node_modules/bcrypt && \
|
||||
gosu wekan:wekan npm install bcrypt && \
|
||||
cd /home/wekan/app_build/bundle/programs/server/ && \
|
||||
gosu wekan npm install && \
|
||||
gosu wekan:wekan npm install && \
|
||||
gosu wekan:wekan npm install bcrypt && \
|
||||
mv /home/wekan/app_build/bundle /build && \
|
||||
\
|
||||
# Cleanup
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014-2016 The Wekan Team
|
||||
Copyright (c) 2014-2018 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,11 +1,19 @@
|
||||
# Wekan
|
||||
|
||||
[](https://quay.io/repository/wekan/wekan)
|
||||
|
||||
<!--
|
||||
[![Wekan Build Status][travis_badge]][travis_status]
|
||||
-->
|
||||
|
||||
Freenode IRC #wekan
|
||||
|
||||
[![Wekan chat][vanila_badge]][vanila_chat]
|
||||
|
||||
[Translate Wekan at Transifex][translate_wekan]
|
||||
|
||||
[Open Hub analysis of Wekan code](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 :)
|
||||
|
||||
@@ -22,18 +30,20 @@ Wekan has real-time user interface. Not all features are implemented.
|
||||
|
||||
[Features][features]
|
||||
|
||||
Wekan supports many [Platforms][platforms], and plan is to add more.
|
||||
|
||||
[Integrations][integrations]
|
||||
|
||||
[Team](https://github.com/wekan/wekan/wiki/Team)
|
||||
|
||||
Wekan supports many [Platforms][platforms], and plan is to add more.
|
||||
|
||||
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.
|
||||
|
||||
## 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]
|
||||
@@ -46,108 +56,47 @@ 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.
|
||||
|
||||
[Roadmap is self-hosted on Wekan][roadmap_wefork]
|
||||
Actual work happens at [Wekan GitHub issues][wekan_issues].
|
||||
|
||||
Roadmaps is not currently up-to-date. You can find more up-to-date
|
||||
info from [Features][features] and [Integrations][integrations] pages,
|
||||
where is links to [Wekan GitHub issues][wekan_issues] where actual
|
||||
work happens.
|
||||
See [Development links on Wekan
|
||||
wiki](https://github.com/wekan/wekan/wiki#Development)
|
||||
bottom of the page for more info.
|
||||
|
||||
## Demo
|
||||
|
||||
[Wekan demo][roadmap_wefork]
|
||||
|
||||
## Screenshot
|
||||
|
||||
[![Screenshot of Wekan][screenshot_wefork]][roadmap_wefork]
|
||||
[More screenshots at Features page](https://github.com/wekan/wekan/wiki/Features)
|
||||
|
||||
Content is being copied from [old Wekan roadmap][roadmap_wekan] to
|
||||
new one in process of merging Wefork back to Wekan.
|
||||
[![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.
|
||||
|
||||
## Cleanup and stats
|
||||
|
||||
[Wekan database cleanup script][wekan_cleanup]
|
||||
|
||||
[Docker cleanup](https://github.com/wekan/wekan/issues/985)
|
||||
|
||||
[Daily export of Wekan changes as JSON to Logstash and
|
||||
ElasticSearch / Kibana (ELK)][wekan_logstash]
|
||||
|
||||
[Wekan stats][wekan_stats]
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
Automatic generated newest builds are available for Docker, and platforms that
|
||||
install directly from this repo. Automatic builds will be added later for more
|
||||
platforms.
|
||||
|
||||
First registered Wekan user will get [Admin Panel][features] on new
|
||||
Docker and source based installs. You can also
|
||||
[enable Admin Panel manually][enable_adminpanel].
|
||||
|
||||
[![Deploy][heroku_button]][heroku_deploy]
|
||||
[![SignUp][indiehosters_button]][indiehosters_saas]
|
||||
[![Deploy to Scalingo][scalingo_button]][scalingo_deploy]
|
||||
[![Install on Cloudron][cloudron_button]][cloudron_install]
|
||||
[![Try on Sandstorm][sandstorm_button]][sandstorm_appdemo]
|
||||
|
||||
[VirtualBox][virtualbox]
|
||||
|
||||
[Install via Docker](https://github.com/wekan/wekan/wiki/Docker)
|
||||
|
||||
[Install from source][install_source]
|
||||
|
||||
[Install from source on Windows][installsource_windows]
|
||||
|
||||
[Debian Wheezy 64bit & Devuan Jessie 64 bit][debian_wheezy_devuan_jessie]
|
||||
|
||||
[More Platforms, and Upcoming Platforms](https://github.com/wekan/wekan/wiki/Platforms)
|
||||
|
||||
## License
|
||||
|
||||
Wekan is released under the very permissive [MIT license](LICENSE), and made
|
||||
with [Meteor](https://www.meteor.com).
|
||||
|
||||
[vanila_badge]: https://vanila.io/img/join-chat-button2.png
|
||||
[vanila_chat]: https://chat.vanila.io/channel/wekan
|
||||
[platforms]: https://github.com/wekan/wekan/wiki/Platforms
|
||||
[dev_docs]: https://github.com/wekan/wekan/wiki/Developer-Documentation
|
||||
[screenshot_wekan]: http://i.imgur.com/cI4jW2h.png
|
||||
[screenshot_wefork]: http://i.imgur.com/lzvpeS9.png
|
||||
[screenshot_wefork]: https://wekan.github.io/wekan-markdown.png
|
||||
[features]: https://github.com/wekan/wekan/wiki/Features
|
||||
[integrations]: https://github.com/wekan/wekan/wiki/Integrations
|
||||
[roadmap_wekan]: http://try.wekan.io/b/MeSsFJaSqeuo9M6bs/wekan-roadmap
|
||||
[roadmap_wefork]: https://wekan.indie.host/b/t2YaGmyXgNkppcFBq/wekan-fork-roadmap
|
||||
[wekan_issues]: https://github.com/wekan/wekan/issues
|
||||
[wefork_issues]: https://github.com/wefork/wekan/issues
|
||||
[sandstorm_button]: https://img.shields.io/badge/try-Wekan%20on%20Sandstorm-783189.svg
|
||||
[sandstorm_appdemo]: https://demo.sandstorm.io/appdemo/m86q05rdvj14yvn78ghaxynqz7u2svw6rnttptxx49g1785cdv1h
|
||||
[docker_image]: https://hub.docker.com/r/wekanteam/wekan/
|
||||
[heroku_button]: https://www.herokucdn.com/deploy/button.png
|
||||
[heroku_deploy]: https://heroku.com/deploy?template=https://github.com/wekan/wekan/tree/master
|
||||
[indiehosters_button]: https://indie.host/signup.png
|
||||
[indiehosters_saas]: https://indiehosters.net/shop/product/wekan-20
|
||||
[scalingo_button]: https://cdn.scalingo.com/deploy/button.svg
|
||||
[scalingo_deploy]: https://my.scalingo.com/deploy?source=https://github.com/wekan/wekan#master
|
||||
[cloudron_button]: https://cloudron.io/img/button.svg
|
||||
[cloudron_install]: https://cloudron.io/button.html?app=io.wekan.cloudronapp
|
||||
[debian_wheezy_devuan_jessie]: https://github.com/soohwa/sps/blob/master/example/docs/1/wekan.md
|
||||
[travis_badge]: https://travis-ci.org/wekan/wekan.svg?branch=meteor-1.4
|
||||
[travis_badge]: https://travis-ci.org/wekan/wekan.svg?branch=devel
|
||||
[travis_status]: https://travis-ci.org/wekan/wekan
|
||||
[install_source]: https://github.com/wekan/wekan/wiki/Install-and-Update#install-manually-from-source
|
||||
[installsource_windows]: https://github.com/wekan/wekan/wiki/Install-Wekan-from-source-on-Windows
|
||||
[virtualbox]: https://github.com/wekan/wekan/wiki/virtual-appliance
|
||||
[docker_image]: https://hub.docker.com/r/wekanteam/wekan/
|
||||
[wekan_wiki]: https://github.com/wekan/wekan/wiki
|
||||
[translate_wekan]: https://www.transifex.com/wekan/wekan/
|
||||
[autoinstall]: https://github.com/wekan/wekan-autoinstall
|
||||
[autoinstall_issue]: https://github.com/anselal/wekan/issues/18
|
||||
[dev_docs]: https://github.com/wekan/wekan/wiki/Developer-Documentation
|
||||
[wekan_mongodb]: https://github.com/wekan/wekan-mongodb
|
||||
[wekan_postgresql]: https://github.com/wekan/wekan-postgresql
|
||||
[wekan_cleanup]: https://github.com/wekan/wekan-cleanup
|
||||
[wekan_logstash]: https://github.com/wekan/wekan-logstash
|
||||
[wekan_stats]: https://github.com/wekan/wekan-stats
|
||||
[logstash_issue]: https://github.com/wekan/wekan/issues/855
|
||||
[enable_adminpanel]: https://github.com/wekan/wekan/blob/devel/CHANGELOG.md#v0111-rc2-2017-03-05-wekan-prerelease
|
||||
[open_source]: https://en.wikipedia.org/wiki/Open-source_software
|
||||
[free_software]: https://en.wikipedia.org/wiki/Free_software
|
||||
[platforms]: https://github.com/wekan/wekan/wiki/Platforms
|
||||
[vanila_badge]: https://vanila.io/img/join-chat-button2.png
|
||||
[vanila_chat]: https://chat.vanila.io/channel/wekan
|
||||
@@ -4,7 +4,7 @@
|
||||
"repository": "https://github.com/wekan/wekan",
|
||||
"logo": "https://raw.githubusercontent.com/wekan/wekan/master/meta/icons/wekan-150.png",
|
||||
"keywords": ["productivity", "tool", "team", "kanban"],
|
||||
"website": "https://wekan.io",
|
||||
"website": "https://wekan.github.io",
|
||||
"env": {
|
||||
"BUILDPACK_URL": "https://github.com/AdmitHub/meteor-buildpack-horse.git",
|
||||
"ROOT_URL": {
|
||||
|
||||
@@ -32,12 +32,21 @@ template(name="boardActivities")
|
||||
+viewer
|
||||
= checklist.title
|
||||
|
||||
if($eq activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklistItem.title
|
||||
|
||||
if($eq activityType 'archivedCard')
|
||||
| {{{_ 'activity-archived' cardLink}}}.
|
||||
|
||||
if($eq activityType 'archivedList')
|
||||
| {{_ 'activity-archived' list.title}}.
|
||||
|
||||
if($eq activityType 'archivedSwimlane')
|
||||
| {{_ 'activity-archived' swimlane.title}}.
|
||||
|
||||
if($eq activityType 'createBoard')
|
||||
| {{_ 'activity-created' boardLabel}}.
|
||||
|
||||
@@ -47,6 +56,9 @@ template(name="boardActivities")
|
||||
if($eq activityType 'createList')
|
||||
| {{_ 'activity-added' list.title boardLabel}}.
|
||||
|
||||
if($eq activityType 'createSwimlane')
|
||||
| {{_ 'activity-added' swimlane.title boardLabel}}.
|
||||
|
||||
if($eq activityType 'removeList')
|
||||
| {{_ 'activity-removed' title boardLabel}}.
|
||||
|
||||
@@ -117,6 +129,11 @@ template(name="cardActivities")
|
||||
.activity-checklist
|
||||
+viewer
|
||||
= checklist.title
|
||||
if($eq activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklistItem.title
|
||||
|
||||
if($eq activityType 'addComment')
|
||||
+inlinedForm(classNames='js-edit-comment')
|
||||
|
||||
@@ -86,7 +86,7 @@ BlazeComponent.extendComponent({
|
||||
const attachment = this.currentData().attachment();
|
||||
// trying to display url before file is stored generates js errors
|
||||
return attachment && attachment.url({ download: true }) && Blaze.toHTML(HTML.A({
|
||||
href: FlowRouter.path(attachment.url({ download: true })),
|
||||
href: attachment.url({ download: true }),
|
||||
target: '_blank',
|
||||
}, attachment.name()));
|
||||
},
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
@import 'nib'
|
||||
|
||||
.activity-title
|
||||
margin: 0 0.5em 0.8em
|
||||
display: flex
|
||||
justify-content:space-between
|
||||
|
||||
.activities
|
||||
clear: both
|
||||
|
||||
@@ -12,10 +17,14 @@
|
||||
height: @width
|
||||
|
||||
.activity-desc
|
||||
word-wrap: break-word
|
||||
overflow: hidden
|
||||
flex: 1
|
||||
align-self: center
|
||||
margin: 0
|
||||
margin-left: 3px
|
||||
overflow: hidden;
|
||||
word-break: break-word;
|
||||
|
||||
.activity-comment
|
||||
display: block
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
template(name="archivedBoards")
|
||||
h2
|
||||
i.fa.fa-archive
|
||||
| Archived boards
|
||||
| {{_ 'archived-boards'}}
|
||||
|
||||
ul.archived-lists
|
||||
each archivedBoards
|
||||
li.archived-lists-item
|
||||
button.js-restore-board
|
||||
i.fa.fa-undo
|
||||
| Restore board
|
||||
| {{_ 'restore-board'}}
|
||||
= title
|
||||
else
|
||||
li.no-items-message No archived board.
|
||||
li.no-items-message {{_ 'no-archived-boards'}}
|
||||
@@ -18,6 +18,13 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{
|
||||
'click .js-restore-board'() {
|
||||
// TODO : Make isSandstorm variable global
|
||||
const isSandstorm = Meteor.settings && Meteor.settings.public &&
|
||||
Meteor.settings.public.sandstorm;
|
||||
if (isSandstorm && Session.get('currentBoard')) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
currentBoard.archive();
|
||||
}
|
||||
const board = this.currentData();
|
||||
board.restore();
|
||||
Utils.goBoardId(board._id);
|
||||
|
||||
@@ -14,30 +14,14 @@ template(name="board")
|
||||
template(name="boardBody")
|
||||
.board-wrapper(class=currentBoard.colorClass)
|
||||
+sidebar
|
||||
.board-canvas(
|
||||
.board-canvas.js-swimlanes.js-perfect-scrollbar(
|
||||
class="{{#if Sidebar.isOpen}}is-sibling-sidebar-open{{/if}}"
|
||||
class="{{#if MultiSelection.isActive}}is-multiselection-active{{/if}}"
|
||||
class="{{#if draggingActive.get}}is-dragging-active{{/if}}")
|
||||
if showOverlay.get
|
||||
.board-overlay
|
||||
.lists.js-lists
|
||||
each currentBoard.lists
|
||||
+list(this)
|
||||
if currentCardIsInThisList
|
||||
+cardDetails(currentCard)
|
||||
if canSeeAddList
|
||||
+addListForm
|
||||
|
||||
template(name="addListForm")
|
||||
.list.js-list.list-composer.js-list-composer
|
||||
.list-header
|
||||
+inlinedForm(autoclose=false)
|
||||
input.list-name-input.full-line(type="text" placeholder="{{_ 'add-list'}}"
|
||||
autocomplete="off" autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-list'}}
|
||||
if isViewSwimlanes
|
||||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
if isViewLists
|
||||
+listsGroup
|
||||
@@ -1,9 +1,8 @@
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndex } = Utils;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.draggingActive = new ReactiveVar(false);
|
||||
this.showOverlay = new ReactiveVar(false);
|
||||
this.isBoardReady = new ReactiveVar(false);
|
||||
|
||||
// The pattern we use to manually handle data loading is described here:
|
||||
@@ -21,42 +20,94 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
this._isDragging = false;
|
||||
this._lastDragPositionX = 0;
|
||||
|
||||
// Used to set the overlay
|
||||
this.mouseHasEnterCardDetails = false;
|
||||
},
|
||||
|
||||
openNewListForm() {
|
||||
this.childComponents('addListForm')[0].open();
|
||||
},
|
||||
|
||||
// XXX Flow components allow us to avoid creating these two setter methods by
|
||||
// exposing a public API to modify the component state. We need to investigate
|
||||
// best practices here.
|
||||
setIsDragging(bool) {
|
||||
this.draggingActive.set(bool);
|
||||
},
|
||||
|
||||
scrollLeft(position = 0) {
|
||||
const lists = this.$('.js-lists');
|
||||
lists && lists.animate({
|
||||
scrollLeft: position,
|
||||
});
|
||||
},
|
||||
|
||||
currentCardIsInThisList() {
|
||||
const currentCard = Cards.findOne(Session.get('currentCard'));
|
||||
const listId = this.currentData()._id;
|
||||
return currentCard && currentCard.listId === listId;
|
||||
},
|
||||
|
||||
onlyShowCurrentCard() {
|
||||
return Utils.isMiniScreen() && Session.get('currentCard');
|
||||
},
|
||||
|
||||
}).register('board');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.showOverlay = new ReactiveVar(false);
|
||||
this.draggingActive = new ReactiveVar(false);
|
||||
this._isDragging = false;
|
||||
// Used to set the overlay
|
||||
this.mouseHasEnterCardDetails = false;
|
||||
},
|
||||
onRendered() {
|
||||
const boardComponent = this;
|
||||
const $swimlanesDom = boardComponent.$('.js-swimlanes');
|
||||
|
||||
$swimlanesDom.sortable({
|
||||
tolerance: 'pointer',
|
||||
appendTo: '.board-canvas',
|
||||
helper: 'clone',
|
||||
handle: '.js-swimlane-header',
|
||||
items: '.js-swimlane:not(.placeholder)',
|
||||
placeholder: 'swimlane placeholder',
|
||||
distance: 7,
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
boardComponent.setIsDragging(true);
|
||||
},
|
||||
stop(evt, ui) {
|
||||
// To attribute the new index number, we need to get the DOM element
|
||||
// of the previous and the following card -- if any.
|
||||
const prevSwimlaneDom = ui.item.prev('.js-swimlane').get(0);
|
||||
const nextSwimlaneDom = ui.item.next('.js-swimlane').get(0);
|
||||
const sortIndex = calculateIndex(prevSwimlaneDom, nextSwimlaneDom, 1);
|
||||
|
||||
$swimlanesDom.sortable('cancel');
|
||||
const swimlaneDomElement = ui.item.get(0);
|
||||
const swimlane = Blaze.getData(swimlaneDomElement);
|
||||
|
||||
Swimlanes.update(swimlane._id, {
|
||||
$set: {
|
||||
sort: sortIndex.base,
|
||||
},
|
||||
});
|
||||
|
||||
boardComponent.setIsDragging(false);
|
||||
},
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
}
|
||||
|
||||
// If there is no data in the board (ie, no lists) we autofocus the list
|
||||
// creation form by clicking on the corresponding element.
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (userIsMember() && currentBoard.lists().count() === 0) {
|
||||
boardComponent.openNewListForm();
|
||||
}
|
||||
},
|
||||
|
||||
isViewSwimlanes() {
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
const board = Boards.findOne(currentBoardId);
|
||||
return (board.view === 'board-view-swimlanes');
|
||||
},
|
||||
|
||||
isViewLists() {
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
const board = Boards.findOne(currentBoardId);
|
||||
return (board.view === 'board-view-lists');
|
||||
},
|
||||
|
||||
openNewListForm() {
|
||||
if (this.isViewSwimlanes()) {
|
||||
this.childComponents('swimlane')[0]
|
||||
.childComponents('addListAndSwimlaneForm')[0].open();
|
||||
} else if (this.isViewLists()) {
|
||||
this.childComponents('listsGroup')[0]
|
||||
.childComponents('addListForm')[0].open();
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
// XXX The board-overlay div should probably be moved to the parent
|
||||
@@ -66,147 +117,26 @@ BlazeComponent.extendComponent({
|
||||
this.showOverlay.set(false);
|
||||
}
|
||||
},
|
||||
|
||||
// Click-and-drag action
|
||||
'mousedown .board-canvas'(evt) {
|
||||
// Translating the board canvas using the click-and-drag action can
|
||||
// conflict with the build-in browser mechanism to select text. We
|
||||
// define a list of elements in which we disable the dragging because
|
||||
// the user will legitimately expect to be able to select some text with
|
||||
// his mouse.
|
||||
const noDragInside = ['a', 'input', 'textarea', 'p', '.js-list-header'];
|
||||
if ($(evt.target).closest(noDragInside.join(',')).length === 0) {
|
||||
this._isDragging = true;
|
||||
this._lastDragPositionX = evt.clientX;
|
||||
}
|
||||
},
|
||||
'mouseup'() {
|
||||
if (this._isDragging) {
|
||||
this._isDragging = false;
|
||||
}
|
||||
},
|
||||
'mousemove'(evt) {
|
||||
if (this._isDragging) {
|
||||
// Update the canvas position
|
||||
this.listsDom.scrollLeft -= evt.clientX - this._lastDragPositionX;
|
||||
this._lastDragPositionX = evt.clientX;
|
||||
// Disable browser text selection while dragging
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
// Don't close opened card or inlined form at the end of the
|
||||
// click-and-drag.
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
EscapeActions.preventNextClick();
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('board');
|
||||
|
||||
Template.boardBody.onRendered(function() {
|
||||
const self = BlazeComponent.getComponentForElement(this.firstNode);
|
||||
|
||||
self.listsDom = this.find('.js-lists');
|
||||
|
||||
if (!Session.get('currentCard')) {
|
||||
self.scrollLeft();
|
||||
}
|
||||
|
||||
// We want to animate the card details window closing. We rely on CSS
|
||||
// transition for the actual animation.
|
||||
self.listsDom._uihooks = {
|
||||
removeElement(node) {
|
||||
const removeNode = _.once(() => {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
if ($(node).hasClass('js-card-details')) {
|
||||
$(node).css({
|
||||
flexBasis: 0,
|
||||
padding: 0,
|
||||
});
|
||||
$(self.listsDom).one(CSSEvents.transitionend, removeNode);
|
||||
} else {
|
||||
removeNode();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
$(self.listsDom).sortable({
|
||||
tolerance: 'pointer',
|
||||
helper: 'clone',
|
||||
handle: '.js-list-header',
|
||||
items: '.js-list:not(.js-list-composer)',
|
||||
placeholder: 'list placeholder',
|
||||
distance: 7,
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
Popup.close();
|
||||
},
|
||||
stop() {
|
||||
$(self.listsDom).find('.js-list:not(.js-list-composer)').each(
|
||||
(i, list) => {
|
||||
const data = Blaze.getData(list);
|
||||
Lists.update(data._id, {
|
||||
$set: {
|
||||
sort: i,
|
||||
},
|
||||
});
|
||||
}
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember();
|
||||
}
|
||||
|
||||
// Disable drag-dropping while in multi-selection mode, or if the current user
|
||||
// is not a board member
|
||||
self.autorun(() => {
|
||||
const $listDom = $(self.listsDom);
|
||||
if ($listDom.data('sortable')) {
|
||||
$(self.listsDom).sortable('option', 'disabled',
|
||||
MultiSelection.isActive() || !userIsMember());
|
||||
}
|
||||
});
|
||||
|
||||
// If there is no data in the board (ie, no lists) we autofocus the list
|
||||
// creation form by clicking on the corresponding element.
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (userIsMember() && currentBoard.lists().count() === 0) {
|
||||
self.openNewListForm();
|
||||
}
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
// Proxy
|
||||
open() {
|
||||
this.childComponents('inlinedForm')[0].open();
|
||||
// XXX Flow components allow us to avoid creating these two setter methods by
|
||||
// exposing a public API to modify the component state. We need to investigate
|
||||
// best practices here.
|
||||
setIsDragging(bool) {
|
||||
this.draggingActive.set(bool);
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
submit(evt) {
|
||||
evt.preventDefault();
|
||||
const titleInput = this.find('.list-name-input');
|
||||
const title = titleInput.value.trim();
|
||||
if (title) {
|
||||
Lists.insert({
|
||||
title,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.list').length,
|
||||
});
|
||||
|
||||
titleInput.value = '';
|
||||
titleInput.focus();
|
||||
}
|
||||
},
|
||||
}];
|
||||
scrollLeft(position = 0) {
|
||||
const swimlanes = this.$('.js-swimlanes');
|
||||
swimlanes && swimlanes.animate({
|
||||
scrollLeft: position,
|
||||
});
|
||||
},
|
||||
}).register('addListForm');
|
||||
|
||||
Template.boardBody.helpers({
|
||||
canSeeAddList() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
});
|
||||
}).register('boardBody');
|
||||
@@ -1,8 +1,11 @@
|
||||
@import 'nib'
|
||||
|
||||
position()
|
||||
if arguments[0] == cover
|
||||
position: absolute
|
||||
if arguments[0] == cover || arguments[0] == fixed-cover
|
||||
if arguments[0] == cover
|
||||
position: absolute
|
||||
else
|
||||
position: fixed
|
||||
left: 0
|
||||
right: 0
|
||||
top: 0
|
||||
@@ -12,26 +15,18 @@ position()
|
||||
|
||||
.board-wrapper
|
||||
position: cover
|
||||
overflow-y: hidden;
|
||||
|
||||
.board-canvas
|
||||
position: cover
|
||||
transition: margin .1s
|
||||
overflow-y: auto;
|
||||
|
||||
&.is-sibling-sidebar-open
|
||||
margin-right: 248px
|
||||
|
||||
.lists
|
||||
align-items: flex-start
|
||||
display: flex
|
||||
flex-direction: row
|
||||
margin: 0 0 10px
|
||||
padding: 0 40px 5px 0
|
||||
overflow-x: auto
|
||||
overflow-y: hidden
|
||||
position: cover
|
||||
|
||||
.board-overlay
|
||||
position: cover
|
||||
position: fixed-cover
|
||||
top: -100px
|
||||
right: -400px
|
||||
background: black
|
||||
@@ -43,3 +38,17 @@ position()
|
||||
.open-minicard-composer,
|
||||
.minicard-wrapper.is-checked
|
||||
display: none
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
.board-wrapper
|
||||
|
||||
.board-canvas
|
||||
|
||||
.swimlane
|
||||
border-bottom: 1px solid #CCC
|
||||
display: flex
|
||||
flex-direction: column
|
||||
margin: 0
|
||||
padding: 0 40px 0px 0
|
||||
overflow-x: hidden
|
||||
overflow-y: auto
|
||||
@@ -51,11 +51,25 @@ setBoardColor(color)
|
||||
&:not(.is-checked) + .minicard:hover:not(.minicard-composer)
|
||||
background: lighten(color, 97%)
|
||||
|
||||
.toggle-label
|
||||
|
||||
&:after
|
||||
background-color: darken(color, 20%)
|
||||
|
||||
.toggle-switch:checked ~ .toggle-label
|
||||
background-color: lighten(color, 20%)
|
||||
|
||||
&:after
|
||||
background-color: darken(color, 20%)
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
&.pop-over .header
|
||||
background: color
|
||||
color: white
|
||||
|
||||
&#header ul li.current, &#header-quick-access ul li.current
|
||||
border-bottom: 4px solid lighten(color, 20%)
|
||||
|
||||
.board-color-nephritis
|
||||
setBoardColor(#27AE60)
|
||||
|
||||
|
||||
@@ -71,6 +71,12 @@ template(name="boardHeaderBar")
|
||||
title="{{_ 'log-in'}}")
|
||||
i.fa.fa-sign-in
|
||||
span {{_ 'log-in'}}
|
||||
|
||||
if isSandstorm
|
||||
if currentUser
|
||||
a.board-header-btn.js-open-archived-board
|
||||
i.fa.fa-archive
|
||||
span {{_ 'archives'}}
|
||||
|
||||
a.board-header-btn.js-open-filter-view(
|
||||
title="{{#if Filter.isActive}}{{_ 'filter-on-desc'}}{{else}}{{_ 'filter'}}{{/if}}"
|
||||
@@ -81,6 +87,15 @@ template(name="boardHeaderBar")
|
||||
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
|
||||
i.fa.fa-times-thin
|
||||
|
||||
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
|
||||
i.fa.fa-search
|
||||
span {{_ 'search'}}
|
||||
|
||||
a.board-header-btn.js-toggle-board-view(
|
||||
title="{{_ 'board-view'}}")
|
||||
i.fa.fa-th-large
|
||||
span {{_ currentBoard.view}}
|
||||
|
||||
if canModifyBoard
|
||||
a.board-header-btn.js-multiselection-activate(
|
||||
title="{{#if MultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
|
||||
@@ -112,6 +127,12 @@ template(name="boardMenuPopup")
|
||||
ul.pop-over-list
|
||||
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
|
||||
li: a.js-archive-board {{_ 'archive-board'}}
|
||||
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
|
||||
if isSandstorm
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
|
||||
li: a.js-import-board {{_ 'import-board-c'}}
|
||||
|
||||
template(name="boardVisibilityList")
|
||||
ul.pop-over-list
|
||||
@@ -191,8 +212,14 @@ template(name="createBoard")
|
||||
input.primary.wide(type="submit" value="{{_ 'create'}}")
|
||||
span.quiet
|
||||
| {{_ 'or'}}
|
||||
a(href="{{pathFor 'import'}}") {{_ 'import-board'}}
|
||||
a.js-import-board {{_ 'import-board'}}
|
||||
|
||||
template(name="chooseBoardSource")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
|
||||
li
|
||||
a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
|
||||
|
||||
template(name="boardChangeTitlePopup")
|
||||
form
|
||||
@@ -207,3 +234,23 @@ template(name="boardChangeTitlePopup")
|
||||
template(name="archiveBoardPopup")
|
||||
p {{_ 'close-board-pop'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
|
||||
|
||||
template(name="outgoingWebhooksPopup")
|
||||
each integrations
|
||||
form.integration-form
|
||||
if title
|
||||
h4 {{title}}
|
||||
else
|
||||
h4 {{_ 'no-name'}}
|
||||
label
|
||||
| URL
|
||||
input.js-outgoing-webhooks-url(type="text" name="url" value=url)
|
||||
input(type="hidden" value=_id name="id")
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
form.integration-form
|
||||
h4
|
||||
| {{_ 'new-outgoing-webhook'}}
|
||||
label
|
||||
| URL
|
||||
input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -13,19 +13,25 @@ Template.boardMenuPopup.events({
|
||||
// confirm that the board was successfully archived.
|
||||
FlowRouter.go('home');
|
||||
}),
|
||||
'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'),
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
});
|
||||
|
||||
// Template.boardMenuPopup.helpers({
|
||||
// exportUrl() {
|
||||
// const boardId = Session.get('currentBoard');
|
||||
// const loginToken = Accounts._storedLoginToken();
|
||||
// return FlowRouter.url(`api/boards/${boardId}?authToken=${loginToken}`);
|
||||
// },
|
||||
// exportFilename() {
|
||||
// const boardId = Session.get('currentBoard');
|
||||
// return `wekan-export-board-${boardId}.json`;
|
||||
// },
|
||||
// });
|
||||
Template.boardMenuPopup.helpers({
|
||||
exportUrl() {
|
||||
const params = {
|
||||
boardId: Session.get('currentBoard'),
|
||||
};
|
||||
const queryParams = {
|
||||
authToken: Accounts._storedLoginToken(),
|
||||
};
|
||||
return FlowRouter.path('/api/boards/:boardId/export', params, queryParams);
|
||||
},
|
||||
exportFilename() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return `wekan-export-board-${boardId}.json`;
|
||||
},
|
||||
});
|
||||
|
||||
Template.boardChangeTitlePopup.events({
|
||||
submit(evt, tpl) {
|
||||
@@ -52,10 +58,6 @@ BlazeComponent.extendComponent({
|
||||
return user && user.hasStarred(boardId);
|
||||
},
|
||||
|
||||
isMiniScreen() {
|
||||
return Utils.isMiniScreen();
|
||||
},
|
||||
|
||||
// Only show the star counter if the number of star is greater than 2
|
||||
showStarCounter() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
@@ -71,6 +73,25 @@ BlazeComponent.extendComponent({
|
||||
'click .js-open-board-menu': Popup.open('boardMenu'),
|
||||
'click .js-change-visibility': Popup.open('boardChangeVisibility'),
|
||||
'click .js-watch-board': Popup.open('boardChangeWatch'),
|
||||
'click .js-open-archived-board'() {
|
||||
Modal.open('archivedBoards');
|
||||
},
|
||||
'click .js-toggle-board-view'() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
if (currentBoard.view === 'board-view-swimlanes') {
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
view: 'board-view-lists',
|
||||
},
|
||||
});
|
||||
} else if (currentBoard.view === 'board-view-lists') {
|
||||
Boards.update(currentBoard._id, {
|
||||
$set: {
|
||||
view: 'board-view-swimlanes',
|
||||
},
|
||||
});
|
||||
}
|
||||
},
|
||||
'click .js-open-filter-view'() {
|
||||
Sidebar.setView('filter');
|
||||
},
|
||||
@@ -79,6 +100,9 @@ BlazeComponent.extendComponent({
|
||||
Sidebar.setView();
|
||||
Filter.reset();
|
||||
},
|
||||
'click .js-open-search-view'() {
|
||||
Sidebar.setView('search');
|
||||
},
|
||||
'click .js-multiselection-activate'() {
|
||||
const currentCard = Session.get('currentCard');
|
||||
MultiSelection.activate();
|
||||
@@ -159,6 +183,11 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
permission: visibility,
|
||||
}));
|
||||
|
||||
Swimlanes.insert({
|
||||
title: 'Default',
|
||||
boardId: this.boardId.get(),
|
||||
});
|
||||
|
||||
Utils.goBoardId(this.boardId.get());
|
||||
},
|
||||
|
||||
@@ -170,10 +199,17 @@ const CreateBoard = BlazeComponent.extendComponent({
|
||||
'click .js-change-visibility': this.toggleVisibilityMenu,
|
||||
'click .js-import': Popup.open('boardImportBoard'),
|
||||
submit: this.onSubmit,
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
}];
|
||||
},
|
||||
}).register('createBoardPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
return 'chooseBoardSource';
|
||||
},
|
||||
}).register('chooseBoardSourcePopup');
|
||||
|
||||
(class HeaderBarCreateBoard extends CreateBoard {
|
||||
onSubmit(evt) {
|
||||
super.onSubmit(evt);
|
||||
@@ -223,3 +259,50 @@ BlazeComponent.extendComponent({
|
||||
}];
|
||||
},
|
||||
}).register('boardChangeWatchPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
integrations() {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return Integrations.find({ boardId: `${boardId}` }).fetch();
|
||||
},
|
||||
|
||||
integration(id) {
|
||||
const boardId = Session.get('currentBoard');
|
||||
return Integrations.findOne({ _id: id, boardId: `${boardId}` });
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'submit'(evt) {
|
||||
evt.preventDefault();
|
||||
const url = evt.target.url.value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
let id = null;
|
||||
let integration = null;
|
||||
if (evt.target.id) {
|
||||
id = evt.target.id.value;
|
||||
integration = this.integration(id);
|
||||
if (url) {
|
||||
Integrations.update(integration._id, {
|
||||
$set: {
|
||||
url: `${url}`,
|
||||
},
|
||||
});
|
||||
} else {
|
||||
Integrations.remove(integration._id);
|
||||
}
|
||||
} else if (url) {
|
||||
Integrations.insert({
|
||||
userId: Meteor.userId(),
|
||||
enabled: true,
|
||||
type: 'outgoing-webhooks',
|
||||
url: `${url}`,
|
||||
boardId: `${boardId}`,
|
||||
activities: ['all'],
|
||||
});
|
||||
}
|
||||
Popup.close();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('outgoingWebhooksPopup');
|
||||
@@ -0,0 +1,3 @@
|
||||
.integration-form
|
||||
padding: 5px
|
||||
border-bottom: 1px solid #ccc
|
||||
@@ -20,6 +20,12 @@ template(name="boardList")
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
|
||||
p.board-list-item-desc= description
|
||||
li.js-add-board
|
||||
a.board-list-item.label {{_ 'add-board'}}
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
boards() {
|
||||
return Boards.find({
|
||||
archived: false,
|
||||
@@ -13,6 +19,16 @@ BlazeComponent.extendComponent({
|
||||
return user && user.hasStarred(this.currentData()._id);
|
||||
},
|
||||
|
||||
hasOvertimeCards() {
|
||||
subManager.subscribe('board', this.currentData()._id);
|
||||
return this.currentData().hasOvertimeCards();
|
||||
},
|
||||
|
||||
hasSpentTimeCards() {
|
||||
subManager.subscribe('board', this.currentData()._id);
|
||||
return this.currentData().hasSpentTimeCards();
|
||||
},
|
||||
|
||||
isInvited() {
|
||||
const user = Meteor.user();
|
||||
return user && user.isInvitedTo(this.currentData()._id);
|
||||
|
||||
@@ -17,6 +17,7 @@ $spaceBetweenTiles = 16px
|
||||
opacity: 1
|
||||
|
||||
.board-list-item
|
||||
overflow: hidden;
|
||||
background-color: #999
|
||||
color: #f6f6f6
|
||||
height: 90px
|
||||
@@ -73,6 +74,23 @@ $spaceBetweenTiles = 16px
|
||||
transition-duration: .15s
|
||||
transition-property: color, font-size, background
|
||||
|
||||
.fa-circle
|
||||
bottom: 0;
|
||||
font-size: 10px;
|
||||
height: 10px;
|
||||
line-height: 10px;
|
||||
padding: 9px 9px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
transition-duration: .15s
|
||||
transition-property: color, font-size, background
|
||||
|
||||
.has-overtime-card-active
|
||||
color: #eb4646 !important
|
||||
|
||||
.no-overtime-card-active
|
||||
color: #3cb500 !important
|
||||
|
||||
.is-star-active
|
||||
color: white
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ template(name="previewClipboardImagePopup")
|
||||
button.primary.js-upload-pasted-image {{_ 'upload'}}
|
||||
|
||||
template(name="previewAttachedImagePopup")
|
||||
img.preview-large-image.js-large-image-clicked(src="{{pathFor url}}")
|
||||
img.preview-large-image.js-large-image-clicked(src="{{url}}")
|
||||
|
||||
template(name="attachmentDeletePopup")
|
||||
p {{_ "attachment-delete-pop"}}
|
||||
@@ -21,11 +21,11 @@ template(name="attachmentDeletePopup")
|
||||
template(name="attachmentsGalery")
|
||||
.attachments-galery
|
||||
each attachments
|
||||
a.attachment-item.js-open-viewer(title="{{_ 'added'}} {{ moment uploadedAt }}")
|
||||
.attachment-thumbnail
|
||||
.attachment-item
|
||||
a.attachment-thumbnail.swipebox(href="{{url}}" title="{{name}}")
|
||||
if isUploaded
|
||||
if isImage
|
||||
img.attachment-thumbnail-img.js-preview-image(src="{{pathFor url}}")
|
||||
img.attachment-thumbnail-img(src="{{url}}")
|
||||
else
|
||||
span.attachment-thumbnail-ext= extension
|
||||
else
|
||||
|
||||
@@ -11,9 +11,6 @@ Template.attachmentsGalery.events({
|
||||
'click .js-download'(event) {
|
||||
event.stopPropagation();
|
||||
},
|
||||
'click .js-open-viewer'() {
|
||||
// XXX Not implemented!
|
||||
},
|
||||
'click .js-add-cover'() {
|
||||
Cards.findOne(this.cardId).setCover(this._id);
|
||||
},
|
||||
@@ -62,8 +59,14 @@ Template.cardAttachmentsPopup.events({
|
||||
const file = new FS.File(f);
|
||||
file.boardId = card.boardId;
|
||||
file.cardId = card._id;
|
||||
file.userId = Meteor.userId();
|
||||
|
||||
const attachment = Attachments.insert(file);
|
||||
|
||||
if (attachment && attachment._id && attachment.isImage()) {
|
||||
card.setCover(attachment._id);
|
||||
}
|
||||
|
||||
Attachments.insert(file);
|
||||
Popup.close();
|
||||
});
|
||||
},
|
||||
@@ -109,7 +112,13 @@ Template.previewClipboardImagePopup.events({
|
||||
file.updatedAt(new Date());
|
||||
file.boardId = card.boardId;
|
||||
file.cardId = card._id;
|
||||
Attachments.insert(file);
|
||||
file.userId = Meteor.userId();
|
||||
const attachment = Attachments.insert(file);
|
||||
|
||||
if (attachment && attachment._id && attachment.isImage()) {
|
||||
card.setCover(attachment._id);
|
||||
}
|
||||
|
||||
pastedResults = null;
|
||||
$(document.body).pasteImageReader(() => {});
|
||||
Popup.close();
|
||||
|
||||
@@ -58,7 +58,28 @@
|
||||
|
||||
.preview-clipboard-image
|
||||
width: 280px
|
||||
max-width: 100%;
|
||||
height: 200px
|
||||
display: block
|
||||
border: 1px solid black
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2)
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
.attachments-galery
|
||||
flex-direction
|
||||
row
|
||||
.attachment-item
|
||||
width: 50% - 2%
|
||||
|
||||
.attachment-thumbnail
|
||||
height: 130px
|
||||
.attachment-details
|
||||
font-size: 1.1em
|
||||
|
||||
@media screen and (max-width: 360px)
|
||||
.attachments-galery
|
||||
.attachment-item
|
||||
width: 100%
|
||||
|
||||
.attachment-thumbnail
|
||||
height: 200px
|
||||
@@ -171,11 +171,12 @@ class CardStartDate extends CardDate {
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'start-date' + ' ';
|
||||
if (this.date.get().isBefore(this.now.get(), 'minute') &&
|
||||
this.now.get().isBefore(this.data().dueAt)) {
|
||||
return 'current';
|
||||
classes += 'current';
|
||||
}
|
||||
return '';
|
||||
return classes;
|
||||
}
|
||||
|
||||
showTitle() {
|
||||
@@ -200,13 +201,14 @@ class CardDueDate extends CardDate {
|
||||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'due-date' + ' ';
|
||||
if (this.now.get().diff(this.date.get(), 'days') >= 2)
|
||||
return 'long-overdue';
|
||||
classes += 'long-overdue';
|
||||
else if (this.now.get().diff(this.date.get(), 'minute') >= 0)
|
||||
return 'due';
|
||||
classes += 'due';
|
||||
else if (this.now.get().diff(this.date.get(), 'days') >= -1)
|
||||
return 'almost-due';
|
||||
return '';
|
||||
classes += 'almost-due';
|
||||
return classes;
|
||||
}
|
||||
|
||||
showTitle() {
|
||||
|
||||
@@ -49,10 +49,20 @@
|
||||
&:hover, &.is-active
|
||||
background-color: darken(#fd5d47, 7)
|
||||
|
||||
&.due-date
|
||||
time
|
||||
&::before
|
||||
content: "\f090" // symbol: fa-sign-in
|
||||
|
||||
&.start-date
|
||||
time
|
||||
&::before
|
||||
content: "\f08b" // symbol: fa-sign-out
|
||||
|
||||
time
|
||||
&::before
|
||||
font: normal normal normal 14px/1 FontAwesome
|
||||
font-size: inherit
|
||||
-webkit-font-smoothing: antialiased
|
||||
content: "\f017" // clock symbol
|
||||
margin-right: 0.3em
|
||||
margin-right: 0.3em
|
||||
|
||||
@@ -9,9 +9,10 @@ template(name="cardDetails")
|
||||
a.fa.fa-navicon.card-details-menu.js-open-card-details-menu
|
||||
h2.card-details-title.js-card-title(
|
||||
class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
|
||||
= title
|
||||
if isWatching
|
||||
i.fa.fa-eye.card-details-watch
|
||||
+viewer
|
||||
= title
|
||||
if isWatching
|
||||
i.fa.fa-eye.card-details-watch
|
||||
|
||||
if archived
|
||||
p.warning {{_ 'card-archived'}}
|
||||
@@ -45,6 +46,14 @@ template(name="cardDetails")
|
||||
h3.card-details-item-title {{_ 'card-due'}}
|
||||
+cardDueDate
|
||||
|
||||
.card-details-items
|
||||
if spentTime
|
||||
.card-details-item.card-details-item-spent
|
||||
if isOvertime
|
||||
h3.card-details-item-title {{_ 'overtime-hours'}}
|
||||
else
|
||||
h3.card-details-item-title {{_ 'spent-time-hours'}}
|
||||
+cardSpentTime
|
||||
|
||||
//- XXX We should use "editable" to avoid repetiting ourselves
|
||||
if canModifyCard
|
||||
@@ -76,16 +85,24 @@ template(name="cardDetails")
|
||||
hr
|
||||
+checklists(cardId = _id)
|
||||
|
||||
if attachments.count
|
||||
hr
|
||||
h2
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
hr
|
||||
h2
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
|
||||
+attachmentsGalery
|
||||
+attachmentsGalery
|
||||
|
||||
hr
|
||||
h2 {{ _ 'activity'}}
|
||||
.activity-title
|
||||
h2 {{ _ '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
|
||||
@@ -109,6 +126,7 @@ template(name="cardDetailsActionsPopup")
|
||||
li: a.js-attachments {{_ 'card-edit-attachments'}}
|
||||
li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
||||
li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||
li: a.js-spent-time {{_ 'editCardSpentTimePopup-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
|
||||
@@ -116,12 +134,58 @@ template(name="cardDetailsActionsPopup")
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-move-card {{_ 'moveCardPopup-title'}}
|
||||
li: a.js-copy-card {{_ 'copyCardPopup-title'}}
|
||||
li: a.js-copy-checklist-cards {{_ 'copyChecklistToManyCardsPopup-title'}}
|
||||
unless archived
|
||||
li: a.js-archive {{_ 'archive-card'}}
|
||||
li: a.js-more {{_ 'cardMorePopup-title'}}
|
||||
|
||||
template(name="moveCardPopup")
|
||||
+boardLists
|
||||
if isSandstorm
|
||||
+boardLists
|
||||
else
|
||||
+boardsAndLists
|
||||
|
||||
template(name="copyCardPopup")
|
||||
label(for='copy-card-title') {{_ 'title'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
= title
|
||||
if isSandstorm
|
||||
+boardLists
|
||||
else
|
||||
+boardsAndLists
|
||||
|
||||
|
||||
template(name="copyChecklistToManyCardsPopup")
|
||||
label(for='copy-checklist-cards-title') {{_ 'copyChecklistToManyCardsPopup-instructions'}}:
|
||||
textarea#copy-card-title.minicard-composer-textarea.js-card-title(autofocus)
|
||||
| {{_ 'copyChecklistToManyCardsPopup-format'}}
|
||||
if isSandstorm
|
||||
+boardLists
|
||||
else
|
||||
+boardsAndLists
|
||||
|
||||
template(name="boardsAndLists")
|
||||
label {{_ 'boards'}}:
|
||||
select.js-select-boards
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'swimlanes'}}:
|
||||
select.js-select-swimlanes
|
||||
each swimlanes
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
label {{_ 'lists'}}:
|
||||
select.js-select-lists
|
||||
each aBoardLists
|
||||
option(value="{{_id}}") {{title}}
|
||||
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-done {{_ 'done'}}
|
||||
|
||||
template(name="cardMembersPopup")
|
||||
ul.pop-over-list.js-card-member-list
|
||||
@@ -141,7 +205,10 @@ template(name="cardMorePopup")
|
||||
span {{_ 'link-card'}}
|
||||
= ' '
|
||||
i.fa.colorful(class="{{#if board.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
||||
input.inline-input(type="text" readonly value="{{ rootUrl }}")
|
||||
input.inline-input(type="text" id="cardURL" readonly value="{{ absoluteUrl }}")
|
||||
button.js-copy-card-link-to-clipboard(class="btn") {{_ 'copy-card-link-to-clipboard'}}
|
||||
span.clearfix
|
||||
br
|
||||
| {{_ 'added'}}
|
||||
span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
|
||||
a.js-delete(title="{{_ 'card-delete-notice'}}") {{_ 'delete'}}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
const subManager = new SubsManager();
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling, Mixins.PerfectScrollbar];
|
||||
@@ -18,9 +20,11 @@ BlazeComponent.extendComponent({
|
||||
|
||||
onCreated() {
|
||||
this.isLoaded = new ReactiveVar(false);
|
||||
this.parentComponent().showOverlay.set(true);
|
||||
this.parentComponent().mouseHasEnterCardDetails = false;
|
||||
this.parentComponent().parentComponent().showOverlay.set(true);
|
||||
this.parentComponent().parentComponent().mouseHasEnterCardDetails = false;
|
||||
this.calculateNextPeak();
|
||||
|
||||
Meteor.subscribe('unsaved-edits');
|
||||
},
|
||||
|
||||
isWatching() {
|
||||
@@ -28,16 +32,20 @@ BlazeComponent.extendComponent({
|
||||
return card.findWatcher(Meteor.userId());
|
||||
},
|
||||
|
||||
hiddenSystemMessages() {
|
||||
return Meteor.user().hasHiddenSystemMessages();
|
||||
},
|
||||
|
||||
canModifyCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
|
||||
scrollParentContainer() {
|
||||
const cardPanelWidth = 510;
|
||||
const bodyBoardComponent = this.parentComponent();
|
||||
const bodyBoardComponent = this.parentComponent().parentComponent();
|
||||
|
||||
const $cardContainer = bodyBoardComponent.$('.js-lists');
|
||||
const $cardView = this.$(this.firstNode());
|
||||
const $cardContainer = bodyBoardComponent.$('.js-swimlanes');
|
||||
const cardContainerScroll = $cardContainer.scrollLeft();
|
||||
const cardContainerWidth = $cardContainer.width();
|
||||
|
||||
@@ -47,7 +55,7 @@ BlazeComponent.extendComponent({
|
||||
let offset = false;
|
||||
if (cardViewStart < 0) {
|
||||
offset = cardViewStart;
|
||||
} else if(cardViewEnd > cardContainerWidth) {
|
||||
} else if (cardViewEnd > cardContainerWidth) {
|
||||
offset = cardViewEnd - cardContainerWidth;
|
||||
}
|
||||
|
||||
@@ -61,7 +69,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
onDestroyed() {
|
||||
this.parentComponent().showOverlay.set(false);
|
||||
this.parentComponent().parentComponent().showOverlay.set(false);
|
||||
},
|
||||
|
||||
events() {
|
||||
@@ -76,16 +84,16 @@ BlazeComponent.extendComponent({
|
||||
|
||||
return [{
|
||||
...events,
|
||||
'click .js-close-card-details'() {
|
||||
'click .js-close-card-details' () {
|
||||
Utils.goBoardId(this.data().boardId);
|
||||
},
|
||||
'click .js-open-card-details-menu': Popup.open('cardDetailsActions'),
|
||||
'submit .js-card-description'(evt) {
|
||||
'submit .js-card-description' (evt) {
|
||||
evt.preventDefault();
|
||||
const description = this.currentComponent().getValue();
|
||||
this.data().setDescription(description);
|
||||
},
|
||||
'submit .js-card-details-title'(evt) {
|
||||
'submit .js-card-details-title' (evt) {
|
||||
evt.preventDefault();
|
||||
const title = this.currentComponent().getValue().trim();
|
||||
if (title) {
|
||||
@@ -95,9 +103,12 @@ BlazeComponent.extendComponent({
|
||||
'click .js-member': Popup.open('cardMember'),
|
||||
'click .js-add-members': Popup.open('cardMembers'),
|
||||
'click .js-add-labels': Popup.open('cardLabels'),
|
||||
'mouseenter .js-card-details'() {
|
||||
this.parentComponent().showOverlay.set(true);
|
||||
this.parentComponent().mouseHasEnterCardDetails = true;
|
||||
'mouseenter .js-card-details' () {
|
||||
this.parentComponent().parentComponent().showOverlay.set(true);
|
||||
this.parentComponent().parentComponent().mouseHasEnterCardDetails = true;
|
||||
},
|
||||
'click #toggleButton'() {
|
||||
Meteor.call('toggleSystemMessages');
|
||||
},
|
||||
}];
|
||||
},
|
||||
@@ -156,24 +167,27 @@ Template.cardDetailsActionsPopup.events({
|
||||
'click .js-attachments': Popup.open('cardAttachments'),
|
||||
'click .js-start-date': Popup.open('editCardStartDate'),
|
||||
'click .js-due-date': Popup.open('editCardDueDate'),
|
||||
'click .js-spent-time': Popup.open('editCardSpentTime'),
|
||||
'click .js-move-card': Popup.open('moveCard'),
|
||||
'click .js-move-card-to-top'(evt) {
|
||||
'click .js-copy-card': Popup.open('copyCard'),
|
||||
'click .js-copy-checklist-cards': Popup.open('copyChecklistToManyCards'),
|
||||
'click .js-move-card-to-top' (evt) {
|
||||
evt.preventDefault();
|
||||
const minOrder = _.min(this.list().cards().map((c) => c.sort));
|
||||
this.move(this.listId, minOrder - 1);
|
||||
const minOrder = _.min(this.list().cards(this.swimlaneId).map((c) => c.sort));
|
||||
this.move(this.swimlaneId, this.listId, minOrder - 1);
|
||||
},
|
||||
'click .js-move-card-to-bottom'(evt) {
|
||||
'click .js-move-card-to-bottom' (evt) {
|
||||
evt.preventDefault();
|
||||
const maxOrder = _.max(this.list().cards().map((c) => c.sort));
|
||||
this.move(this.listId, maxOrder + 1);
|
||||
const maxOrder = _.max(this.list().cards(this.swimlaneId).map((c) => c.sort));
|
||||
this.move(this.swimlaneId, this.listId, maxOrder + 1);
|
||||
},
|
||||
'click .js-archive'(evt) {
|
||||
'click .js-archive' (evt) {
|
||||
evt.preventDefault();
|
||||
this.archive();
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-more': Popup.open('cardMore'),
|
||||
'click .js-toggle-watch-card'() {
|
||||
'click .js-toggle-watch-card' () {
|
||||
const currentCard = this;
|
||||
const level = currentCard.findWatcher(Meteor.userId()) ? null : 'watching';
|
||||
Meteor.call('watch', 'card', currentCard._id, level, (err, ret) => {
|
||||
@@ -182,32 +196,197 @@ Template.cardDetailsActionsPopup.events({
|
||||
},
|
||||
});
|
||||
|
||||
Template.editCardTitleForm.onRendered(function() {
|
||||
Template.editCardTitleForm.onRendered(function () {
|
||||
autosize(this.$('.js-edit-card-title'));
|
||||
});
|
||||
|
||||
Template.editCardTitleForm.events({
|
||||
'keydown .js-edit-card-title'(evt) {
|
||||
'keydown .js-edit-card-title' (evt) {
|
||||
// If enter key was pressed, submit the data
|
||||
if (evt.keyCode === 13) {
|
||||
// Unless the shift key is also being pressed
|
||||
if (evt.keyCode === 13 && !evt.shiftKey) {
|
||||
$('.js-submit-edit-card-title-form').click();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.moveCardPopup.events({
|
||||
'click .js-select-list'() {
|
||||
'click .js-done' () {
|
||||
// XXX We should *not* get the currentCard from the global state, but
|
||||
// instead from a “component” state.
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
const newListId = this._id;
|
||||
card.move(newListId);
|
||||
const lSelect = $('.js-select-lists')[0];
|
||||
const newListId = lSelect.options[lSelect.selectedIndex].value;
|
||||
const slSelect = $('.js-select-swimlanes')[0];
|
||||
card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
|
||||
card.move(card.swimlaneId, newListId, 0);
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
subManager.subscribe('board', Session.get('currentBoard'));
|
||||
this.selectedBoardId = new ReactiveVar(Session.get('currentBoard'));
|
||||
},
|
||||
|
||||
boards() {
|
||||
const boards = Boards.find({
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
}, {
|
||||
sort: ['title'],
|
||||
});
|
||||
return boards;
|
||||
},
|
||||
|
||||
swimlanes() {
|
||||
const board = Boards.findOne(this.selectedBoardId.get());
|
||||
return board.swimlanes();
|
||||
},
|
||||
|
||||
aBoardLists() {
|
||||
const board = Boards.findOne(this.selectedBoardId.get());
|
||||
return board.lists();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'change .js-select-boards'(evt) {
|
||||
this.selectedBoardId.set($(evt.currentTarget).val());
|
||||
subManager.subscribe('board', this.selectedBoardId.get());
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('boardsAndLists');
|
||||
|
||||
Template.copyCardPopup.events({
|
||||
'click .js-done'() {
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
const oldId = card._id;
|
||||
card._id = null;
|
||||
const lSelect = $('.js-select-lists')[0];
|
||||
card.listId = lSelect.options[lSelect.selectedIndex].value;
|
||||
const slSelect = $('.js-select-swimlanes')[0];
|
||||
card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
|
||||
const bSelect = $('.js-select-boards')[0];
|
||||
card.boardId = bSelect.options[bSelect.selectedIndex].value;
|
||||
const textarea = $('#copy-card-title');
|
||||
const title = textarea.val().trim();
|
||||
// insert new card to the bottom of new list
|
||||
card.sort = Lists.findOne(card.listId).cards().count();
|
||||
|
||||
if (title) {
|
||||
card.title = title;
|
||||
card.coverId = '';
|
||||
const _id = Cards.insert(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.
|
||||
// See https://github.com/wekan/wekan/issues/80
|
||||
Filter.addException(_id);
|
||||
|
||||
// copy checklists
|
||||
let cursor = Checklists.find({cardId: oldId});
|
||||
cursor.forEach(function() {
|
||||
'use strict';
|
||||
const checklist = arguments[0];
|
||||
checklist.cardId = _id;
|
||||
checklist._id = null;
|
||||
Checklists.insert(checklist);
|
||||
});
|
||||
|
||||
// copy card comments
|
||||
cursor = CardComments.find({cardId: oldId});
|
||||
cursor.forEach(function () {
|
||||
'use strict';
|
||||
const comment = arguments[0];
|
||||
comment.cardId = _id;
|
||||
comment._id = null;
|
||||
CardComments.insert(comment);
|
||||
});
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.copyChecklistToManyCardsPopup.events({
|
||||
'click .js-select-list' (evt) {
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
const oldId = card._id;
|
||||
card._id = null;
|
||||
card.listId = this._id;
|
||||
const list = Lists.findOne(card.listId);
|
||||
card.boardId = list.boardId;
|
||||
const textarea = $(evt.currentTarget).parents('.content').find('textarea');
|
||||
const titleEntry = textarea.val().trim();
|
||||
// insert new card to the bottom of new list
|
||||
card.sort = Lists.findOne(this._id).cards().count();
|
||||
|
||||
if (titleEntry) {
|
||||
const titleList = JSON.parse(titleEntry);
|
||||
for (let i = 0; i < titleList.length; i++){
|
||||
const obj = titleList[i];
|
||||
card.title = obj.title;
|
||||
card.description = obj.description;
|
||||
card.coverId = '';
|
||||
const _id = Cards.insert(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.
|
||||
// See https://github.com/wekan/wekan/issues/80
|
||||
Filter.addException(_id);
|
||||
|
||||
// copy checklists
|
||||
let cursor = Checklists.find({cardId: oldId});
|
||||
cursor.forEach(function() {
|
||||
'use strict';
|
||||
const checklist = arguments[0];
|
||||
checklist.cardId = _id;
|
||||
checklist._id = null;
|
||||
Checklists.insert(checklist);
|
||||
});
|
||||
|
||||
// copy card comments
|
||||
cursor = CardComments.find({cardId: oldId});
|
||||
cursor.forEach(function () {
|
||||
'use strict';
|
||||
const comment = arguments[0];
|
||||
comment.cardId = _id;
|
||||
comment._id = null;
|
||||
CardComments.insert(comment);
|
||||
});
|
||||
}
|
||||
Popup.close();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
Template.cardMorePopup.events({
|
||||
'click .js-delete': Popup.afterConfirm('cardDelete', function() {
|
||||
'click .js-copy-card-link-to-clipboard' () {
|
||||
// Clipboard code from:
|
||||
// https://stackoverflow.com/questions/6300213/copy-selected-text-to-the-clipboard-without-using-flash-must-be-cross-browser
|
||||
const StringToCopyElement = document.getElementById('cardURL');
|
||||
StringToCopyElement.select();
|
||||
if (document.execCommand('copy')) {
|
||||
StringToCopyElement.blur();
|
||||
} else {
|
||||
document.getElementById('cardURL').selectionStart = 0;
|
||||
document.getElementById('cardURL').selectionEnd = 999;
|
||||
document.execCommand('copy');
|
||||
if (window.getSelection) {
|
||||
if (window.getSelection().empty) { // Chrome
|
||||
window.getSelection().empty();
|
||||
} else if (window.getSelection().removeAllRanges) { // Firefox
|
||||
window.getSelection().removeAllRanges();
|
||||
}
|
||||
} else if (document.selection) { // IE?
|
||||
document.selection.empty();
|
||||
}
|
||||
}
|
||||
},
|
||||
'click .js-delete': Popup.afterConfirm('cardDelete', function () {
|
||||
Popup.close();
|
||||
Cards.remove(this._id);
|
||||
Utils.goBoardId(this.boardId);
|
||||
@@ -216,8 +395,12 @@ Template.cardMorePopup.events({
|
||||
|
||||
// Close the card details pane by pressing escape
|
||||
EscapeActions.register('detailsPane',
|
||||
() => { Utils.goBoardId(Session.get('currentBoard')); },
|
||||
() => { return !Session.equals('currentCard', null); }, {
|
||||
() => {
|
||||
Utils.goBoardId(Session.get('currentBoard'));
|
||||
},
|
||||
() => {
|
||||
return !Session.equals('currentCard', null);
|
||||
}, {
|
||||
noClickEscapeOn: '.js-card-details,.board-sidebar,#header',
|
||||
}
|
||||
);
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
.card-details
|
||||
padding: 0 20px
|
||||
height: 100%
|
||||
flex-shrink: 0
|
||||
flex-basis: 470px
|
||||
will-change: flex-basis
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
template(name="editCardSpentTime")
|
||||
.edit-card-time
|
||||
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)
|
||||
label(for="overtime") {{_ 'overtime'}}
|
||||
a.js-toggle-overtime
|
||||
.materialCheckBox#overtime(class="{{#if card.isOvertime}}is-checked{{/if}}" name="overtime")
|
||||
|
||||
if error.get
|
||||
.warning {{_ error.get}}
|
||||
button.primary.wide.left.js-submit-time(type="submit") {{_ 'save'}}
|
||||
button.js-delete-time.negate.wide.right {{_ 'delete'}}
|
||||
|
||||
template(name="timeBadge")
|
||||
if canModifyCard
|
||||
a.js-edit-time.card-time(title="{{showTitle}}" class="{{#if isOvertime}}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}}")
|
||||
| {{showTime}}
|
||||
@@ -0,0 +1,81 @@
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
return 'editCardSpentTime';
|
||||
},
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.card = this.data();
|
||||
},
|
||||
toggleOvertime() {
|
||||
this.card.isOvertime = !this.card.isOvertime;
|
||||
$('#overtime .materialCheckBox').toggleClass('is-checked');
|
||||
|
||||
$('#overtime').toggleClass('is-checked');
|
||||
},
|
||||
storeTime(spentTime, isOvertime) {
|
||||
this.card.setSpentTime(spentTime);
|
||||
this.card.setOvertime(isOvertime);
|
||||
},
|
||||
deleteTime() {
|
||||
this.card.unsetSpentTime();
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
//TODO : need checking this portion
|
||||
'submit .edit-time'(evt) {
|
||||
evt.preventDefault();
|
||||
|
||||
const spentTime = parseFloat(evt.target.time.value);
|
||||
const isOvertime = this.card.isOvertime;
|
||||
|
||||
if (spentTime >= 0) {
|
||||
this.storeTime(spentTime, isOvertime);
|
||||
Popup.close();
|
||||
} else {
|
||||
this.error.set('invalid-time');
|
||||
evt.target.time.focus();
|
||||
}
|
||||
},
|
||||
'click .js-delete-time'(evt) {
|
||||
evt.preventDefault();
|
||||
this.deleteTime();
|
||||
Popup.close();
|
||||
},
|
||||
'click a.js-toggle-overtime': this.toggleOvertime,
|
||||
}];
|
||||
},
|
||||
}).register('editCardSpentTimePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
template() {
|
||||
return 'timeBadge';
|
||||
},
|
||||
onCreated() {
|
||||
const self = this;
|
||||
self.time = ReactiveVar();
|
||||
},
|
||||
showTitle() {
|
||||
if (this.data().isOvertime) {
|
||||
return `${TAPi18n.__('overtime')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||
} else {
|
||||
return `${TAPi18n.__('card-spent')} ${this.data().spentTime} ${TAPi18n.__('hours')}`;
|
||||
}
|
||||
},
|
||||
showTime() {
|
||||
return this.data().spentTime;
|
||||
},
|
||||
isOvertime() {
|
||||
return this.data().isOvertime;
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click .js-edit-time': Popup.open('editCardSpentTime'),
|
||||
}];
|
||||
},
|
||||
}).register('cardSpentTime');
|
||||
|
||||
Template.timeBadge.helpers({
|
||||
canModifyCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,17 @@
|
||||
.card-time
|
||||
display: block
|
||||
border-radius: 4px
|
||||
padding: 1px 3px
|
||||
color: #fff
|
||||
|
||||
background-color: #dbdbdb
|
||||
&:hover, &.is-active
|
||||
background-color: #b3b3b3
|
||||
|
||||
time
|
||||
&::before
|
||||
font: normal normal normal 14px/1 FontAwesome
|
||||
font-size: inherit
|
||||
-webkit-font-smoothing: antialiased
|
||||
content: "\f017" // clock symbol
|
||||
margin-right: 0.3em
|
||||
@@ -1,10 +1,16 @@
|
||||
template(name="checklists")
|
||||
h2 {{_ 'checklists'}}
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+checklistDeleteDialog(checklist = checklistToDelete)
|
||||
|
||||
|
||||
.card-checklist-items
|
||||
each checklist in currentCard.checklists
|
||||
+checklistDetail(checklist = checklist)
|
||||
|
||||
if canModifyCard
|
||||
+inlinedForm(classNames="js-add-checklist" cardId = cardId)
|
||||
+inlinedForm(autoclose=false classNames="js-add-checklist" cardId = cardId)
|
||||
+addChecklistItemForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
@@ -18,14 +24,31 @@ template(name="checklistDetail")
|
||||
.checklist-title
|
||||
.checkbox.fa.fa-check-square-o
|
||||
if canModifyCard
|
||||
a.js-delete-checklist {{_ "delete"}}...
|
||||
a.js-delete-checklist.toggle-delete-checklist-dialog {{_ "delete"}}...
|
||||
|
||||
span.checklist-stat(class="{{#if checklist.isFinished}}is-finished{{/if}}") {{checklist.finishedCount}}/{{checklist.itemCount}}
|
||||
if canModifyCard
|
||||
h2.title.js-open-inlined-form.is-editable {{checklist.title}}
|
||||
h2.title.js-open-inlined-form.is-editable
|
||||
+viewer
|
||||
= checklist.title
|
||||
else
|
||||
h2.title {{checklist.title}}
|
||||
h2.title
|
||||
+viewer
|
||||
= checklist.title
|
||||
+checklistItems(checklist = checklist)
|
||||
|
||||
template(name="checklistDeleteDialog")
|
||||
.js-confirm-checklist-delete
|
||||
p
|
||||
i(class="fa fa-exclamation-triangle" aria-hidden="true")
|
||||
p
|
||||
| {{_ 'confirm-checklist-delete-dialog'}}
|
||||
span {{checklist.title}}
|
||||
| ?
|
||||
.js-checklist-delete-buttons
|
||||
button.confirm-checklist-delete(type="button") {{_ 'delete'}}
|
||||
button.toggle-delete-checklist-dialog(type="button") {{_ 'cancel'}}
|
||||
|
||||
template(name="addChecklistItemForm")
|
||||
textarea.js-add-checklist-item(rows='1' autofocus)
|
||||
.edit-controls.clearfix
|
||||
@@ -46,14 +69,14 @@ template(name="editChecklistItemForm")
|
||||
a.js-delete-checklist-item {{_ "delete"}}...
|
||||
|
||||
template(name="checklistItems")
|
||||
.checklist-items
|
||||
each item in checklist.items
|
||||
.checklist-items.js-checklist-items
|
||||
each item in checklist.getItemsSorted
|
||||
+inlinedForm(classNames="js-edit-checklist-item" item = item checklist = checklist)
|
||||
+editChecklistItemForm(type = 'item' item = item checklist = checklist)
|
||||
else
|
||||
+itemDetail(item = item checklist = checklist)
|
||||
if canModifyCard
|
||||
+inlinedForm(classNames="js-add-checklist-item" checklist = checklist)
|
||||
+inlinedForm(autoclose=false classNames="js-add-checklist-item" checklist = checklist)
|
||||
+addChecklistItemForm
|
||||
else
|
||||
a.add-checklist-item.js-open-inlined-form
|
||||
@@ -61,11 +84,14 @@ template(name="checklistItems")
|
||||
| {{_ 'add-checklist-item'}}...
|
||||
|
||||
template(name='itemDetail')
|
||||
.item
|
||||
.item.js-checklist-item
|
||||
if canModifyCard
|
||||
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
.item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
|
||||
.item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
+viewer
|
||||
= item.title
|
||||
else
|
||||
.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
.item-title(class="{{#if item.isFinished }}is-checked{{/if}}") {{item.title}}
|
||||
|
||||
.item-title(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
+viewer
|
||||
= item.title
|
||||
@@ -1,13 +1,91 @@
|
||||
function initSorting(items) {
|
||||
items.sortable({
|
||||
tolerance: 'pointer',
|
||||
helper: 'clone',
|
||||
items: '.js-checklist-item:not(.placeholder)',
|
||||
axis: 'y',
|
||||
distance: 7,
|
||||
placeholder: 'placeholder',
|
||||
scroll: false,
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
},
|
||||
stop(evt, ui) {
|
||||
const parent = ui.item.parents('.js-checklist-items');
|
||||
const orderedItems = [];
|
||||
parent.find('.js-checklist-item').each(function(i, item) {
|
||||
const checklistItem = Blaze.getData(item).item;
|
||||
orderedItems.push(checklistItem._id);
|
||||
});
|
||||
items.sortable('cancel');
|
||||
const formerParent = ui.item.parents('.js-checklist-items');
|
||||
const checklist = Blaze.getData(parent.get(0)).checklist;
|
||||
const oldChecklist = Blaze.getData(formerParent.get(0)).checklist;
|
||||
if (oldChecklist._id !== checklist._id) {
|
||||
const currentItem = Blaze.getData(ui.item.get(0)).item;
|
||||
for (let i = 0; i < orderedItems.length; i++) {
|
||||
const itemId = orderedItems[i];
|
||||
if (itemId !== currentItem._id) continue;
|
||||
const newItem = {
|
||||
_id: checklist.getNewItemId(),
|
||||
title: currentItem.title,
|
||||
sort: i,
|
||||
isFinished: currentItem.isFinished,
|
||||
};
|
||||
checklist.addFullItem(newItem);
|
||||
orderedItems[i] = currentItem._id;
|
||||
oldChecklist.removeItem(itemId);
|
||||
}
|
||||
} else {
|
||||
checklist.sortItems(orderedItems);
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
Template.checklists.onRendered(function () {
|
||||
const self = BlazeComponent.getComponentForElement(this.firstNode);
|
||||
self.itemsDom = this.$('.card-checklist-items');
|
||||
initSorting(self.itemsDom);
|
||||
self.itemsDom.mousedown(function(evt) {
|
||||
evt.stopPropagation();
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember();
|
||||
}
|
||||
|
||||
// Disable sorting if the current user is not a board member
|
||||
self.autorun(() => {
|
||||
const $itemsDom = $(self.itemsDom);
|
||||
if ($itemsDom.data('sortable')) {
|
||||
$(self.itemsDom).sortable('option', 'disabled', !userIsMember());
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
|
||||
addChecklist(event) {
|
||||
event.preventDefault();
|
||||
const textarea = this.find('textarea.js-add-checklist-item');
|
||||
const title = textarea.value.trim();
|
||||
const cardId = this.currentData().cardId;
|
||||
Checklists.insert({
|
||||
cardId,
|
||||
title,
|
||||
});
|
||||
const card = Cards.findOne(cardId);
|
||||
|
||||
if (title) {
|
||||
Checklists.insert({
|
||||
cardId,
|
||||
title,
|
||||
sort: card.checklists().count(),
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.$('.add-checklist-item').last().click();
|
||||
}, 100);
|
||||
}
|
||||
textarea.value = '';
|
||||
textarea.focus();
|
||||
},
|
||||
|
||||
addChecklistItem(event) {
|
||||
@@ -15,7 +93,33 @@ BlazeComponent.extendComponent({
|
||||
const textarea = this.find('textarea.js-add-checklist-item');
|
||||
const title = textarea.value.trim();
|
||||
const checklist = this.currentData().checklist;
|
||||
checklist.addItem(title);
|
||||
|
||||
if (title) {
|
||||
checklist.addItem(title);
|
||||
}
|
||||
// We keep the form opened, empty it.
|
||||
textarea.value = '';
|
||||
textarea.focus();
|
||||
},
|
||||
|
||||
canModifyCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
|
||||
deleteChecklist() {
|
||||
const checklist = this.currentData().checklist;
|
||||
if (checklist && checklist._id) {
|
||||
Checklists.remove(checklist._id);
|
||||
this.toggleDeleteDialog.set(false);
|
||||
}
|
||||
},
|
||||
|
||||
deleteItem() {
|
||||
const checklist = this.currentData().checklist;
|
||||
const item = this.currentData().item;
|
||||
if (checklist && item && item._id) {
|
||||
checklist.removeItem(item._id);
|
||||
}
|
||||
},
|
||||
|
||||
editChecklist(event) {
|
||||
@@ -26,10 +130,6 @@ BlazeComponent.extendComponent({
|
||||
checklist.setTitle(title);
|
||||
},
|
||||
|
||||
canModifyCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
|
||||
editChecklistItem(event) {
|
||||
event.preventDefault();
|
||||
|
||||
@@ -40,24 +140,15 @@ BlazeComponent.extendComponent({
|
||||
checklist.editItem(itemId, title);
|
||||
},
|
||||
|
||||
deleteItem() {
|
||||
const checklist = this.currentData().checklist;
|
||||
const item = this.currentData().item;
|
||||
if (checklist && item && item._id) {
|
||||
checklist.removeItem(item._id);
|
||||
}
|
||||
},
|
||||
|
||||
deleteChecklist() {
|
||||
const checklist = this.currentData().checklist;
|
||||
if (checklist && checklist._id) {
|
||||
Checklists.remove(checklist._id);
|
||||
}
|
||||
onCreated() {
|
||||
this.toggleDeleteDialog = new ReactiveVar(false);
|
||||
this.checklistToDelete = null; //Store data context to pass to checklistDeleteDialog template
|
||||
},
|
||||
|
||||
pressKey(event) {
|
||||
//If user press enter key inside a form, submit it, so user doesn't have to leave keyboard to submit a form.
|
||||
if (event.keyCode === 13) {
|
||||
//If user press enter key inside a form, submit it
|
||||
//Unless the user is also holding down the 'shift' key
|
||||
if (event.keyCode === 13 && !event.shiftKey) {
|
||||
event.preventDefault();
|
||||
const $form = $(event.currentTarget).closest('form');
|
||||
$form.find('button[type=submit]').click();
|
||||
@@ -65,18 +156,50 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
events() {
|
||||
const events = {
|
||||
'click .toggle-delete-checklist-dialog'(event) {
|
||||
if($(event.target).hasClass('js-delete-checklist')){
|
||||
this.checklistToDelete = this.currentData().checklist; //Store data context
|
||||
}
|
||||
this.toggleDeleteDialog.set(!this.toggleDeleteDialog.get());
|
||||
},
|
||||
};
|
||||
|
||||
return [{
|
||||
...events,
|
||||
'submit .js-add-checklist': this.addChecklist,
|
||||
'submit .js-edit-checklist-title': this.editChecklist,
|
||||
'submit .js-add-checklist-item': this.addChecklistItem,
|
||||
'submit .js-edit-checklist-item': this.editChecklistItem,
|
||||
'click .js-delete-checklist-item': this.deleteItem,
|
||||
'click .js-delete-checklist': this.deleteChecklist,
|
||||
'click .confirm-checklist-delete': this.deleteChecklist,
|
||||
keydown: this.pressKey,
|
||||
}];
|
||||
},
|
||||
}).register('checklists');
|
||||
|
||||
Template.checklistDeleteDialog.onCreated(() => {
|
||||
const $cardDetails = this.$('.card-details');
|
||||
this.scrollState = { position: $cardDetails.scrollTop(), //save current scroll position
|
||||
top: false, //required for smooth scroll animation
|
||||
};
|
||||
//Callback's purpose is to only prevent scrolling after animation is complete
|
||||
$cardDetails.animate({ scrollTop: 0 }, 500, () => { this.scrollState.top = true; });
|
||||
|
||||
//Prevent scrolling while dialog is open
|
||||
$cardDetails.on('scroll', () => {
|
||||
if(this.scrollState.top) { //If it's already in position, keep it there. Otherwise let animation scroll
|
||||
$cardDetails.scrollTop(0);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.checklistDeleteDialog.onDestroyed(() => {
|
||||
const $cardDetails = this.$('.card-details');
|
||||
$cardDetails.off('scroll'); //Reactivate scrolling
|
||||
$cardDetails.animate( { scrollTop: this.scrollState.position });
|
||||
});
|
||||
|
||||
Template.itemDetail.helpers({
|
||||
canModifyCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
|
||||
@@ -38,6 +38,46 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
.js-delete-checklist
|
||||
@extends .delete-text
|
||||
|
||||
|
||||
.js-confirm-checklist-delete
|
||||
background-color: darken(white, 3%)
|
||||
position: absolute
|
||||
float: left;
|
||||
width: 60%
|
||||
margin-top: 0
|
||||
margin-left: 13%
|
||||
padding-bottom: 2%
|
||||
padding-left: 3%
|
||||
padding-right: 3%
|
||||
z-index: 17
|
||||
border-radius: 3px
|
||||
|
||||
p
|
||||
position: relative
|
||||
margin-top: 3%
|
||||
width: 100%
|
||||
text-align: center
|
||||
span
|
||||
font-weight: bold
|
||||
|
||||
i
|
||||
font-size: 2em
|
||||
|
||||
.js-checklist-delete-buttons
|
||||
position: relative
|
||||
padding: left 2% right 2%
|
||||
.confirm-checklist-delete
|
||||
margin-left: 12%
|
||||
float: left
|
||||
.toggle-delete-checklist-dialog
|
||||
margin-right: 12%
|
||||
float: right
|
||||
|
||||
#card-details-overlay
|
||||
top: 0
|
||||
bottom: -600px
|
||||
right: 0
|
||||
|
||||
.checklist-items
|
||||
margin: 0 0 0.5em 1.33em
|
||||
|
||||
@@ -46,6 +86,8 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
font-size: 1.1em
|
||||
margin-top: 3px
|
||||
display: flex
|
||||
&:hover
|
||||
background-color: darken(white, 8%)
|
||||
|
||||
.check-box
|
||||
margin-top: 5px
|
||||
@@ -54,6 +96,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
border-right: 2px solid #3cb500
|
||||
|
||||
.item-title
|
||||
flex: 1
|
||||
padding-left: 10px;
|
||||
&.is-checked
|
||||
color: #8c8c8c
|
||||
|
||||
@@ -34,4 +34,5 @@ template(name="cardLabelsPopup")
|
||||
= name
|
||||
if(isLabelSelected ../_id)
|
||||
i.card-label-selectable-icon.fa.fa-check
|
||||
a.quiet-button.full.js-add-label {{_ 'label-create'}}
|
||||
if currentUser.isBoardAdmin
|
||||
a.quiet-button.full.js-add-label {{_ 'label-create'}}
|
||||
@@ -1,19 +1,25 @@
|
||||
template(name="minicard")
|
||||
.minicard
|
||||
if cover
|
||||
.minicard-cover(style="background-image: url('{{pathFor cover.url}}');")
|
||||
.minicard-cover(style="background-image: url('{{cover.url}}');")
|
||||
if labels
|
||||
.minicard-labels
|
||||
each labels
|
||||
.minicard-label(class="card-label-{{color}}" title="{{name}}")
|
||||
.minicard-title= title
|
||||
.minicard-title
|
||||
+viewer
|
||||
= title
|
||||
.dates
|
||||
if startAt
|
||||
.date
|
||||
+minicardStartDate
|
||||
.date
|
||||
+minicardStartDate
|
||||
if dueAt
|
||||
.date
|
||||
+minicardDueDate
|
||||
.date
|
||||
+minicardDueDate
|
||||
if spentTime
|
||||
.date
|
||||
+cardSpentTime
|
||||
|
||||
if members
|
||||
.minicard-members.js-minicard-members
|
||||
each members
|
||||
|
||||
@@ -77,6 +77,9 @@
|
||||
height: @width
|
||||
border-radius: 2px
|
||||
margin-left: 3px
|
||||
.minicard-title
|
||||
p:last-child
|
||||
margin-bottom: 0
|
||||
.dates
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
||||
@@ -630,6 +630,59 @@ button
|
||||
a, .quiet
|
||||
color: white
|
||||
|
||||
// Material Design Toggle Switch
|
||||
.material-toggle-switch
|
||||
display: flex
|
||||
|
||||
.toggle-label
|
||||
position: relative
|
||||
display: block
|
||||
height: 20px
|
||||
width: 44px
|
||||
background-color: #a6a6a6
|
||||
border-radius: 100px
|
||||
cursor: pointer
|
||||
transition: all 0.3s ease
|
||||
|
||||
&:after
|
||||
position: absolute
|
||||
left: -2px
|
||||
top: -3px
|
||||
display: block
|
||||
width: 26px
|
||||
height: 26px
|
||||
border-radius: 100px
|
||||
background-color: #fff
|
||||
box-shadow: 0px 3px 3px rgba(0,0,0,0.05)
|
||||
content: ''
|
||||
transition: all 0.3s ease
|
||||
|
||||
&:active
|
||||
&:after
|
||||
transform: scale(1.15, 0.85)
|
||||
|
||||
.toggle-switch:checked ~ .toggle-label
|
||||
background-color: #6fbeb5
|
||||
|
||||
&:after
|
||||
left: 20px
|
||||
background-color: #179588
|
||||
|
||||
.toggle-switch:checked:disabled ~ .toggle-label
|
||||
background-color: #d5d5d5
|
||||
pointer-events: none
|
||||
|
||||
&:after
|
||||
background-color: #bcbdbc
|
||||
|
||||
.toggle-switch
|
||||
display: none
|
||||
|
||||
.toggle-switch-title
|
||||
margin: 0 0.5em
|
||||
display: flex
|
||||
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
.edit-controls,
|
||||
.add-controls
|
||||
|
||||
@@ -2,7 +2,7 @@ template(name="importHeaderBar")
|
||||
h1
|
||||
a.back-btn(href="{{pathFor 'home'}}")
|
||||
i.fa.fa-chevron-left
|
||||
| {{_ 'import-board-title'}}
|
||||
| {{_ title}}
|
||||
|
||||
template(name="import")
|
||||
.wrapper
|
||||
@@ -12,9 +12,12 @@ template(name="import")
|
||||
|
||||
template(name="importTextarea")
|
||||
form
|
||||
p: label(for='import-textarea') {{_ 'import-board-trello-instruction'}}
|
||||
p: label(for='import-textarea') {{_ instruction}}
|
||||
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
|
||||
p.warning {{_ 'import-sandstorm-warning'}}
|
||||
input.primary.wide(type="submit" value="{{_ 'import'}}")
|
||||
|
||||
template(name="importMapMembers")
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
import trelloMembersMapper from './trelloMembersMapper';
|
||||
import wekanMembersMapper from './wekanMembersMapper';
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
title() {
|
||||
return `import-board-title-${Session.get('importSource')}`;
|
||||
},
|
||||
}).register('importHeaderBar');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
@@ -5,6 +14,7 @@ BlazeComponent.extendComponent({
|
||||
this._currentStepIndex = new ReactiveVar(0);
|
||||
this.importedData = new ReactiveVar();
|
||||
this.membersToMap = new ReactiveVar([]);
|
||||
this.importSource = Session.get('importSource');
|
||||
},
|
||||
|
||||
currentTemplate() {
|
||||
@@ -27,7 +37,10 @@ BlazeComponent.extendComponent({
|
||||
const dataObject = JSON.parse(dataJson);
|
||||
this.setError('');
|
||||
this.importedData.set(dataObject);
|
||||
this._prepareAdditionalData(dataObject);
|
||||
const membersToMap = this._prepareAdditionalData(dataObject);
|
||||
// store members data and mapping in Session
|
||||
// (we go deep and 2-way, so storing in data context is not a viable option)
|
||||
this.membersToMap.set(membersToMap);
|
||||
this.nextStep();
|
||||
} catch (e) {
|
||||
this.setError('error-json-malformed');
|
||||
@@ -51,11 +64,16 @@ BlazeComponent.extendComponent({
|
||||
additionalData.membersMapping = mappingById;
|
||||
}
|
||||
this.membersToMap.set([]);
|
||||
Meteor.call('importTrelloBoard', this.importedData.get(), additionalData,
|
||||
Meteor.call('importBoard',
|
||||
this.importedData.get(),
|
||||
additionalData,
|
||||
this.importSource,
|
||||
Session.get('fromBoard'),
|
||||
(err, res) => {
|
||||
if (err) {
|
||||
this.setError(err.error);
|
||||
} else {
|
||||
Session.set('fromBoard', null);
|
||||
Utils.goBoardId(res);
|
||||
}
|
||||
}
|
||||
@@ -63,20 +81,16 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
_prepareAdditionalData(dataObject) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
const membersToMap = dataObject.members;
|
||||
// auto-map based on username
|
||||
membersToMap.forEach((importedMember) => {
|
||||
const wekanUser = Users.findOne({ username: importedMember.username });
|
||||
if (wekanUser) {
|
||||
importedMember.wekanId = wekanUser._id;
|
||||
}
|
||||
});
|
||||
// store members data and mapping in Session
|
||||
// (we go deep and 2-way, so storing in data context is not a viable option)
|
||||
this.membersToMap.set(membersToMap);
|
||||
const importSource = Session.get('importSource');
|
||||
let membersToMap;
|
||||
switch (importSource) {
|
||||
case 'trello':
|
||||
membersToMap = trelloMembersMapper.getMembersToMap(dataObject);
|
||||
break;
|
||||
case 'wekan':
|
||||
membersToMap = wekanMembersMapper.getMembersToMap(dataObject);
|
||||
break;
|
||||
}
|
||||
return membersToMap;
|
||||
},
|
||||
|
||||
@@ -90,6 +104,10 @@ BlazeComponent.extendComponent({
|
||||
return 'importTextarea';
|
||||
},
|
||||
|
||||
instruction() {
|
||||
return `import-board-instruction-${Session.get('importSource')}`;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
submit(evt) {
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
export function getMembersToMap(data) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
const membersToMap = data.members;
|
||||
// auto-map based on username
|
||||
membersToMap.forEach((importedMember) => {
|
||||
const wekanUser = Users.findOne({ username: importedMember.username });
|
||||
if (wekanUser) {
|
||||
importedMember.wekanId = wekanUser._id;
|
||||
}
|
||||
});
|
||||
return membersToMap;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
export function getMembersToMap(data) {
|
||||
// we will work on the list itself (an ordered array of objects) when a
|
||||
// mapping is done, we add a 'wekan' field to the object representing the
|
||||
// imported member
|
||||
const membersToMap = data.members;
|
||||
const users = data.users;
|
||||
// auto-map based on username
|
||||
membersToMap.forEach((importedMember) => {
|
||||
importedMember.id = importedMember.userId;
|
||||
delete importedMember.userId;
|
||||
const user = users.filter((user) => {
|
||||
return user._id === importedMember.id;
|
||||
})[0];
|
||||
if (user.profile && user.profile.fullname) {
|
||||
importedMember.fullName = user.profile.fullname;
|
||||
}
|
||||
importedMember.username = user.username;
|
||||
const wekanUser = Users.findOne({ username: importedMember.username });
|
||||
if (wekanUser) {
|
||||
importedMember.wekanId = wekanUser._id;
|
||||
}
|
||||
});
|
||||
return membersToMap;
|
||||
}
|
||||
@@ -2,3 +2,7 @@ template(name='list')
|
||||
.list.js-list(id="js-list-{{_id}}")
|
||||
+listHeader
|
||||
+listBody
|
||||
|
||||
template(name='miniList')
|
||||
a.mini-list.js-select-list.js-list(id="js-list-{{_id}}")
|
||||
+listHeader
|
||||
@@ -18,13 +18,18 @@ BlazeComponent.extendComponent({
|
||||
// callback, we basically solve all issues related to reactive updates. A
|
||||
// comment below provides further details.
|
||||
onRendered() {
|
||||
const boardComponent = this.parentComponent();
|
||||
const boardComponent = this.parentComponent().parentComponent();
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
}
|
||||
|
||||
const itemsSelector = '.js-minicard:not(.placeholder, .js-card-composer)';
|
||||
const $cards = this.$('.js-minicards');
|
||||
$cards.sortable({
|
||||
connectWith: '.js-minicards',
|
||||
connectWith: '.js-minicards:not(.js-list-full)',
|
||||
tolerance: 'pointer',
|
||||
appendTo: 'body',
|
||||
appendTo: '.board-canvas',
|
||||
helper(evt, item) {
|
||||
const helper = item.clone();
|
||||
if (MultiSelection.isActive()) {
|
||||
@@ -40,7 +45,6 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
distance: 7,
|
||||
items: itemsSelector,
|
||||
scroll: false,
|
||||
placeholder: 'minicard-wrapper placeholder',
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
@@ -55,6 +59,7 @@ BlazeComponent.extendComponent({
|
||||
const nCards = MultiSelection.isActive() ? MultiSelection.count() : 1;
|
||||
const sortIndex = calculateIndex(prevCardDom, nextCardDom, nCards);
|
||||
const listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
|
||||
const swimlaneId = Blaze.getData(ui.item.parents('.swimlane').get(0))._id;
|
||||
|
||||
// Normally the jquery-ui sortable library moves the dragged DOM element
|
||||
// to its new position, which disrupts Blaze reactive updates mechanism
|
||||
@@ -67,21 +72,17 @@ BlazeComponent.extendComponent({
|
||||
|
||||
if (MultiSelection.isActive()) {
|
||||
Cards.find(MultiSelection.getMongoSelector()).forEach((card, i) => {
|
||||
card.move(listId, sortIndex.base + i * sortIndex.increment);
|
||||
card.move(swimlaneId, listId, sortIndex.base + i * sortIndex.increment);
|
||||
});
|
||||
} else {
|
||||
const cardDomElement = ui.item.get(0);
|
||||
const card = Blaze.getData(cardDomElement);
|
||||
card.move(listId, sortIndex.base);
|
||||
card.move(swimlaneId, listId, sortIndex.base);
|
||||
}
|
||||
boardComponent.setIsDragging(false);
|
||||
},
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
}
|
||||
|
||||
// Disable drag-dropping if the current user is not a board member or is comment only
|
||||
this.autorun(() => {
|
||||
$cards.sortable('option', 'disabled', !userIsMember());
|
||||
@@ -114,3 +115,10 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
},
|
||||
}).register('list');
|
||||
|
||||
Template.miniList.events({
|
||||
'click .js-select-list'() {
|
||||
const listId = this._id;
|
||||
Session.set('currentList', listId);
|
||||
},
|
||||
});
|
||||
@@ -9,8 +9,8 @@
|
||||
// Even if this background color is the same as the body we can't leave it
|
||||
// transparent, because that won't work during a list drag.
|
||||
background: darken(white, 13%)
|
||||
height: 100%
|
||||
border-left: 1px solid darken(white, 20%)
|
||||
border-bottom: 1px solid #CCC
|
||||
padding: 0
|
||||
float: left
|
||||
|
||||
@@ -53,6 +53,9 @@
|
||||
&.ui-sortable-handle
|
||||
cursor: grab
|
||||
|
||||
.list-header-left-icon
|
||||
display: none
|
||||
|
||||
.list-header-name
|
||||
display: inline
|
||||
font-size: 16px
|
||||
@@ -69,21 +72,30 @@
|
||||
padding-left: 10px
|
||||
color: #a6a6a6
|
||||
|
||||
.list-header-menu-icon
|
||||
.list-header-menu
|
||||
position: absolute
|
||||
padding: 7px
|
||||
margin-top: 1px
|
||||
top: -@padding
|
||||
right: -@padding
|
||||
|
||||
.list-header-plus-icon
|
||||
color: #a6a6a6
|
||||
margin-right: 10px
|
||||
|
||||
.highlight
|
||||
color: #ce1414
|
||||
|
||||
.list-body
|
||||
flex: 1
|
||||
flex: 1 1 auto
|
||||
flex-direction: column
|
||||
display: flex
|
||||
overflow-y: auto
|
||||
padding: 5px 11px
|
||||
|
||||
.minicards
|
||||
flex: 1
|
||||
flex-grow: 1
|
||||
flex-shrink: 0
|
||||
|
||||
form
|
||||
margin-bottom: 9px
|
||||
@@ -107,3 +119,71 @@
|
||||
background: #fafafa
|
||||
color: #222
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,.2)
|
||||
|
||||
#js-wip-limit-edit
|
||||
padding-top: 2%
|
||||
|
||||
p
|
||||
margin-bottom: 0
|
||||
|
||||
input
|
||||
display: inline-block
|
||||
|
||||
.wip-limit-value
|
||||
width: 20%
|
||||
margin-right: 5%
|
||||
|
||||
.wip-limit-error
|
||||
display: none
|
||||
|
||||
.soft-wip-limit
|
||||
margin-right: 8px
|
||||
|
||||
div
|
||||
float: left
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
.mini-list
|
||||
flex: 0 0 60px
|
||||
height: 60px
|
||||
width: 100%
|
||||
border-left: 0px
|
||||
border-bottom: 1px solid darken(white, 20%)
|
||||
|
||||
.list
|
||||
display: block
|
||||
width: 100%
|
||||
border-left: 0px
|
||||
|
||||
&.ui-sortable-helper
|
||||
flex: 0 0 60px
|
||||
height: 60px
|
||||
width: 100%
|
||||
border-left: 0px
|
||||
border-bottom: 1px solid darken(white, 20%)
|
||||
|
||||
.list-header.ui-sortable-handle
|
||||
cursor: grabbing
|
||||
|
||||
&.placeholder
|
||||
flex: 0 0 60px
|
||||
height: 60px
|
||||
width: 100%
|
||||
border-left: 0px
|
||||
border-bottom: 1px solid darken(white, 20%)
|
||||
|
||||
.list-header
|
||||
|
||||
.list-header-left-icon
|
||||
display: inline
|
||||
padding: 7px
|
||||
padding-right: 27px
|
||||
margin-top: 1px
|
||||
top: -@padding
|
||||
left: -@padding
|
||||
|
||||
.list-header-menu-icon
|
||||
position: absolute
|
||||
padding: 7px
|
||||
top: -@padding
|
||||
right: 17px
|
||||
@@ -1,10 +1,10 @@
|
||||
template(name="listBody")
|
||||
.list-body.js-perfect-scrollbar
|
||||
.minicards.clearfix.js-minicards
|
||||
.minicards.clearfix.js-minicards(class="{{#if reachedWipLimit}}js-list-full{{/if}}")
|
||||
if cards.count
|
||||
+inlinedForm(autoclose=false position="top")
|
||||
+addCardForm(listId=_id position="top")
|
||||
each cards
|
||||
each (cards (idOrNull ../../_id))
|
||||
a.minicard-wrapper.js-minicard(href=absoluteUrl
|
||||
class="{{#if cardIsSelected}}is-selected{{/if}}"
|
||||
class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}")
|
||||
|
||||
@@ -36,6 +36,14 @@ BlazeComponent.extendComponent({
|
||||
const members = formComponent.members.get();
|
||||
const labelIds = formComponent.labels.get();
|
||||
|
||||
const boardId = this.data().board()._id;
|
||||
const board = Boards.findOne(boardId);
|
||||
let swimlaneId = '';
|
||||
if (board.view === 'board-view-swimlanes')
|
||||
swimlaneId = this.parentComponent().parentComponent().data()._id;
|
||||
else
|
||||
swimlaneId = Swimlanes.findOne({boardId})._id;
|
||||
|
||||
if (title) {
|
||||
const _id = Cards.insert({
|
||||
title,
|
||||
@@ -44,6 +52,7 @@ BlazeComponent.extendComponent({
|
||||
listId: this.data()._id,
|
||||
boardId: this.data().board()._id,
|
||||
sort: sortIndex,
|
||||
swimlaneId,
|
||||
});
|
||||
// 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
|
||||
@@ -96,6 +105,22 @@ BlazeComponent.extendComponent({
|
||||
MultiSelection.toggle(this.currentData()._id);
|
||||
},
|
||||
|
||||
idOrNull(swimlaneId) {
|
||||
const board = Boards.findOne(Session.get('currentBoard'));
|
||||
if (board.view === 'board-view-swimlanes')
|
||||
return swimlaneId;
|
||||
return undefined;
|
||||
},
|
||||
|
||||
canSeeAddCard() {
|
||||
return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
|
||||
reachedWipLimit() {
|
||||
const list = Template.currentData();
|
||||
return !list.getWipLimit('soft') && list.getWipLimit('enabled') && list.getWipLimit('value') <= list.cards().count();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-minicard': this.clickOnMiniCard,
|
||||
@@ -180,7 +205,7 @@ BlazeComponent.extendComponent({
|
||||
$textarea.escapeableTextComplete([
|
||||
// User mentions
|
||||
{
|
||||
match: /\B@(\w*)$/,
|
||||
match: /\B@([\w.]*)$/,
|
||||
search(term, callback) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
callback($.map(currentBoard.activeMembers(), (member) => {
|
||||
@@ -239,10 +264,3 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
},
|
||||
}).register('addCardForm');
|
||||
|
||||
|
||||
Template.listBody.helpers({
|
||||
canSeeAddCard() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
});
|
||||
@@ -3,17 +3,40 @@ template(name="listHeader")
|
||||
+inlinedForm
|
||||
+editListTitleForm
|
||||
else
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
||||
h2.list-header-name(
|
||||
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
|
||||
= title
|
||||
if wipLimit.enabled
|
||||
| (
|
||||
span(class="{{#if reachedWipLimit}}highlight{{/if}}") {{cards.count}}
|
||||
|/#{wipLimit.value})
|
||||
|
||||
if showCardsCountForList cards.count
|
||||
= cards.count
|
||||
span.lowercase
|
||||
| {{_ 'cards'}}
|
||||
if currentUser.isBoardMember
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
if isWatching
|
||||
i.list-header-watch-icon.fa.fa-eye
|
||||
div.list-header-menu
|
||||
unless currentUser.isCommentOnly
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
else
|
||||
a.list-header-menu-icon.fa.fa-angle-right.js-select-list
|
||||
else if currentUser.isBoardMember
|
||||
if isWatching
|
||||
i.list-header-watch-icon.fa.fa-eye
|
||||
a.list-header-menu-icon.fa.fa-navicon.js-open-list-menu
|
||||
div.list-header-menu
|
||||
unless currentUser.isCommentOnly
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
|
||||
template(name="editListTitleForm")
|
||||
.list-composer
|
||||
@@ -28,15 +51,18 @@ template(name="listActionPopup")
|
||||
unless currentUser.isCommentOnly
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-add-card {{_ 'add-card'}}
|
||||
if cards.count
|
||||
li: a.js-select-cards {{_ 'list-select-cards'}}
|
||||
hr
|
||||
hr
|
||||
if currentUser.isBoardAdmin
|
||||
ul.pop-over-list
|
||||
li: a.js-set-wip-limit {{#if isWipLimitEnabled }}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-close-list {{_ 'archive-list'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-remove-list {{_ 'remove-list'}}
|
||||
li: a.js-more {{_ 'listMorePopup-title'}}
|
||||
|
||||
template(name="boardLists")
|
||||
ul.pop-over-list
|
||||
@@ -46,3 +72,43 @@ template(name="boardLists")
|
||||
a.disabled {{title}} ({{_ 'current'}})
|
||||
else
|
||||
a.js-select-list= title
|
||||
|
||||
template(name="listMorePopup")
|
||||
p.quiet
|
||||
span.clearfix
|
||||
span {{_ 'link-list'}}
|
||||
= ' '
|
||||
i.fa.colorful(class="{{#if board.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
|
||||
input.inline-input(type="text" readonly value="{{ rootUrl }}")
|
||||
| {{_ 'added'}}
|
||||
span.date(title=list.createdAt) {{ moment createdAt 'LLL' }}
|
||||
a.js-delete {{_ 'delete'}}
|
||||
|
||||
template(name="listDeletePopup")
|
||||
p {{_ "list-delete-pop"}}
|
||||
unless archived
|
||||
p {{_ "list-delete-suggest-archive"}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
|
||||
|
||||
template(name="setWipLimitPopup")
|
||||
#js-wip-limit-edit
|
||||
label {{_ 'set-wip-limit-value'}}
|
||||
ul.pop-over-list
|
||||
li: a.js-enable-wip-limit {{_ 'enable-wip-limit'}}
|
||||
if isWipLimitEnabled
|
||||
i.fa.fa-check
|
||||
if isWipLimitEnabled
|
||||
p
|
||||
input.wip-limit-value(type="number" value="{{ wipLimitValue }}" min="1" max="99")
|
||||
input.wip-limit-apply(type="submit" value="{{_ 'apply'}}")
|
||||
input.wip-limit-error
|
||||
p
|
||||
.soft-wip-limit
|
||||
.materialCheckBox(class="{{#if isWipLimitSoft}}is-checked{{/if}}")
|
||||
label {{_ 'soft-wip-limit'}}
|
||||
|
||||
template(name="wipLimitErrorPopup")
|
||||
.wip-limit-invalid
|
||||
p {{_ 'wipLimitErrorPopup-dialog-pt1'}}
|
||||
p {{_ 'wipLimitErrorPopup-dialog-pt2'}}
|
||||
button.full.js-back-view(type="submit") {{_ 'cancel'}}
|
||||
@@ -1,4 +1,9 @@
|
||||
BlazeComponent.extendComponent({
|
||||
canSeeAddCard() {
|
||||
const list = Template.currentData();
|
||||
return !list.getWipLimit('enabled') || list.getWipLimit('soft') || !this.reachedWipLimit();
|
||||
},
|
||||
|
||||
editTitle(evt) {
|
||||
evt.preventDefault();
|
||||
const newTitle = this.childComponents('inlinedForm')[0].getValue().trim();
|
||||
@@ -17,6 +22,11 @@ BlazeComponent.extendComponent({
|
||||
return Meteor.user().getLimitToShowCardsCount();
|
||||
},
|
||||
|
||||
reachedWipLimit() {
|
||||
const list = Template.currentData();
|
||||
return list.getWipLimit('enabled') && list.getWipLimit('value') <= list.cards().count();
|
||||
},
|
||||
|
||||
showCardsCountForList(count) {
|
||||
return count > this.limitToShowCardsCount();
|
||||
},
|
||||
@@ -24,46 +34,112 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [{
|
||||
'click .js-open-list-menu': Popup.open('listAction'),
|
||||
'click .js-add-card' () {
|
||||
const listDom = document.getElementById(`js-list-${this.currentData()._id}`);
|
||||
const listComponent = BlazeComponent.getComponentForElement(listDom);
|
||||
listComponent.openForm({
|
||||
position: 'top',
|
||||
});
|
||||
},
|
||||
'click .js-unselect-list'() {
|
||||
Session.set('currentList', null);
|
||||
},
|
||||
submit: this.editTitle,
|
||||
}];
|
||||
},
|
||||
}).register('listHeader');
|
||||
|
||||
Template.listActionPopup.helpers({
|
||||
isWipLimitEnabled() {
|
||||
return Template.currentData().getWipLimit('enabled');
|
||||
},
|
||||
|
||||
isWatching() {
|
||||
return this.findWatcher(Meteor.userId());
|
||||
},
|
||||
});
|
||||
|
||||
Template.listActionPopup.events({
|
||||
'click .js-add-card'() {
|
||||
const listDom = document.getElementById(`js-list-${this._id}`);
|
||||
const listComponent = BlazeComponent.getComponentForElement(listDom);
|
||||
listComponent.openForm({ position: 'top' });
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-list-subscribe'() {},
|
||||
'click .js-select-cards'() {
|
||||
'click .js-list-subscribe' () {},
|
||||
'click .js-select-cards' () {
|
||||
const cardIds = this.allCards().map((card) => card._id);
|
||||
MultiSelection.add(cardIds);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-toggle-watch-list'() {
|
||||
'click .js-toggle-watch-list' () {
|
||||
const currentList = this;
|
||||
const level = currentList.findWatcher(Meteor.userId()) ? null : 'watching';
|
||||
Meteor.call('watch', 'list', currentList._id, level, (err, ret) => {
|
||||
if (!err && ret) Popup.close();
|
||||
});
|
||||
},
|
||||
'click .js-close-list'(evt) {
|
||||
'click .js-close-list' (evt) {
|
||||
evt.preventDefault();
|
||||
this.archive();
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-remove-list'(evt) {
|
||||
const currentList = this;
|
||||
evt.preventDefault();
|
||||
Lists.remove(currentList._id);
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-set-wip-limit': Popup.open('setWipLimit'),
|
||||
'click .js-more': Popup.open('listMore'),
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
applyWipLimit() {
|
||||
const list = Template.currentData();
|
||||
const limit = parseInt(Template.instance().$('.wip-limit-value').val(), 10);
|
||||
|
||||
if(limit < list.cards().count() && !list.getWipLimit('soft')){
|
||||
Template.instance().$('.wip-limit-error').click();
|
||||
} else {
|
||||
Meteor.call('applyWipLimit', list._id, limit);
|
||||
Popup.back();
|
||||
}
|
||||
},
|
||||
|
||||
enableSoftLimit() {
|
||||
const list = Template.currentData();
|
||||
|
||||
if(list.getWipLimit('soft') && list.getWipLimit('value') < list.cards().count()){
|
||||
list.setWipLimit(list.cards().count());
|
||||
}
|
||||
Meteor.call('enableSoftLimit', Template.currentData()._id);
|
||||
},
|
||||
|
||||
enableWipLimit() {
|
||||
const list = Template.currentData();
|
||||
// Prevent user from using previously stored wipLimit.value if it is less than the current number of cards in the list
|
||||
if(!list.getWipLimit('enabled') && list.getWipLimit('value') < list.cards().count()){
|
||||
list.setWipLimit(list.cards().count());
|
||||
}
|
||||
Meteor.call('enableWipLimit', list._id);
|
||||
},
|
||||
|
||||
isWipLimitSoft() {
|
||||
return Template.currentData().getWipLimit('soft');
|
||||
},
|
||||
|
||||
isWipLimitEnabled() {
|
||||
return Template.currentData().getWipLimit('enabled');
|
||||
},
|
||||
|
||||
wipLimitValue(){
|
||||
return Template.currentData().getWipLimit('value');
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-enable-wip-limit': this.enableWipLimit,
|
||||
'click .wip-limit-apply': this.applyWipLimit,
|
||||
'click .wip-limit-error': Popup.open('wipLimitError'),
|
||||
'click .materialCheckBox': this.enableSoftLimit,
|
||||
}];
|
||||
},
|
||||
}).register('setWipLimitPopup');
|
||||
|
||||
Template.listMorePopup.events({
|
||||
'click .js-delete': Popup.afterConfirm('listDelete', function () {
|
||||
Popup.close();
|
||||
this.allCards().map((card) => Cards.remove(card._id));
|
||||
Lists.remove(this._id);
|
||||
Utils.goBoardId(this.boardId);
|
||||
}),
|
||||
});
|
||||
@@ -0,0 +1,13 @@
|
||||
BlazeComponent.extendComponent({
|
||||
currentCardIsInThisList(listId, swimlaneId) {
|
||||
const currentCard = Cards.findOne(Session.get('currentCard'));
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
const board = Boards.findOne(currentBoardId);
|
||||
if (board.view === 'board-view-lists')
|
||||
return currentCard && currentCard.listId === listId;
|
||||
else if (board.view === 'board-view-swimlanes')
|
||||
return currentCard && currentCard.listId === listId && currentCard.swimlaneId === swimlaneId;
|
||||
else
|
||||
return false;
|
||||
},
|
||||
}).register('listsGroup');
|
||||
@@ -9,6 +9,5 @@ template(name="editor")
|
||||
template(name="viewer")
|
||||
.viewer
|
||||
+mentions
|
||||
+emoji
|
||||
+markdown
|
||||
{{> UI.contentBlock }}
|
||||
+markdown
|
||||
{{> UI.contentBlock }}
|
||||
@@ -4,28 +4,9 @@ Template.editor.onRendered(() => {
|
||||
autosize($textarea);
|
||||
|
||||
$textarea.escapeableTextComplete([
|
||||
// Emoji
|
||||
{
|
||||
match: /\B:([\-+\w]*)$/,
|
||||
search(term, callback) {
|
||||
callback(Emoji.values.map((emoji) => {
|
||||
return emoji.includes(term) ? emoji : null;
|
||||
}).filter(Boolean));
|
||||
},
|
||||
template(value) {
|
||||
const imgSrc = Emoji.baseImagePath + value;
|
||||
const image = `<img src="${imgSrc}.png" />`;
|
||||
return image + value;
|
||||
},
|
||||
replace(value) {
|
||||
return `:${value}:`;
|
||||
},
|
||||
index: 1,
|
||||
},
|
||||
|
||||
// User mentions
|
||||
{
|
||||
match: /\B@(\w*)$/,
|
||||
match: /\B@([\w.]*)$/,
|
||||
search(term, callback) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
callback(currentBoard.activeMembers().map((member) => {
|
||||
@@ -47,7 +28,7 @@ Template.editor.onRendered(() => {
|
||||
import sanitizeXss from 'xss';
|
||||
|
||||
// XXX I believe we should compute a HTML rendered field on the server that
|
||||
// would handle markdown, emoji and user mentions. We can simply have two
|
||||
// would handle markdown and user mentions. We can simply have two
|
||||
// fields, one source, and one compiled version (in HTML) and send only the
|
||||
// compiled version to most users -- who don't need to edit.
|
||||
// In the meantime, all the transformation are done on the client using the
|
||||
@@ -60,7 +41,7 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
|
||||
member.username = Users.findOne(member.userId).username;
|
||||
return member;
|
||||
});
|
||||
const mentionRegex = /\B@(\w*)/gi;
|
||||
const mentionRegex = /\B@([\w.]*)/gi;
|
||||
let content = Blaze.toHTML(view.templateContentBlock);
|
||||
|
||||
let currentMention;
|
||||
|
||||
@@ -7,19 +7,31 @@ template(name="header")
|
||||
unless isSandstorm
|
||||
if currentUser
|
||||
#header-quick-access(class=currentBoard.colorClass)
|
||||
ul
|
||||
li
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
each currentUser.starredBoards
|
||||
li.separator -
|
||||
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
|
||||
a(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
= title
|
||||
else
|
||||
li.current {{_ 'quick-access-description'}}
|
||||
if isMiniScreen
|
||||
ul
|
||||
li
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
|
||||
if currentList
|
||||
each currentBoard.lists
|
||||
li(class="{{#if $.Session.equals 'currentList' _id}}current{{/if}}")
|
||||
a.js-select-list
|
||||
= title
|
||||
#header-new-board-icon
|
||||
else
|
||||
ul
|
||||
li
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
each currentUser.starredBoards
|
||||
li.separator -
|
||||
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
|
||||
a(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
= title
|
||||
else
|
||||
li.current {{_ 'quick-access-description'}}
|
||||
|
||||
a#header-new-board-icon.js-create-board
|
||||
i.fa.fa-plus(title="Create a new board")
|
||||
@@ -49,6 +61,14 @@ template(name="header")
|
||||
if appIsOffline
|
||||
+offlineWarning
|
||||
|
||||
if currentUser.isBoardMember
|
||||
if hasAnnouncement
|
||||
.announcement
|
||||
p
|
||||
i.fa.fa-bullhorn
|
||||
| #{announcement}
|
||||
i.fa.fa-times-circle.js-close-announcement
|
||||
|
||||
template(name="offlineWarning")
|
||||
.offline-warning
|
||||
p
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
Meteor.subscribe('user-admin');
|
||||
Meteor.subscribe('boards');
|
||||
|
||||
Template.header.helpers({
|
||||
wrappedHeader() {
|
||||
return !Session.get('currentBoard');
|
||||
@@ -10,8 +13,26 @@ Template.header.helpers({
|
||||
appIsOffline() {
|
||||
return !Meteor.status().connected;
|
||||
},
|
||||
|
||||
hasAnnouncement() {
|
||||
const announcements = Announcements.findOne();
|
||||
return announcements && announcements.enabled;
|
||||
},
|
||||
|
||||
announcement() {
|
||||
$('.announcement').show();
|
||||
const announcements = Announcements.findOne();
|
||||
return announcements && announcements.body;
|
||||
},
|
||||
});
|
||||
|
||||
Template.header.events({
|
||||
'click .js-create-board': Popup.open('headerBarCreateBoard'),
|
||||
'click .js-close-announcement'() {
|
||||
$('.announcement').hide();
|
||||
},
|
||||
'click .js-select-list'() {
|
||||
Session.set('currentList', this._id);
|
||||
Session.set('currentCard', null);
|
||||
},
|
||||
});
|
||||
@@ -4,6 +4,7 @@
|
||||
color: white
|
||||
transition: background-color 0.4s
|
||||
background: #2980B9
|
||||
z-index: 17
|
||||
|
||||
#header-main-bar
|
||||
height: 40px
|
||||
@@ -99,6 +100,7 @@
|
||||
height: 28px
|
||||
font-size: 12px
|
||||
display: flex
|
||||
z-index: 17
|
||||
|
||||
#header-user-bar,
|
||||
#header-new-board-icon,
|
||||
@@ -191,12 +193,35 @@
|
||||
bottom: 0px
|
||||
|
||||
ul
|
||||
width: calc(100% - 150px)
|
||||
width: calc(100% - 60px)
|
||||
overflow: ellipsis
|
||||
padding: 10px
|
||||
margin: -10px
|
||||
|
||||
li
|
||||
height: 28px
|
||||
height: 100%
|
||||
padding: 12px 0px
|
||||
margin: -10px 0px
|
||||
|
||||
a
|
||||
height: 100%
|
||||
padding: 12px 10px
|
||||
margin: -10px 0px
|
||||
|
||||
.fa-home
|
||||
font-size: 26px
|
||||
margin-top: -2px
|
||||
|
||||
#header-new-board-icon
|
||||
display: none
|
||||
|
||||
#header-user-bar
|
||||
position: absolute
|
||||
right: 0px
|
||||
padding: 10px
|
||||
margin: -10px
|
||||
|
||||
.announcement,
|
||||
.offline-warning
|
||||
width: 100%
|
||||
text-align: center
|
||||
|
||||
@@ -8,6 +8,8 @@ head
|
||||
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")
|
||||
|
||||
template(name="userFormsLayout")
|
||||
section.auth-layout
|
||||
|
||||
@@ -1,7 +1,3 @@
|
||||
Meteor.subscribe('boards');
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('user-admin');
|
||||
|
||||
BlazeLayout.setRoot('body');
|
||||
|
||||
const i18nTagToT9n = (i18nTag) => {
|
||||
@@ -20,9 +16,21 @@ Template.userFormsLayout.onRendered(() => {
|
||||
|
||||
Template.userFormsLayout.helpers({
|
||||
languages() {
|
||||
return _.map(TAPi18n.getLanguages(), (lang, tag) => {
|
||||
const name = lang.name;
|
||||
return _.map(TAPi18n.getLanguages(), (lang, code) => {
|
||||
const tag = code;
|
||||
let name = lang.name;
|
||||
if (lang.name === 'br') {
|
||||
name = 'Brezhoneg';
|
||||
} else if (lang.name === 'ig') {
|
||||
name = 'Igbo';
|
||||
}
|
||||
return { tag, name };
|
||||
}).sort(function(a, b) {
|
||||
if (a.name === b.name) {
|
||||
return 0;
|
||||
} else {
|
||||
return a.name > b.name ? 1 : -1;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -270,11 +270,6 @@ kbd
|
||||
.grabbing
|
||||
cursor: grabbing
|
||||
|
||||
.emoji
|
||||
height: 18px
|
||||
width: 18px
|
||||
vertical-align: text-bottom
|
||||
|
||||
// Implement a thiner close icon as suggested in
|
||||
// https://github.com/FortAwesome/Font-Awesome/issues/1540#issuecomment-68689950
|
||||
.fa.fa-times-thin:before
|
||||
@@ -335,6 +330,8 @@ a
|
||||
margin-left: 38px
|
||||
|
||||
.viewer
|
||||
min-height: 18px
|
||||
|
||||
ol
|
||||
list-style-type: decimal
|
||||
padding-left: 20px
|
||||
@@ -366,7 +363,8 @@ a
|
||||
|
||||
@keyframes flexGrowIn
|
||||
from
|
||||
flex-basis: 0
|
||||
// Support IE11 https://github.com/wekan/wekan/pull/646
|
||||
height: 100%
|
||||
|
||||
@media screen and (max-width: 800px)
|
||||
#content
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
template(name='information')
|
||||
.setting-content
|
||||
unless currentUser.isAdmin
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-title
|
||||
span {{_ 'info'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="information-display") {{_ 'info'}}
|
||||
.main-body
|
||||
+statistics
|
||||
|
||||
template(name='statistics')
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'Wekan_version'}}
|
||||
td {{statistics.version}}
|
||||
tr
|
||||
th {{_ 'Node_version'}}
|
||||
td {{statistics.process.nodeVersion}}
|
||||
tr
|
||||
th {{_ 'OS_Type'}}
|
||||
td {{statistics.os.type}}
|
||||
tr
|
||||
th {{_ 'OS_Platform'}}
|
||||
td {{statistics.os.platform}}
|
||||
tr
|
||||
th {{_ 'OS_Arch'}}
|
||||
td {{statistics.os.arch}}
|
||||
tr
|
||||
th {{_ 'OS_Release'}}
|
||||
td {{statistics.os.release}}
|
||||
tr
|
||||
th {{_ 'OS_Uptime'}}
|
||||
td {{humanReadableTime statistics.os.uptime}}
|
||||
tr
|
||||
th {{_ 'OS_Loadavg'}}
|
||||
td {{numFormat statistics.os.loadavg.[0]}}, {{numFormat statistics.os.loadavg.[1]}}, {{numFormat statistics.os.loadavg.[2]}}
|
||||
tr
|
||||
th {{_ 'OS_Totalmem'}}
|
||||
td {{bytesToSize statistics.os.totalmem}}
|
||||
tr
|
||||
th {{_ 'OS_Freemem'}}
|
||||
td {{bytesToSize statistics.os.freemem}}
|
||||
tr
|
||||
th {{_ 'OS_Cpus'}}
|
||||
td {{statistics.os.cpus.length}}
|
||||
@@ -0,0 +1,48 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.info = new ReactiveVar({});
|
||||
Meteor.call('getStatistics', (error, ret) => {
|
||||
if (!error && ret) {
|
||||
this.info.set(ret);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
statistics() {
|
||||
return this.info.get();
|
||||
},
|
||||
|
||||
humanReadableTime(time) {
|
||||
const days = Math.floor(time / 86400);
|
||||
const hours = Math.floor((time % 86400) / 3600);
|
||||
const minutes = Math.floor(((time % 86400) % 3600) / 60);
|
||||
const seconds = Math.floor(((time % 86400) % 3600) % 60);
|
||||
let out = '';
|
||||
if (days > 0) {
|
||||
out += `${days} ${TAPi18n.__('days')}, `;
|
||||
}
|
||||
if (hours > 0) {
|
||||
out += `${hours} ${TAPi18n.__('hours')}, `;
|
||||
}
|
||||
if (minutes > 0) {
|
||||
out += `${minutes} ${TAPi18n.__('minutes')}, `;
|
||||
}
|
||||
if (seconds > 0) {
|
||||
out += `${seconds} ${TAPi18n.__('seconds')}`;
|
||||
}
|
||||
return out;
|
||||
},
|
||||
|
||||
numFormat(number) {
|
||||
return parseFloat(number).toFixed(2);
|
||||
},
|
||||
|
||||
bytesToSize(bytes) {
|
||||
const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
|
||||
if (bytes === 0) {
|
||||
return '0 Byte';
|
||||
}
|
||||
const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)), 10);
|
||||
return `${Math.round(bytes / Math.pow(1024, i), 2)} ${sizes[i]}`;
|
||||
},
|
||||
}).register('statistics');
|
||||
@@ -1,6 +1,6 @@
|
||||
Template.invitationCode.onRendered(() => {
|
||||
const setting = Settings.findOne();
|
||||
if (!setting || !setting.disableRegistration) {
|
||||
if (setting || setting.disableRegistration) {
|
||||
$('#invitationcode').hide();
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,90 @@
|
||||
template(name="people")
|
||||
.setting-content
|
||||
unless currentUser.isAdmin
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-title
|
||||
span {{_ 'people'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="people-setting") {{_ 'people'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if people.get
|
||||
+peopleGeneral
|
||||
|
||||
template(name="peopleGeneral")
|
||||
table
|
||||
tbody
|
||||
tr
|
||||
th {{_ 'username'}}
|
||||
th {{_ 'fullname'}}
|
||||
th {{_ 'admin'}}
|
||||
th {{_ 'email'}}
|
||||
th {{_ 'verified'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
th
|
||||
each user in peopleList
|
||||
+peopleRow(userId=user._id)
|
||||
|
||||
template(name="peopleRow")
|
||||
tr
|
||||
td.username {{ userData.username }}
|
||||
td {{ userData.profile.fullname }}
|
||||
td
|
||||
if userData.isAdmin
|
||||
| {{_ 'yes'}}
|
||||
else
|
||||
| {{_ 'no'}}
|
||||
td {{ userData.emails.[0].address }}
|
||||
td
|
||||
if userData.emails.[0].verified
|
||||
| {{_ 'yes'}}
|
||||
else
|
||||
| {{_ 'no'}}
|
||||
td {{ moment userData.createdAt 'LLL' }}
|
||||
td
|
||||
if userData.loginDisabled
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
td
|
||||
a.edit-user
|
||||
| {{_ 'edit'}}
|
||||
|
||||
template(name="editUserPopup")
|
||||
form
|
||||
label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname autofocus)
|
||||
label
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
| {{_ 'error-username-taken'}}
|
||||
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}}")
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
option(value="false") {{_ 'no'}}
|
||||
option(value="true" selected="{{user.isAdmin}}") {{_ 'yes'}}
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-profile-isactive
|
||||
option(value="false") {{_ 'yes'}}
|
||||
option(value="true" selected="{{user.loginDisabled}}") {{_ 'no'}}
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
input.js-profile-password(type="password")
|
||||
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -0,0 +1,158 @@
|
||||
const usersPerPage = 25;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
mixins() {
|
||||
return [Mixins.InfiniteScrolling];
|
||||
},
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.people = new ReactiveVar(true);
|
||||
|
||||
this.page = new ReactiveVar(1);
|
||||
this.loadNextPageLocked = false;
|
||||
this.callFirstWith(null, 'resetNextPeak');
|
||||
this.autorun(() => {
|
||||
const limit = this.page.get() * usersPerPage;
|
||||
|
||||
this.subscribe('people', limit, () => {
|
||||
this.loadNextPageLocked = false;
|
||||
const nextPeakBefore = this.callFirstWith(null, 'getNextPeak');
|
||||
this.calculateNextPeak();
|
||||
const nextPeakAfter = this.callFirstWith(null, 'getNextPeak');
|
||||
if (nextPeakBefore === nextPeakAfter) {
|
||||
this.callFirstWith(null, 'resetNextPeak');
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
loadNextPage() {
|
||||
if (this.loadNextPageLocked === false) {
|
||||
this.page.set(this.page.get() + 1);
|
||||
this.loadNextPageLocked = true;
|
||||
}
|
||||
},
|
||||
calculateNextPeak() {
|
||||
const element = this.find('.main-body');
|
||||
if (element) {
|
||||
const altitude = element.scrollHeight;
|
||||
this.callFirstWith(this, 'setNextPeak', altitude);
|
||||
}
|
||||
},
|
||||
reachNextPeak() {
|
||||
this.loadNextPage();
|
||||
},
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
peopleList() {
|
||||
return Users.find({}, {
|
||||
fields: {_id: true},
|
||||
});
|
||||
},
|
||||
}).register('people');
|
||||
|
||||
Template.peopleRow.helpers({
|
||||
userData() {
|
||||
const userCollection = this.esSearch ? ESSearchResults : Users;
|
||||
return userCollection.findOne(this.userId);
|
||||
},
|
||||
});
|
||||
|
||||
Template.editUserPopup.helpers({
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
},
|
||||
user() {
|
||||
return Users.findOne(this.userId);
|
||||
},
|
||||
events() {
|
||||
return [{
|
||||
'click a.edit-user': Popup.open('editUser'),
|
||||
}];
|
||||
},
|
||||
}).register('peopleRow');
|
||||
|
||||
Template.editUserPopup.events({
|
||||
submit(evt, tpl) {
|
||||
evt.preventDefault();
|
||||
const user = Users.findOne(this.userId);
|
||||
const fullname = tpl.find('.js-profile-fullname').value.trim();
|
||||
const username = tpl.find('.js-profile-username').value.trim();
|
||||
const password = tpl.find('.js-profile-password').value;
|
||||
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 isChangePassword = password.length > 0;
|
||||
const isChangeUserName = username !== user.username;
|
||||
const isChangeEmail = email.toLowerCase() !== user.emails[0].address.toLowerCase();
|
||||
|
||||
Users.update(this.userId, {
|
||||
$set: {
|
||||
'profile.fullname': fullname,
|
||||
'isAdmin': isAdmin === 'true',
|
||||
'loginDisabled': isActive === 'true',
|
||||
},
|
||||
});
|
||||
|
||||
if(isChangePassword){
|
||||
Meteor.call('setPassword', password, this.userId);
|
||||
}
|
||||
|
||||
if (isChangeUserName && isChangeEmail) {
|
||||
Meteor.call('setUsernameAndEmail', username, email.toLowerCase(), this.userId, function (error) {
|
||||
const usernameMessageElement = tpl.$('.username-taken');
|
||||
const emailMessageElement = tpl.$('.email-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'username-already-taken') {
|
||||
usernameMessageElement.show();
|
||||
emailMessageElement.hide();
|
||||
} else if (errorElement === 'email-already-taken') {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
} else if (isChangeUserName) {
|
||||
Meteor.call('setUsername', username, this.userId, function (error) {
|
||||
const usernameMessageElement = tpl.$('.username-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'username-already-taken') {
|
||||
usernameMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
usernameMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
} else if (isChangeEmail) {
|
||||
Meteor.call('setEmail', email.toLowerCase(), this.userId, function (error) {
|
||||
const emailMessageElement = tpl.$('.email-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'email-already-taken') {
|
||||
emailMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
emailMessageElement.hide();
|
||||
Popup.close();
|
||||
}
|
||||
});
|
||||
} else Popup.close();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
.main-body
|
||||
overflow: scroll;
|
||||
|
||||
table
|
||||
font-family: arial, sans-serif;
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
|
||||
td, th
|
||||
border: 1px solid #d2d0d0;
|
||||
text-align: left;
|
||||
padding: 8px;
|
||||
|
||||
tr:nth-child(even)
|
||||
background-color: #dddddd;
|
||||
@@ -1,21 +1,32 @@
|
||||
template(name="setting")
|
||||
.setting-content
|
||||
.content-title
|
||||
span {{_ 'settings'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if generalSetting.get
|
||||
+general
|
||||
else if emailSetting.get
|
||||
+email
|
||||
unless currentUser.isAdmin
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-title
|
||||
span {{_ 'settings'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="account-setting") {{_ 'accounts'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="announcement-setting") {{_ 'admin-announcement'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
else if generalSetting.get
|
||||
+general
|
||||
else if emailSetting.get
|
||||
+email
|
||||
else if accountSetting.get
|
||||
+accountSettings
|
||||
else if announcementSetting.get
|
||||
+announcementSettings
|
||||
|
||||
template(name="general")
|
||||
ul#registration-setting.setting-detail
|
||||
@@ -76,4 +87,35 @@ template(name='email')
|
||||
input.form-control#mail-server-from(type="email", placeholder="no-reply@domain.com" value="{{currentSetting.mailServer.from}}")
|
||||
|
||||
li
|
||||
button.js-save.primary Save
|
||||
button.js-save.primary {{_ 'save'}}
|
||||
|
||||
li
|
||||
button.js-send-smtp-test-email.primary {{_ 'send-smtp-test'}}
|
||||
|
||||
template(name='accountSettings')
|
||||
ul#account-setting.setting-detail
|
||||
li.smtp-form
|
||||
.title {{_ 'accounts-allowEmailChange'}}
|
||||
.form-group.flex
|
||||
input.form-control#accounts-allowEmailChange(type="radio" name="allowEmailChange" value="true" checked="{{#if allowEmailChange}}checked{{/if}}")
|
||||
span {{_ 'yes'}}
|
||||
input.form-control#accounts-allowEmailChange(type="radio" name="allowEmailChange" value="false" checked="{{#unless allowEmailChange}}checked{{/unless}}")
|
||||
span {{_ 'no'}}
|
||||
li
|
||||
button.js-accounts-save.primary {{_ 'save'}}
|
||||
|
||||
template(name='announcementSettings')
|
||||
ul#announcement-setting.setting-detail
|
||||
li
|
||||
a.flex.js-toggle-activemessage
|
||||
.materialCheckBox(class="{{#if currentSetting.enabled}}is-checked{{/if}}")
|
||||
|
||||
span {{_ 'admin-announcement-active'}}
|
||||
li
|
||||
.admin-announcement(class="{{#if currentSetting.enabled}}{{else}}hide{{/if}}")
|
||||
ul
|
||||
li
|
||||
.title {{_ 'admin-announcement-title'}}
|
||||
textarea#admin-announcement.form-control= currentSetting.body
|
||||
li
|
||||
button.js-announcement-save.primary {{_ 'save'}}
|
||||
@@ -1,12 +1,16 @@
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
this.generalSetting = new ReactiveVar(true);
|
||||
this.emailSetting = new ReactiveVar(false);
|
||||
this.accountSetting = new ReactiveVar(false);
|
||||
this.announcementSetting = new ReactiveVar(false);
|
||||
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('mailServer');
|
||||
Meteor.subscribe('accountSettings');
|
||||
Meteor.subscribe('announcements');
|
||||
},
|
||||
|
||||
setError(error) {
|
||||
@@ -62,6 +66,8 @@ BlazeComponent.extendComponent({
|
||||
const targetID = target.data('id');
|
||||
this.generalSetting.set('registration-setting' === targetID);
|
||||
this.emailSetting.set('email-setting' === targetID);
|
||||
this.accountSetting.set('account-setting' === targetID);
|
||||
this.announcementSetting.set('announcement-setting' === targetID);
|
||||
}
|
||||
},
|
||||
|
||||
@@ -110,7 +116,7 @@ BlazeComponent.extendComponent({
|
||||
const from = this.checkField('#mail-server-from');
|
||||
const tls = $('#mail-server-tls.is-checked').length > 0;
|
||||
Settings.update(Settings.findOne()._id, {$set:{'mailServer.host':host, 'mailServer.port': port, 'mailServer.username': username,
|
||||
'mailServer.password': password, 'mailServer.enableTLS': tls, 'mailServer.from': from}});
|
||||
'mailServer.password': password, 'mailServer.enableTLS': tls, 'mailServer.from': from}});
|
||||
} catch (e) {
|
||||
return;
|
||||
} finally {
|
||||
@@ -119,6 +125,21 @@ BlazeComponent.extendComponent({
|
||||
|
||||
},
|
||||
|
||||
sendSMTPTestEmail() {
|
||||
Meteor.call('sendSMTPTestEmail', (err, ret) => {
|
||||
if (!err && ret) { /* eslint-disable no-console */
|
||||
const message = `${TAPi18n.__(ret.message)}: ${ret.email}`;
|
||||
console.log(message);
|
||||
alert(message);
|
||||
} else {
|
||||
const reason = err.reason || '';
|
||||
const message = `${TAPi18n.__(err.error)}\n${reason}`;
|
||||
console.log(message, err);
|
||||
alert(message);
|
||||
} /* eslint-enable no-console */
|
||||
});
|
||||
},
|
||||
|
||||
events(){
|
||||
return [{
|
||||
'click a.js-toggle-registration': this.toggleRegistration,
|
||||
@@ -127,6 +148,68 @@ BlazeComponent.extendComponent({
|
||||
'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,
|
||||
}];
|
||||
},
|
||||
}).register('setting');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
saveAllowEmailChange() {
|
||||
const allowEmailChange = ($('input[name=allowEmailChange]:checked').val() === 'true');
|
||||
AccountSettings.update('accounts-allowEmailChange', {
|
||||
$set: { 'booleanValue': allowEmailChange },
|
||||
});
|
||||
},
|
||||
|
||||
allowEmailChange() {
|
||||
return AccountSettings.findOne('accounts-allowEmailChange').booleanValue;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click button.js-accounts-save': this.saveAllowEmailChange,
|
||||
}];
|
||||
},
|
||||
}).register('accountSettings');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.loading = new ReactiveVar(false);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
},
|
||||
|
||||
currentSetting(){
|
||||
return Announcements.findOne();
|
||||
},
|
||||
|
||||
saveMessage() {
|
||||
const message = $('#admin-announcement').val().trim();
|
||||
Announcements.update(Announcements.findOne()._id, {
|
||||
$set: { 'body': message },
|
||||
});
|
||||
},
|
||||
|
||||
toggleActive(){
|
||||
this.setLoading(true);
|
||||
const isActive = this.currentSetting().enabled;
|
||||
Announcements.update(Announcements.findOne()._id, {
|
||||
$set:{ 'enabled': !isActive},
|
||||
});
|
||||
this.setLoading(false);
|
||||
if(isActive){
|
||||
$('.admin-announcement').slideUp();
|
||||
}else{
|
||||
$('.admin-announcement').slideDown();
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click a.js-toggle-activemessage': this.toggleActive,
|
||||
'click button.js-announcement-save': this.saveMessage,
|
||||
}];
|
||||
},
|
||||
}).register('announcementSettings');
|
||||
@@ -61,10 +61,11 @@
|
||||
.is-checked
|
||||
border-bottom: 2px solid #2980b9;
|
||||
border-right: 2px solid #2980b9;
|
||||
|
||||
span
|
||||
|
||||
span
|
||||
padding: 0 0.5rem
|
||||
|
||||
|
||||
.admin-announcement,
|
||||
.invite-people
|
||||
padding-left 20px;
|
||||
li
|
||||
|
||||
@@ -6,13 +6,17 @@ template(name="settingHeaderBar")
|
||||
unless isMiniScreen
|
||||
unless isSandstorm
|
||||
if currentUser
|
||||
a.setting-header-btn.settings.active
|
||||
a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
|
||||
i.fa(class="fa-cog")
|
||||
span {{_ 'settings'}}
|
||||
//TODO
|
||||
// a.setting-header-btn.people
|
||||
// i.fa(class="fa-users")
|
||||
// span {{_ 'people'}}
|
||||
|
||||
a.setting-header-btn.people(href="{{pathFor 'people'}}")
|
||||
i.fa(class="fa-users")
|
||||
span {{_ 'people'}}
|
||||
|
||||
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
|
||||
i.fa(class="fa-info-circle")
|
||||
span {{_ 'info'}}
|
||||
|
||||
else
|
||||
a.setting-header-btn.js-log-in(
|
||||
|
||||
@@ -82,23 +82,27 @@ template(name="memberPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-filter-member {{_ 'filter-cards'}}
|
||||
if currentUser.isBoardAdmin
|
||||
unless isSandstorm
|
||||
unless isSandstorm
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-change-role
|
||||
| {{_ 'change-permissions'}}
|
||||
span.quiet (#{memberType})
|
||||
li
|
||||
if $eq currentUser._id userId
|
||||
a.js-leave-member {{_ 'leave-board'}}
|
||||
else
|
||||
a.js-remove-member {{_ 'remove-from-board'}}
|
||||
li
|
||||
if $eq currentUser._id userId
|
||||
a.js-leave-member {{_ 'leave-board'}}
|
||||
else if currentUser.isBoardAdmin
|
||||
a.js-remove-member {{_ 'remove-from-board'}}
|
||||
|
||||
|
||||
template(name="removeMemberPopup")
|
||||
p {{_ 'remove-member-pop' name=user.profile.fullname username=user.username boardTitle=board.title}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'remove-member'}}
|
||||
|
||||
template(name="leaveBoardPopup")
|
||||
p {{_ 'leave-board-pop' boardTitle=board.title}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'leave-board'}}
|
||||
|
||||
template(name="addMemberPopup")
|
||||
.js-search-member
|
||||
+esInput(index="users")
|
||||
|
||||
@@ -4,6 +4,7 @@ const defaultView = 'home';
|
||||
|
||||
const viewTitles = {
|
||||
filter: 'filter-cards',
|
||||
search: 'search-cards',
|
||||
multiselection: 'multi-selection',
|
||||
archives: 'archives',
|
||||
};
|
||||
@@ -153,15 +154,13 @@ Template.memberPopup.events({
|
||||
Boards.findOne(boardId).removeMember(memberId);
|
||||
Popup.close();
|
||||
}),
|
||||
'click .js-leave-member'() {
|
||||
'click .js-leave-member': Popup.afterConfirm('leaveBoard', () => {
|
||||
const boardId = Session.get('currentBoard');
|
||||
Meteor.call('quitBoard', boardId, (err, ret) => {
|
||||
if (!ret && ret) {
|
||||
Popup.close();
|
||||
FlowRouter.go('home');
|
||||
}
|
||||
Meteor.call('quitBoard', boardId, () => {
|
||||
Popup.close();
|
||||
FlowRouter.go('home');
|
||||
});
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
Template.removeMemberPopup.helpers({
|
||||
@@ -173,6 +172,12 @@ Template.removeMemberPopup.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.leaveBoardPopup.helpers({
|
||||
board() {
|
||||
return Boards.findOne(Session.get('currentBoard'));
|
||||
},
|
||||
});
|
||||
|
||||
Template.membersWidget.helpers({
|
||||
isInvited() {
|
||||
const user = Meteor.user();
|
||||
|
||||
@@ -25,3 +25,14 @@ template(name="archivesSidebar")
|
||||
= title
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-lists'}}
|
||||
|
||||
+tabContent(slug="swimlanes")
|
||||
ul.archived-lists
|
||||
each archivedSwimlanes
|
||||
li.archived-lists-item
|
||||
if currentUser.isBoardMember
|
||||
button.js-restore-swimlane
|
||||
i.fa.fa-undo
|
||||
= title
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-swimlanes'}}
|
||||
@@ -3,6 +3,7 @@ BlazeComponent.extendComponent({
|
||||
return [
|
||||
{ name: TAPi18n.__('cards'), slug: 'cards' },
|
||||
{ name: TAPi18n.__('lists'), slug: 'lists' },
|
||||
{ name: TAPi18n.__('swimlanes'), slug: 'swimlanes' },
|
||||
];
|
||||
},
|
||||
|
||||
@@ -20,6 +21,13 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
},
|
||||
|
||||
archivedSwimlanes() {
|
||||
return Swimlanes.find({
|
||||
archived: true,
|
||||
boardId: Session.get('currentBoard'),
|
||||
});
|
||||
},
|
||||
|
||||
cardIsInArchivedList() {
|
||||
return this.currentData().list().archived;
|
||||
},
|
||||
@@ -32,7 +40,9 @@ BlazeComponent.extendComponent({
|
||||
return [{
|
||||
'click .js-restore-card'() {
|
||||
const card = this.currentData();
|
||||
card.restore();
|
||||
if(card.canBeRestored()){
|
||||
card.restore();
|
||||
}
|
||||
},
|
||||
'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
|
||||
const cardId = this._id;
|
||||
@@ -43,6 +53,10 @@ BlazeComponent.extendComponent({
|
||||
const list = this.currentData();
|
||||
list.restore();
|
||||
},
|
||||
'click .js-restore-swimlane'() {
|
||||
const swimlane = this.currentData();
|
||||
swimlane.restore();
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('archivesSidebar');
|
||||
@@ -59,7 +59,7 @@ template(name="multiselectionSidebar")
|
||||
if name
|
||||
= name
|
||||
else
|
||||
span.quiet {{_ "label-default" color}}
|
||||
span.quiet {{_ "label-default" (_ (concat "color-" color))}}
|
||||
if allSelectedElementHave 'label' _id
|
||||
i.fa.fa-check
|
||||
else if someSelectedElementHave 'label' _id
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
template(name="searchSidebar")
|
||||
form.js-search-term-form
|
||||
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
|
||||
.list-body.js-perfect-scrollbar
|
||||
.minicards.clearfix.js-minicards
|
||||
each (results)
|
||||
a.minicard-wrapper.js-minicard(href=absoluteUrl)
|
||||
+minicard(this)
|
||||
@@ -0,0 +1,19 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.term = new ReactiveVar('');
|
||||
},
|
||||
|
||||
results() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return currentBoard.searchCards(this.term.get());
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'submit .js-search-term-form'(evt) {
|
||||
evt.preventDefault();
|
||||
this.term.set(evt.target.searchTerm.value);
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('searchSidebar');
|
||||
@@ -0,0 +1,2 @@
|
||||
input
|
||||
max-width: 100%
|
||||
@@ -0,0 +1,23 @@
|
||||
template(name="swimlaneHeader")
|
||||
.swimlane-header-wrap.js-swimlane-header
|
||||
+inlinedForm
|
||||
+editSwimlaneTitleForm
|
||||
else
|
||||
.swimlane-header(
|
||||
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
|
||||
= title
|
||||
.swimlane-header-menu
|
||||
unless currentUser.isCommentOnly
|
||||
a.fa.fa-navicon.js-open-swimlane-menu
|
||||
|
||||
template(name="editSwimlaneTitleForm")
|
||||
.list-composer
|
||||
input.list-name-input.full-line(type="text" value=title autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
|
||||
template(name="swimlaneActionPopup")
|
||||
unless currentUser.isCommentOnly
|
||||
ul.pop-over-list
|
||||
li: a.js-close-swimlane {{_ 'archive-swimlane'}}
|
||||
@@ -0,0 +1,25 @@
|
||||
BlazeComponent.extendComponent({
|
||||
editTitle(evt) {
|
||||
evt.preventDefault();
|
||||
const newTitle = this.childComponents('inlinedForm')[0].getValue().trim();
|
||||
const swimlane = this.currentData();
|
||||
if (newTitle) {
|
||||
swimlane.rename(newTitle.trim());
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
'click .js-open-swimlane-menu': Popup.open('swimlaneAction'),
|
||||
submit: this.editTitle,
|
||||
}];
|
||||
},
|
||||
}).register('swimlaneHeader');
|
||||
|
||||
Template.swimlaneActionPopup.events({
|
||||
'click .js-close-swimlane' (evt) {
|
||||
evt.preventDefault();
|
||||
this.archive();
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,75 @@
|
||||
template(name="swimlane")
|
||||
.swimlane.js-lists.js-swimlane
|
||||
+swimlaneHeader
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
+list(currentList)
|
||||
else
|
||||
each currentBoard.lists
|
||||
+miniList(this)
|
||||
if currentUser.isBoardMember
|
||||
+addListForm
|
||||
else
|
||||
each currentBoard.lists
|
||||
+list(this)
|
||||
if currentCardIsInThisList _id ../_id
|
||||
+cardDetails(currentCard)
|
||||
if currentUser.isBoardMember
|
||||
+addListAndSwimlaneForm
|
||||
|
||||
template(name="listsGroup")
|
||||
.swimlane.list-group.js-lists
|
||||
if isMiniScreen
|
||||
if currentList
|
||||
+list(currentList)
|
||||
else
|
||||
each currentBoard.lists
|
||||
+miniList(this)
|
||||
if currentUser.isBoardMember
|
||||
+addListForm
|
||||
else
|
||||
each currentBoard.lists
|
||||
+list(this)
|
||||
if currentCardIsInThisList _id null
|
||||
+cardDetails(currentCard)
|
||||
if currentUser.isBoardMember
|
||||
+addListForm
|
||||
|
||||
template(name="addListAndSwimlaneForm")
|
||||
.list.list-composer.js-list-composer
|
||||
.list-header
|
||||
+inlinedForm(autoclose=false)
|
||||
input.list-name-input.full-line(type="text" placeholder="{{_ 'add-list'}}"
|
||||
autocomplete="off" autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-list'}}
|
||||
.list-header
|
||||
+inlinedForm(autoclose=false)
|
||||
input.swimlane-name-input.full-line(type="text" placeholder="{{_ 'add-swimlane'}}"
|
||||
autocomplete="off" autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-swimlane'}}
|
||||
|
||||
template(name="addListForm")
|
||||
.list.list-composer.js-list-composer
|
||||
.list-header
|
||||
+inlinedForm(autoclose=false)
|
||||
input.list-name-input.full-line(type="text" placeholder="{{_ 'add-list'}}"
|
||||
autocomplete="off" autofocus)
|
||||
.edit-controls.clearfix
|
||||
button.primary.confirm(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-list'}}
|
||||
@@ -0,0 +1,212 @@
|
||||
const { calculateIndex } = Utils;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onRendered() {
|
||||
const boardComponent = this.parentComponent();
|
||||
const $listsDom = this.$('.js-lists');
|
||||
|
||||
if (!Session.get('currentCard')) {
|
||||
boardComponent.scrollLeft();
|
||||
}
|
||||
|
||||
// We want to animate the card details window closing. We rely on CSS
|
||||
// transition for the actual animation.
|
||||
$listsDom._uihooks = {
|
||||
removeElement(node) {
|
||||
const removeNode = _.once(() => {
|
||||
node.parentNode.removeChild(node);
|
||||
});
|
||||
if ($(node).hasClass('js-card-details')) {
|
||||
$(node).css({
|
||||
flexBasis: 0,
|
||||
padding: 0,
|
||||
});
|
||||
$listsDom.one(CSSEvents.transitionend, removeNode);
|
||||
} else {
|
||||
removeNode();
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
$listsDom.sortable({
|
||||
tolerance: 'pointer',
|
||||
helper: 'clone',
|
||||
handle: '.js-list-header',
|
||||
items: '.js-list:not(.js-list-composer)',
|
||||
placeholder: 'list placeholder',
|
||||
distance: 7,
|
||||
start(evt, ui) {
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
boardComponent.setIsDragging(true);
|
||||
},
|
||||
stop(evt, ui) {
|
||||
// To attribute the new index number, we need to get the DOM element
|
||||
// of the previous and the following card -- if any.
|
||||
const prevListDom = ui.item.prev('.js-list').get(0);
|
||||
const nextListDom = ui.item.next('.js-list').get(0);
|
||||
const sortIndex = calculateIndex(prevListDom, nextListDom, 1);
|
||||
|
||||
$listsDom.sortable('cancel');
|
||||
const listDomElement = ui.item.get(0);
|
||||
const list = Blaze.getData(listDomElement);
|
||||
|
||||
Lists.update(list._id, {
|
||||
$set: {
|
||||
sort: sortIndex.base,
|
||||
},
|
||||
});
|
||||
|
||||
boardComponent.setIsDragging(false);
|
||||
},
|
||||
});
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
}
|
||||
|
||||
// Disable drag-dropping while in multi-selection mode, or if the current user
|
||||
// is not a board member
|
||||
boardComponent.autorun(() => {
|
||||
const $listDom = $listsDom;
|
||||
if ($listDom.data('sortable')) {
|
||||
$listsDom.sortable('option', 'disabled',
|
||||
MultiSelection.isActive() || !userIsMember());
|
||||
}
|
||||
});
|
||||
},
|
||||
onCreated() {
|
||||
this.draggingActive = new ReactiveVar(false);
|
||||
|
||||
this._isDragging = false;
|
||||
this._lastDragPositionX = 0;
|
||||
},
|
||||
|
||||
id() {
|
||||
return this._id;
|
||||
},
|
||||
|
||||
currentCardIsInThisList(listId, swimlaneId) {
|
||||
const currentCard = Cards.findOne(Session.get('currentCard'));
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
const board = Boards.findOne(currentBoardId);
|
||||
if (board.view === 'board-view-lists')
|
||||
return currentCard && currentCard.listId === listId;
|
||||
else if (board.view === 'board-view-swimlanes')
|
||||
return currentCard && currentCard.listId === listId && currentCard.swimlaneId === swimlaneId;
|
||||
else
|
||||
return false;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
// Click-and-drag action
|
||||
'mousedown .board-canvas'(evt) {
|
||||
// Translating the board canvas using the click-and-drag action can
|
||||
// conflict with the build-in browser mechanism to select text. We
|
||||
// define a list of elements in which we disable the dragging because
|
||||
// the user will legitimately expect to be able to select some text with
|
||||
// his mouse.
|
||||
const noDragInside = ['a', 'input', 'textarea', 'p', '.js-list-header'];
|
||||
if ($(evt.target).closest(noDragInside.join(',')).length === 0 && this.$('.swimlane').prop('clientHeight') > evt.offsetY) {
|
||||
this._isDragging = true;
|
||||
this._lastDragPositionX = evt.clientX;
|
||||
}
|
||||
},
|
||||
'mouseup'() {
|
||||
if (this._isDragging) {
|
||||
this._isDragging = false;
|
||||
}
|
||||
},
|
||||
'mousemove'(evt) {
|
||||
if (this._isDragging) {
|
||||
// Update the canvas position
|
||||
this.listsDom.scrollLeft -= evt.clientX - this._lastDragPositionX;
|
||||
this._lastDragPositionX = evt.clientX;
|
||||
// Disable browser text selection while dragging
|
||||
evt.stopPropagation();
|
||||
evt.preventDefault();
|
||||
// Don't close opened card or inlined form at the end of the
|
||||
// click-and-drag.
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
EscapeActions.preventNextClick();
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('swimlane');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
// Proxy
|
||||
open() {
|
||||
this.childComponents('inlinedForm')[0].open();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
submit(evt) {
|
||||
evt.preventDefault();
|
||||
const titleInput = this.find('.list-name-input');
|
||||
const title = titleInput.value.trim();
|
||||
if (title) {
|
||||
Lists.insert({
|
||||
title,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.list').length,
|
||||
});
|
||||
|
||||
titleInput.value = '';
|
||||
titleInput.focus();
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('addListForm');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
// Proxy
|
||||
open() {
|
||||
this.childComponents('inlinedForm')[0].open();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [{
|
||||
submit(evt) {
|
||||
evt.preventDefault();
|
||||
let titleInput = this.find('.list-name-input');
|
||||
if (titleInput) {
|
||||
const title = titleInput.value.trim();
|
||||
if (title) {
|
||||
Lists.insert({
|
||||
title,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.list').length,
|
||||
});
|
||||
|
||||
titleInput.value = '';
|
||||
titleInput.focus();
|
||||
}
|
||||
} else {
|
||||
titleInput = this.find('.swimlane-name-input');
|
||||
const title = titleInput.value.trim();
|
||||
if (title) {
|
||||
Swimlanes.insert({
|
||||
title,
|
||||
boardId: Session.get('currentBoard'),
|
||||
sort: $('.swimlane').length,
|
||||
});
|
||||
|
||||
titleInput.value = '';
|
||||
titleInput.focus();
|
||||
}
|
||||
}
|
||||
},
|
||||
}];
|
||||
},
|
||||
}).register('addListAndSwimlaneForm');
|
||||
|
||||
Template.swimlane.helpers({
|
||||
canSeeAddList() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,54 @@
|
||||
@import 'nib'
|
||||
|
||||
.swimlane
|
||||
// Even if this background color is the same as the body we can't leave it
|
||||
// transparent, because that won't work during a swimlane drag.
|
||||
background: darken(white, 13%)
|
||||
display: flex
|
||||
flex-direction: row
|
||||
overflow: 0;
|
||||
max-height: 100%
|
||||
|
||||
&.placeholder
|
||||
background-color: rgba(0, 0, 0, .2)
|
||||
border-color: transparent
|
||||
box-shadow: none
|
||||
height: 100px
|
||||
|
||||
&.ui-sortable-helper
|
||||
box-shadow: -2px 2px 8px rgba(0, 0, 0, .3),
|
||||
0 0 1px rgba(0, 0, 0, .5)
|
||||
transform: rotate(2deg)
|
||||
cursor: grabbing
|
||||
|
||||
.swimlane-header.ui-sortable-handle
|
||||
cursor: grabbing
|
||||
|
||||
.swimlane-header-wrap
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex: 0 0 50px;
|
||||
padding-bottom: 30px;
|
||||
border-bottom: 1px solid #CCC
|
||||
|
||||
.swimlane-header
|
||||
writing-mode: vertical-rl;
|
||||
transform: rotate(180deg);
|
||||
font-size: 14px;
|
||||
line-height: 50px;
|
||||
margin-top: 50px;
|
||||
font-weight: bold;
|
||||
min-height: 9px;
|
||||
min-width: 30px;
|
||||
overflow: hidden;
|
||||
-o-text-overflow: ellipsis;
|
||||
text-overflow: ellipsis;
|
||||
word-wrap: break-word;
|
||||
text-align: center;
|
||||
|
||||
.swimlane-header-menu
|
||||
position: absolute
|
||||
padding: 20px 20px
|
||||
|
||||
.list-group
|
||||
height: 100%
|
||||
@@ -55,7 +55,7 @@ template(name="changeAvatarPopup")
|
||||
li: a.js-select-initials
|
||||
.member
|
||||
+userAvatarInitials(userId=currentUser._id)
|
||||
| Initials
|
||||
| {{_ 'initials' }}
|
||||
if noAvatarUrl
|
||||
i.fa.fa-check
|
||||
p.sub-name {{_ 'default-avatar'}}
|
||||
@@ -71,10 +71,10 @@ template(name="cardMemberPopup")
|
||||
.info
|
||||
h3= user.profile.fullname
|
||||
p.quiet @{{ user.username }}
|
||||
if currentUser.isBoardMember
|
||||
ul.pop-over-list
|
||||
li: a.js-remove-member {{_ 'remove-member-from-card'}}
|
||||
ul.pop-over-list
|
||||
if currentUser.isNotCommentOnly
|
||||
li: a.js-remove-member {{_ 'remove-member-from-card'}}
|
||||
|
||||
if $eq currentUser._id user._id
|
||||
with currentUser
|
||||
li: a.js-edit-profile {{_ 'edit-profile'}}
|
||||
if $eq currentUser._id user._id
|
||||
with currentUser
|
||||
li: a.js-edit-profile {{_ 'edit-profile'}}
|
||||
@@ -1,5 +1,3 @@
|
||||
Meteor.subscribe('my-avatars');
|
||||
|
||||
Template.userAvatar.helpers({
|
||||
userData() {
|
||||
// We need to handle a special case for the search results provided by the
|
||||
@@ -54,6 +52,8 @@ Template.userAvatarInitials.helpers({
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
|
||||
Meteor.subscribe('my-avatars');
|
||||
},
|
||||
|
||||
avatarUrlOptions() {
|
||||
|
||||
@@ -3,10 +3,11 @@ template(name="headerUserBar")
|
||||
a.header-user-bar-name.js-open-header-member-menu
|
||||
.header-user-bar-avatar
|
||||
+userAvatar(userId=currentUser._id)
|
||||
if currentUser.profile.fullname
|
||||
= currentUser.profile.fullname
|
||||
else
|
||||
= currentUser.username
|
||||
unless isMiniScreen
|
||||
if currentUser.profile.fullname
|
||||
= currentUser.profile.fullname
|
||||
else
|
||||
= currentUser.username
|
||||
|
||||
template(name="memberMenuPopup")
|
||||
ul.pop-over-list
|
||||
@@ -18,7 +19,7 @@ template(name="memberMenuPopup")
|
||||
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
|
||||
li: a.js-edit-notification {{_ 'editNotificationPopup-title'}}
|
||||
if currentUser.isAdmin
|
||||
li: a.js-go-setting(href='/setting') {{_ 'admin-panel'}}
|
||||
li: a.js-go-setting(href="{{pathFor 'setting'}}") {{_ 'admin-panel'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-logout {{_ 'log-out'}}
|
||||
@@ -36,6 +37,14 @@ template(name="editProfilePopup")
|
||||
label
|
||||
| {{_ 'initials'}}
|
||||
input.js-profile-initials(type="text" value=profile.initials)
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
| {{_ 'error-email-taken'}}
|
||||
if allowEmailChange
|
||||
input.js-profile-email(type="email" value="{{emails.[0].address}}")
|
||||
else
|
||||
input.js-profile-email(type="email" value="{{emails.[0].address}}" readonly)
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
|
||||
template(name="editNotificationPopup")
|
||||
|
||||
@@ -20,19 +20,50 @@ Template.memberMenuPopup.events({
|
||||
},
|
||||
});
|
||||
|
||||
Template.editProfilePopup.helpers({
|
||||
allowEmailChange() {
|
||||
return AccountSettings.findOne('accounts-allowEmailChange').booleanValue;
|
||||
},
|
||||
});
|
||||
|
||||
Template.editProfilePopup.events({
|
||||
submit(evt, tpl) {
|
||||
evt.preventDefault();
|
||||
const fullname = tpl.find('.js-profile-fullname').value.trim();
|
||||
const username = tpl.find('.js-profile-username').value.trim();
|
||||
const initials = tpl.find('.js-profile-initials').value.trim();
|
||||
Users.update(Meteor.userId(), {$set: {
|
||||
'profile.fullname': fullname,
|
||||
'profile.initials': initials,
|
||||
}});
|
||||
|
||||
if (username !== Meteor.user().username) {
|
||||
Meteor.call('setUsername', username, function(error) {
|
||||
const email = tpl.find('.js-profile-email').value.trim();
|
||||
let isChangeUserName = false;
|
||||
let isChangeEmail = false;
|
||||
Users.update(Meteor.userId(), {
|
||||
$set: {
|
||||
'profile.fullname': fullname,
|
||||
'profile.initials': initials,
|
||||
},
|
||||
});
|
||||
isChangeUserName = username !== Meteor.user().username;
|
||||
isChangeEmail = email.toLowerCase() !== Meteor.user().emails[0].address.toLowerCase();
|
||||
if (isChangeUserName && isChangeEmail) {
|
||||
Meteor.call('setUsernameAndEmail', username, email.toLowerCase(), Meteor.userId(), function (error) {
|
||||
const usernameMessageElement = tpl.$('.username-taken');
|
||||
const emailMessageElement = tpl.$('.email-taken');
|
||||
if (error) {
|
||||
const errorElement = error.error;
|
||||
if (errorElement === 'username-already-taken') {
|
||||
usernameMessageElement.show();
|
||||
emailMessageElement.hide();
|
||||
} else if (errorElement === 'email-already-taken') {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.show();
|
||||
}
|
||||
} else {
|
||||
usernameMessageElement.hide();
|
||||
emailMessageElement.hide();
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
} else if (isChangeUserName) {
|
||||
Meteor.call('setUsername', username, Meteor.userId(), function (error) {
|
||||
const messageElement = tpl.$('.username-taken');
|
||||
if (error) {
|
||||
messageElement.show();
|
||||
@@ -41,6 +72,16 @@ Template.editProfilePopup.events({
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
} else if (isChangeEmail) {
|
||||
Meteor.call('setEmail', email.toLowerCase(), Meteor.userId(), function (error) {
|
||||
const messageElement = tpl.$('.email-taken');
|
||||
if (error) {
|
||||
messageElement.show();
|
||||
} else {
|
||||
messageElement.hide();
|
||||
Popup.back();
|
||||
}
|
||||
});
|
||||
} else Popup.back();
|
||||
},
|
||||
});
|
||||
@@ -66,15 +107,29 @@ Template.editNotificationPopup.events({
|
||||
|
||||
// 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() {
|
||||
Template.changePasswordPopup.onRendered(function () {
|
||||
this.find('#at-field-current_password').focus();
|
||||
});
|
||||
|
||||
Template.changeLanguagePopup.helpers({
|
||||
languages() {
|
||||
return _.map(TAPi18n.getLanguages(), (lang, tag) => {
|
||||
const name = lang.name;
|
||||
return _.map(TAPi18n.getLanguages(), (lang, code) => {
|
||||
// Same code in /client/components/main/layouts.js
|
||||
// TODO : Make code reusable
|
||||
const tag = code;
|
||||
let name = lang.name;
|
||||
if (lang.name === 'br') {
|
||||
name = 'Brezhoneg';
|
||||
} else if (lang.name === 'ig') {
|
||||
name = 'Igbo';
|
||||
}
|
||||
return { tag, name };
|
||||
}).sort(function (a, b) {
|
||||
if (a.name === b.name) {
|
||||
return 0;
|
||||
} else {
|
||||
return a.name > b.name ? 1 : -1;
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
@@ -16,6 +16,17 @@ Blaze.registerHelper('currentCard', () => {
|
||||
}
|
||||
});
|
||||
|
||||
Blaze.registerHelper('currentList', () => {
|
||||
const listId = Session.get('currentList');
|
||||
if (listId) {
|
||||
return Lists.findOne(listId);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
Blaze.registerHelper('getUser', (userId) => Users.findOne(userId));
|
||||
|
||||
Blaze.registerHelper('concat', (...args) => args.slice(0, -1).join(''));
|
||||
|
||||
Blaze.registerHelper('isMiniScreen', () => Utils.isMiniScreen());
|
||||
@@ -1,152 +0,0 @@
|
||||
Emoji.values = ['+1', '-1', '100', '1234', '8ball', 'a', 'ab', 'abc', 'abcd',
|
||||
'accept', 'aerial_tramway', 'airplane', 'alarm_clock', 'alien', 'ambulance',
|
||||
'anchor', 'angel', 'anger', 'angry', 'anguished', 'ant', 'apple', 'aquarius',
|
||||
'aries', 'arrow_backward', 'arrow_double_down', 'arrow_double_up', 'arrow_down',
|
||||
'arrow_down_small', 'arrow_forward', 'arrow_heading_down', 'arrow_heading_up',
|
||||
'arrow_left', 'arrow_lower_left', 'arrow_lower_right', 'arrow_right',
|
||||
'arrow_right_hook', 'arrow_up', 'arrow_up_down', 'arrow_up_small',
|
||||
'arrow_upper_left', 'arrow_upper_right', 'arrows_clockwise',
|
||||
'arrows_counterclockwise', 'art', 'articulated_lorry', 'astonished', 'atm', 'b',
|
||||
'baby', 'baby_bottle', 'baby_chick', 'baby_symbol', 'baggage_claim', 'balloon',
|
||||
'ballot_box_with_check', 'bamboo', 'banana', 'bangbang', 'bank', 'bar_chart',
|
||||
'barber', 'baseball', 'basketball', 'bath', 'bathtub', 'battery', 'bear', 'bee',
|
||||
'beer', 'beers', 'beetle', 'beginner', 'bell', 'bento', 'bicyclist', 'bike',
|
||||
'bikini', 'bird', 'birthday', 'black_circle', 'black_joker', 'black_nib',
|
||||
'black_square', 'black_square_button', 'blossom', 'blowfish', 'blue_book',
|
||||
'blue_car', 'blue_heart', 'blush', 'boar', 'boat', 'bomb', 'book', 'bookmark',
|
||||
'bookmark_tabs', 'books', 'boom', 'boot', 'bouquet', 'bow', 'bowling', 'bowtie',
|
||||
'boy', 'bread', 'bride_with_veil', 'bridge_at_night', 'briefcase',
|
||||
'broken_heart', 'bug', 'bulb', 'bullettrain_front', 'bullettrain_side', 'bus',
|
||||
'busstop', 'bust_in_silhouette', 'busts_in_silhouette', 'cactus', 'cake',
|
||||
'calendar', 'calling', 'camel', 'camera', 'cancer', 'candy', 'capital_abcd',
|
||||
'capricorn', 'car', 'card_index', 'carousel_horse', 'cat', 'cat2', 'cd',
|
||||
'chart', 'chart_with_downwards_trend', 'chart_with_upwards_trend',
|
||||
'checkered_flag', 'cherries', 'cherry_blossom', 'chestnut', 'chicken',
|
||||
'children_crossing', 'chocolate_bar', 'christmas_tree', 'church', 'cinema',
|
||||
'circus_tent', 'city_sunrise', 'city_sunset', 'cl', 'clap', 'clapper',
|
||||
'clipboard', 'clock1', 'clock10', 'clock1030', 'clock11', 'clock1130',
|
||||
'clock12', 'clock1230', 'clock130', 'clock2', 'clock230', 'clock3', 'clock330',
|
||||
'clock4', 'clock430', 'clock5', 'clock530', 'clock6', 'clock630', 'clock7',
|
||||
'clock730', 'clock8', 'clock830', 'clock9', 'clock930', 'closed_book',
|
||||
'closed_lock_with_key', 'closed_umbrella', 'cloud', 'clubs', 'cn', 'cocktail',
|
||||
'coffee', 'cold_sweat', 'collision', 'computer', 'confetti_ball', 'confounded',
|
||||
'confused', 'congratulations', 'construction', 'construction_worker',
|
||||
'convenience_store', 'cookie', 'cool', 'cop', 'copyright', 'corn', 'couple',
|
||||
'couple_with_heart', 'couplekiss', 'cow', 'cow2', 'credit_card', 'crocodile',
|
||||
'crossed_flags', 'crown', 'cry', 'crying_cat_face', 'crystal_ball', 'cupid',
|
||||
'curly_loop', 'currency_exchange', 'curry', 'custard', 'customs', 'cyclone',
|
||||
'dancer', 'dancers', 'dango', 'dart', 'dash', 'date', 'de', 'deciduous_tree',
|
||||
'department_store', 'diamond_shape_with_a_dot_inside', 'diamonds',
|
||||
'disappointed', 'disappointed_relieved', 'dizzy', 'dizzy_face', 'do_not_litter',
|
||||
'dog', 'dog2', 'dollar', 'dolls', 'dolphin', 'donut', 'door', 'doughnut',
|
||||
'dragon', 'dragon_face', 'dress', 'dromedary_camel', 'droplet', 'dvd', 'e-mail',
|
||||
'ear', 'ear_of_rice', 'earth_africa', 'earth_americas', 'earth_asia', 'egg',
|
||||
'eggplant', 'eight', 'eight_pointed_black_star', 'eight_spoked_asterisk',
|
||||
'electric_plug', 'elephant', 'email', 'end', 'envelope', 'es', 'euro',
|
||||
'european_castle', 'european_post_office', 'evergreen_tree', 'exclamation',
|
||||
'expressionless', 'eyeglasses', 'eyes', 'facepunch', 'factory', 'fallen_leaf',
|
||||
'family', 'fast_forward', 'fax', 'fearful', 'feelsgood', 'feet', 'ferris_wheel',
|
||||
'file_folder', 'finnadie', 'fire', 'fire_engine', 'fireworks',
|
||||
'first_quarter_moon', 'first_quarter_moon_with_face', 'fish', 'fish_cake',
|
||||
'fishing_pole_and_fish', 'fist', 'five', 'flags', 'flashlight', 'floppy_disk',
|
||||
'flower_playing_cards', 'flushed', 'foggy', 'football', 'fork_and_knife',
|
||||
'fountain', 'four', 'four_leaf_clover', 'fr', 'free', 'fried_shrimp', 'fries',
|
||||
'frog', 'frowning', 'fu', 'fuelpump', 'full_moon', 'full_moon_with_face',
|
||||
'game_die', 'gb', 'gem', 'gemini', 'ghost', 'gift', 'gift_heart', 'girl',
|
||||
'globe_with_meridians', 'goat', 'goberserk', 'godmode', 'golf', 'grapes',
|
||||
'green_apple', 'green_book', 'green_heart', 'grey_exclamation', 'grey_question',
|
||||
'grimacing', 'grin', 'grinning', 'guardsman', 'guitar', 'gun', 'haircut',
|
||||
'hamburger', 'hammer', 'hamster', 'hand', 'handbag', 'hankey', 'hash',
|
||||
'hatched_chick', 'hatching_chick', 'headphones', 'hear_no_evil', 'heart',
|
||||
'heart_decoration', 'heart_eyes', 'heart_eyes_cat', 'heartbeat', 'heartpulse',
|
||||
'hearts', 'heavy_check_mark', 'heavy_division_sign', 'heavy_dollar_sign',
|
||||
'heavy_exclamation_mark', 'heavy_minus_sign', 'heavy_multiplication_x',
|
||||
'heavy_plus_sign', 'helicopter', 'herb', 'hibiscus', 'high_brightness',
|
||||
'high_heel', 'hocho', 'honey_pot', 'honeybee', 'horse', 'horse_racing',
|
||||
'hospital', 'hotel', 'hotsprings', 'hourglass', 'hourglass_flowing_sand',
|
||||
'house', 'house_with_garden', 'hurtrealbad', 'hushed', 'ice_cream', 'icecream',
|
||||
'id', 'ideograph_advantage', 'imp', 'inbox_tray', 'incoming_envelope',
|
||||
'information_desk_person', 'information_source', 'innocent', 'interrobang',
|
||||
'iphone', 'it', 'izakaya_lantern', 'jack_o_lantern', 'japan', 'japanese_castle',
|
||||
'japanese_goblin', 'japanese_ogre', 'jeans', 'joy', 'joy_cat', 'jp', 'key',
|
||||
'keycap_ten', 'kimono', 'kiss', 'kissing', 'kissing_cat', 'kissing_closed_eyes',
|
||||
'kissing_face', 'kissing_heart', 'kissing_smiling_eyes', 'koala', 'koko', 'kr',
|
||||
'large_blue_circle', 'large_blue_diamond', 'large_orange_diamond',
|
||||
'last_quarter_moon', 'last_quarter_moon_with_face', 'laughing', 'leaves',
|
||||
'ledger', 'left_luggage', 'left_right_arrow', 'leftwards_arrow_with_hook',
|
||||
'lemon', 'leo', 'leopard', 'libra', 'light_rail', 'link', 'lips', 'lipstick',
|
||||
'lock', 'lock_with_ink_pen', 'lollipop', 'loop', 'loudspeaker', 'love_hotel',
|
||||
'love_letter', 'low_brightness', 'm', 'mag', 'mag_right', 'mahjong', 'mailbox',
|
||||
'mailbox_closed', 'mailbox_with_mail', 'mailbox_with_no_mail', 'man',
|
||||
'man_with_gua_pi_mao', 'man_with_turban', 'mans_shoe', 'maple_leaf', 'mask',
|
||||
'massage', 'meat_on_bone', 'mega', 'melon', 'memo', 'mens', 'metal', 'metro',
|
||||
'microphone', 'microscope', 'milky_way', 'minibus', 'minidisc',
|
||||
'mobile_phone_off', 'money_with_wings', 'moneybag', 'monkey', 'monkey_face',
|
||||
'monorail', 'moon', 'mortar_board', 'mount_fuji', 'mountain_bicyclist',
|
||||
'mountain_cableway', 'mountain_railway', 'mouse', 'mouse2', 'movie_camera',
|
||||
'moyai', 'muscle', 'mushroom', 'musical_keyboard', 'musical_note',
|
||||
'musical_score', 'mute', 'nail_care', 'name_badge', 'neckbeard', 'necktie',
|
||||
'negative_squared_cross_mark', 'neutral_face', 'new', 'new_moon',
|
||||
'new_moon_with_face', 'newspaper', 'ng', 'nine', 'no_bell', 'no_bicycles',
|
||||
'no_entry', 'no_entry_sign', 'no_good', 'no_mobile_phones', 'no_mouth',
|
||||
'no_pedestrians', 'no_smoking', 'non-potable_water', 'nose', 'notebook',
|
||||
'notebook_with_decorative_cover', 'notes', 'nut_and_bolt', 'o', 'o2', 'ocean',
|
||||
'octocat', 'octopus', 'oden', 'office', 'ok', 'ok_hand', 'ok_woman',
|
||||
'older_man', 'older_woman', 'on', 'oncoming_automobile', 'oncoming_bus',
|
||||
'oncoming_police_car', 'oncoming_taxi', 'one', 'open_file_folder', 'open_hands',
|
||||
'open_mouth', 'ophiuchus', 'orange_book', 'outbox_tray', 'ox', 'page_facing_up',
|
||||
'page_with_curl', 'pager', 'palm_tree', 'panda_face', 'paperclip', 'parking',
|
||||
'part_alternation_mark', 'partly_sunny', 'passport_control', 'paw_prints',
|
||||
'peach', 'pear', 'pencil', 'pencil2', 'penguin', 'pensive', 'performing_arts',
|
||||
'persevere', 'person_frowning', 'person_with_blond_hair',
|
||||
'person_with_pouting_face', 'phone', 'pig', 'pig2', 'pig_nose', 'pill',
|
||||
'pineapple', 'pisces', 'pizza', 'plus1', 'point_down', 'point_left',
|
||||
'point_right', 'point_up', 'point_up_2', 'police_car', 'poodle', 'poop',
|
||||
'post_office', 'postal_horn', 'postbox', 'potable_water', 'pouch',
|
||||
'poultry_leg', 'pound', 'pouting_cat', 'pray', 'princess', 'punch',
|
||||
'purple_heart', 'purse', 'pushpin', 'put_litter_in_its_place', 'question',
|
||||
'rabbit', 'rabbit2', 'racehorse', 'radio', 'radio_button', 'rage', 'rage1',
|
||||
'rage2', 'rage3', 'rage4', 'railway_car', 'rainbow', 'raised_hand',
|
||||
'raised_hands', 'raising_hand', 'ram', 'ramen', 'rat', 'recycle', 'red_car',
|
||||
'red_circle', 'registered', 'relaxed', 'relieved', 'repeat', 'repeat_one',
|
||||
'restroom', 'revolving_hearts', 'rewind', 'ribbon', 'rice', 'rice_ball',
|
||||
'rice_cracker', 'rice_scene', 'ring', 'rocket', 'roller_coaster', 'rooster',
|
||||
'rose', 'rotating_light', 'round_pushpin', 'rowboat', 'ru', 'rugby_football',
|
||||
'runner', 'running', 'running_shirt_with_sash', 'sa', 'sagittarius', 'sailboat',
|
||||
'sake', 'sandal', 'santa', 'satellite', 'satisfied', 'saxophone', 'school',
|
||||
'school_satchel', 'scissors', 'scorpius', 'scream', 'scream_cat', 'scroll',
|
||||
'seat', 'secret', 'see_no_evil', 'seedling', 'seven', 'shaved_ice', 'sheep',
|
||||
'shell', 'ship', 'shipit', 'shirt', 'shit', 'shoe', 'shower', 'signal_strength',
|
||||
'six', 'six_pointed_star', 'ski', 'skull', 'sleeping', 'sleepy', 'slot_machine',
|
||||
'small_blue_diamond', 'small_orange_diamond', 'small_red_triangle',
|
||||
'small_red_triangle_down', 'smile', 'smile_cat', 'smiley', 'smiley_cat',
|
||||
'smiling_imp', 'smirk', 'smirk_cat', 'smoking', 'snail', 'snake', 'snowboarder',
|
||||
'snowflake', 'snowman', 'sob', 'soccer', 'soon', 'sos', 'sound',
|
||||
'space_invader', 'spades', 'spaghetti', 'sparkler', 'sparkles',
|
||||
'sparkling_heart', 'speak_no_evil', 'speaker', 'speech_balloon', 'speedboat',
|
||||
'squirrel', 'star', 'star2', 'stars', 'station', 'statue_of_liberty',
|
||||
'steam_locomotive', 'stew', 'straight_ruler', 'strawberry', 'stuck_out_tongue',
|
||||
'stuck_out_tongue_closed_eyes', 'stuck_out_tongue_winking_eye', 'sun_with_face',
|
||||
'sunflower', 'sunglasses', 'sunny', 'sunrise', 'sunrise_over_mountains',
|
||||
'surfer', 'sushi', 'suspect', 'suspension_railway', 'sweat', 'sweat_drops',
|
||||
'sweat_smile', 'sweet_potato', 'swimmer', 'symbols', 'syringe', 'tada',
|
||||
'tanabata_tree', 'tangerine', 'taurus', 'taxi', 'tea', 'telephone',
|
||||
'telephone_receiver', 'telescope', 'tennis', 'tent', 'thought_balloon', 'three',
|
||||
'thumbsdown', 'thumbsup', 'ticket', 'tiger', 'tiger2', 'tired_face', 'tm',
|
||||
'toilet', 'tokyo_tower', 'tomato', 'tongue', 'top', 'tophat', 'tractor',
|
||||
'traffic_light', 'train', 'train2', 'tram', 'triangular_flag_on_post',
|
||||
'triangular_ruler', 'trident', 'triumph', 'trolleybus', 'trollface', 'trophy',
|
||||
'tropical_drink', 'tropical_fish', 'truck', 'trumpet', 'tshirt', 'tulip',
|
||||
'turtle', 'tv', 'twisted_rightwards_arrows', 'two', 'two_hearts',
|
||||
'two_men_holding_hands', 'two_women_holding_hands', 'u5272', 'u5408', 'u55b6',
|
||||
'u6307', 'u6708', 'u6709', 'u6e80', 'u7121', 'u7533', 'u7981', 'u7a7a', 'uk',
|
||||
'umbrella', 'unamused', 'underage', 'unlock', 'up', 'us', 'v',
|
||||
'vertical_traffic_light', 'vhs', 'vibration_mode', 'video_camera', 'video_game',
|
||||
'violin', 'virgo', 'volcano', 'vs', 'walking', 'waning_crescent_moon',
|
||||
'waning_gibbous_moon', 'warning', 'watch', 'water_buffalo', 'watermelon',
|
||||
'wave', 'wavy_dash', 'waxing_crescent_moon', 'waxing_gibbous_moon', 'wc',
|
||||
'weary', 'wedding', 'whale', 'whale2', 'wheelchair', 'white_check_mark',
|
||||
'white_circle', 'white_flower', 'white_square', 'white_square_button',
|
||||
'wind_chime', 'wine_glass', 'wink', 'wolf', 'woman', 'womans_clothes',
|
||||
'womans_hat', 'womens', 'worried', 'wrench', 'x', 'yellow_heart', 'yen', 'yum',
|
||||
'zap', 'zero', 'zzz'];
|
||||
@@ -134,3 +134,7 @@ $(document).on('click', (evt) => {
|
||||
EscapeActions.clickExecute(evt.target, 'multiselection');
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on('click', 'a[href=#]', (evt) => {
|
||||
evt.preventDefault();
|
||||
});
|
||||
@@ -3,6 +3,7 @@
|
||||
// information provided by the browser, and default to english.
|
||||
|
||||
Meteor.startup(() => {
|
||||
TAPi18n.conf.i18n_files_route = Meteor._relativeToSiteRootUrl('/tap-i18n');
|
||||
Tracker.autorun(() => {
|
||||
const currentUser = Meteor.user();
|
||||
let language;
|
||||
|
||||
@@ -6,7 +6,11 @@ Mousetrap.bind('?', () => {
|
||||
});
|
||||
|
||||
Mousetrap.bind('w', () => {
|
||||
Sidebar.toggle();
|
||||
if (Sidebar.isOpen() && Sidebar.getView() === 'home') {
|
||||
Sidebar.toggle();
|
||||
} else {
|
||||
Sidebar.setView();
|
||||
}
|
||||
});
|
||||
|
||||
Mousetrap.bind('q', () => {
|
||||
@@ -86,9 +90,6 @@ Template.keyboardShortcuts.helpers({
|
||||
}, {
|
||||
keys: ['@'],
|
||||
action: 'shortcut-autocomplete-members',
|
||||
}, {
|
||||
keys: [':'],
|
||||
action: 'shortcut-autocomplete-emoji',
|
||||
}, {
|
||||
keys: ['SPACE'],
|
||||
action: 'shortcut-assign-self',
|
||||
|
||||
Loaded 100 of 206 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user