Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a7cb809f4 | ||
|
|
3244c3c32b | ||
|
|
09666585e2 | ||
|
|
ee106d1cb4 | ||
|
|
8ef435c83e | ||
|
|
3a74b88294 | ||
|
|
c5079096b5 | ||
|
|
927e43ab3f | ||
|
|
eddcb2260b | ||
|
|
ff73aa4566 | ||
|
|
de993a079d | ||
|
|
7bb0aa7488 | ||
|
|
fe7398faef | ||
|
|
8e709c1b79 | ||
|
|
3908fe0ab8 | ||
|
|
5d2ff89e9b | ||
|
|
7f38bc7b95 | ||
|
|
ed0c64a270 | ||
|
|
e63e7b1131 | ||
|
|
3f7d9fd42c | ||
|
|
867344f070 | ||
|
|
a84195179e | ||
|
|
f1b18d79cd | ||
|
|
6d1cdebfe2 | ||
|
|
7cf8487f57 | ||
|
|
5403027c9d | ||
|
|
daf397a1ba | ||
|
|
6104c1711f | ||
|
|
db41e41d90 | ||
|
|
1235363465 | ||
|
|
7263d7497f | ||
|
|
666186fee8 | ||
|
|
27d1b5acca | ||
|
|
5eb5ca5752 | ||
|
|
16d371b814 | ||
|
|
df9b4db49d | ||
|
|
2e8e58004d | ||
|
|
a83aa6162b | ||
|
|
07c915ccf0 | ||
|
|
405f176bbb | ||
|
|
6476503137 | ||
|
|
981ed546f1 | ||
|
|
c1287248a6 | ||
|
|
52f884f2b1 | ||
|
|
4550e10fbe | ||
|
|
2efe974195 | ||
|
|
6b808dd74b | ||
|
|
8a917e0efc | ||
|
|
d1f98d0c47 | ||
|
|
323de77a83 | ||
|
|
738e7f9ebc | ||
|
|
b5b4af73a9 | ||
|
|
ab1014b7d8 | ||
|
|
12964aa742 | ||
|
|
e4b1106acd | ||
|
|
d0524532a4 | ||
|
|
7de18eccea | ||
|
|
f9747bc908 | ||
|
|
6fd827792a | ||
|
|
9e95c06415 | ||
|
|
e7603298d7 | ||
|
|
8e14459cff | ||
|
|
3ac5dba243 | ||
|
|
9969c89b1c | ||
|
|
5a5b19d4fc | ||
|
|
4d48fa4d95 | ||
|
|
57545f66d2 | ||
|
|
8586c843a4 | ||
|
|
b2acc3ba45 | ||
|
|
9f0273aa44 | ||
|
|
3407b0e65b | ||
|
|
6cd92ab2c6 | ||
|
|
e92ebe5151 | ||
|
|
8cb838c0de | ||
|
|
6cae14d6e9 | ||
|
|
b42d8346cd | ||
|
|
1a065ff351 | ||
|
|
3565ff2700 | ||
|
|
e354715a9d | ||
|
|
e7002f417b | ||
|
|
ef5f38f431 | ||
|
|
b3efa71d13 | ||
|
|
10fcc19b7f | ||
|
|
948f05fecb | ||
|
|
927bb83813 | ||
|
|
9f396e9038 | ||
|
|
2400c91013 | ||
|
|
f583645744 | ||
|
|
42b3cff99f | ||
|
|
960fe5163b | ||
|
|
41665c079d | ||
|
|
8a0defc988 | ||
|
|
d7e0350ecf | ||
|
|
bf15fa988d | ||
|
|
db2d59181c | ||
|
|
dcc9a0d498 | ||
|
|
936dea591a | ||
|
|
cf7e5472ba | ||
|
|
5c61119716 | ||
|
|
3558d711ff | ||
|
|
72c1c49da3 | ||
|
|
93f8ff946f | ||
|
|
61d582ffd9 | ||
|
|
60384be5ff | ||
|
|
8ac305778a | ||
|
|
5be93741ee | ||
|
|
c2f91baaf9 | ||
|
|
9df5c0e2de | ||
|
|
f1a9e30956 | ||
|
|
4b202aaa08 | ||
|
|
5ef1a92366 | ||
|
|
1a836969e1 | ||
|
|
079b3da6ef | ||
|
|
13563e20e7 | ||
|
|
4f1330c777 | ||
|
|
94b558cf43 | ||
|
|
e22e24d917 | ||
|
|
55545a52ca | ||
|
|
e0cb5a0c7a | ||
|
|
efd3faf9ef | ||
|
|
2fd577d2c0 | ||
|
|
659e8418f7 | ||
|
|
18610d2fe6 | ||
|
|
1389ed0fce | ||
|
|
c39364af83 | ||
|
|
3e817257ef | ||
|
|
c5f782976b | ||
|
|
b841f798f8 | ||
|
|
35ae07e2a6 | ||
|
|
2c792363bf | ||
|
|
a68ecc079d | ||
|
|
b2d546579c | ||
|
|
4bc6ad3b4c | ||
|
|
7f558fede0 | ||
|
|
544bc1d6ad | ||
|
|
89d25f52fa | ||
|
|
2fd71d5be8 | ||
|
|
dc643f3d43 | ||
|
|
4469b12203 | ||
|
|
9cacaafb8f | ||
|
|
269382869e | ||
|
|
8648e32108 | ||
|
|
edf52bc438 | ||
|
|
58ce859368 | ||
|
|
e23aacedb3 | ||
|
|
7f02990626 | ||
|
|
c86155f1aa | ||
|
|
3fae5355d4 | ||
|
|
20e88159ae | ||
|
|
a81921382a | ||
|
|
8f28a409c7 | ||
|
|
7566f05b97 | ||
|
|
268d7fcb32 | ||
|
|
70edd44a01 | ||
|
|
6db717b9b3 | ||
|
|
f389fd95fb | ||
|
|
363bcab98b | ||
|
|
c4a7e53661 | ||
|
|
c6afe8d007 | ||
|
|
93eccffd44 | ||
|
|
fe66169415 | ||
|
|
6ced47aa8c | ||
|
|
e661d03e8d | ||
|
|
f09219cbfd | ||
|
|
7c25542976 | ||
|
|
121686a928 | ||
|
|
3563e0145d | ||
|
|
c630714245 | ||
|
|
5ebb47cb0e | ||
|
|
115701fa65 | ||
|
|
a182dde11f | ||
|
|
1e20e2601f | ||
|
|
4d066b1f30 | ||
|
|
7856692946 | ||
|
|
7e7c8fd001 | ||
|
|
feb602ecd4 | ||
|
|
6ed26e373a | ||
|
|
4fba0fb1a1 | ||
|
|
968ae122b0 | ||
|
|
06c32cb497 | ||
|
|
d2a4925cae | ||
|
|
9c97c301bd | ||
|
|
d4a91d30ff | ||
|
|
6a56a495ad | ||
|
|
3330aff12c | ||
|
|
43bdd56a41 | ||
|
|
a602f4b9ec | ||
|
|
053e47173f | ||
|
|
fe285c62e1 | ||
|
|
a3d44b0774 | ||
|
|
0e79bd25ed | ||
|
|
71f7a680b6 | ||
|
|
411b8d3f56 | ||
|
|
2bbc312ad0 | ||
|
|
14de17b667 | ||
|
|
9083c341c1 | ||
|
|
e0930c32a6 | ||
|
|
f438d04c42 | ||
|
|
d798f6e3ef | ||
|
|
c96ca4e875 | ||
|
|
8a71fe39c5 | ||
|
|
e4ec5c38b7 | ||
|
|
b849d4c2ba | ||
|
|
db9c895da8 | ||
|
|
a938c386cf | ||
|
|
a376fb2fab | ||
|
|
06c2ff0904 | ||
|
|
76e832c3a6 | ||
|
|
b7fd79aef0 | ||
|
|
28a9ab7131 | ||
|
|
8e0b1cc056 | ||
|
|
b424b34cab | ||
|
|
45a83da7be | ||
|
|
6e86292b99 | ||
|
|
e47ff25d45 | ||
|
|
89fe030fa3 | ||
|
|
1e0b53eb9b | ||
|
|
a5f2ae497a | ||
|
|
6441ebec83 | ||
|
|
7c609d402a | ||
|
|
e34f240c35 | ||
|
|
8ea86ae0b9 | ||
|
|
f4d0791c6c | ||
|
|
fcb1def355 | ||
|
|
56667112d7 | ||
|
|
d0003a334f | ||
|
|
35427063ff | ||
|
|
f5182e6328 | ||
|
|
0c911694c8 | ||
|
|
2eed1ca0eb | ||
|
|
99e5293ef5 | ||
|
|
c60a092fc0 | ||
|
|
b33f44e23f | ||
|
|
a65e39563b | ||
|
|
703efa5216 | ||
|
|
6b902bdb36 | ||
|
|
d599fc12ff | ||
|
|
e7d2343593 | ||
|
|
c8ec5d5f62 | ||
|
|
033d671047 | ||
|
|
6ef3f8a1c8 | ||
|
|
3546d7aa02 | ||
|
|
9819c9f801 | ||
|
|
7fa9603f9d | ||
|
|
c41c1e5293 | ||
|
|
29d62440a5 | ||
|
|
5bd0459cc2 | ||
|
|
8b118c1939 | ||
|
|
d7a0ab3c15 | ||
|
|
8609e0e82d | ||
|
|
b9099a8b7e | ||
|
|
87a81789d1 | ||
|
|
12ab8fac5d | ||
|
|
10b09b2da1 | ||
|
|
7c5f4a3849 | ||
|
|
ec71849d84 | ||
|
|
482682e500 | ||
|
|
3a6303e5c2 | ||
|
|
81635d9217 | ||
|
|
e8f89a8c4c | ||
|
|
393482315f | ||
|
|
cb67af02d7 | ||
|
|
a064b8d643 | ||
|
|
556621e60e | ||
|
|
0f95a513bf | ||
|
|
dce624486f | ||
|
|
64e76af8de | ||
|
|
acf2ede94e | ||
|
|
b3a7c4dc88 | ||
|
|
8d83c641e3 | ||
|
|
c1aa0047c6 | ||
|
|
7af4fe75ba | ||
|
|
ea6baa5c2b | ||
|
|
8183b7bdaa | ||
|
|
51514ae22c | ||
|
|
14b8610837 | ||
|
|
369a29707b | ||
|
|
ae240af323 | ||
|
|
2a715ec6c6 | ||
|
|
fca4cdcebf | ||
|
|
49bbfef3ec | ||
|
|
f968109e73 | ||
|
|
c0349c1ff9 | ||
|
|
e009bcf06e | ||
|
|
8aae812aa4 | ||
|
|
0b8f1cabef | ||
|
|
e80d3ac79a | ||
|
|
ed9ba169fe | ||
|
|
4720a6fbc3 | ||
|
|
ad45f82e27 | ||
|
|
2174936613 | ||
|
|
a6d7388919 | ||
|
|
f4e2bc0d32 | ||
|
|
2f13141907 | ||
|
|
365eded5c4 | ||
|
|
ed365c3d41 | ||
|
|
e16c65babc | ||
|
|
6e0fa78022 | ||
|
|
06fb201d80 | ||
|
|
62e5622523 | ||
|
|
2b26bbe78a | ||
|
|
a6d702d1ab | ||
|
|
aaecac0912 | ||
|
|
08b35e1fe7 | ||
|
|
78cf4618d5 | ||
|
|
9d13001b90 | ||
|
|
965c3fb07f | ||
|
|
c43366b7ac | ||
|
|
3a50556656 | ||
|
|
b26e65c70c | ||
|
|
75073bbdb2 | ||
|
|
88573ad2cd | ||
|
|
058180687a | ||
|
|
897506eeac | ||
|
|
aac7c380c8 | ||
|
|
fc35c234a7 | ||
|
|
0d3002f69d | ||
|
|
7d920e938b | ||
|
|
26b521e86e | ||
|
|
83b042701f | ||
|
|
21b75edcdd | ||
|
|
493d71a198 | ||
|
|
27f9c6b925 | ||
|
|
fa07dcf422 | ||
|
|
2b9540ce02 | ||
|
|
906c25d5e8 | ||
|
|
e9924a2f03 | ||
|
|
16e7fc6edc | ||
|
|
e0ca960a35 | ||
|
|
0e755e021b | ||
|
|
9be3f3714a | ||
|
|
02e425b39d | ||
|
|
ec01206030 | ||
|
|
cbbb5deff7 | ||
|
|
4377be8aa4 | ||
|
|
26010476b8 | ||
|
|
aac27d4db3 | ||
|
|
9762030920 | ||
|
|
cb1ffea5d6 | ||
|
|
a4ff6cc0af | ||
|
|
84acc65d04 | ||
|
|
2b1727c6e1 | ||
|
|
178f376e21 | ||
|
|
92538a6ac3 | ||
|
|
3fcde252f7 | ||
|
|
e89965f642 | ||
|
|
b4e5583065 | ||
|
|
65b11ce3bd | ||
|
|
ea74e6ad23 | ||
|
|
4467a68b97 | ||
|
|
799bf5735b | ||
|
|
92d0385911 | ||
|
|
9a21b0a1c9 | ||
|
|
6eb21faca2 | ||
|
|
2a54218f3f | ||
|
|
6eac38bde5 | ||
|
|
947c1f81ee | ||
|
|
2fce02afbc | ||
|
|
a58e6be78d | ||
|
|
77b43e75a2 | ||
|
|
228e5389cf | ||
|
|
bf78b093ba | ||
|
|
8384d68a06 | ||
|
|
120a430deb | ||
|
|
8e7b9b73b5 | ||
|
|
47afee63d1 | ||
|
|
243e4c856e | ||
|
|
f22785dbcd | ||
|
|
5848e7fe29 | ||
|
|
4c5398f643 | ||
|
|
45ecd2d04f | ||
|
|
132ddfa931 | ||
|
|
b7f9dc77d1 | ||
|
|
b68557a293 | ||
|
|
bc6e78608b | ||
|
|
1350694538 | ||
|
|
65fa2f626f | ||
|
|
0b00a8095c | ||
|
|
58df99d5be | ||
|
|
e37bbb9e44 | ||
|
|
85d47c4ff2 | ||
|
|
928973e310 | ||
|
|
9e93540970 | ||
|
|
ecf76f2c61 | ||
|
|
79223b0b8c | ||
|
|
5e6469bddc | ||
|
|
2216cc1b07 | ||
|
|
f275eb5e47 | ||
|
|
4b56bbfe6d | ||
|
|
d8c09369eb | ||
|
|
6ef532d187 | ||
|
|
c610ba0976 | ||
|
|
362b6432a9 | ||
|
|
f868b3d1f9 | ||
|
|
7bba07ccbf | ||
|
|
70f5326099 | ||
|
|
a64204a0c4 | ||
|
|
ea73d9a424 | ||
|
|
3e2415631f | ||
|
|
f425fbfcdf | ||
|
|
a0e9f4615c | ||
|
|
5e5ab95410 | ||
|
|
d7663316f1 | ||
|
|
a0b6b6dac7 | ||
|
|
62328c2d2a | ||
|
|
48f8050c25 | ||
|
|
135b770400 | ||
|
|
f20c2e4565 | ||
|
|
9b905c2833 | ||
|
|
7efbf30af6 | ||
|
|
d9778c1220 | ||
|
|
10f142a1a0 | ||
|
|
6a01170d86 | ||
|
|
55a2aa90cb | ||
|
|
feafa1827a | ||
|
|
116e63aa03 | ||
|
|
1159199e90 | ||
|
|
0009c4c650 | ||
|
|
b591727b64 | ||
|
|
218b44d476 | ||
|
|
cc020485c1 | ||
|
|
fc6149d232 | ||
|
|
8090b6f701 | ||
|
|
7fc2f2e2e5 | ||
|
|
76c7fa67d8 | ||
|
|
4d73eccaa8 | ||
|
|
634706ca6a | ||
|
|
88ef717793 | ||
|
|
870dfc4489 | ||
|
|
e01f4dbf13 | ||
|
|
5bece0dd1e | ||
|
|
83e4d214cd | ||
|
|
891fd60a6c | ||
|
|
ecb76842fc | ||
|
|
da8ae71963 | ||
|
|
031df54a2e | ||
|
|
6849bb8af9 | ||
|
|
2b382b940b | ||
|
|
8a64531ad9 | ||
|
|
39bf1e375e | ||
|
|
b3e1b8683c | ||
|
|
be96f16069 | ||
|
|
785f3cf88b | ||
|
|
d16a601c04 | ||
|
|
5724674e73 | ||
|
|
ba0068598c | ||
|
|
8f16c8bf8e | ||
|
|
29726453a0 | ||
|
|
5058233509 | ||
|
|
8442e1e83b | ||
|
|
ef0689baf7 | ||
|
|
ddce0ada09 | ||
|
|
60df1fa1ee | ||
|
|
8e93912389 | ||
|
|
064e4a2cf9 | ||
|
|
8ce9939217 | ||
|
|
41a28df430 | ||
|
|
c36a74b956 | ||
|
|
f6f7705f23 | ||
|
|
6209b792aa | ||
|
|
f8873b009b | ||
|
|
1a1f610977 | ||
|
|
3d7871ebfc | ||
|
|
cd253522a3 |
No files matched your search
@@ -1 +1,2 @@
|
||||
packages/*
|
||||
.snap-meteor-1.8/*
|
||||
@@ -11,6 +11,7 @@
|
||||
"browser": true,
|
||||
"meteor": true
|
||||
},
|
||||
"parser": "babel-eslint",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
|
||||
@@ -0,0 +1,257 @@
|
||||
name: wekan
|
||||
version: 0
|
||||
version-script: git describe --tags | cut -c 2-
|
||||
summary: The open-source kanban
|
||||
description: |
|
||||
Wekan is an open-source and collaborative kanban board application.
|
||||
|
||||
Whether you’re maintaining a personal todo list, planning your holidays with some friends, or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool to keep your things organized. They give you a visual overview of the current state of your project, and make you productive by allowing you to focus on the few items that matter the most.
|
||||
Depending on target environment, some configuration settings might need to be adjusted.
|
||||
For full list of configuration options call:
|
||||
$ wekan.help
|
||||
|
||||
confinement: strict
|
||||
grade: stable
|
||||
|
||||
architectures:
|
||||
- amd64
|
||||
|
||||
plugs:
|
||||
mongodb-plug:
|
||||
interface: content
|
||||
target: $SNAP_DATA/shared
|
||||
|
||||
hooks:
|
||||
configure:
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
|
||||
slots:
|
||||
mongodb-slot:
|
||||
interface: content
|
||||
write:
|
||||
- $SNAP_DATA/share
|
||||
|
||||
apps:
|
||||
wekan:
|
||||
command: wekan-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
mongodb:
|
||||
command: mongodb-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
caddy:
|
||||
command: caddy-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
help:
|
||||
command: wekan-help
|
||||
|
||||
database-backup:
|
||||
command: mongodb-backup
|
||||
plugs: [network, network-bind]
|
||||
|
||||
database-list-backups:
|
||||
command: ls -al $SNAP_COMMON/db-backups/
|
||||
|
||||
database-restore:
|
||||
command: mongodb-restore
|
||||
plugs: [network, network-bind]
|
||||
|
||||
parts:
|
||||
mongodb:
|
||||
source: https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-4.2.6.tgz
|
||||
plugin: dump
|
||||
stage-packages: [libssl1.0.0, libcurl3]
|
||||
filesets:
|
||||
mongo:
|
||||
- usr
|
||||
- bin
|
||||
- lib
|
||||
stage:
|
||||
- $mongo
|
||||
prime:
|
||||
- $mongo
|
||||
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.16.2
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
- fibers
|
||||
build-packages:
|
||||
- ca-certificates
|
||||
- apt-utils
|
||||
- python
|
||||
- python3
|
||||
- g++
|
||||
- capnproto
|
||||
- curl
|
||||
- libcurl3
|
||||
- execstack
|
||||
- nodejs
|
||||
- npm
|
||||
stage-packages:
|
||||
- libfontconfig1
|
||||
override-build: |
|
||||
echo "Cleaning environment first"
|
||||
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
|
||||
# Create the OpenAPI specification
|
||||
rm -rf .build
|
||||
## Use Meteor 1.8.x on Snap
|
||||
#rm -rf .meteor
|
||||
#mv .snap-meteor-1.8/.meteor .
|
||||
#mv .snap-meteor-1.8/package.json .
|
||||
#mv .snap-meteor-1.8/package-lock.json .
|
||||
## Meteor 1.9.x has changes to Buffer() => Buffer.alloc(), so reverting those
|
||||
#mv .snap-meteor-1.8/cfs_access-point.txt fix-download-unicode/
|
||||
#mv .snap-meteor-1.8/export.js models/
|
||||
#mv .snap-meteor-1.8/wekanCreator.js models/
|
||||
#mv .snap-meteor-1.8/ldap.js packages/wekan-ldap/server/ldap.js
|
||||
#mv .snap-meteor-1.8/oidc_server.js packages/wekan-oidc/oidc_server.js
|
||||
rm -rf .snap-meteor-1.8
|
||||
#mkdir -p .build/python
|
||||
#cd .build/python
|
||||
#git clone --depth 1 -b master https://github.com/Kronuz/esprima-python
|
||||
#cd esprima-python
|
||||
#python3 setup.py install
|
||||
#cd ../../..
|
||||
#mkdir -p ./public/api
|
||||
#python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml
|
||||
# we temporary need api2html and mkdirp
|
||||
#npm install -g api2html@0.3.0
|
||||
#npm install -g mkdirp
|
||||
#api2html -c ./public/logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml
|
||||
#npm uninstall -g mkdirp
|
||||
#npm uninstall -g api2html
|
||||
# Node Fibers 100% CPU usage issue:
|
||||
# https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
|
||||
# https://github.com/meteor/meteor/issues/9796#issuecomment-381676326
|
||||
# https://github.com/sandstorm-io/sandstorm/blob/0f1fec013fe7208ed0fd97eb88b31b77e3c61f42/shell/server/00-startup.js#L99-L129
|
||||
# Also see beginning of wekan/server/authentication.js
|
||||
# import Fiber from "fibers";
|
||||
# Fiber.poolSize = 1e9;
|
||||
# OLD: Download node version 8.12.0 prerelease build => Official node 8.12.0 has been released
|
||||
# Description at https://releases.wekan.team/node.txt
|
||||
##echo "375bd8db50b9c692c0bbba6e96d4114cd29bee3770f901c1ff2249d1038f1348 node" >> node-SHASUMS256.txt.asc
|
||||
##curl https://releases.wekan.team/node -o node
|
||||
# Verify Fibers patched node authenticity
|
||||
##echo "Fibers 100% CPU issue patched node authenticity:"
|
||||
##grep node node-SHASUMS256.txt.asc | shasum -a 256 -c -
|
||||
##rm -f node-SHASUMS256.txt.asc
|
||||
##chmod +x node
|
||||
##mv node `which node`
|
||||
# DOES NOT WORK: paxctl fix.
|
||||
# Removed from build-packages: - paxctl
|
||||
#echo "Applying paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303"
|
||||
#paxctl -mC `which node`
|
||||
#echo "Installing npm"
|
||||
#curl -L https://www.npmjs.com/install.sh | sh
|
||||
echo "Installing meteor"
|
||||
curl https://install.meteor.com/ -o install_meteor.sh
|
||||
#sed -i "s|RELEASE=.*|RELEASE=\"1.8.1-beta.0\"|g" install_meteor.sh
|
||||
chmod +x install_meteor.sh
|
||||
sh install_meteor.sh
|
||||
rm install_meteor.sh
|
||||
# REPOS BELOW ARE INCLUDED TO WEKAN REPO
|
||||
#if [ ! -d "packages" ]; then
|
||||
# mkdir packages
|
||||
#fi
|
||||
#if [ ! -d "packages/kadira-flow-router" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/meteor-useraccounts-core" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core
|
||||
# sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' meteor-useraccounts-core/package.js
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/meteor-accounts-cas" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git meteor-accounts-cas
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/wekan-ldap" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/wekan-scrollbar" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/wekan_accounts-oidc" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git
|
||||
# mv meteor-accounts-oidc/packages/switch_accounts-oidc wekan-accounts-oidc
|
||||
# mv meteor-accounts-oidc/packages/switch_oidc wekan-oidc
|
||||
# rm -rf meteor-accounts-oidc
|
||||
# cd ..
|
||||
#fi
|
||||
#if [ ! -d "packages/markdown" ]; then
|
||||
# cd packages
|
||||
# git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git
|
||||
# cd ..
|
||||
#fi
|
||||
rm -rf .build
|
||||
meteor add standard-minifier-js --allow-superuser
|
||||
meteor npm install --allow-superuser
|
||||
meteor npm install --allow-superuser --save babel-runtime
|
||||
meteor build .build --directory --allow-superuser
|
||||
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
|
||||
#Removed binary version of bcrypt because of security vulnerability that is not fixed yet.
|
||||
#https://github.com/wekan/wekan/commit/4b2010213907c61b0e0482ab55abb06f6a668eac
|
||||
#https://github.com/wekan/wekan/commit/7eeabf14be3c63fae2226e561ef8a0c1390c8d3c
|
||||
#cd .build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt
|
||||
#rm -rf node_modules/bcrypt
|
||||
#meteor npm install --save bcrypt
|
||||
# Change from npm-bcrypt directory back to .build/bundle/programs/server directory.
|
||||
#cd ../../../../
|
||||
# Change to directory .build/bundle/programs/server
|
||||
cd .build/bundle/programs/server
|
||||
npm install
|
||||
npm install --allow-superuser --save babel-runtime
|
||||
#meteor npm install --save bcrypt
|
||||
# Change back to Wekan source directory
|
||||
cd ../../../..
|
||||
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
|
||||
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/wekan
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/tar/lib/.mkdir.js.swp
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
# Meteor 1.8.x additional .swp remove
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
|
||||
organize:
|
||||
README: README.wekan
|
||||
prime:
|
||||
- -lib/node_modules/node-pre-gyp/node_modules/tar/lib/.unpack.js.swp
|
||||
|
||||
helpers:
|
||||
source: snap-src
|
||||
plugin: dump
|
||||
|
||||
caddy:
|
||||
plugin: dump
|
||||
source: https://caddyserver.com/download/linux/amd64?license=personal&telemetry=off
|
||||
source-type: tar
|
||||
organize:
|
||||
caddy: bin/caddy
|
||||
CHANGES.txt: CADDY_CHANGES.txt
|
||||
EULA.txt: CADDY_EULA.txt
|
||||
LICENSES.txt: CADDY_LICENSES.txt
|
||||
README.txt: CADDY_README.txt
|
||||
stage:
|
||||
- -init
|
||||
@@ -0,0 +1,155 @@
|
||||
name: wekan
|
||||
version: git
|
||||
summary: The open-source kanban
|
||||
description: |
|
||||
Wekan is an open-source and collaborative kanban board application.
|
||||
|
||||
Whether you’re maintaining a personal todo list, planning your holidays with some friends, or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool to keep your things organized. They give you a visual overview of the current state of your project, and make you productive by allowing you to focus on the few items that matter the most.
|
||||
Depending on target environment, some configuration settings might need to be adjusted.
|
||||
For full list of configuration options call:
|
||||
$ wekan.help
|
||||
|
||||
confinement: strict
|
||||
grade: stable
|
||||
base: core18
|
||||
|
||||
architectures:
|
||||
- amd64
|
||||
|
||||
plugs:
|
||||
mongodb-plug:
|
||||
interface: content
|
||||
target: $SNAP_DATA/shared
|
||||
|
||||
hooks:
|
||||
configure:
|
||||
plugs:
|
||||
- network
|
||||
- network-bind
|
||||
|
||||
slots:
|
||||
mongodb-slot:
|
||||
interface: content
|
||||
write:
|
||||
- $SNAP_DATA/share
|
||||
|
||||
apps:
|
||||
wekan:
|
||||
command: wekan-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
mongodb:
|
||||
command: mongodb-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
caddy:
|
||||
command: caddy-control
|
||||
daemon: simple
|
||||
plugs: [network, network-bind]
|
||||
|
||||
help:
|
||||
command: wekan-help
|
||||
|
||||
database-backup:
|
||||
command: mongodb-backup
|
||||
plugs: [network, network-bind]
|
||||
|
||||
database-list-backups:
|
||||
command: ls -al $SNAP_COMMON/db-backups/
|
||||
|
||||
database-restore:
|
||||
command: mongodb-restore
|
||||
plugs: [network, network-bind]
|
||||
|
||||
parts:
|
||||
mongodb:
|
||||
source: https://repo.mongodb.org/apt/ubuntu/dists/xenial/mongodb-org/4.2/multiverse/binary-amd64/mongodb-org-server_4.2.2_amd64.deb
|
||||
#https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.14.tgz
|
||||
#https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.2.22.tgz
|
||||
plugin: dump
|
||||
stage-packages: [libssl1.0.0, libcurl3]
|
||||
filesets:
|
||||
mongo:
|
||||
- usr
|
||||
- bin
|
||||
- lib
|
||||
stage:
|
||||
- $mongo
|
||||
prime:
|
||||
- $mongo
|
||||
|
||||
wekan:
|
||||
source: .
|
||||
plugin: nodejs
|
||||
node-engine: 12.14.1
|
||||
node-packages:
|
||||
- node-gyp
|
||||
- node-pre-gyp
|
||||
- fibers
|
||||
build-packages:
|
||||
- ca-certificates
|
||||
- apt-utils
|
||||
- build-essential
|
||||
- python
|
||||
- python3
|
||||
- g++
|
||||
- capnproto
|
||||
- curl
|
||||
- libcurl3
|
||||
- execstack
|
||||
- nodejs
|
||||
- npm
|
||||
stage-packages:
|
||||
- libfontconfig1
|
||||
override-build: |
|
||||
echo "Cleaning environment first"
|
||||
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
|
||||
rm -rf .build
|
||||
echo "Installing meteor"
|
||||
curl https://install.meteor.com/ -o install_meteor.sh
|
||||
chmod +x install_meteor.sh
|
||||
sh install_meteor.sh
|
||||
rm install_meteor.sh
|
||||
rm -rf .build
|
||||
meteor add standard-minifier-js --allow-superuser
|
||||
meteor npm install --allow-superuser
|
||||
meteor npm install --allow-superuser --save babel-runtime
|
||||
meteor build .build --directory --allow-superuser
|
||||
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
|
||||
cd .build/bundle/programs/server
|
||||
npm install
|
||||
npm install --allow-superuser --save babel-runtime
|
||||
# Change back to Wekan source directory
|
||||
cd ../../../..
|
||||
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
|
||||
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/wekan
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/tar/lib/.mkdir.js.swp
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
|
||||
|
||||
organize:
|
||||
README: README.wekan
|
||||
prime:
|
||||
- -lib/node_modules/node-pre-gyp/node_modules/tar/lib/.unpack.js.swp
|
||||
|
||||
helpers:
|
||||
source: snap-src
|
||||
plugin: dump
|
||||
|
||||
caddy:
|
||||
plugin: dump
|
||||
source: https://caddyserver.com/download/linux/amd64?license=personal&telemetry=off
|
||||
source-type: tar
|
||||
organize:
|
||||
caddy: bin/caddy
|
||||
CHANGES.txt: CADDY_CHANGES.txt
|
||||
EULA.txt: CADDY_EULA.txt
|
||||
LICENSES.txt: CADDY_LICENSES.txt
|
||||
README.txt: CADDY_README.txt
|
||||
stage:
|
||||
- -init
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
Add these issues to elsewhere:
|
||||
- Snap: https://github.com/wekan/wekan-snap/issues
|
||||
- LDAP: https://github.com/wekan/wekan-ldap/issues
|
||||
- UCS: https://github.com/wekan/univention/issues
|
||||
|
||||
Other Wekan issues can be added here.
|
||||
|
||||
|
||||
Vendored
+10
@@ -0,0 +1,10 @@
|
||||
FROM gitpod/workspace-mongodb
|
||||
|
||||
USER gitpod
|
||||
|
||||
# Install custom tools, runtime, etc. using apt-get
|
||||
# For example, the command below would install "bastet" - a command line tetris clone:
|
||||
#
|
||||
# RUN sudo apt-get -q update && # sudo apt-get install -yq bastet && # sudo rm -rf /var/lib/apt/lists/*
|
||||
#
|
||||
# More information: https://www.gitpod.io/docs/config-docker/
|
||||
@@ -0,0 +1,4 @@
|
||||
tasks:
|
||||
- init: npm install
|
||||
image:
|
||||
file: .gitpod.Dockerfile
|
||||
+11
-10
@@ -6,10 +6,11 @@
|
||||
meteor-base@1.4.0
|
||||
|
||||
# Build system
|
||||
ecmascript@0.13.2
|
||||
standard-minifier-css@1.5.4
|
||||
standard-minifier-js@2.5.2
|
||||
ecmascript@0.14.3
|
||||
standard-minifier-css@1.6.0
|
||||
standard-minifier-js@2.6.0
|
||||
mquandalle:jade
|
||||
coffeescript@2.4.1!
|
||||
|
||||
# Polyfills
|
||||
es5-shim@4.8.0
|
||||
@@ -22,7 +23,7 @@ dburles:collection-helpers
|
||||
idmontie:migrations
|
||||
matb33:collection-hooks
|
||||
matteodem:easy-search
|
||||
mongo@1.7.0
|
||||
mongo@1.10.0
|
||||
mquandalle:collection-mutations
|
||||
|
||||
# Account system
|
||||
@@ -37,13 +38,12 @@ wekan-accounts-oidc
|
||||
# Utilities
|
||||
check@1.3.1
|
||||
jquery@1.11.10
|
||||
random@1.1.0
|
||||
random@1.2.0
|
||||
reactive-dict@1.3.0
|
||||
session@1.2.0
|
||||
tracker@1.2.0
|
||||
underscore@1.0.10
|
||||
3stack:presence
|
||||
alethes:pages
|
||||
arillo:flow-router-helpers
|
||||
audit-argument-checks@1.0.7
|
||||
kadira:blaze-layout
|
||||
@@ -67,15 +67,15 @@ templates:tabs
|
||||
verron:autosize
|
||||
simple:json-routes
|
||||
rajit:bootstrap3-datepicker
|
||||
shell-server@0.4.0
|
||||
shell-server@0.5.0
|
||||
simple:rest-accounts-password
|
||||
useraccounts:core
|
||||
email@1.2.3
|
||||
horka:swipebox
|
||||
dynamic-import@0.5.1
|
||||
dynamic-import@0.5.2
|
||||
staringatlights:fast-render
|
||||
|
||||
accounts-password@1.5.2
|
||||
accounts-password@1.6.0
|
||||
cfs:gridfs
|
||||
rzymek:fullcalendar
|
||||
momentjs:moment@2.22.2
|
||||
@@ -85,7 +85,8 @@ msavin:usercache
|
||||
wekan-scrollbar
|
||||
mquandalle:perfect-scrollbar
|
||||
mdg:meteor-apm-agent@3.2.0-rc.0!
|
||||
coagmano:stylus
|
||||
# Keep stylus in 1.1.0, because building v2 takes extra 52 minutes.
|
||||
coagmano:stylus@1.1.0!
|
||||
lucasantoniassi:accounts-lockout
|
||||
meteorhacks:subs-manager
|
||||
meteorhacks:picker
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
METEOR@1.8.3
|
||||
METEOR@1.10.2
|
||||
+38
-38
@@ -1,29 +1,28 @@
|
||||
3stack:presence@1.1.2
|
||||
accounts-base@1.4.5
|
||||
accounts-oauth@1.1.16
|
||||
accounts-password@1.5.2
|
||||
accounts-base@1.6.0
|
||||
accounts-oauth@1.2.0
|
||||
accounts-password@1.6.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.4
|
||||
alethes:pages@1.8.6
|
||||
allow-deny@1.1.0
|
||||
arillo:flow-router-helpers@0.5.2
|
||||
audit-argument-checks@1.0.7
|
||||
autoupdate@1.6.0
|
||||
babel-compiler@7.4.2
|
||||
babel-runtime@1.4.0
|
||||
babel-compiler@7.5.3
|
||||
babel-runtime@1.5.0
|
||||
base64@1.0.12
|
||||
binary-heap@1.0.11
|
||||
blaze@2.3.4
|
||||
blaze-tools@1.0.10
|
||||
boilerplate-generator@1.6.0
|
||||
boilerplate-generator@1.7.0
|
||||
browser-policy-common@1.0.11
|
||||
browser-policy-framing@1.1.0
|
||||
caching-compiler@1.2.1
|
||||
caching-compiler@1.2.2
|
||||
caching-html-compiler@1.1.3
|
||||
callback-hook@1.2.0
|
||||
callback-hook@1.3.0
|
||||
cfs:access-point@0.1.49
|
||||
cfs:base-package@0.0.30
|
||||
cfs:collection@0.5.5
|
||||
@@ -44,23 +43,24 @@ cfs:upload-http@0.0.20
|
||||
cfs:worker@0.1.5
|
||||
check@1.3.1
|
||||
chuangbo:cookie@1.1.0
|
||||
coagmano:stylus@2.0.0
|
||||
coffeescript@1.0.17
|
||||
coagmano:stylus@1.1.0
|
||||
coffeescript@2.4.1
|
||||
coffeescript-compiler@2.4.1
|
||||
cottz:publish-relations@2.0.8
|
||||
dburles:collection-helpers@1.1.0
|
||||
ddp@1.4.0
|
||||
ddp-client@2.3.3
|
||||
ddp-common@1.4.0
|
||||
ddp-rate-limiter@1.0.7
|
||||
ddp-server@2.3.0
|
||||
ddp-server@2.3.1
|
||||
deps@1.0.12
|
||||
diff-sequence@1.1.1
|
||||
dynamic-import@0.5.1
|
||||
dynamic-import@0.5.2
|
||||
easylogic:summernote@0.8.8
|
||||
ecmascript@0.13.2
|
||||
ecmascript@0.14.3
|
||||
ecmascript-runtime@0.7.0
|
||||
ecmascript-runtime-client@0.9.0
|
||||
ecmascript-runtime-server@0.8.0
|
||||
ecmascript-runtime-client@0.10.0
|
||||
ecmascript-runtime-server@0.9.0
|
||||
ejson@1.1.1
|
||||
email@1.2.3
|
||||
es5-shim@4.8.0
|
||||
@@ -75,7 +75,7 @@ htmljs@1.0.11
|
||||
http@1.4.2
|
||||
id-map@1.1.0
|
||||
idmontie:migrations@1.0.3
|
||||
inter-process-messaging@0.1.0
|
||||
inter-process-messaging@0.1.1
|
||||
jquery@1.11.11
|
||||
kadira:blaze-layout@2.3.0
|
||||
kadira:dochead@1.5.0
|
||||
@@ -84,7 +84,7 @@ kenton:accounts-sandstorm@0.7.0
|
||||
konecty:mongo-counter@0.0.5_3
|
||||
lamhieu:meteorx@2.1.1
|
||||
lamhieu:unblock@1.0.0
|
||||
launch-screen@1.1.1
|
||||
launch-screen@1.2.0
|
||||
livedata@1.0.18
|
||||
localstorage@1.2.0
|
||||
logging@1.1.20
|
||||
@@ -101,16 +101,16 @@ meteorhacks:collection-utils@1.2.0
|
||||
meteorhacks:picker@1.0.3
|
||||
meteorhacks:subs-manager@1.6.4
|
||||
meteorspark:util@0.2.0
|
||||
minifier-css@1.4.3
|
||||
minifier-js@2.5.1
|
||||
minifier-css@1.5.0
|
||||
minifier-js@2.6.0
|
||||
minifiers@1.1.8-faster-rebuild.0
|
||||
minimongo@1.4.5
|
||||
mobile-status-bar@1.0.14
|
||||
modern-browsers@0.1.4
|
||||
modules@0.14.0
|
||||
modules-runtime@0.11.0
|
||||
minimongo@1.6.0
|
||||
mobile-status-bar@1.1.0
|
||||
modern-browsers@0.1.5
|
||||
modules@0.15.0
|
||||
modules-runtime@0.12.0
|
||||
momentjs:moment@2.24.0
|
||||
mongo@1.7.0
|
||||
mongo@1.10.0
|
||||
mongo-decimal@0.1.1
|
||||
mongo-dev-server@1.1.0
|
||||
mongo-id@1.0.7
|
||||
@@ -127,13 +127,13 @@ mquandalle:mousetrap-bindglobal@0.0.1
|
||||
mquandalle:perfect-scrollbar@0.6.5_2
|
||||
msavin:usercache@1.8.0
|
||||
npm-bcrypt@0.9.3
|
||||
npm-mongo@3.2.0
|
||||
oauth@1.2.8
|
||||
oauth2@1.2.1
|
||||
npm-mongo@3.7.0
|
||||
oauth@1.3.0
|
||||
oauth2@1.3.0
|
||||
observe-sequence@1.0.16
|
||||
ongoworks:speakingurl@1.1.0
|
||||
ordered-dict@1.1.0
|
||||
ostrio:cookies@2.5.0
|
||||
ostrio:cookies@2.6.0
|
||||
peerlibrary:assert@0.3.0
|
||||
peerlibrary:base-component@0.16.0
|
||||
peerlibrary:blaze-components@0.15.1
|
||||
@@ -144,7 +144,7 @@ promise@0.11.2
|
||||
raix:eventemitter@0.1.3
|
||||
raix:handlebar-helpers@0.2.5
|
||||
rajit:bootstrap3-datepicker@1.7.1_1
|
||||
random@1.1.0
|
||||
random@1.2.0
|
||||
rate-limit@1.0.9
|
||||
reactive-dict@1.3.0
|
||||
reactive-var@1.0.11
|
||||
@@ -156,19 +156,19 @@ server-render@0.3.1
|
||||
service-configuration@1.0.11
|
||||
session@1.2.0
|
||||
sha@1.0.9
|
||||
shell-server@0.4.0
|
||||
shell-server@0.5.0
|
||||
simple:authenticate-user-by-token@1.0.1
|
||||
simple:json-routes@2.1.0
|
||||
simple:rest-accounts-password@1.1.2
|
||||
simple:rest-bearer-token-parser@1.0.1
|
||||
simple:rest-json-error-handler@1.0.1
|
||||
socket-stream-client@0.2.2
|
||||
socket-stream-client@0.3.0
|
||||
softwarerero:accounts-t9n@1.3.11
|
||||
spacebars@1.0.15
|
||||
spacebars-compiler@1.1.3
|
||||
srp@1.0.12
|
||||
standard-minifier-css@1.5.4
|
||||
standard-minifier-js@2.5.2
|
||||
srp@1.1.0
|
||||
standard-minifier-css@1.6.0
|
||||
standard-minifier-js@2.6.0
|
||||
staringatlights:fast-render@3.2.0
|
||||
staringatlights:inject-data@2.3.0
|
||||
tap:i18n@1.8.2
|
||||
@@ -181,12 +181,12 @@ tracker@1.2.0
|
||||
twbs:bootstrap@3.3.6
|
||||
ui@1.0.13
|
||||
underscore@1.0.10
|
||||
url@1.2.0
|
||||
url@1.3.0
|
||||
useraccounts:core@1.14.2
|
||||
useraccounts:flow-routing@1.14.2
|
||||
useraccounts:unstyled@1.14.2
|
||||
verron:autosize@3.0.8
|
||||
webapp@1.7.5
|
||||
webapp@1.9.1
|
||||
webapp-hashing@1.0.9
|
||||
wekan-accounts-cas@0.1.0
|
||||
wekan-accounts-oidc@1.0.10
|
||||
|
||||
@@ -5,3 +5,4 @@ node_modules/
|
||||
.vscode/
|
||||
.tx/
|
||||
.github/
|
||||
.snap-meteor-1.8/
|
||||
+2
-2
@@ -1,9 +1,9 @@
|
||||
dist: disco
|
||||
dist: eoan
|
||||
sudo: required
|
||||
|
||||
env:
|
||||
TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
|
||||
TRAVIS_NODE_VERSION: 8.17.0
|
||||
TRAVIS_NODE_VERSION: 12.16.2
|
||||
TRAVIS_NPM_VERSION: latest
|
||||
|
||||
before_install:
|
||||
|
||||
+689
-2
@@ -1,3 +1,690 @@
|
||||
# v3.99 2020-04-27 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Boards are very hard to tap in mobile](https://github.com/wekan/wekan/pull/3051).
|
||||
Thanks to marc1006.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.98 2020-04-25 Wekan release
|
||||
|
||||
News:
|
||||
|
||||
- There is now many mobile and desktop webbrowser fixes. Please test does your
|
||||
favourite Javascript enabled webbrowser work, and add issues if something
|
||||
does not work, and there is no existing issue about that yet.
|
||||
- Desktop browser mode has setting for Show/Hide drag handles:
|
||||
top right click username / Change Settings / Show desktop drag handles.
|
||||
You can request desktop website also at mobile webbrowsers on Android.
|
||||
At iOS requesting desktop website did not seem to work yet.
|
||||
- At iOS Safari and Chrome, to see swimlane buttons you need to scroll to right.
|
||||
Fixes to this and other issues are welcome as pull request.
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Pre-fill the title of checklists (Trello-style)](https://github.com/wekan/wekan/pull/3030).
|
||||
Thanks to boeserwolf.
|
||||
- [Implement option to change the first day of the week in user settings](https://github.com/wekan/wekan/pull/3032).
|
||||
Thanks to marc1006.
|
||||
- [Add babel to build chain and linter. Enables fancy Javascript language
|
||||
features like optional chaining, for developer happiness](https://github.com/wekan/wekan/pull/3034).
|
||||
Thanks to boeserwolf.
|
||||
- [Use only one 'Apply' button for applying the user settings](https://github.com/wekan/wekan/pull/3039).
|
||||
Thanks to marc1006.
|
||||
- [Allow variable height for board list items. Allow words in title/description to be able to break
|
||||
and wrap onto the next line](https://github.com/wekan/wekan/pull/3046).
|
||||
Thanks to marc1006.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Upgrade to Meteor 1.10.2](https://github.com/wekan/wekan/commit/d1f98d0c472fb41e25fb29a9a6f6dae7db003f6f).
|
||||
Thanks to Meteor developers and xet7.
|
||||
- [Set Snap MongoDB compatibility to 4.2 according to Meteor ChangeLog](https://github.com/wekan/wekan/commit/7de18eccea3854db3be6197bf21afbfd3ddb65a6).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Multiple lint issue fixes](https://github.com/wekan/wekan/pull/3031).
|
||||
Thanks to marc1006.
|
||||
- [Fix lint errors in lint error fix](https://github.com/wekan/wekan/commit/9e95c06415e614e587d684ff9660cc53c5f8c8d3).
|
||||
Thanks to xet7.
|
||||
- [Fix getStartDayOfWeek function](https://github.com/wekan/wekan/pull/3038).
|
||||
Thanks to marc1006 and boeserwolf.
|
||||
- Improve mobile devices support [Part1](https://github.com/wekan/wekan/pull/3040) and [Part2](https://github.com/wekan/wekan/pull/3045).
|
||||
Thanks to marc1006.
|
||||
- [Fix Wekan not load at all in Firefox v.68 for Android](https://github.com/wekan/wekan/commit/1235363465b824d26129d4aa74a4445f362c1a73).
|
||||
Thanks to xet7.
|
||||
- [Fix comment typo in docker-compose.yml](https://github.com/wekan/wekan/pull/3044).
|
||||
Thanks to VictorioBerra.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.97 2020-04-19 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Sortable boards](https://github.com/wekan/wekan/pull/3027).
|
||||
Thanks to boeserwolf.
|
||||
- [Added dockerfiles for multi-arch builds and manifest](https://github.com/wekan/wekan/pull/3023).
|
||||
[In Progress](https://github.com/wekan/wekan/issues/2999).
|
||||
Thanks to brokencode64.
|
||||
- [Make linked card clickable](https://github.com/wekan/wekan/pull/3025).
|
||||
Thanks to boeserwolf.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix using checklists on mobile and iPad](https://github.com/wekan/wekan/pull/3019).
|
||||
Thanks to devinsm.
|
||||
- [Improve card layout on mobile devices](https://github.com/wekan/wekan/pull/3024).
|
||||
Thanks to marc1006.
|
||||
- [Make OCP OAuth work with Openshift 4.x](https://github.com/wekan/wekan/pull/3020).
|
||||
Thanks to ckavili.
|
||||
- [Remove old warning from Sandstorm import board data loss, because bug has been already
|
||||
fixed](https://github.com/wekan/wekan/commit/960fe5163b6a2f7c3dca03b5e31d69611b49f079).
|
||||
Thanks to aputsiaq and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.96 2020-04-15 Wekan release
|
||||
|
||||
This release adds the following Sandstorm updates:
|
||||
|
||||
- This is the first Sandstorm Wekan release that uses newest Meteor 1.10.1 and Node 12.x.
|
||||
Now all Wekan platforms use newest Meteor and Node 12.x LTS.
|
||||
Thanks to kentonv and xet7.
|
||||
- [Fix capnp workaround to work with newest Meteor and
|
||||
Node 12.x](https://github.com/wekan/wekan/commit/b2d546579c4957352c29b36c0c8a4a08b944dbb4).
|
||||
Thanks to kentonv.
|
||||
- [Update Sandstorm release script for newest Meteor and
|
||||
Node 12.x](https://github.com/wekan/wekan/commit/c5f782976b971fa3f2323e80a013bbf6a49c0596).
|
||||
Thanks to xet7.
|
||||
- [Remove Meteor 1.8.x files because Sandstorm Wekan now uses newest
|
||||
Meteor](https://github.com/wekan/wekan/commit/1a836969e10215bad47ac56a9b0d9de801b66fd2).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following new features:
|
||||
|
||||
- [Hide password auth with environment variable PASSWORD_LOGIN_ENABLED=false](https://github.com/wekan/wekan/pull/3014).
|
||||
Snap example: `sudo snap set wekan password-login-enabled='false'` .
|
||||
Thanks to salleman33.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Board admins can not clone or archive their boards at All Boards
|
||||
page](https://github.com/wekan/wekan/pull/3013).
|
||||
Thanks to salleman33.
|
||||
- [Fix `<p>` margin in card labels](https://github.com/wekan/wekan/pull/3015).
|
||||
Thanks to boeserwolf.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.95 2020-04-12 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Add gitpod config](https://github.com/wekan/wekan/pull/3009).
|
||||
This adds support for Gitpod.io, a free automated
|
||||
dev environment that makes contributing and generally working on GitHub
|
||||
projects much easier. It allows anyone to start a ready-to-code dev
|
||||
environment for any branch, issue and pull request with a single click.
|
||||
Thanks to juniormendonca.
|
||||
- [Public boards overview](https://github.com/wekan/wekan/pull/3008).
|
||||
Thanks to NicoP-S.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix styling issue in notifications drawer](https://github.com/wekan/wekan/pull/3012).
|
||||
Thanks to boeserwolf.
|
||||
- [Fix error in notifications cleanup cron](https://github.com/wekan/wekan/pull/3010).
|
||||
Thanks to jtbairdsr.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.94 2020-04-12 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Public vote](https://github.com/wekan/wekan/pull/3006).
|
||||
Thanks to NicoP-S.
|
||||
- [Add robots.txt disallow all](https://github.com/wekan/wekan/commit/3fae5355d40055757bf4a5f0c503581195609720).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.93 2020-04-10 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Trello vote import & hide export button if with_api is
|
||||
disabled](https://github.com/wekan/wekan/pull/3000).
|
||||
Thanks to NicoP-S.
|
||||
- [When adding a user to a board that has subtasks, also add user to the subtask
|
||||
board](https://github.com/wekan/wekan/pull/3004).
|
||||
Thanks to slvrpdr.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- Upgrade to Node v12.16.2 [Part1](https://github.com/wekan/wekan/commit/6db717b9b384fe1491063e507b80e67791a07e3a)
|
||||
and [Part2](https://github.com/wekan/wekan/commit/268d7fcb32186a902a84e7f6d80c50b1f3790bad).
|
||||
Thanks to Node developers and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix bug that prevents editing or deleting
|
||||
comments](https://github.com/wekan/wekan/pull/3005).
|
||||
Thanks to jtbairdsr.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.92 2020-04-09 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Scheduler to clean up read notifications. Also added a button to manually remove all
|
||||
read notifications, and a fix to prevent users form getting notifications for their own
|
||||
actions](https://github.com/wekan/wekan/pull/2998).
|
||||
Thanks to jtbairdsr.
|
||||
- [Add setting](https://github.com/wekan/wekan/commit/5ebb47cb0ec7272894a37d99579ede872251f55c)
|
||||
default [NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE=2](https://github.com/wekan/wekan/pull/2998)
|
||||
to all Wekan platforms.
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.91 2020-04-08 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [OpenShift: Route template added to helm chart for Openshift v4x
|
||||
cluster](https://github.com/wekan/wekan/pull/2996).
|
||||
Thanks to ckavili.
|
||||
- [Filter by Assignee](https://github.com/wekan/wekan/pull/2997).
|
||||
Thanks to daniel-eder.
|
||||
- [Vote on Card](https://github.com/wekan/wekan/pull/2994).
|
||||
Thanks to NicoP-S and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.90 2020-04-06 Wekan release
|
||||
|
||||
This release makes the following updates:
|
||||
|
||||
- [Update dependencies](https://github.com/wekan/wekan/commit/d798f6e3ef09595ce4f1d1fbc053eec70fc91fb9).
|
||||
|
||||
and updates the following translations:
|
||||
|
||||
- [Update layouts.js for zh-TW language name](https://github.com/wekan/wekan/pull/2988).
|
||||
Thanks to doggy8088.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.89 2020-04-05 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Create subtasks in parenttask swimlane](https://github.com/wekan/wekan/issues/1953).
|
||||
Thanks to TOSCom-DanielEder.
|
||||
- [When searching cards in a board, also search from Custom Fields](https://github.com/wekan/wekan/pull/2985).
|
||||
Thanks to slvrpdr.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.88 2020-04-02 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Notification drawer](https://github.com/wekan/wekan/pull/2975) [like Trello](https://github.com/wekan/wekan/issues/2471).
|
||||
Thanks to jtbairdsr and xet7.
|
||||
|
||||
and makes the following UI changes:
|
||||
|
||||
- [Minicard labels on the top and title on bottom](https://github.com/wekan/wekan/issues/2980).
|
||||
Thanks to helioguardabaxo and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix start-wekan.sh MongoDB port to 27017](https://github.com/wekan/wekan/commit/c60a092fc0ed9fe15c417bcb443b1e3e3aaedf7e).
|
||||
Thanks to Keelan and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.87 2020-04-01 Wekan release
|
||||
|
||||
This release makes the following UI changes:
|
||||
|
||||
- [Move "Rules" from "Board View" to "Board Settings"](https://github.com/wekan/wekan/issues/2973).
|
||||
Thanks to helioguardabaxo and xet7.
|
||||
- [Improvements on card details visualization](https://github.com/wekan/wekan/issues/2974).
|
||||
Thanks to helioguardabaxo and xet7.
|
||||
- [Hide duplicate "Hide system messages" at Change Settings/Member Settings, because it's also on card
|
||||
slider](https://github.com/wekan/wekan/issues/2837).
|
||||
Thanks to notohiro and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Browser always reload the whole page when I change one of the card
|
||||
color](https://github.com/wekan/wekan/commit/3546d7aa02bc65cf1183cb493adeb543ba51945d).
|
||||
Fixed by making label colors and text again editable.
|
||||
Regression from [Wekan v3.86 2)](https://github.com/wekan/wekan/commit/b9099a8b7ea6f63c79bdcbb871cb993b2cb7e325).
|
||||
Thanks to javen9881 and xet7.
|
||||
- [Fix richer editor submit did not clear edit area](https://github.com/wekan/wekan/commit/033d6710470b2ecd7a0ec0b2f0741ff459e68b32).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.86 2020-03-24 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Rich editor can not be disabled, regression from changes yesterday at Wekan v3.85](https://github.com/wekan/wekan/commit/12ab8fac5db9c5ac8069d0ca2bca340d6004a25b).
|
||||
Thanks to uusijani, vjrj and xet7.
|
||||
- [1) Fix Pasting text into a card is adding a line before and after
|
||||
(and multiplies by pasting more) by changing paste "p" to "br".
|
||||
2) Fixes to summernote and markdown comment editors, related
|
||||
to keeping them open when adding comments, having
|
||||
@member mention not close card, and disabling clicking of
|
||||
@member mention](https://github.com/wekan/wekan/commit/b9099a8b7ea6f63c79bdcbb871cb993b2cb7e325).
|
||||
Thanks to xet7 !
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.85 2020-03-23 Wekan release
|
||||
|
||||
This release fixes the following CRITICAL SECURITY VULNERABILITIES:
|
||||
|
||||
- [Fix XSS bug reported today 4 hours ago by Cyb3rjunky](https://github.com/wekan/wekan/commit/482682e50079d70c5113169020d6834013b57c11).
|
||||
Logged in users could run javascript in input fields.
|
||||
This affects Wekan versions v3.12-v3.84.
|
||||
In [Wekan v3.12](https://github.com/wekan/wekan/blob/master/CHANGELOG.md#v312-2019-08-09-wekan-release)
|
||||
there was [changes for XSS filter to allow inserting images, videos etc
|
||||
on comment WYSIWYG editor](https://github.com/wekan/wekan/pull/2593)
|
||||
so features related to that are now removed.
|
||||
After this fix, Javascript in input fields is not executed.
|
||||
Thanks to Cyb3rjunky and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.84 2020-03-16 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- Add settings for mouse wheel scroll inertia and scroll
|
||||
amount [Part1](https://github.com/wekan/wekan/commit/9d13001b903f9ec50f5fa3a4bdbacae32b27ac65)
|
||||
and [Part2](https://github.com/wekan/wekan/commit/aaecac091209e90c0c2123830728f5e7a835ccb4).
|
||||
For example: sudo snap set wekan scrollinertia='200' , sudo snap set wekan scrollamount='200' .
|
||||
Thanks to danger89 and xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Upgrade to Meteor 1.10.1](https://github.com/wekan/wekan/commit/e16c65babc1f021c35a3d46bc61e649ec94d1e82).
|
||||
Thanks to xet7.
|
||||
- [Update markdown](https://github.com/wekan/wekan/commit/6e0fa78022ea487176eb0a32ec5a4a441f8e0c3c).
|
||||
Thanks to xet7.
|
||||
- [Update minimist](https://github.com/wekan/wekan/commit/ea6baa5c2b956ee28b0a7e63f988e2fc1998201a).
|
||||
Thanks to xet7.
|
||||
- [Update acorn](https://github.com/wekan/wekan/commit/369a29707bbec3bf89717c16e8b698fb4666087a).
|
||||
Thanks to xet7.
|
||||
- [Update prettier-eslint](https://github.com/wekan/wekan/commit/8183b7bdaa01d2ce53ac7215beafd5efe21373e8).
|
||||
Thanks to xet7.
|
||||
- [Update ostrio:cookies](https://github.com/wekan/wekan/commit/14b8610837117616d436e2bac6a9dc653e315662).
|
||||
Thanks to xet7.
|
||||
- [Add build time profiling to build script](https://github.com/wekan/wekan/commit/f968109e7390139e50375ee29bc7bc3cf1e1ab41).
|
||||
Thanks to zodern.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Downgrade stylus to v1.1.0 to speed up building Wekan](https://github.com/wekan/wekan/commit/fca4cdcebf1cc6642aefeb78b911cb5b95ebe473).
|
||||
This is because building newer stylus v2 takes 52 minutes. After this change, building Wekan takes 3 minutes.
|
||||
Thanks to zodern.
|
||||
- [Fix: Error when retrieve token from some OIDC due to not necessary scope
|
||||
parameter](https://github.com/wekan/wekan/pull/2955).
|
||||
Thanks to benoitm76.
|
||||
- [Fix: img tag did not allow width and height. Removed swipebox from markdown editor
|
||||
img tag and updated marked markdown to newest version](https://github.com/wekan/wekan/commit/2b26bbe78a1a2b8b427963a6c44c3853efdb737e).
|
||||
Thanks to hradec and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.83 2020-03-01 Wekan release
|
||||
|
||||
This release tries to revert remaining the following changes:
|
||||
|
||||
- [Revert](https://github.com/wekan/wekan/88573ad2cdb8596b795a82ef40a0662180e8a7d7) change made at Wekan v3.81,
|
||||
because building did not work: [Try to make Meteor build time shorter
|
||||
by excluding legacy and cordova. This was made possible by
|
||||
Meteor 1.10-rc.2](https://github.com/wekan/wekan/commit/0d3002f69d97e646fa7368bfdade4f78c51e9884).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.82 2020-03-01 Wekan release
|
||||
|
||||
This release reverts the following changes:
|
||||
|
||||
- Revert change made at Wekan v3.81, because building did not work: [Try to make Meteor build time shorter
|
||||
by excluding legacy and cordova. This was made possible by
|
||||
Meteor 1.10-rc.2](https://github.com/wekan/wekan/commit/0d3002f69d97e646fa7368bfdade4f78c51e9884).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.81 2020-03-01 Wekan release
|
||||
|
||||
This release [fixes](https://github.com/wekan/wekan/commit/aac7c380c8c389b0683b2bd64e2cc856993f0e30) the following CRITICAL SECURITY VULNERABILITIES and other bugs:
|
||||
|
||||
- Fix critical and moderate security vulnerabilities reported at 2020-02-26 with
|
||||
responsible disclosure by [Dejan Zelic](https://twitter.com/dejandayoff),
|
||||
Justin Benjamin and others at [Offensive Security](https://twitter.com/offsectraining),
|
||||
that follow standard 90 days before public disclosure.
|
||||
Thanks to xet7.
|
||||
- Fix webhook error that prevented some card etc deleting from web UI of board.
|
||||
Thanks to xet7.
|
||||
- Add missing Font Awesome icon to Board Settings Menu.
|
||||
Thanks to xet7.
|
||||
- Remove autofocus from many form input boxes so that they would not cause warnings.
|
||||
Thanks to xet7.
|
||||
|
||||
and does the following upgrades:
|
||||
|
||||
- [Upgrade Meteor to 1.10-rc.2](https://github.com/wekan/wekan/commit/26b521e86e6ac40b7ba25bbe8dac7bf4d48d43ce).
|
||||
Thanks to xet7.
|
||||
- [Try to make Meteor build time shorter by excluding legacy and cordova. This was made possible by
|
||||
Meteor 1.10-rc.2](https://github.com/wekan/wekan/commit/0d3002f69d97e646fa7368bfdade4f78c51e9884).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Try to fix afterwards loading of cards by adding fallback when requestIdleCallback is not
|
||||
available](https://github.com/wekan/wekan/commit/2b9540ce02de604bf84ea082f2dcb1d01673708c).
|
||||
Thanks to xet7.
|
||||
- [Make profile.initials available in publications](https://github.com/wekan/wekan/pull/2948).
|
||||
Thanks to NicoP-S.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.80 2020-02-22 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- [Create New User in Admin Panel](https://github.com/wekan/wekan/commit/e0ca960a35cf006880019ba28fc82aa30f289a71).
|
||||
Works, but does not save fullname yet, so currently it's needed to edit add fullname later.
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Update to Meteor 1.9.1, Node 12.16.1 etc newest dependencies](https://github.com/wekan/wekan/commit/cbbb5deff7d84a91c40becc9caaf70f5b6738b63).
|
||||
Thanks to xet7.
|
||||
- [Update to Meteor 1.9.2](https://github.com/wekan/wekan/commit/9be3f3714ae680ff9fc1855c960c9831e84c2b07).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Update Sandstorm release build script](https://github.com/wekan/wekan/commit/a4ff6cc0af8545ca4d3e97fa2cabbe7981c025b2).
|
||||
Thanks to xet7.
|
||||
- [Fix docker-compose link](https://github.com/wekan/wekan/pull/2937).
|
||||
Thanks to pbek.
|
||||
- [Remove alethes:pages package, that had some indentation error.
|
||||
Package is about pagination, but I did not find any pagination related code in Wekan
|
||||
yet](https://github.com/wekan/wekan/commit/ec012060305bc16fbf8d2ac218f5c847e02c4301).
|
||||
Thanks to xet7 !
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.79 2020-02-13 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Card Opened Webhook can not be disabled](https://github.com/wekan/wekan/commit/178f376e2138b5522c2e92ddfd2babb113df8d9f).
|
||||
Thanks to mvanvoorden and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.78 2020-02-12 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- [Card Settings / Show on Card: Description Title and Description Text](https://github.com/wekan/wekan/commit/e89965f6422fd95b4ad2112ae407b1dde4853510).
|
||||
Thanks to e-stoniauk, 2020product and xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Remove card element grouping to create compact card layout](https://github.com/wekan/wekan/commit/e89965f6422fd95b4ad2112ae407b1dde4853510).
|
||||
Thanks to e-stoniauk, 2020product and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.77 2020-02-10 Wekan release
|
||||
|
||||
This release removes the following features:
|
||||
|
||||
- [Remove hiding comments and activities](https://github.com/wekan/wekan/commit/2a54218f3f68547032bd53a04a968b233be21e15).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- Fix Copy Card Link to Clipboard button at card title did not
|
||||
work [Part 1](https://github.com/wekan/wekan/commit/9a21b0a1c933e7f778e4e57a8258e150ccea1620)
|
||||
and [Part2](https://github.com/wekan/wekan/commit/4467a68b97a3fbf0fbae7f05177d978f2aa80287).
|
||||
Thanks to 2020product and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.76 2020-02-07 Wekan release
|
||||
|
||||
This release adds the following updates:
|
||||
|
||||
- [Use Meteor 1.9 and Node.js 12.15.0 on Snap and Docker](https://github.com/wekan/wekan/commit/8384d68a060ef8f2c202ce2fa6064c5c823d28dc).
|
||||
This also fixes bug that exporting some boards was not possible, downloading export file failed.
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix Bug enable/disable Comments in Card Settings](https://github.com/wekan/wekan/issues/2923).
|
||||
Thanks to warnt, mdurokov and xet7.
|
||||
- [Try to disable dragging Swimlanes/Lists/Cards/Checklists/Subtasks on small mobile smartphones webbrowsers,
|
||||
and hide drag handles on mobile web](https://github.com/wekan/wekan/commit/bf78b093bad7d463ee325ad96e8b485264d4a3be).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.75 2020-02-05 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Fix](https://github.com/wekan/wekan/commit/f22785dbcde42e425c9ead209ec224aef6e11c16)
|
||||
[adding comments](https://github.com/wekan/wekan/issues/2918).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Added some working layout changes like activities using less space from https://github.com/wekan/wekan/pull/2920](https://github.com/wekan/wekan/commit/f22785dbcde42e425c9ead209ec224aef6e11c16).
|
||||
Thanks to 2020product.
|
||||
- [Fixed Card Settings not working at Sandstorm](https://github.com/wekan/wekan/commit/f22785dbcde42e425c9ead209ec224aef6e11c16).
|
||||
Thanks to xet7.
|
||||
- Add [Card Description title](https://github.com/wekan/wekan/issues/2918#issuecomment-582346577)
|
||||
[back](https://github.com/wekan/wekan/commit/f22785dbcde42e425c9ead209ec224aef6e11c16).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.74 2020-02-05 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [For BoardAdmin, add way to hide parts of a card, at Board Settings/Card Settings/Show on Card: Received, Start, ... etc.
|
||||
Add to card title bar Copy card to Clipboard button](https://github.com/wekan/wekan/pull/2915).
|
||||
Thanks to 2020product and xet7.
|
||||
- [Set default to RICHER_CARD_COMMENT_EDITOR=false](https://github.com/wekan/wekan/commit/65fa2f626f503b8089e0d982901cffb3990426cb).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.73 2020-01-29 Wekan release
|
||||
|
||||
This release adds the following new features:
|
||||
|
||||
- [Login to Wekan with Nextcloud](https://github.com/wekan/wekan/pull/2897).
|
||||
Thanks to bogie.
|
||||
- [Add rule action to move cards to other boards](https://github.com/wekan/wekan/pull/2899).
|
||||
Thanks to peterverraedt.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Show System Wide Announcement in one line](https://github.com/wekan/wekan/pull/2891).
|
||||
Thanks to tsia.
|
||||
- [Fixed board export with attachment in Wekan Meteor 1.9.x version](https://github.com/wekan/wekan/pull/2898).
|
||||
Thanks to izadpoor.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.72 2020-01-19 Sandstorm-only Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- Try to fix Wekan at Sandstorm.
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.71 2020-01-18 Sandstorm-only Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Try to fix Wekan at Sandstorm by using Meteor 1.8.x and Node 8.17.0 at Sandstorm](https://github.com/wekan/wekan/commit/5e5ab95410c715a4379631456fc5547c497898b0).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.70 2020-01-18 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Add missing LD_LIBRARY_PATH to use libssl and libcurl](https://github.com/wekan/wekan/10f142a1a05acb98a175ccb0326fb0c1d3e3713f).
|
||||
Thanks to xet7.
|
||||
- [Use Meteor 1.8.x](https://github.com/wekan/wekan/commit/55a2aa90cbbf44200e9b0b9f4bd08b6177f1bb95)
|
||||
[on Snap](https://github.com/wekan/wekan/commit/6a01170d8696322462c4065ce0cf4a637a058975), because
|
||||
Snap builds do not work yet for Meteor 1.9, Node 12.14.1 and MongoDB 4.2.2.
|
||||
Docker version works with Meteor 1.9.
|
||||
Thanks to xet7.
|
||||
- [Try to fix Node 12 Buffer() deprecation errors](https://github.com/wekan/wekan/commit/9b905c2833d54cf34d1875148075b2bf756d943a).
|
||||
Thanks to xet7.
|
||||
- [Add Snap Meteor 1.8.x files to lint ignore files](https://github.com/wekan/wekan/commit/48f8050c25e40f737dfdd3a98923cb87cd4e77e2).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.69 2020-01-10 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix docker-compose.yml to not use --smallfiles that is not supported in
|
||||
MongoDB 4.x](https://github.com/wekan/wekan/commit/ecb76842fcbd81701afcab8db0ed106e6be0fdec).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.68 2020-01-10 Wekan release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- [Try to fix Snap by removing MongoDB option --smallfiles that is not supported
|
||||
in MongoDB 4.x](https://github.com/wekan/wekan/commit/031df54a2e0a03dcb7a2586667e60e5bd4eef706)
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.67 2020-01-10 Wekan release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- [Try to fix Snap](https://github.com/wekan/wekan/commit/2b382b940be9af575fab4c2e955702d8cde55ae9).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.66 2020-01-10 Wekan release
|
||||
|
||||
This release tries to fix the following bugs:
|
||||
|
||||
- [Try to fix Snap](https://github.com/wekan/wekan/commit/39bf1e375e2962f824e6f8cfa425ea51aa4efa24).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.65 2020-01-10 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- [More keyboard shortcuts: c for archive card](https://github.com/wekan/wekan/commit/d16a601c04aeb1d3550c5c541be02a67276a34cf).
|
||||
Thanks to xet7.
|
||||
|
||||
and adds the following updates:
|
||||
|
||||
- [Upgrade to Meteor 1.9, Node 12.14.1 and MongoDB 4.2.2](https://github.com/wekan/wekan/commit/785f3cf88b61f687ef5ad4a529768221d1a54c86).
|
||||
Thanks to xet7.
|
||||
- [Add more issue repo links to GitHub issue template](https://github.com/wekan/wekan/commit/5724674e73246f4e52843a6d6906c0ecdd85cccc).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.64 2020-01-06 Wekan release
|
||||
|
||||
This release adds the following warning for CentOS 7 users:
|
||||
|
||||
- [WARNING: DO NOT USE SNAP ON CENTOS 7, THERE IS UPDATE BUG](https://github.com/wekan/wekan-snap/wiki/CentOS-7).
|
||||
Thanks to andy-twosticks and xet7.
|
||||
|
||||
and adds the following features:
|
||||
|
||||
- [Wider sidebar](https://github.com/wekan/wekan/commit/5058233509e44916296e38fb8a6c5dd591c46d8b).
|
||||
Thanks to vjrj.
|
||||
|
||||
and removes the following features:
|
||||
|
||||
- [Removed Custom HTML feature that does not work](https://github.com/wekan/wekan/commit/ddce0ada094e6450be260b4cda21fdfa09ae0133).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.63 2020-01-06 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix: Unable to find Archive Card/List/Swimlane in board
|
||||
settings](https://github.com/wekan/wekan/commit/8ce993921718f3e10c2daa5fabb145b939d789dd).
|
||||
Thanks to neobradley and xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.62 2020-01-05 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- [Add Worker role](https://github.com/wekan/wekan/issues/2788).
|
||||
This was originally added at Wekan v3.58, reverted at Wekan v3.60 because of bugs,
|
||||
and now after fixes added back.
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.61 2020-01-03 Wekan release
|
||||
|
||||
This release adds the following features:
|
||||
|
||||
- [Add more Font Awesome icons. This was originally added
|
||||
at Wekan v3.58, removed at Wekan v3.60, and now
|
||||
added back at Wekan v3.61](https://github.com/wekan/wekan/commit/cd253522a305523e3e36bb73313e8c4db500a717).
|
||||
Thanks to xet7.
|
||||
|
||||
and fixes the following bugs:
|
||||
|
||||
- [Fix browser javascript console errors when editing profile. This was originally added
|
||||
at Wekan v3.58, removed at Wekan v3.60, and now added back at
|
||||
Wekan v3.61](https://github.com/wekan/wekan/commit/cd253522a305523e3e36bb73313e8c4db500a717).
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v3.60 2020-01-03 Wekan release
|
||||
|
||||
This release fixes the following bugs:
|
||||
@@ -5,7 +692,7 @@ This release fixes the following bugs:
|
||||
- [Revert to Wekan v3.57 version of client and models directories,
|
||||
removing Worker role temporarily, because Worker role changes
|
||||
broke saving card](https://github.com/wekan/wekan/commit/27943796ade78ca3c503637a1340918bf06a1267).
|
||||
Thanks to xet7 !
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
@@ -14,7 +701,7 @@ Thanks to above GitHub users for their contributions and translators for their t
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix not being able to edit received date](https://github.com/wekan/wekan/commit/5376bc7b7905c0dd99fae1aeae3f63b4583a3e3f).
|
||||
Thanks to xet7.
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
|
||||
+10
-4
@@ -6,8 +6,8 @@ LABEL maintainer="wekan"
|
||||
# ENV BUILD_DEPS="paxctl"
|
||||
ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-essential git ca-certificates python3" \
|
||||
DEBUG=false \
|
||||
NODE_VERSION=v8.17.0 \
|
||||
METEOR_RELEASE=1.8.1 \
|
||||
NODE_VERSION=v12.16.2 \
|
||||
METEOR_RELEASE=1.10.2 \
|
||||
USE_EDGE=false \
|
||||
METEOR_EDGE=1.5-beta.17 \
|
||||
NPM_VERSION=latest \
|
||||
@@ -21,11 +21,12 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE=3 \
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60 \
|
||||
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15 \
|
||||
RICHER_CARD_COMMENT_EDITOR=true \
|
||||
RICHER_CARD_COMMENT_EDITOR=false \
|
||||
CARD_OPENED_WEBHOOK_ENABLED=false \
|
||||
ATTACHMENTS_STORE_PATH="" \
|
||||
MAX_IMAGE_PIXEL="" \
|
||||
IMAGE_COMPRESS_RATIO="" \
|
||||
NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE="" \
|
||||
BIGEVENTS_PATTERN=NONE \
|
||||
NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="" \
|
||||
NOTIFY_DUE_AT_HOUR_OF_DAY="" \
|
||||
@@ -110,7 +111,10 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
|
||||
CORS="" \
|
||||
CORS_ALLOW_HEADERS="" \
|
||||
CORS_EXPOSE_HEADERS="" \
|
||||
DEFAULT_AUTHENTICATION_METHOD=""
|
||||
DEFAULT_AUTHENTICATION_METHOD="" \
|
||||
SCROLLINERTIA="0" \
|
||||
SCROLLAMOUNT="auto" \
|
||||
PASSWORD_LOGIN_ENABLED=true
|
||||
|
||||
# Copy the app to the image
|
||||
COPY ${SRC_PATH} /home/wekan/app
|
||||
@@ -267,6 +271,8 @@ RUN \
|
||||
cd /home/wekan/app_build/bundle/programs/server/ && \
|
||||
gosu wekan:wekan npm install && \
|
||||
#gosu wekan:wekan npm install bcrypt && \
|
||||
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
|
||||
rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy && \
|
||||
mv /home/wekan/app_build/bundle /build && \
|
||||
\
|
||||
# Put back the original tar
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
FROM amd64/alpine:3.7 AS builder
|
||||
|
||||
# Set the environment variables for builder
|
||||
ENV QEMU_VERSION=v4.2.0-6 \
|
||||
QEMU_ARCHITECTURE=aarch64 \
|
||||
NODE_ARCHITECTURE=linux-arm64 \
|
||||
NODE_VERSION=v12.16.1 \
|
||||
WEKAN_VERSION=3.96 \
|
||||
WEKAN_ARCHITECTURE=arm64
|
||||
|
||||
# Install dependencies
|
||||
RUN apk update && apk add ca-certificates outils-sha1 && \
|
||||
\
|
||||
# Download qemu static for our architecture
|
||||
wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-${QEMU_ARCHITECTURE}-static.tar.gz -O - | tar -xz && \
|
||||
\
|
||||
# Download wekan and shasum
|
||||
wget https://releases.wekan.team/raspi3/wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip && \
|
||||
wget https://releases.wekan.team/raspi3/SHA256SUMS.txt && \
|
||||
# Verify wekan
|
||||
grep wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip SHA256SUMS.txt | sha256sum -c - && \
|
||||
\
|
||||
# Unzip wekan
|
||||
unzip wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip && \
|
||||
\
|
||||
# Download node and shasums
|
||||
wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz && \
|
||||
wget https://nodejs.org/dist/${NODE_VERSION}/SHASUMS256.txt.asc && \
|
||||
\
|
||||
# Verify nodejs authenticity
|
||||
grep node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz SHASUMS256.txt.asc | sha256sum -c - && \
|
||||
\
|
||||
# Extract node and remove tar.gz
|
||||
tar xvzf node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz
|
||||
|
||||
# Build wekan dockerfile
|
||||
FROM arm64v8/ubuntu:19.10
|
||||
LABEL maintainer="wekan"
|
||||
|
||||
# Set the environment variables (defaults where required)
|
||||
ENV QEMU_ARCHITECTURE=aarch64 \
|
||||
NODE_ARCHITECTURE=linux-arm64 \
|
||||
NODE_VERSION=v12.16.1 \
|
||||
NODE_ENV=production \
|
||||
NPM_VERSION=latest \
|
||||
WITH_API=true \
|
||||
PORT=8080 \
|
||||
ROOT_URL=http://localhost \
|
||||
MONGO_URL=mongodb://127.0.0.1:27017/wekan
|
||||
|
||||
# Copy qemu-static to image
|
||||
COPY --from=builder qemu-${QEMU_ARCHITECTURE}-static /usr/bin
|
||||
|
||||
# Copy the app to the image
|
||||
COPY --from=builder bundle /home/wekan/bundle
|
||||
|
||||
# Copy
|
||||
COPY --from=builder node-${NODE_VERSION}-${NODE_ARCHITECTURE} /opt/nodejs
|
||||
|
||||
RUN \
|
||||
set -o xtrace && \
|
||||
# Add non-root user wekan
|
||||
useradd --user-group --system --home-dir /home/wekan wekan && \
|
||||
\
|
||||
# Install Node
|
||||
ln -s /opt/nodejs/bin/node /usr/bin/node && \
|
||||
ln -s /opt/nodejs/bin/npm /usr/bin/npm && \
|
||||
mkdir -p /opt/nodejs/lib/node_modules/fibers/.node-gyp /root/.node-gyp/8.16.1 /home/wekan/.config && \
|
||||
chown wekan --recursive /home/wekan/.config && \
|
||||
\
|
||||
# Install Node dependencies
|
||||
npm install -g npm@${NPM_VERSION}
|
||||
|
||||
EXPOSE $PORT
|
||||
USER wekan
|
||||
|
||||
CMD ["node", "/home/wekan/bundle/main.js"]
|
||||
@@ -1,3 +1,5 @@
|
||||
[](https://gitpod.io/#https://github.com/wekan/wekan)
|
||||
|
||||
# Wekan - Open Source kanban
|
||||
|
||||
[](https://github.com/wekan/wekan/graphs/contributors)
|
||||
@@ -32,7 +34,7 @@ and PWA app that can be added as icon on Android and bookmark on iOS, used like
|
||||
|
||||
**NOTE**:
|
||||
- Please read the [FAQ](https://github.com/wekan/wekan/wiki/FAQ) first
|
||||
- Please don't feed the trolls and spammers that are mentioned in the FAQ :)
|
||||
- Please don't feed the [trolls](https://github.com/wekan/wekan/wiki/FAQ#why-am-i-called-a-troll) and [spammers](https://github.com/wekan/wekan/wiki/FAQ#why-am-i-called-a-spammer) that are mentioned in the FAQ :)
|
||||
|
||||
## About Wekan
|
||||
|
||||
@@ -61,7 +63,7 @@ that by providing one-click installation on various platforms.
|
||||
[Mac](https://github.com/wekan/wekan/wiki/Mac) / [Windows](https://github.com/wekan/wekan/wiki/Install-Wekan-from-source-on-Windows).
|
||||
[More Platforms](https://github.com/wekan/wekan/wiki/Platforms), bundle for RasPi3 ARM and other CPUs where Node.js and MongoDB exists.
|
||||
- 1 GB RAM minimum free for Wekan. Production server should have minimum total 4 GB RAM.
|
||||
For thousands of users, for example with [Docker](https://github.com/wekan/wekan/blob/devel/docker-compose.yml): 3 frontend servers,
|
||||
For thousands of users, for example with [Docker](https://github.com/wekan/wekan/blob/master/docker-compose.yml): 3 frontend servers,
|
||||
each having 2 CPU and 2 wekan-app containers. One backend wekan-db server with many CPUs.
|
||||
- Enough disk space and alerts about low disk space. If you run out disk space, MongoDB database gets corrupted.
|
||||
- SECURITY: Updating to newest Wekan version very often. Please check you do not have automatic updates of Sandstorm or Snap turned off.
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v3.60.0"
|
||||
appVersion: "v3.99.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
||||
@@ -8,234 +8,201 @@ template(name="activities")
|
||||
+cardActivities
|
||||
|
||||
template(name="boardActivities")
|
||||
each currentBoard.activities
|
||||
.activity
|
||||
+userAvatar(userId=user._id)
|
||||
p.activity-desc
|
||||
+memberName(user=user)
|
||||
|
||||
if($eq activityType 'deleteAttachment')
|
||||
| {{{_ 'activity-delete-attach' cardLink}}}.
|
||||
|
||||
if($eq activityType 'addAttachment')
|
||||
| {{{_ 'activity-attached' attachmentLink cardLink}}}.
|
||||
|
||||
if($eq activityType 'addBoardMember')
|
||||
| {{{_ 'activity-added' memberLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'addComment')
|
||||
| {{{_ 'activity-on' cardLink}}}
|
||||
a.activity-comment(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= comment.text
|
||||
|
||||
if($eq activityType 'addChecklist')
|
||||
| {{{_ 'activity-checklist-added' cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklist.title
|
||||
if($eq activityType 'removeChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLink}}}.
|
||||
|
||||
if($eq activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item' checkItem checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item' checkItem checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'checklistCompleted')
|
||||
| {{{_ 'activity-checklist-completed' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'checklistUncompleted')
|
||||
| {{{_ 'activity-checklist-uncompleted' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklistItem.title
|
||||
if($eq activityType 'removedChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-removed' checklist.title cardLink}}}.
|
||||
|
||||
if($eq activityType 'archivedCard')
|
||||
| {{{_ 'activity-archived' cardLink}}}.
|
||||
|
||||
if($eq activityType 'archivedList')
|
||||
| {{_ 'activity-archived' list.title}}.
|
||||
|
||||
if($eq activityType 'archivedSwimlane')
|
||||
| {{_ 'activity-archived' swimlane.title}}.
|
||||
|
||||
if($eq activityType 'createBoard')
|
||||
| {{_ 'activity-created' boardLabel}}.
|
||||
|
||||
if($eq activityType 'createCard')
|
||||
| {{{_ 'activity-added' cardLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'createCustomField')
|
||||
| {{_ 'activity-customfield-created' customField}}.
|
||||
|
||||
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}}.
|
||||
|
||||
if($eq activityType 'importBoard')
|
||||
| {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activityType 'importCard')
|
||||
| {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activityType 'importList')
|
||||
| {{{_ 'activity-imported' listLabel boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activityType 'joinMember')
|
||||
if($eq user._id member._id)
|
||||
| {{{_ 'activity-joined' cardLink}}}.
|
||||
else
|
||||
| {{{_ 'activity-added' memberLink cardLink}}}.
|
||||
|
||||
if($eq activityType 'moveCardBoard')
|
||||
| {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
|
||||
|
||||
if($eq activityType 'moveCard')
|
||||
| {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
|
||||
|
||||
if($eq activityType 'removeBoardMember')
|
||||
| {{{_ 'activity-excluded' memberLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'restoredCard')
|
||||
| {{{_ 'activity-sent' cardLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label' lastLabel cardLink}}}.
|
||||
|
||||
if($eq activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
|
||||
|
||||
if($eq activityType 'setCustomField')
|
||||
| {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
|
||||
|
||||
if($eq activityType 'unsetCustomField')
|
||||
| {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
|
||||
|
||||
if($eq activityType 'unjoinMember')
|
||||
if($eq user._id member._id)
|
||||
| {{{_ 'activity-unjoined' cardLink}}}.
|
||||
else
|
||||
| {{{_ 'activity-removed' memberLink cardLink}}}.
|
||||
|
||||
span(title=createdAt).activity-meta {{ moment createdAt }}
|
||||
each activityData in currentBoard.activities
|
||||
+activity(activity=activityData card=card mode=mode)
|
||||
|
||||
template(name="cardActivities")
|
||||
each currentCard.activities
|
||||
.activity
|
||||
+userAvatar(userId=user._id)
|
||||
p.activity-desc
|
||||
+memberName(user=user)
|
||||
if($eq activityType 'createCard')
|
||||
| {{_ 'activity-added' cardLabel listName}}.
|
||||
if($eq activityType 'importCard')
|
||||
| {{{_ 'activity-imported' cardLabel list.title sourceLink}}}.
|
||||
if($eq activityType 'joinMember')
|
||||
if($eq user._id member._id)
|
||||
| {{_ 'activity-joined' cardLabel}}.
|
||||
else
|
||||
| {{{_ 'activity-added' memberLink cardLabel}}}.
|
||||
if($eq activityType 'unjoinMember')
|
||||
if($eq user._id member._id)
|
||||
| {{_ 'activity-unjoined' cardLabel}}.
|
||||
else
|
||||
| {{{_ 'activity-removed' cardLabel memberLink}}}.
|
||||
if($eq activityType 'archivedCard')
|
||||
| {{_ 'activity-archived' cardLabel}}.
|
||||
each activityData in currentCard.activities
|
||||
+activity(activity=activityData card=card mode=mode)
|
||||
|
||||
if($eq activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label-card' lastLabel }}}.
|
||||
template(name="activity")
|
||||
.activity
|
||||
+userAvatar(userId=activity.user._id)
|
||||
p.activity-desc
|
||||
+memberName(user=activity.user)
|
||||
|
||||
if($eq activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label-card' lastLabel }}}.
|
||||
//- attachment activity -------------------------------------------------
|
||||
if($eq activity.activityType 'deleteAttachment')
|
||||
| {{{_ 'activity-delete-attach' cardLink}}}.
|
||||
|
||||
if($eq activityType 'removeChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLabel}}}.
|
||||
if($eq activity.activityType 'addAttachment')
|
||||
| {{{_ 'activity-attached' attachmentLink cardLink}}}.
|
||||
if($neq mode 'board')
|
||||
if activity.attachment.isImage
|
||||
img.attachment-image-preview(src=activity.attachment.url)
|
||||
|
||||
if($eq activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item-card' checkItem checklist.title }}}.
|
||||
//- board activity ------------------------------------------------------
|
||||
if($eq mode 'board')
|
||||
if($eq activity.activityType 'createBoard')
|
||||
| {{_ 'activity-created' boardLabel}}.
|
||||
|
||||
if($eq activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item-card' checkItem checklist.title }}}.
|
||||
if($eq activity.activityType 'importBoard')
|
||||
| {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activityType 'checklistCompleted')
|
||||
| {{{_ 'activity-checklist-completed-card' checklist.title }}}.
|
||||
if($eq activity.activityType 'addBoardMember')
|
||||
| {{{_ 'activity-added' memberLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'checklistUncompleted')
|
||||
| {{{_ 'activity-checklist-uncompleted-card' checklist.title }}}.
|
||||
if($eq activity.activityType 'removeBoardMember')
|
||||
| {{{_ 'activity-excluded' memberLink boardLabel}}}.
|
||||
|
||||
if($eq activityType 'restoredCard')
|
||||
| {{_ 'activity-sent' cardLabel boardLabel}}.
|
||||
if($eq activityType 'moveCard')
|
||||
| {{_ 'activity-moved' cardLabel oldList.title list.title}}.
|
||||
//- card activity -------------------------------------------------------
|
||||
if($eq activity.activityType 'createCard')
|
||||
if($eq mode 'card')
|
||||
| {{{_ 'activity-added' cardLabel activity.listName}}}.
|
||||
else
|
||||
| {{{_ 'activity-added' cardLabel boardLabel}}}.
|
||||
|
||||
if($eq activityType 'moveCardBoard')
|
||||
| {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
|
||||
if($eq activity.activityType 'importCard')
|
||||
| {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activityType 'addAttachment')
|
||||
| {{{_ 'activity-attached' attachmentLink cardLabel}}}.
|
||||
if attachment.isImage
|
||||
img.attachment-image-preview(src=attachment.url)
|
||||
if($eq activityType 'deleteAttachment')
|
||||
| {{{_ 'activity-delete-attach' cardLabel}}}.
|
||||
if($eq activityType 'removedChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLabel}}}.
|
||||
if($eq activityType 'addChecklist')
|
||||
| {{{_ 'activity-checklist-added' cardLabel}}}.
|
||||
if($eq activity.activityType 'moveCard')
|
||||
| {{{_ 'activity-moved' cardLabel activity.oldList.title activity.list.title}}}.
|
||||
|
||||
if($eq activity.activityType 'moveCardBoard')
|
||||
| {{{_ 'activity-moved' cardLink activity.oldBoardName activity.boardName}}}.
|
||||
|
||||
if($eq activity.activityType 'archivedCard')
|
||||
| {{{_ 'activity-archived' cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'restoredCard')
|
||||
| {{{_ 'activity-sent' cardLink boardLabel}}}.
|
||||
|
||||
//- checklist activity --------------------------------------------------
|
||||
if($eq activity.activityType 'addChecklist')
|
||||
| {{{_ 'activity-checklist-added' cardLink}}}.
|
||||
if($eq mode 'card')
|
||||
.activity-checklist
|
||||
+viewer
|
||||
= checklist.title
|
||||
if($eq activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ card.absoluteUrl }}")
|
||||
= activity.checklist.title
|
||||
else
|
||||
a.activity-checklist(href="{{ activity.card.absoluteUrl }}")
|
||||
+viewer
|
||||
= checklistItem.title
|
||||
|
||||
if(currentData.timeKey)
|
||||
| {{{_ activityType }}}
|
||||
= ' '
|
||||
i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
|
||||
if (currentData.timeOldValue)
|
||||
= ' '
|
||||
| {{{_ "previous_as" }}}
|
||||
= ' '
|
||||
i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
|
||||
= ' @'
|
||||
else if(currentData.timeValue)
|
||||
| {{{_ activityType currentData.timeValue}}}
|
||||
|
||||
= activity.checklist.title
|
||||
|
||||
if($eq activityType 'deleteComment')
|
||||
| {{{_ 'activity-deleteComment' currentData.commentId}}}.
|
||||
if($eq activityType 'editComment')
|
||||
| {{{_ 'activity-editComment' currentData.commentId}}}.
|
||||
if($eq activityType 'addComment')
|
||||
if($eq activity.activityType 'removedChecklist')
|
||||
| {{{_ 'activity-checklist-removed' cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'completeChecklist')
|
||||
| {{{_ 'activity-checklist-completed' activity.checklist.title cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'uncompleteChecklist')
|
||||
| {{{_ 'activity-checklist-uncompleted' activity.checklist.title cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'checkedItem')
|
||||
| {{{_ 'activity-checked-item' checkItem activity.checklist.title cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'uncheckedItem')
|
||||
| {{{_ 'activity-unchecked-item' checkItem activity.checklist.title cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'addChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-added' activity.checklist.title cardLink}}}.
|
||||
.activity-checklist(href="{{ activity.card.absoluteUrl }}")
|
||||
+viewer
|
||||
= activity.checklistItem.title
|
||||
|
||||
if($eq activity.activityType 'removedChecklistItem')
|
||||
| {{{_ 'activity-checklist-item-removed' activity.checklist.title cardLink}}}.
|
||||
|
||||
//- comment activity ----------------------------------------------------
|
||||
if($eq mode 'card')
|
||||
//- if we are in card mode we display the comment in a way that it
|
||||
//- can be edited by the owner
|
||||
if($eq activity.activityType 'addComment')
|
||||
+inlinedForm(classNames='js-edit-comment')
|
||||
+editor(autofocus=true)
|
||||
= comment.text
|
||||
= activity.comment.text
|
||||
.edit-controls
|
||||
button.primary(type="submit") {{_ 'edit'}}
|
||||
else
|
||||
.activity-comment
|
||||
+viewer
|
||||
= comment.text
|
||||
span(title=createdAt).activity-meta {{ moment createdAt }}
|
||||
if ($eq currentUser._id comment.userId)
|
||||
= activity.comment.text
|
||||
span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
|
||||
if ($eq currentUser._id activity.comment.userId)
|
||||
= ' - '
|
||||
a.js-open-inlined-form {{_ "edit"}}
|
||||
= ' - '
|
||||
a.js-delete-comment {{_ "delete"}}
|
||||
|
||||
if($eq activity.activityType 'deleteComment')
|
||||
| {{{_ 'activity-deleteComment' currentData.commentId}}}.
|
||||
|
||||
if($eq activity.activityType 'editComment')
|
||||
| {{{_ 'activity-editComment' currentData.commentId}}}.
|
||||
else
|
||||
//- if we are not in card mode we only display a summary of the comment
|
||||
if($eq activity.activityType 'addComment')
|
||||
| {{{_ 'activity-on' cardLink}}}
|
||||
a.activity-comment(href="{{ activity.card.absoluteUrl }}")
|
||||
+viewer
|
||||
= activity.comment.text
|
||||
|
||||
//- customField activity ------------------------------------------------
|
||||
if($eq mode 'board')
|
||||
if($eq activity.activityType 'createCustomField')
|
||||
| {{_ 'activity-customfield-created' customField}}.
|
||||
|
||||
if($eq activity.activityType 'setCustomField')
|
||||
| {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'unsetCustomField')
|
||||
| {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
|
||||
|
||||
//- label activity ------------------------------------------------------
|
||||
if($eq activity.activityType 'addedLabel')
|
||||
| {{{_ 'activity-added-label' lastLabel cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'removedLabel')
|
||||
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
|
||||
|
||||
//- list activity -------------------------------------------------------
|
||||
if($neq mode 'card')
|
||||
if($eq activity.activityType 'createList')
|
||||
| {{{_ 'activity-added' listLabel boardLabel}}}.
|
||||
|
||||
if($eq activity.activityType 'importList')
|
||||
| {{{_ 'activity-imported' listLabel boardLabel sourceLink}}}.
|
||||
|
||||
if($eq activity.activityType 'removeList')
|
||||
| {{{_ 'activity-removed' activity.title boardLabel}}}.
|
||||
|
||||
if($eq activity.activityType 'archivedList')
|
||||
| {{_ 'activity-archived' listLabel}}.
|
||||
|
||||
//- member activity ----------------------------------------------------
|
||||
if($eq activity.activityType 'joinMember')
|
||||
if($eq user._id activity.member._id)
|
||||
| {{{_ 'activity-joined' cardLink}}}.
|
||||
else
|
||||
span(title=createdAt).activity-meta {{ moment createdAt }}
|
||||
| {{{_ 'activity-added' memberLink cardLink}}}.
|
||||
|
||||
if($eq activity.activityType 'unjoinMember')
|
||||
if($eq user._id activity.member._id)
|
||||
| {{{_ 'activity-unjoined' cardLink}}}.
|
||||
else
|
||||
| {{{_ 'activity-removed' memberLink cardLink}}}.
|
||||
|
||||
//- swimlane activity --------------------------------------------------
|
||||
if($neq mode 'card')
|
||||
if($eq activity.activityType 'createSwimlane')
|
||||
| {{{_ 'activity-added' activity.swimlane.title boardLabel}}}.
|
||||
|
||||
if($eq activity.activityType 'archivedSwimlane')
|
||||
| {{_ 'activity-archived' activity.swimlane.title}}.
|
||||
|
||||
|
||||
//- I don't understand this part ----------------------------------------
|
||||
if(currentData.timeKey)
|
||||
| {{{_ activity.activityType }}}
|
||||
= ' '
|
||||
i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
|
||||
if (currentData.timeOldValue)
|
||||
= ' '
|
||||
| {{{_ "previous_as" }}}
|
||||
= ' '
|
||||
i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
|
||||
= ' @'
|
||||
else if(currentData.timeValue)
|
||||
| {{{_ activity.activityType currentData.timeValue}}}
|
||||
|
||||
span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
|
||||
@@ -41,7 +41,9 @@ BlazeComponent.extendComponent({
|
||||
});
|
||||
});
|
||||
},
|
||||
}).register('activities');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
loadNextPage() {
|
||||
if (this.loadNextPageLocked === false) {
|
||||
this.page.set(this.page.get() + 1);
|
||||
@@ -50,41 +52,37 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
checkItem() {
|
||||
const checkItemId = this.currentData().checklistItemId;
|
||||
const checkItemId = this.currentData().activity.checklistItemId;
|
||||
const checkItem = ChecklistItems.findOne({ _id: checkItemId });
|
||||
return checkItem.title;
|
||||
return checkItem && checkItem.title;
|
||||
},
|
||||
|
||||
boardLabel() {
|
||||
const data = this.currentData();
|
||||
if (data.mode !== 'board') {
|
||||
return createBoardLink(data.activity.board(), data.activity.listName);
|
||||
}
|
||||
return TAPi18n.__('this-board');
|
||||
},
|
||||
|
||||
cardLabel() {
|
||||
const data = this.currentData();
|
||||
if (data.mode !== 'card') {
|
||||
return createCardLink(this.currentData().activity.card());
|
||||
}
|
||||
return TAPi18n.__('this-card');
|
||||
},
|
||||
|
||||
cardLink() {
|
||||
const card = this.currentData().card();
|
||||
return (
|
||||
card &&
|
||||
Blaze.toHTML(
|
||||
HTML.A(
|
||||
{
|
||||
href: card.absoluteUrl(),
|
||||
class: 'action-card',
|
||||
},
|
||||
card.title,
|
||||
),
|
||||
)
|
||||
);
|
||||
return createCardLink(this.currentData().activity.card());
|
||||
},
|
||||
|
||||
lastLabel() {
|
||||
const lastLabelId = this.currentData().labelId;
|
||||
const lastLabelId = this.currentData().activity.labelId;
|
||||
if (!lastLabelId) return null;
|
||||
const lastLabel = Boards.findOne(Session.get('currentBoard')).getLabelById(
|
||||
lastLabelId,
|
||||
);
|
||||
const lastLabel = Boards.findOne(
|
||||
this.currentData().activity.boardId,
|
||||
).getLabelById(lastLabelId);
|
||||
if (lastLabel && (lastLabel.name === undefined || lastLabel.name === '')) {
|
||||
return lastLabel.color;
|
||||
} else {
|
||||
@@ -94,7 +92,7 @@ BlazeComponent.extendComponent({
|
||||
|
||||
lastCustomField() {
|
||||
const lastCustomField = CustomFields.findOne(
|
||||
this.currentData().customFieldId,
|
||||
this.currentData().activity.customFieldId,
|
||||
);
|
||||
if (!lastCustomField) return null;
|
||||
return lastCustomField.name;
|
||||
@@ -102,10 +100,10 @@ BlazeComponent.extendComponent({
|
||||
|
||||
lastCustomFieldValue() {
|
||||
const lastCustomField = CustomFields.findOne(
|
||||
this.currentData().customFieldId,
|
||||
this.currentData().activity.customFieldId,
|
||||
);
|
||||
if (!lastCustomField) return null;
|
||||
const value = this.currentData().value;
|
||||
const value = this.currentData().activity.value;
|
||||
if (
|
||||
lastCustomField.settings.dropdownItems &&
|
||||
lastCustomField.settings.dropdownItems.length > 0
|
||||
@@ -122,11 +120,13 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
listLabel() {
|
||||
return this.currentData().list().title;
|
||||
const activity = this.currentData().activity;
|
||||
const list = activity.list();
|
||||
return (list && list.title) || activity.title;
|
||||
},
|
||||
|
||||
sourceLink() {
|
||||
const source = this.currentData().source;
|
||||
const source = this.currentData().activity.source;
|
||||
if (source) {
|
||||
if (source.url) {
|
||||
return Blaze.toHTML(
|
||||
@@ -146,30 +146,31 @@ BlazeComponent.extendComponent({
|
||||
|
||||
memberLink() {
|
||||
return Blaze.toHTMLWithData(Template.memberName, {
|
||||
user: this.currentData().member(),
|
||||
user: this.currentData().activity.member(),
|
||||
});
|
||||
},
|
||||
|
||||
attachmentLink() {
|
||||
const attachment = this.currentData().attachment();
|
||||
const attachment = this.currentData().activity.attachment();
|
||||
// trying to display url before file is stored generates js errors
|
||||
return (
|
||||
attachment &&
|
||||
attachment.url({ download: true }) &&
|
||||
Blaze.toHTML(
|
||||
HTML.A(
|
||||
{
|
||||
href: attachment.url({ download: true }),
|
||||
target: '_blank',
|
||||
},
|
||||
attachment.name(),
|
||||
),
|
||||
)
|
||||
(attachment &&
|
||||
attachment.url({ download: true }) &&
|
||||
Blaze.toHTML(
|
||||
HTML.A(
|
||||
{
|
||||
href: attachment.url({ download: true }),
|
||||
target: '_blank',
|
||||
},
|
||||
attachment.name(),
|
||||
),
|
||||
)) ||
|
||||
this.currentData().activity.attachmentName
|
||||
);
|
||||
},
|
||||
|
||||
customField() {
|
||||
const customField = this.currentData().customField();
|
||||
const customField = this.currentData().activity.customField();
|
||||
if (!customField) return null;
|
||||
return customField.name;
|
||||
},
|
||||
@@ -179,7 +180,7 @@ BlazeComponent.extendComponent({
|
||||
{
|
||||
// XXX We should use Popup.afterConfirmation here
|
||||
'click .js-delete-comment'() {
|
||||
const commentId = this.currentData().commentId;
|
||||
const commentId = this.currentData().activity.commentId;
|
||||
CardComments.remove(commentId);
|
||||
},
|
||||
'submit .js-edit-comment'(evt) {
|
||||
@@ -187,7 +188,7 @@ BlazeComponent.extendComponent({
|
||||
const commentText = this.currentComponent()
|
||||
.getValue()
|
||||
.trim();
|
||||
const commentId = Template.parentData().commentId;
|
||||
const commentId = Template.parentData().activity.commentId;
|
||||
if (commentText) {
|
||||
CardComments.update(commentId, {
|
||||
$set: {
|
||||
@@ -199,4 +200,36 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('activities');
|
||||
}).register('activity');
|
||||
|
||||
function createCardLink(card) {
|
||||
return (
|
||||
card &&
|
||||
Blaze.toHTML(
|
||||
HTML.A(
|
||||
{
|
||||
href: card.absoluteUrl(),
|
||||
class: 'action-card',
|
||||
},
|
||||
card.title,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
function createBoardLink(board, list) {
|
||||
let text = board.title;
|
||||
if (list) text += `: ${list}`;
|
||||
return (
|
||||
board &&
|
||||
Blaze.toHTML(
|
||||
HTML.A(
|
||||
{
|
||||
href: board.absoluteUrl(),
|
||||
class: 'action-board',
|
||||
},
|
||||
text,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
clear: both
|
||||
|
||||
.activity
|
||||
margin: 10px 0
|
||||
margin: 0.5px 0
|
||||
display: flex
|
||||
|
||||
.member
|
||||
|
||||
@@ -46,3 +46,23 @@
|
||||
|
||||
&:is-open
|
||||
cursor: auto
|
||||
|
||||
.comment-item
|
||||
background-color: #fff
|
||||
border: 0
|
||||
box-shadow: 0 1px 2px rgba(0, 0, 0, .23)
|
||||
color: #8c8c8c
|
||||
height: 36px
|
||||
margin: 4px 4px 6px 0
|
||||
width: 92%
|
||||
|
||||
&:hover
|
||||
background: darken(white, 12%)
|
||||
|
||||
&.add-comment
|
||||
display: flex
|
||||
margin: 5px
|
||||
|
||||
a
|
||||
display: block
|
||||
margin: auto
|
||||
@@ -7,7 +7,7 @@ BlazeComponent.extendComponent({
|
||||
return Boards.find(
|
||||
{ archived: true },
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndex, enableClickOnTouch } = Utils;
|
||||
const { calculateIndex } = Utils;
|
||||
const swimlaneWhileSortingHeight = 150;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -191,9 +191,6 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch('.js-swimlane:not(.placeholder)');
|
||||
|
||||
this.autorun(() => {
|
||||
let showDesktopDragHandles = false;
|
||||
currentUser = Meteor.user();
|
||||
@@ -205,20 +202,17 @@ BlazeComponent.extendComponent({
|
||||
} else {
|
||||
showDesktopDragHandles = false;
|
||||
}
|
||||
if (
|
||||
Utils.isMiniScreen() ||
|
||||
(!Utils.isMiniScreen() && showDesktopDragHandles)
|
||||
) {
|
||||
if (Utils.isMiniScreen() || showDesktopDragHandles) {
|
||||
$swimlanesDom.sortable({
|
||||
handle: '.js-swimlane-header-handle',
|
||||
});
|
||||
} else {
|
||||
} else if (!Utils.isMiniScreen() && !showDesktopDragHandles) {
|
||||
$swimlanesDom.sortable({
|
||||
handle: '.swimlane-header',
|
||||
});
|
||||
}
|
||||
|
||||
// Disable drag-dropping if the current user is not a board member or is comment only
|
||||
// Disable drag-dropping if the current user is not a board member
|
||||
$swimlanesDom.sortable('option', 'disabled', !userIsMember());
|
||||
});
|
||||
|
||||
|
||||
@@ -193,20 +193,6 @@ template(name="boardChangeViewPopup")
|
||||
| {{_ 'board-view-cal'}}
|
||||
if $eq Utils.boardView "board-view-cal"
|
||||
i.fa.fa-check
|
||||
if currentUser.isAdmin
|
||||
hr
|
||||
li
|
||||
with "board-view-rules"
|
||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rules'}}
|
||||
else if currentUser.isBoardAdmin
|
||||
hr
|
||||
li
|
||||
with "board-view-rules"
|
||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rules'}}
|
||||
|
||||
template(name="createBoard")
|
||||
form
|
||||
|
||||
@@ -30,22 +30,7 @@ Template.boardMenuPopup.events({
|
||||
'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'),
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
'click .js-subtask-settings': Popup.open('boardSubtaskSettings'),
|
||||
});
|
||||
|
||||
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`;
|
||||
},
|
||||
'click .js-card-settings': Popup.open('boardCardSettings'),
|
||||
});
|
||||
|
||||
Template.boardChangeTitlePopup.events({
|
||||
@@ -190,10 +175,6 @@ Template.boardChangeViewPopup.events({
|
||||
Utils.setBoardView('board-view-cal');
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-open-rules-view'() {
|
||||
Modal.openWide('rulesMain');
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
|
||||
const CreateBoard = BlazeComponent.extendComponent({
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
template(name="boardList")
|
||||
.wrapper
|
||||
ul.board-list.clearfix
|
||||
ul.board-list.clearfix.js-boards
|
||||
li.js-add-board
|
||||
a.board-list-item.label {{_ 'add-board'}}
|
||||
each boards
|
||||
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass)
|
||||
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board
|
||||
if isInvited
|
||||
.board-list-item
|
||||
span.details
|
||||
@@ -39,7 +39,7 @@ template(name="boardList")
|
||||
i.fa.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
else if currentUser.isBoardAdmin
|
||||
else if isAdministrable
|
||||
i.fa.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
@@ -55,7 +55,7 @@ template(name="boardList")
|
||||
title="{{_ 'archive-board'}}")
|
||||
|
||||
template(name="boardListHeaderBar")
|
||||
h1 {{_ 'my-boards'}}
|
||||
h1 {{_ title }}
|
||||
.board-header-btns.right
|
||||
a.board-header-btn.js-open-archived-board
|
||||
i.fa.fa-archive
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndex, enableClickOnTouch } = Utils;
|
||||
|
||||
Template.boardListHeaderBar.events({
|
||||
'click .js-open-archived-board'() {
|
||||
@@ -7,6 +8,9 @@ Template.boardListHeaderBar.events({
|
||||
});
|
||||
|
||||
Template.boardListHeaderBar.helpers({
|
||||
title() {
|
||||
return FlowRouter.getRouteName() === 'home' ? 'my-boards' : 'public';
|
||||
},
|
||||
templatesBoardId() {
|
||||
return Meteor.user() && Meteor.user().getTemplatesBoardId();
|
||||
},
|
||||
@@ -20,20 +24,80 @@ BlazeComponent.extendComponent({
|
||||
Meteor.subscribe('setting');
|
||||
},
|
||||
|
||||
boards() {
|
||||
return Boards.find(
|
||||
{
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
type: 'board',
|
||||
onRendered() {
|
||||
const self = this;
|
||||
function userIsAllowedToMove() {
|
||||
return Meteor.user();
|
||||
}
|
||||
|
||||
const itemsSelector = '.js-board:not(.placeholder)';
|
||||
|
||||
const $boards = this.$('.js-boards');
|
||||
$boards.sortable({
|
||||
connectWith: '.js-boards',
|
||||
tolerance: 'pointer',
|
||||
appendTo: '.board-list',
|
||||
helper: 'clone',
|
||||
distance: 7,
|
||||
items: itemsSelector,
|
||||
placeholder: 'board-wrapper placeholder',
|
||||
start(evt, ui) {
|
||||
ui.helper.css('z-index', 1000);
|
||||
ui.placeholder.height(ui.helper.height());
|
||||
EscapeActions.executeUpTo('popup-close');
|
||||
},
|
||||
{ sort: ['title'] },
|
||||
);
|
||||
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 prevBoardDom = ui.item.prev('.js-board').get(0);
|
||||
const nextBoardBom = ui.item.next('.js-board').get(0);
|
||||
const sortIndex = calculateIndex(prevBoardDom, nextBoardBom, 1);
|
||||
|
||||
const boardDomElement = ui.item.get(0);
|
||||
const board = Blaze.getData(boardDomElement);
|
||||
// Normally the jquery-ui sortable library moves the dragged DOM element
|
||||
// to its new position, which disrupts Blaze reactive updates mechanism
|
||||
// (especially when we move the last card of a list, or when multiple
|
||||
// users move some cards at the same time). To prevent these UX glitches
|
||||
// we ask sortable to gracefully cancel the move, and to put back the
|
||||
// DOM in its initial state. The card move is then handled reactively by
|
||||
// Blaze with the below query.
|
||||
$boards.sortable('cancel');
|
||||
|
||||
board.move(sortIndex.base);
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch(itemsSelector);
|
||||
|
||||
// Disable drag-dropping if the current user is not a board member or is comment only
|
||||
this.autorun(() => {
|
||||
$boards.sortable('option', 'disabled', !userIsAllowedToMove());
|
||||
});
|
||||
},
|
||||
|
||||
boards() {
|
||||
let query = {
|
||||
archived: false,
|
||||
type: 'board',
|
||||
};
|
||||
if (FlowRouter.getRouteName() === 'home')
|
||||
query['members.userId'] = Meteor.userId();
|
||||
else query.permission = 'public';
|
||||
|
||||
return Boards.find(query, {
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
});
|
||||
},
|
||||
isStarred() {
|
||||
const user = Meteor.user();
|
||||
return user && user.hasStarred(this.currentData()._id);
|
||||
},
|
||||
isAdministrable() {
|
||||
const user = Meteor.user();
|
||||
return user && user.isBoardAdmin(this.currentData()._id);
|
||||
},
|
||||
|
||||
hasOvertimeCards() {
|
||||
subManager.subscribe('board', this.currentData()._id, false);
|
||||
|
||||
@@ -11,6 +11,19 @@ $spaceBetweenTiles = 16px
|
||||
box-sizing: border-box
|
||||
position: relative
|
||||
|
||||
&.placeholder:after
|
||||
content: '';
|
||||
display: block;
|
||||
background: darken(white, 20%)
|
||||
border-radius: 3px;
|
||||
height: 106px;
|
||||
margin: 8px;
|
||||
|
||||
&.ui-sortable-helper
|
||||
cursor: grabbing
|
||||
transform: rotate(4deg)
|
||||
display: block !important
|
||||
|
||||
&.starred
|
||||
.fa-star,
|
||||
.fa-star-o
|
||||
@@ -20,7 +33,7 @@ $spaceBetweenTiles = 16px
|
||||
overflow: hidden;
|
||||
background-color: #999
|
||||
color: #f6f6f6
|
||||
height: 90px
|
||||
height: auto
|
||||
font-size: 16px
|
||||
line-height: 22px
|
||||
border-radius: 3px
|
||||
@@ -31,6 +44,7 @@ $spaceBetweenTiles = 16px
|
||||
margin: ($spaceBetweenTiles/2)
|
||||
position: relative
|
||||
text-decoration: none
|
||||
word-wrap: break-word
|
||||
|
||||
&.tile
|
||||
background-size: auto
|
||||
@@ -183,7 +197,7 @@ $spaceBetweenTiles = 16px
|
||||
overflow: scroll
|
||||
|
||||
li
|
||||
width: 50%
|
||||
width: 50%
|
||||
|
||||
.board-list-item
|
||||
overflow: hidden
|
||||
|
||||
@@ -38,18 +38,22 @@ template(name="attachmentsGalery")
|
||||
| {{_ 'download'}}
|
||||
if currentUser.isBoardMember
|
||||
unless currentUser.isCommentOnly
|
||||
if isImage
|
||||
a(class="{{#if $eq ../coverId _id}}js-remove-cover{{else}}js-add-cover{{/if}}")
|
||||
i.fa.fa-thumb-tack
|
||||
if($eq ../coverId _id)
|
||||
| {{_ 'remove-cover'}}
|
||||
else
|
||||
| {{_ 'add-cover'}}
|
||||
a.js-confirm-delete
|
||||
i.fa.fa-close
|
||||
| {{_ 'delete'}}
|
||||
unless currentUser.isWorker
|
||||
if isImage
|
||||
a(class="{{#if $eq ../coverId _id}}js-remove-cover{{else}}js-add-cover{{/if}}")
|
||||
i.fa.fa-thumb-tack
|
||||
if($eq ../coverId _id)
|
||||
| {{_ 'remove-cover'}}
|
||||
else
|
||||
| {{_ 'add-cover'}}
|
||||
a.js-confirm-delete
|
||||
i.fa.fa-close
|
||||
| {{_ 'delete'}}
|
||||
|
||||
if currentUser.isBoardMember
|
||||
unless currentUser.isCommentOnly
|
||||
li.attachment-item.add-attachment
|
||||
a.js-add-attachment {{_ 'add-attachment' }}
|
||||
unless currentUser.isWorker
|
||||
//li.attachment-item.add-attachment
|
||||
a.js-add-attachment
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-attachment' }}
|
||||
@@ -97,7 +97,8 @@ Template.dateBadge.helpers({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -8,16 +8,23 @@ template(name="cardDetails")
|
||||
a.fa.fa-times-thin.close-card-details.js-close-card-details
|
||||
if currentUser.isBoardMember
|
||||
a.fa.fa-navicon.card-details-menu.js-open-card-details-menu
|
||||
input.inline-input(type="text" id="cardURL_copy" value="{{ absoluteUrl }}")
|
||||
a.fa.fa-link.card-copy-button.js-copy-link(
|
||||
class="fa-link"
|
||||
title="{{_ 'copy-card-link-to-clipboard'}}"
|
||||
value="{{ absoluteUrl }}"
|
||||
)
|
||||
if isMiniScreen
|
||||
a.fa.fa-times-thin.close-card-details-mobile-web.js-close-card-details
|
||||
if currentUser.isBoardMember
|
||||
a.fa.fa-navicon.card-details-menu-mobile-web.js-open-card-details-menu
|
||||
a.fa.fa-link.card-copy-mobile-button
|
||||
h2.card-details-title.js-card-title(
|
||||
class="{{#if canModifyCard}}js-open-inlined-form is-editable{{/if}}")
|
||||
+viewer
|
||||
= getTitle
|
||||
if isWatching
|
||||
i.fa.fa-eye.card-details-watch
|
||||
if isWatching
|
||||
i.card-details-watch.fa.fa-eye
|
||||
.card-details-path
|
||||
each parentList
|
||||
| >
|
||||
@@ -25,7 +32,7 @@ template(name="cardDetails")
|
||||
// else
|
||||
{{_ 'top-level-card'}}
|
||||
if isLinkedCard
|
||||
h3.linked-card-location
|
||||
a.linked-card-location.js-go-to-linked-card
|
||||
+viewer
|
||||
| {{getBoardTitle}} > {{getTitle}}
|
||||
|
||||
@@ -36,70 +43,105 @@ template(name="cardDetails")
|
||||
p.warning {{_ 'card-archived'}}
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-received
|
||||
h3.card-details-item-title {{_ 'card-received'}}
|
||||
if getReceived
|
||||
+cardReceivedDate
|
||||
else
|
||||
if currentBoard.allowsReceivedDate
|
||||
.card-details-item.card-details-item-received
|
||||
h3
|
||||
i.fa.fa-sign-out
|
||||
card-details-item-title {{_ 'card-received'}}
|
||||
if getReceived
|
||||
+cardReceivedDate
|
||||
else
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-received-date
|
||||
i.fa.fa-plus
|
||||
|
||||
if currentBoard.allowsStartDate
|
||||
.card-details-item.card-details-item-start
|
||||
h3
|
||||
i.fa.fa-hourglass-start
|
||||
card-details-item-title {{_ 'card-start'}}
|
||||
if getStart
|
||||
+cardStartDate
|
||||
else
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-start-date
|
||||
i.fa.fa-plus
|
||||
|
||||
if currentBoard.allowsDueDate
|
||||
.card-details-item.card-details-item-due
|
||||
h3
|
||||
i.fa.fa-sign-in
|
||||
card-details-item-title {{_ 'card-due'}}
|
||||
if getDue
|
||||
+cardDueDate
|
||||
else
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-due-date
|
||||
i.fa.fa-plus
|
||||
|
||||
if currentBoard.allowsEndDate
|
||||
.card-details-item.card-details-item-end
|
||||
h3
|
||||
i.fa.fa-hourglass-end
|
||||
card-details-item-title {{_ 'card-end'}}
|
||||
if getEnd
|
||||
+cardEndDate
|
||||
else
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-end-date
|
||||
i.fa.fa-plus
|
||||
|
||||
//.card-details-items
|
||||
if currentBoard.allowsMembers
|
||||
.card-details-item.card-details-item-members
|
||||
h3
|
||||
i.fa.fa-users
|
||||
card-details-item-title {{_ 'members'}}
|
||||
each getMembers
|
||||
+userAvatar(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
if canModifyCard
|
||||
a.js-received-date {{_ 'add'}}
|
||||
unless currentUser.isWorker
|
||||
a.member.add-member.card-details-item-add-button.js-add-members(title="{{_ 'card-members-title'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
.card-details-item.card-details-item-start
|
||||
h3.card-details-item-title {{_ 'card-start'}}
|
||||
if getStart
|
||||
+cardStartDate
|
||||
else
|
||||
//if assigneeSelected
|
||||
if currentBoard.allowsAssignee
|
||||
.card-details-item.card-details-item-assignees
|
||||
h3
|
||||
i.fa.fa-user
|
||||
card-details-item-title {{_ 'assignee'}}
|
||||
each getAssignees
|
||||
+userAvatarAssignee(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
if canModifyCard
|
||||
a.js-start-date {{_ 'add'}}
|
||||
|
||||
.card-details-item.card-details-item-due
|
||||
h3.card-details-item-title {{_ 'card-due'}}
|
||||
if getDue
|
||||
+cardDueDate
|
||||
else
|
||||
if canModifyCard
|
||||
a.js-due-date {{_ 'add'}}
|
||||
|
||||
.card-details-item.card-details-item-end
|
||||
h3.card-details-item-title {{_ 'card-end'}}
|
||||
if getEnd
|
||||
+cardEndDate
|
||||
else
|
||||
if canModifyCard
|
||||
a.js-end-date {{_ 'add'}}
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-members
|
||||
h3.card-details-item-title {{_ 'members'}}
|
||||
each getMembers
|
||||
+userAvatar(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
if canModifyCard
|
||||
a.member.add-member.card-details-item-add-button.js-add-members(title="{{_ 'card-members-title'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
.card-details-item.card-details-item-assignees
|
||||
h3.card-details-item-title {{_ 'assignee'}}
|
||||
each getAssignees
|
||||
+userAvatarAssignee(userId=this cardId=../_id)
|
||||
| {{! XXX Hack to hide syntaxic coloration /// }}
|
||||
if canModifyCard
|
||||
unless assigneeSelected
|
||||
a.assignee.add-assignee.card-details-item-add-button.js-add-assignees(title="{{_ 'assignee'}}")
|
||||
i.fa.fa-plus
|
||||
if currentUser.isWorker
|
||||
unless assigneeSelected
|
||||
a.assignee.add-assignee.card-details-item-add-button.js-add-assignees(title="{{_ 'assignee'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
.card-details-item.card-details-item-labels
|
||||
h3.card-details-item-title {{_ 'labels'}}
|
||||
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
|
||||
each labels
|
||||
span.card-label(class="card-label-{{color}}" title=name)
|
||||
+viewer
|
||||
= name
|
||||
if canModifyCard
|
||||
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
|
||||
i.fa.fa-plus
|
||||
if currentBoard.allowsLabels
|
||||
.card-details-item.card-details-item-labels
|
||||
h3
|
||||
i.fa.fa-tags
|
||||
card-details-item-title {{_ 'labels'}}
|
||||
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
|
||||
each labels
|
||||
span.card-label(class="card-label-{{color}}" title=name)
|
||||
+viewer
|
||||
= name
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
|
||||
i.fa.fa-plus
|
||||
|
||||
.card-details-items
|
||||
//.card-details-items
|
||||
each customFieldsWD
|
||||
.card-details-item.card-details-item-customfield
|
||||
h3.card-details-item-title
|
||||
@@ -107,7 +149,7 @@ template(name="cardDetails")
|
||||
= definition.name
|
||||
+cardCustomField
|
||||
|
||||
.card-details-items
|
||||
//.card-details-items
|
||||
if getSpentTime
|
||||
.card-details-item.card-details-item-spent
|
||||
if getIsOvertime
|
||||
@@ -116,84 +158,124 @@ template(name="cardDetails")
|
||||
h3.card-details-item-title {{_ 'spent-time-hours'}}
|
||||
+cardSpentTime
|
||||
|
||||
//.card-details-items
|
||||
if currentBoard.allowsRequestedBy
|
||||
.card-details-item.card-details-item-name
|
||||
h3
|
||||
i.fa.fa-shopping-cart
|
||||
card-details-item-title {{_ 'requested-by'}}
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
+inlinedForm(classNames="js-card-details-requester")
|
||||
+editCardRequesterForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if getRequestedBy
|
||||
+viewer
|
||||
= getRequestedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= getRequestedBy
|
||||
|
||||
if currentBoard.allowsAssignedBy
|
||||
.card-details-item.card-details-item-name
|
||||
h3
|
||||
i.fa.fa-user-plus
|
||||
card-details-item-title {{_ 'assigned-by'}}
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
+inlinedForm(classNames="js-card-details-assigner")
|
||||
+editCardAssignerForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if getAssignedBy
|
||||
+viewer
|
||||
= getAssignedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= getAssignedBy
|
||||
|
||||
if getVoteQuestion
|
||||
hr
|
||||
.vote-title
|
||||
h3
|
||||
i.fa.fa-thumbs-up
|
||||
card-details-item-title {{_ 'vote-question'}}
|
||||
.vote-result
|
||||
if votePublic
|
||||
a.card-label.card-label-green.js-show-positive-votes {{ voteCountPositive }}
|
||||
a.card-label.card-label-red.js-show-negative-votes {{ voteCountNegative }}
|
||||
else
|
||||
.card-label.card-label-green {{ voteCountPositive }}
|
||||
.card-label.card-label-red {{ voteCountNegative }}
|
||||
+viewer
|
||||
= getVoteQuestion
|
||||
button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}") {{_ 'vote-for-it'}}
|
||||
button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}") {{_ 'vote-against'}}
|
||||
|
||||
//- XXX We should use "editable" to avoid repetiting ourselves
|
||||
if canModifyCard
|
||||
h3.card-details-item-title {{_ 'description'}}
|
||||
+inlinedCardDescription(classNames="card-description js-card-description")
|
||||
+editor(autofocus=true)
|
||||
| {{getUnsavedValue 'cardDescription' _id getDescription}}
|
||||
.edit-controls.clearfix
|
||||
button.primary(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if getDescription
|
||||
+viewer
|
||||
= getDescription
|
||||
unless currentUser.isWorker
|
||||
if currentBoard.allowsDescriptionTitle
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-align-left
|
||||
card-details-item-title {{_ 'description'}}
|
||||
if currentBoard.allowsDescriptionText
|
||||
+inlinedCardDescription(classNames="card-description js-card-description")
|
||||
+editor(autofocus=true)
|
||||
| {{getUnsavedValue 'cardDescription' _id getDescription}}
|
||||
.edit-controls.clearfix
|
||||
button.primary(type="submit") {{_ 'save'}}
|
||||
a.fa.fa-times-thin.js-close-inlined-form
|
||||
else
|
||||
| {{_ 'edit'}}
|
||||
if (hasUnsavedValue 'cardDescription' _id)
|
||||
p.quiet
|
||||
| {{_ 'unsaved-description'}}
|
||||
a.js-open-inlined-form {{_ 'view-it'}}
|
||||
= ' - '
|
||||
a.js-close-inlined-form {{_ 'discard'}}
|
||||
if currentBoard.allowsDescriptionText
|
||||
a.js-open-inlined-form
|
||||
if getDescription
|
||||
+viewer
|
||||
= getDescription
|
||||
else
|
||||
| {{_ 'edit'}}
|
||||
if (hasUnsavedValue 'cardDescription' _id)
|
||||
p.quiet
|
||||
| {{_ 'unsaved-description'}}
|
||||
a.js-open-inlined-form {{_ 'view-it'}}
|
||||
= ' - '
|
||||
a.js-close-inlined-form {{_ 'discard'}}
|
||||
else if getDescription
|
||||
h3.card-details-item-title {{_ 'description'}}
|
||||
+viewer
|
||||
= getDescription
|
||||
if currentBoard.allowsDescriptionTitle
|
||||
hr
|
||||
h3.card-details-item-title {{_ 'description'}}
|
||||
if currentBoard.allowsDescriptionText
|
||||
+viewer
|
||||
= getDescription
|
||||
|
||||
.card-details-items
|
||||
.card-details-item.card-details-item-name
|
||||
h3.card-details-item-title {{_ 'requested-by'}}
|
||||
if canModifyCard
|
||||
+inlinedForm(classNames="js-card-details-requester")
|
||||
+editCardRequesterForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if getRequestedBy
|
||||
+viewer
|
||||
= getRequestedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= getRequestedBy
|
||||
|
||||
.card-details-item.card-details-item-name
|
||||
h3.card-details-item-title {{_ 'assigned-by'}}
|
||||
if canModifyCard
|
||||
+inlinedForm(classNames="js-card-details-assigner")
|
||||
+editCardAssignerForm
|
||||
else
|
||||
a.js-open-inlined-form
|
||||
if getAssignedBy
|
||||
+viewer
|
||||
= getAssignedBy
|
||||
else
|
||||
| {{_ 'add'}}
|
||||
else if getRequestedBy
|
||||
+viewer
|
||||
= getAssignedBy
|
||||
|
||||
hr
|
||||
+checklists(cardId = _id)
|
||||
|
||||
if currentBoard.allowsSubtasks
|
||||
hr
|
||||
+subtasks(cardId = _id)
|
||||
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
|
||||
+attachmentsGalery
|
||||
.card-checklist-attachmentGalerys
|
||||
.card-checklist-attachmentGalery.card-checklists
|
||||
if currentBoard.allowsChecklists
|
||||
hr
|
||||
+checklists(cardId = _id)
|
||||
if currentBoard.allowsSubtasks
|
||||
hr
|
||||
+subtasks(cardId = _id)
|
||||
if currentBoard.allowsAttachments
|
||||
hr
|
||||
h3
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
.card-checklist-attachmentGalery.card-attachmentGalery
|
||||
+attachmentsGalery
|
||||
|
||||
hr
|
||||
unless currentUser.isNoComments
|
||||
.activity-title
|
||||
h3 {{ _ 'activity'}}
|
||||
h3
|
||||
i.fa.fa-history
|
||||
| {{ _ 'activity'}}
|
||||
if currentUser.isBoardMember
|
||||
.material-toggle-switch
|
||||
span.toggle-switch-title {{_ 'hide-system-messages'}}
|
||||
@@ -202,9 +284,10 @@ template(name="cardDetails")
|
||||
else
|
||||
input.toggle-switch(type="checkbox" id="toggleButton")
|
||||
label.toggle-label(for="toggleButton")
|
||||
if currentUser.isBoardMember
|
||||
unless currentUser.isNoComments
|
||||
+commentForm
|
||||
if currentBoard.allowsComments
|
||||
if currentUser.isBoardMember
|
||||
unless currentUser.isNoComments
|
||||
+commentForm
|
||||
unless currentUser.isNoComments
|
||||
if isLoaded.get
|
||||
if isLinkedCard
|
||||
@@ -235,32 +318,89 @@ template(name="editCardAssignerForm")
|
||||
|
||||
template(name="cardDetailsActionsPopup")
|
||||
ul.pop-over-list
|
||||
li: a.js-toggle-watch-card {{#if isWatching}}{{_ 'unwatch'}}{{else}}{{_ 'watch'}}{{/if}}
|
||||
li
|
||||
a.js-toggle-watch-card
|
||||
if isWatching
|
||||
i.fa.fa-eye
|
||||
| {{_ 'unwatch'}}
|
||||
else
|
||||
i.fa.fa-eye-slash
|
||||
| {{_ 'watch'}}
|
||||
if canModifyCard
|
||||
hr
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
//li: a.js-members {{_ 'card-edit-members'}}
|
||||
//li: a.js-labels {{_ 'card-edit-labels'}}
|
||||
//li: a.js-attachments {{_ 'card-edit-attachments'}}
|
||||
if getVoteQuestion
|
||||
li
|
||||
a.js-cancel-voting
|
||||
i.fa.fa-thumbs-up
|
||||
| {{_ 'card-cancel-voting'}}
|
||||
else
|
||||
li
|
||||
a.js-start-voting
|
||||
i.fa.fa-thumbs-up
|
||||
| {{_ 'card-start-voting'}}
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'card-edit-custom-fields'}}
|
||||
//li: a.js-received-date {{_ 'editCardReceivedDatePopup-title'}}
|
||||
//li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
||||
//li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||
//li: a.js-end-date {{_ 'editCardEndDatePopup-title'}}
|
||||
li
|
||||
a.js-spent-time
|
||||
i.fa.fa-clock-o
|
||||
| {{_ 'editCardSpentTimePopup-title'}}
|
||||
li
|
||||
a.js-set-card-color
|
||||
i.fa.fa-paint-brush
|
||||
| {{_ 'setCardColorPopup-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
//li: a.js-members {{_ 'card-edit-members'}}
|
||||
//li: a.js-labels {{_ 'card-edit-labels'}}
|
||||
//li: a.js-attachments {{_ 'card-edit-attachments'}}
|
||||
li: a.js-custom-fields {{_ 'card-edit-custom-fields'}}
|
||||
//li: a.js-received-date {{_ 'editCardReceivedDatePopup-title'}}
|
||||
//li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
|
||||
//li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
|
||||
//li: a.js-end-date {{_ 'editCardEndDatePopup-title'}}
|
||||
li: a.js-spent-time {{_ 'editCardSpentTimePopup-title'}}
|
||||
li: a.js-set-card-color {{_ 'setCardColorPopup-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-move-card-to-top {{_ 'moveCardToTop-title'}}
|
||||
li: a.js-move-card-to-bottom {{_ 'moveCardToBottom-title'}}
|
||||
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'}}
|
||||
li
|
||||
a.js-move-card-to-top
|
||||
i.fa.fa-arrow-up
|
||||
| {{_ 'moveCardToTop-title'}}
|
||||
li
|
||||
a.js-move-card-to-bottom
|
||||
i.fa.fa-arrow-down
|
||||
| {{_ 'moveCardToBottom-title'}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-move-card
|
||||
i.fa.fa-arrow-right
|
||||
| {{_ 'moveCardPopup-title'}}
|
||||
li
|
||||
a.js-copy-card
|
||||
i.fa.fa-copy
|
||||
| {{_ 'copyCardPopup-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-copy-checklist-cards
|
||||
i.fa.fa-list
|
||||
i.fa.fa-copy
|
||||
| {{_ 'copyChecklistToManyCardsPopup-title'}}
|
||||
unless archived
|
||||
li: a.js-archive {{_ 'archive-card'}}
|
||||
li: a.js-more {{_ 'cardMorePopup-title'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-archive
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-card'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-more
|
||||
i.fa.fa-link
|
||||
| {{_ 'cardMorePopup-title'}}
|
||||
|
||||
template(name="moveCardPopup")
|
||||
+boardsAndLists
|
||||
@@ -312,16 +452,27 @@ template(name="cardMembersPopup")
|
||||
i.fa.fa-check
|
||||
|
||||
template(name="cardAssigneesPopup")
|
||||
ul.pop-over-list.js-card-assignee-list
|
||||
each board.activeMembers
|
||||
li.item(class="{{#if isCardAssignee}}active{{/if}}")
|
||||
a.name.js-select-assignee(href="#")
|
||||
+userAvatar(userId=user._id)
|
||||
span.full-name
|
||||
= user.profile.fullname
|
||||
| (<span class="username">{{ user.username }}</span>)
|
||||
if isCardAssignee
|
||||
i.fa.fa-check
|
||||
unless currentUser.isWorker
|
||||
ul.pop-over-list.js-card-assignee-list
|
||||
each board.activeMembers
|
||||
li.item(class="{{#if isCardAssignee}}active{{/if}}")
|
||||
a.name.js-select-assignee(href="#")
|
||||
+userAvatar(userId=user._id)
|
||||
span.full-name
|
||||
= user.profile.fullname
|
||||
| (<span class="username">{{ user.username }}</span>)
|
||||
if isCardAssignee
|
||||
i.fa.fa-check
|
||||
if currentUser.isWorker
|
||||
ul.pop-over-list.js-card-assignee-list
|
||||
li.item(class="{{#if currentUser.isCardAssignee}}active{{/if}}")
|
||||
a.name.js-select-assignee(href="#")
|
||||
+userAvatar(userId=currentUser._id)
|
||||
span.full-name
|
||||
= currentUser.profile.fullname
|
||||
| (<span class="username">{{ currentUser.username }}</span>)
|
||||
if currentUser.isCardAssignee
|
||||
i.fa.fa-check
|
||||
|
||||
template(name="userAvatarAssignee")
|
||||
a.assignee.js-assignee(title="{{userData.profile.fullname}} ({{userData.username}})")
|
||||
@@ -349,11 +500,13 @@ template(name="cardAssigneePopup")
|
||||
p.quiet @{{ user.username }}
|
||||
ul.pop-over-list
|
||||
if currentUser.isNotCommentOnly
|
||||
unless currentUser.isWorker
|
||||
li: a.js-remove-assignee {{_ 'remove-member-from-card'}}
|
||||
|
||||
if $eq currentUser._id user._id
|
||||
with currentUser
|
||||
li: a.js-edit-profile {{_ 'edit-profile'}}
|
||||
unless currentUser.isWorker
|
||||
if $eq currentUser._id user._id
|
||||
with currentUser
|
||||
li: a.js-edit-profile {{_ 'edit-profile'}}
|
||||
|
||||
template(name="userAvatarAssigneeInitials")
|
||||
svg.avatar.avatar-assignee-initials(viewBox="0 0 {{viewPortWidth}} 15")
|
||||
@@ -413,3 +566,35 @@ template(name="cardDeletePopup")
|
||||
unless archived
|
||||
p {{_ "card-delete-suggest-archive"}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
|
||||
|
||||
template(name="cardStartVotingPopup")
|
||||
form.edit-vote-question
|
||||
.fields
|
||||
label(for="vote") {{_ 'vote-question'}}
|
||||
input.js-vote-field#vote(type="text" name="vote" value="{{card.getVoteQuestion}}" autofocus)
|
||||
label(for="vote-public") {{_ 'vote-public'}}
|
||||
a.js-toggle-vote-public
|
||||
.materialCheckBox#vote-public(name="vote-public")
|
||||
|
||||
button.primary.confirm.js-submit {{_ 'save'}}
|
||||
//- button.js-remove-color.negate.wide.right {{_ 'delete'}}
|
||||
|
||||
template(name="positiveVoteMembersPopup")
|
||||
ul.pop-over-list.js-card-member-list
|
||||
each m in voteMemberPositive
|
||||
li.item
|
||||
a.name
|
||||
+userAvatar(userId=m._id)
|
||||
span.full-name
|
||||
= m.profile.fullname
|
||||
| (<span class="username">{{ m.username }}</span>)
|
||||
|
||||
template(name="negativeVoteMembersPopup")
|
||||
ul.pop-over-list.js-card-member-list
|
||||
each m in voteMemberNegative
|
||||
li.item
|
||||
a.name
|
||||
+userAvatar(userId=m._id)
|
||||
span.full-name
|
||||
= m.profile.fullname
|
||||
| (<span class="username">{{ m.username }}</span>)
|
||||
@@ -1,5 +1,5 @@
|
||||
const subManager = new SubsManager();
|
||||
const { calculateIndexData, enableClickOnTouch } = Utils;
|
||||
const { calculateIndexData } = Utils;
|
||||
|
||||
let cardColors;
|
||||
Meteor.startup(() => {
|
||||
@@ -38,6 +38,37 @@ BlazeComponent.extendComponent({
|
||||
Meteor.subscribe('unsaved-edits');
|
||||
},
|
||||
|
||||
voteState() {
|
||||
const card = this.currentData();
|
||||
const userId = Meteor.userId();
|
||||
let state;
|
||||
if (card.vote) {
|
||||
if (card.vote.positive) {
|
||||
state = _.contains(card.vote.positive, userId);
|
||||
if (state === true) return true;
|
||||
}
|
||||
if (card.vote.negative) {
|
||||
state = _.contains(card.vote.negative, userId);
|
||||
if (state === true) return false;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
},
|
||||
votePublic() {
|
||||
const card = this.currentData();
|
||||
if (card.vote) return card.vote.public;
|
||||
return null;
|
||||
},
|
||||
voteCountPositive() {
|
||||
const card = this.currentData();
|
||||
if (card.vote && card.vote.positive) return card.vote.positive.length;
|
||||
return null;
|
||||
},
|
||||
voteCountNegative() {
|
||||
const card = this.currentData();
|
||||
if (card.vote && card.vote.negative) return card.vote.negative.length;
|
||||
return null;
|
||||
},
|
||||
isWatching() {
|
||||
const card = this.currentData();
|
||||
return card.findWatcher(Meteor.userId());
|
||||
@@ -51,7 +82,8 @@ BlazeComponent.extendComponent({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
|
||||
@@ -199,9 +231,6 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch('.card-checklist-items .js-checklist');
|
||||
|
||||
const $subtasksDom = this.$('.card-subtasks-items');
|
||||
|
||||
$subtasksDom.sortable({
|
||||
@@ -237,20 +266,21 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch('.card-subtasks-items .js-subtasks');
|
||||
|
||||
function userIsMember() {
|
||||
return Meteor.user() && Meteor.user().isBoardMember();
|
||||
}
|
||||
|
||||
// Disable sorting if the current user is not a board member
|
||||
this.autorun(() => {
|
||||
if ($checklistsDom.data('sortable')) {
|
||||
$checklistsDom.sortable('option', 'disabled', !userIsMember());
|
||||
const disabled = !userIsMember() || Utils.isMiniScreen();
|
||||
if (
|
||||
$checklistsDom.data('uiSortable') ||
|
||||
$checklistsDom.data('sortable')
|
||||
) {
|
||||
$checklistsDom.sortable('option', 'disabled', disabled);
|
||||
}
|
||||
if ($subtasksDom.data('sortable')) {
|
||||
$subtasksDom.sortable('option', 'disabled', !userIsMember());
|
||||
if ($subtasksDom.data('uiSortable') || $subtasksDom.data('sortable')) {
|
||||
$subtasksDom.sortable('option', 'disabled', disabled);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -278,6 +308,29 @@ BlazeComponent.extendComponent({
|
||||
'click .js-close-card-details'() {
|
||||
Utils.goBoardId(this.data().boardId);
|
||||
},
|
||||
'click .js-copy-link'() {
|
||||
StringToCopyElement = document.getElementById('cardURL_copy');
|
||||
StringToCopyElement.select();
|
||||
if (document.execCommand('copy')) {
|
||||
StringToCopyElement.blur();
|
||||
} else {
|
||||
document.getElementById('cardURL_copy').selectionStart = 0;
|
||||
document.getElementById('cardURL_copy').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-open-card-details-menu': Popup.open('cardDetailsActions'),
|
||||
'submit .js-card-description'(event) {
|
||||
event.preventDefault();
|
||||
@@ -317,6 +370,9 @@ BlazeComponent.extendComponent({
|
||||
this.data().setRequestedBy('');
|
||||
}
|
||||
},
|
||||
'click .js-go-to-linked-card'() {
|
||||
Utils.goCardId(this.data().linkedId);
|
||||
},
|
||||
'click .js-member': Popup.open('cardMember'),
|
||||
'click .js-add-members': Popup.open('cardMembers'),
|
||||
'click .js-assignee': Popup.open('cardAssignee'),
|
||||
@@ -326,6 +382,8 @@ BlazeComponent.extendComponent({
|
||||
'click .js-start-date': Popup.open('editCardStartDate'),
|
||||
'click .js-due-date': Popup.open('editCardDueDate'),
|
||||
'click .js-end-date': Popup.open('editCardEndDate'),
|
||||
'click .js-show-positive-votes': Popup.open('positiveVoteMembers'),
|
||||
'click .js-show-negative-votes': Popup.open('negativeVoteMembers'),
|
||||
'mouseenter .js-card-details'() {
|
||||
const parentComponent = this.parentComponent().parentComponent();
|
||||
//on mobile view parent is Board, not BoardBody.
|
||||
@@ -349,6 +407,18 @@ BlazeComponent.extendComponent({
|
||||
'click #toggleButton'() {
|
||||
Meteor.call('toggleSystemMessages');
|
||||
},
|
||||
'click .js-vote'(e) {
|
||||
const forIt = $(e.target).hasClass('js-vote-positive');
|
||||
let newState = null;
|
||||
if (
|
||||
this.voteState() === null ||
|
||||
(this.voteState() === false && forIt) ||
|
||||
(this.voteState() === true && !forIt)
|
||||
) {
|
||||
newState = forIt;
|
||||
}
|
||||
this.data().setVote(Meteor.userId(), newState);
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -370,6 +440,54 @@ Template.cardDetails.helpers({
|
||||
});
|
||||
},
|
||||
|
||||
receivedSelected() {
|
||||
if (this.getReceived().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
startSelected() {
|
||||
if (this.getStart().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
endSelected() {
|
||||
if (this.getEnd().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
dueSelected() {
|
||||
if (this.getDue().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
memberSelected() {
|
||||
if (this.getMembers().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
labelSelected() {
|
||||
if (this.getLabels().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
assigneeSelected() {
|
||||
if (this.getAssignees().length === 0) {
|
||||
return false;
|
||||
@@ -378,6 +496,22 @@ Template.cardDetails.helpers({
|
||||
}
|
||||
},
|
||||
|
||||
requestBySelected() {
|
||||
if (this.getRequestBy().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
assigneeBySelected() {
|
||||
if (this.getAssigneeBy().length === 0) {
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
},
|
||||
|
||||
memberType() {
|
||||
const user = Users.findOne(this.userId);
|
||||
return user && user.isBoardAdmin() ? 'admin' : 'normal';
|
||||
@@ -466,6 +600,7 @@ Template.cardDetailsActionsPopup.events({
|
||||
'click .js-assignees': Popup.open('cardAssignees'),
|
||||
'click .js-labels': Popup.open('cardLabels'),
|
||||
'click .js-attachments': Popup.open('cardAttachments'),
|
||||
'click .js-start-voting': Popup.open('cardStartVoting'),
|
||||
'click .js-custom-fields': Popup.open('cardCustomFields'),
|
||||
'click .js-received-date': Popup.open('editCardReceivedDate'),
|
||||
'click .js-start-date': Popup.open('editCardStartDate'),
|
||||
@@ -476,6 +611,11 @@ Template.cardDetailsActionsPopup.events({
|
||||
'click .js-copy-card': Popup.open('copyCard'),
|
||||
'click .js-copy-checklist-cards': Popup.open('copyChecklistToManyCards'),
|
||||
'click .js-set-card-color': Popup.open('setCardColor'),
|
||||
'click .js-cancel-voting'(event) {
|
||||
event.preventDefault();
|
||||
this.unsetVote();
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-move-card-to-top'(event) {
|
||||
event.preventDefault();
|
||||
const minOrder = _.min(
|
||||
@@ -578,7 +718,7 @@ BlazeComponent.extendComponent({
|
||||
_id: { $ne: Meteor.user().getTemplatesBoardId() },
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
return boards;
|
||||
@@ -754,7 +894,7 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
return boards;
|
||||
@@ -851,6 +991,31 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('cardMorePopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentCard = this.currentData();
|
||||
this.voteQuestion = new ReactiveVar(this.currentCard.voteQuestion);
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'submit .edit-vote-question'(evt) {
|
||||
evt.preventDefault();
|
||||
const voteQuestion = evt.target.vote.value;
|
||||
const publicVote = $('#vote-public').hasClass('is-checked');
|
||||
this.currentCard.setVoteQuestion(voteQuestion, publicVote);
|
||||
Popup.close();
|
||||
},
|
||||
'click a.js-toggle-vote-public'(event) {
|
||||
event.preventDefault();
|
||||
$('#vote-public').toggleClass('is-checked');
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('cardStartVotingPopup');
|
||||
|
||||
// Close the card details pane by pressing escape
|
||||
EscapeActions.register(
|
||||
'detailsPane',
|
||||
|
||||
@@ -4,6 +4,12 @@
|
||||
|
||||
avatar-radius = 50%
|
||||
|
||||
#cardURL_copy
|
||||
// Have clipboard text not visible by moving it to far left
|
||||
position: absolute
|
||||
left: -2000px
|
||||
top: 0px
|
||||
|
||||
.assignee
|
||||
border-radius: 3px
|
||||
display: block
|
||||
@@ -88,17 +94,18 @@ avatar-radius = 50%
|
||||
animation: flexGrowIn 0.1s
|
||||
box-shadow: 0 0 7px 0 darken(white, 30%)
|
||||
transition: flex-basis 0.1s
|
||||
box-sizing: border-box
|
||||
|
||||
.mCustomScrollBox
|
||||
padding-left: 0
|
||||
|
||||
.ps-scrollbar-y-rail
|
||||
pointer-event: all
|
||||
position: absolute;
|
||||
position: absolute
|
||||
|
||||
.card-details-canvas
|
||||
width: 470px
|
||||
padding-left: 20px;
|
||||
padding-left: 20px
|
||||
|
||||
.card-details-header
|
||||
margin: 0 -20px 5px
|
||||
@@ -108,6 +115,8 @@ avatar-radius = 50%
|
||||
|
||||
.close-card-details,
|
||||
.card-details-menu,
|
||||
.card-copy-button,
|
||||
.card-copy-mobile-button,
|
||||
.close-card-details-mobile-web,
|
||||
.card-details-menu-mobile-web
|
||||
float: right
|
||||
@@ -122,6 +131,16 @@ avatar-radius = 50%
|
||||
padding: 5px
|
||||
margin-right: 40px
|
||||
|
||||
.card-copy-button
|
||||
font-size: 17px
|
||||
padding: 10px
|
||||
margin-right: 10px
|
||||
|
||||
.card-copy-mobile-button
|
||||
font-size: 17px
|
||||
padding: 10px
|
||||
margin-right: 10px
|
||||
|
||||
.card-details-menu
|
||||
font-size: 17px
|
||||
padding: 10px
|
||||
@@ -223,7 +242,7 @@ input[type="submit"].attachment-add-link-submit
|
||||
|
||||
.card-details-canvas
|
||||
width: 100%
|
||||
padding-left: 0px;
|
||||
padding-left: 0px
|
||||
|
||||
.card-details-header
|
||||
.close-card-details
|
||||
@@ -312,3 +331,13 @@ card-details-color(background, color...)
|
||||
|
||||
.card-details-indigo
|
||||
card-details-color(#4b0082, #ffffff) //White text for better visibility
|
||||
|
||||
.voted
|
||||
opacity: .7
|
||||
.vote-title
|
||||
display: flex
|
||||
justify-content: space-between
|
||||
.vote-result
|
||||
display: flex
|
||||
.js-show-positive-votes
|
||||
cursor: pointer
|
||||
@@ -1,5 +1,7 @@
|
||||
template(name="checklists")
|
||||
h3 {{_ 'checklists'}}
|
||||
h3
|
||||
i.fa.fa-check
|
||||
| {{_ 'checklists'}}
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+checklistDeleteDialog(checklist = checklistToDelete)
|
||||
@@ -86,7 +88,8 @@ template(name="checklistItems")
|
||||
template(name='checklistItemDetail')
|
||||
.js-checklist-item.checklist-item
|
||||
if canModifyCard
|
||||
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
|
||||
.check-box-container
|
||||
.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}}")
|
||||
+viewer
|
||||
= item.title
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
const { calculateIndexData, enableClickOnTouch } = Utils;
|
||||
const { calculateIndexData, capitalize } = Utils;
|
||||
|
||||
function initSorting(items) {
|
||||
items.sortable({
|
||||
@@ -36,9 +36,6 @@ function initSorting(items) {
|
||||
checklistItem.move(checklistId, sortIndex.base);
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch('.js-checklist-item:not(.placeholder)');
|
||||
}
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
@@ -54,11 +51,15 @@ BlazeComponent.extendComponent({
|
||||
return Meteor.user() && Meteor.user().isBoardMember();
|
||||
}
|
||||
|
||||
// Disable sorting if the current user is not a board member
|
||||
// Disable sorting if the current user is not a board member or is a miniscreen
|
||||
self.autorun(() => {
|
||||
const $itemsDom = $(self.itemsDom);
|
||||
if ($itemsDom.data('sortable')) {
|
||||
$(self.itemsDom).sortable('option', 'disabled', !userIsMember());
|
||||
if ($itemsDom.data('uiSortable') || $itemsDom.data('sortable')) {
|
||||
$(self.itemsDom).sortable(
|
||||
'option',
|
||||
'disabled',
|
||||
!userIsMember() || Utils.isMiniScreen(),
|
||||
);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -67,7 +68,8 @@ BlazeComponent.extendComponent({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
}).register('checklistDetail');
|
||||
@@ -120,7 +122,8 @@ BlazeComponent.extendComponent({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
|
||||
@@ -172,6 +175,16 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
},
|
||||
|
||||
focusChecklistItem(event) {
|
||||
// If a new checklist is created, pre-fill the title and select it.
|
||||
const checklist = this.currentData().checklist;
|
||||
if (!checklist) {
|
||||
const textarea = event.target;
|
||||
textarea.value = capitalize(TAPi18n.__('r-checklist'));
|
||||
textarea.select();
|
||||
}
|
||||
},
|
||||
|
||||
events() {
|
||||
const events = {
|
||||
'click .toggle-delete-checklist-dialog'(event) {
|
||||
@@ -191,6 +204,7 @@ BlazeComponent.extendComponent({
|
||||
'submit .js-edit-checklist-item': this.editChecklistItem,
|
||||
'click .js-delete-checklist-item': this.deleteItem,
|
||||
'click .confirm-checklist-delete': this.deleteChecklist,
|
||||
'focus .js-add-checklist-item': this.focusChecklistItem,
|
||||
keydown: this.pressKey,
|
||||
},
|
||||
];
|
||||
@@ -228,7 +242,8 @@ Template.checklistItemDetail.helpers({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -244,7 +259,7 @@ BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-checklist-item .check-box': this.toggleItem,
|
||||
'click .js-checklist-item .check-box-container': this.toggleItem,
|
||||
},
|
||||
];
|
||||
},
|
||||
|
||||
@@ -113,6 +113,9 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
&:hover
|
||||
background-color: darken(white, 8%)
|
||||
|
||||
.check-box-container
|
||||
padding-right: 1px;
|
||||
|
||||
.check-box
|
||||
margin: 0.1em 0 0 0;
|
||||
&.is-checked
|
||||
@@ -121,7 +124,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
|
||||
|
||||
.item-title
|
||||
flex: 1
|
||||
padding-left: 10px;
|
||||
margin-left: 10px;
|
||||
&.is-checked
|
||||
color: #8c8c8c
|
||||
font-style: italic
|
||||
|
||||
@@ -158,6 +158,8 @@
|
||||
|
||||
.edit-labels-pop-over
|
||||
margin-bottom: 8px
|
||||
.card-label .viewer p
|
||||
margin: 0
|
||||
|
||||
.edit-labels-pop-over .shortcut
|
||||
display: inline-block
|
||||
|
||||
@@ -100,6 +100,10 @@ template(name="minicard")
|
||||
if getDescription
|
||||
.badge.badge-state-image-only(title=getDescription)
|
||||
span.badge-icon.fa.fa-align-left
|
||||
if getVoteQuestion
|
||||
.badge.badge-state-image-only(title=getVoteQuestion)
|
||||
span.badge-icon.fa.fa-thumbs-up
|
||||
span.badge-icon.fa.fa-thumbs-down
|
||||
if attachments.count
|
||||
.badge
|
||||
span.badge-icon.fa.fa-paperclip
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
border-radius: top 2px
|
||||
|
||||
.minicard-labels
|
||||
float: right
|
||||
float: none
|
||||
display: flex
|
||||
flex-wrap: wrap
|
||||
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
template(name="subtasks")
|
||||
h3 {{_ 'subtasks'}}
|
||||
h3
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtasks'}}
|
||||
if toggleDeleteDialog.get
|
||||
.board-overlay#card-details-overlay
|
||||
+subtaskDeleteDialog(subtask = subtaskToDelete)
|
||||
|
||||
@@ -3,7 +3,8 @@ BlazeComponent.extendComponent({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
}).register('subtaskDetail');
|
||||
@@ -19,7 +20,22 @@ BlazeComponent.extendComponent({
|
||||
const crtBoard = Boards.findOne(card.boardId);
|
||||
const targetBoard = crtBoard.getDefaultSubtasksBoard();
|
||||
const listId = targetBoard.getDefaultSubtasksListId();
|
||||
const swimlaneId = targetBoard.getDefaultSwimline()._id;
|
||||
|
||||
//Get the full swimlane data for the parent task.
|
||||
const parentSwimlane = Swimlanes.findOne({
|
||||
boardId: crtBoard._id,
|
||||
_id: card.swimlaneId,
|
||||
});
|
||||
//find the swimlane of the same name in the target board.
|
||||
const targetSwimlane = Swimlanes.findOne({
|
||||
boardId: targetBoard._id,
|
||||
title: parentSwimlane.title,
|
||||
});
|
||||
//If no swimlane with a matching title exists in the target board, fall back to the default swimlane.
|
||||
const swimlaneId =
|
||||
targetSwimlane === undefined
|
||||
? targetBoard.getDefaultSwimline()._id
|
||||
: targetSwimlane._id;
|
||||
|
||||
if (title) {
|
||||
const _id = Cards.insert({
|
||||
@@ -55,7 +71,8 @@ BlazeComponent.extendComponent({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
|
||||
@@ -154,7 +171,8 @@ Template.subtaskItemDetail.helpers({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,9 +15,6 @@ template(name="importTextarea")
|
||||
p: label(for='import-textarea') {{_ instruction}} {{_ 'import-board-instruction-about-errors'}}
|
||||
textarea.js-import-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus)
|
||||
| {{jsonText}}
|
||||
if isSandstorm
|
||||
h1.warning {{_ 'import-sandstorm-backup-warning'}}
|
||||
p.warning {{_ 'import-sandstorm-warning'}}
|
||||
input.primary.wide(type="submit" value="{{_ 'import'}}")
|
||||
|
||||
template(name="importMapMembers")
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
const { calculateIndex, enableClickOnTouch } = Utils;
|
||||
const { calculateIndex } = Utils;
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
// Proxy
|
||||
@@ -114,9 +114,6 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch(itemsSelector);
|
||||
|
||||
this.autorun(() => {
|
||||
let showDesktopDragHandles = false;
|
||||
currentUser = Meteor.user();
|
||||
@@ -129,18 +126,26 @@ BlazeComponent.extendComponent({
|
||||
showDesktopDragHandles = false;
|
||||
}
|
||||
|
||||
if (!Utils.isMiniScreen() && showDesktopDragHandles) {
|
||||
if (Utils.isMiniScreen() || showDesktopDragHandles) {
|
||||
$cards.sortable({
|
||||
handle: '.handle',
|
||||
});
|
||||
} else {
|
||||
} else if (!Utils.isMiniScreen() && !showDesktopDragHandles) {
|
||||
$cards.sortable({
|
||||
handle: '.minicard',
|
||||
});
|
||||
}
|
||||
|
||||
// Disable drag-dropping if the current user is not a board member or is comment only
|
||||
$cards.sortable('option', 'disabled', !userIsMember());
|
||||
if ($cards.data('uiSortable') || $cards.data('sortable')) {
|
||||
$cards.sortable(
|
||||
'option',
|
||||
'disabled',
|
||||
// Disable drag-dropping when user is not member
|
||||
!userIsMember(),
|
||||
// Not disable drag-dropping while in multi-selection mode
|
||||
// MultiSelection.isActive() || !userIsMember(),
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
// We want to re-run this function any time a card is added.
|
||||
|
||||
@@ -189,7 +189,8 @@ BlazeComponent.extendComponent({
|
||||
!this.reachedWipLimit() &&
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
|
||||
@@ -410,7 +411,7 @@ BlazeComponent.extendComponent({
|
||||
type: 'board',
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
return boards;
|
||||
@@ -596,7 +597,7 @@ BlazeComponent.extendComponent({
|
||||
type: 'board',
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
return boards;
|
||||
@@ -742,9 +743,25 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
|
||||
updateList() {
|
||||
// Use fallback when requestIdleCallback is not available on iOS and Safari
|
||||
// https://www.afasterweb.com/2017/11/20/utilizing-idle-moments/
|
||||
checkIdleTime =
|
||||
window.requestIdleCallback ||
|
||||
function(handler) {
|
||||
const startTime = Date.now();
|
||||
return setTimeout(function() {
|
||||
handler({
|
||||
didTimeout: false,
|
||||
timeRemaining() {
|
||||
return Math.max(0, 50.0 - (Date.now() - startTime));
|
||||
},
|
||||
});
|
||||
}, 1);
|
||||
};
|
||||
|
||||
if (this.spinnerInView()) {
|
||||
this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
|
||||
window.requestIdleCallback(() => this.updateList());
|
||||
checkIdleTime(() => this.updateList());
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ template(name="listHeader")
|
||||
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
|
||||
h2.list-header-name(
|
||||
title="{{ moment modifiedAt 'LLL' }}"
|
||||
class="{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}js-open-inlined-form is-editable{{/unless}}{{/if}}")
|
||||
class="{{#if currentUser.isBoardMember}}{{#unless currentUser.isCommentOnly}}{{#unless currentUser.isWorker}}js-open-inlined-form is-editable{{/unless}}{{/unless}}{{/if}}")
|
||||
+viewer
|
||||
= title
|
||||
if wipLimit.enabled
|
||||
@@ -30,7 +30,6 @@ template(name="listHeader")
|
||||
if canSeeAddCard
|
||||
a.js-add-card.fa.fa-plus.list-header-plus-icon
|
||||
a.fa.fa-navicon.js-open-list-menu
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
else
|
||||
a.list-header-menu-icon.fa.fa-angle-right.js-select-list
|
||||
a.list-header-handle.handle.fa.fa-arrows.js-list-handle
|
||||
@@ -56,25 +55,47 @@ template(name="editListTitleForm")
|
||||
|
||||
template(name="listActionPopup")
|
||||
ul.pop-over-list
|
||||
li: a.js-toggle-watch-list {{#if isWatching}}{{_ 'unwatch'}}{{else}}{{_ 'watch'}}{{/if}}
|
||||
li
|
||||
a.js-toggle-watch-list
|
||||
if isWatching
|
||||
i.fa.fa-eye
|
||||
| {{_ 'unwatch'}}
|
||||
else
|
||||
i.fa.fa-eye-slash
|
||||
| {{_ 'watch'}}
|
||||
unless currentUser.isCommentOnly
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-set-color-list {{_ 'set-color-list'}}
|
||||
hr
|
||||
unless currentUser.isWorker
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-set-color-list
|
||||
i.fa.fa-paint-brush
|
||||
| {{_ 'set-color-list'}}
|
||||
ul.pop-over-list
|
||||
if cards.count
|
||||
li: a.js-select-cards {{_ 'list-select-cards'}}
|
||||
hr
|
||||
li
|
||||
a.js-select-cards
|
||||
i.fa.fa-check-square
|
||||
| {{_ 'list-select-cards'}}
|
||||
if currentUser.isBoardAdmin
|
||||
ul.pop-over-list
|
||||
li: a.js-set-wip-limit {{#if isWipLimitEnabled }}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}}
|
||||
li
|
||||
a.js-set-wip-limit
|
||||
i.fa.fa-ban
|
||||
| {{#if isWipLimitEnabled }}{{_ 'edit-wip-limit'}}{{else}}{{_ 'setWipLimitPopup-title'}}{{/if}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-close-list {{_ 'archive-list'}}
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-close-list
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-list'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-more {{_ 'listMorePopup-title'}}
|
||||
li
|
||||
a.js-more
|
||||
i.fa.fa-link
|
||||
| {{_ 'listMorePopup-title'}}
|
||||
|
||||
template(name="boardLists")
|
||||
ul.pop-over-list
|
||||
@@ -94,7 +115,8 @@ template(name="listMorePopup")
|
||||
input.inline-input(type="text" readonly value="{{ rootUrl }}")
|
||||
| {{_ 'added'}}
|
||||
span.date(title=list.createdAt) {{ moment createdAt 'LLL' }}
|
||||
a.js-delete {{_ 'delete'}}
|
||||
unless currentUser.isWorker
|
||||
a.js-delete {{_ 'delete'}}
|
||||
|
||||
template(name="listDeletePopup")
|
||||
p {{_ "list-delete-pop"}}
|
||||
|
||||
@@ -9,9 +9,10 @@ BlazeComponent.extendComponent({
|
||||
canSeeAddCard() {
|
||||
const list = Template.currentData();
|
||||
return (
|
||||
!list.getWipLimit('enabled') ||
|
||||
list.getWipLimit('soft') ||
|
||||
!this.reachedWipLimit()
|
||||
(!list.getWipLimit('enabled') ||
|
||||
list.getWipLimit('soft') ||
|
||||
!this.reachedWipLimit()) &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -1,87 +1,3 @@
|
||||
import _sanitizeXss from 'xss';
|
||||
const ASIS = 'asis';
|
||||
const sanitizeXss = (input, options) => {
|
||||
const defaultAllowedIframeSrc = /^(https:){0,1}\/\/.*?(youtube|vimeo|dailymotion|youku)/i;
|
||||
const allowedIframeSrcRegex = (function() {
|
||||
let reg = defaultAllowedIframeSrc;
|
||||
const SAFE_IFRAME_SRC_PATTERN =
|
||||
Meteor.settings.public.SAFE_IFRAME_SRC_PATTERN;
|
||||
try {
|
||||
if (SAFE_IFRAME_SRC_PATTERN !== undefined) {
|
||||
reg = new RegExp(SAFE_IFRAME_SRC_PATTERN, 'i');
|
||||
}
|
||||
} catch (e) {
|
||||
/*eslint no-console: ["error", { allow: ["warn", "error"] }] */
|
||||
|
||||
console.error('Wrong pattern specified', SAFE_IFRAM_SRC_PATTERN, e);
|
||||
}
|
||||
return reg;
|
||||
})();
|
||||
const targetWindow = '_blank';
|
||||
const getHtmlDOM = html => {
|
||||
const i = document.createElement('i');
|
||||
i.innerHTML = html;
|
||||
return i.firstChild;
|
||||
};
|
||||
options = {
|
||||
onTag(tag, html, options) {
|
||||
const htmlDOM = getHtmlDOM(html);
|
||||
const getAttr = attr => {
|
||||
return htmlDOM && attr && htmlDOM.getAttribute(attr);
|
||||
};
|
||||
if (tag === 'iframe') {
|
||||
const clipCls = 'note-vide-clip';
|
||||
if (!options.isClosing) {
|
||||
const iframeCls = getAttr('class');
|
||||
let safe = iframeCls.indexOf(clipCls) > -1;
|
||||
const src = getAttr('src');
|
||||
if (allowedIframeSrcRegex.exec(src)) {
|
||||
safe = true;
|
||||
}
|
||||
if (safe)
|
||||
return `<iframe src='${src}' class="${clipCls}" width=100% height=auto allowfullscreen></iframe>`;
|
||||
} else {
|
||||
// remove </iframe> tag
|
||||
return '';
|
||||
}
|
||||
} else if (tag === 'a') {
|
||||
if (!options.isClosing) {
|
||||
if (getAttr(ASIS) === 'true') {
|
||||
// if has a ASIS attribute, don't do anything, it's a member id
|
||||
return html;
|
||||
} else {
|
||||
const href = getAttr('href');
|
||||
if (href.match(/^((http(s){0,1}:){0,1}\/\/|\/)/)) {
|
||||
// a valid url
|
||||
return `<a href=${href} target=${targetWindow}>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (tag === 'img') {
|
||||
if (!options.isClosing) {
|
||||
const src = getAttr('src');
|
||||
if (src) {
|
||||
return `<a href='${src}' class='swipebox'><img src='${src}' class="attachment-image-preview mCS_img_loaded"></a>`;
|
||||
}
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
onTagAttr(tag, name, value) {
|
||||
if (tag === 'img' && name === 'src') {
|
||||
if (value && value.substr(0, 5) === 'data:') {
|
||||
// allow image with dataURI src
|
||||
return `${name}='${value}'`;
|
||||
}
|
||||
} else if (tag === 'a' && name === 'target') {
|
||||
return `${name}='${targetWindow}'`; // always change a href target to a new window
|
||||
}
|
||||
return undefined;
|
||||
},
|
||||
...options,
|
||||
};
|
||||
return _sanitizeXss(input, options);
|
||||
};
|
||||
Template.editor.onRendered(() => {
|
||||
const textareaSelector = 'textarea';
|
||||
const mentions = [
|
||||
@@ -94,13 +10,7 @@ Template.editor.onRendered(() => {
|
||||
currentBoard
|
||||
.activeMembers()
|
||||
.map(member => {
|
||||
const user = Users.findOne(member.userId);
|
||||
if (user._id === Meteor.userId()) {
|
||||
return null;
|
||||
}
|
||||
const value = user.username;
|
||||
const username =
|
||||
value && value.match(/\s+/) ? `"${value}"` : value;
|
||||
const username = Users.findOne(member.userId).username;
|
||||
return username.includes(term) ? username : null;
|
||||
})
|
||||
.filter(Boolean),
|
||||
@@ -126,10 +36,9 @@ Template.editor.onRendered(() => {
|
||||
? [
|
||||
['view', ['fullscreen']],
|
||||
['table', ['table']],
|
||||
['font', ['bold']],
|
||||
['color', ['color']],
|
||||
['insert', ['video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
||||
['font', ['bold', 'underline']],
|
||||
//['fontsize', ['fontsize']],
|
||||
['color', ['color']],
|
||||
]
|
||||
: [
|
||||
['style', ['style']],
|
||||
@@ -139,11 +48,47 @@ Template.editor.onRendered(() => {
|
||||
['color', ['color']],
|
||||
['para', ['ul', 'ol', 'paragraph']],
|
||||
['table', ['table']],
|
||||
['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
||||
//['insert', ['link', 'picture', 'video']], // iframe tag will be sanitized TODO if iframe[class=note-video-clip] can be added into safe list, insert video can be enabled
|
||||
//['insert', ['link', 'picture']], // modal popup has issue somehow :(
|
||||
['view', ['fullscreen', 'help']],
|
||||
];
|
||||
const cleanPastedHTML = sanitizeXss;
|
||||
const cleanPastedHTML = function(input) {
|
||||
const badTags = [
|
||||
'style',
|
||||
'script',
|
||||
'applet',
|
||||
'embed',
|
||||
'noframes',
|
||||
'noscript',
|
||||
'meta',
|
||||
'link',
|
||||
'button',
|
||||
'form',
|
||||
].join('|');
|
||||
const badPatterns = new RegExp(
|
||||
`(?:${[
|
||||
`<(${badTags})s*[^>][\\s\\S]*?<\\/\\1>`,
|
||||
`<(${badTags})[^>]*?\\/>`,
|
||||
].join('|')})`,
|
||||
'gi',
|
||||
);
|
||||
let output = input;
|
||||
// remove bad Tags
|
||||
output = output.replace(badPatterns, '');
|
||||
// remove attributes ' style="..."'
|
||||
const badAttributes = new RegExp(
|
||||
`(?:${[
|
||||
'on\\S+=([\'"]?).*?\\1',
|
||||
'href=([\'"]?)javascript:.*?\\2',
|
||||
'style=([\'"]?).*?\\3',
|
||||
'target=\\S+',
|
||||
].join('|')})`,
|
||||
'gi',
|
||||
);
|
||||
output = output.replace(badAttributes, '');
|
||||
output = output.replace(/(<a )/gi, '$1target=_ '); // always to new target
|
||||
return output;
|
||||
};
|
||||
const editor = '.editor';
|
||||
const selectors = [
|
||||
`.js-new-comment-form ${editor}`,
|
||||
@@ -163,37 +108,14 @@ Template.editor.onRendered(() => {
|
||||
}
|
||||
return undefined;
|
||||
};
|
||||
let popupShown = false;
|
||||
inputs.each(function(idx, input) {
|
||||
mSummernotes[idx] = $(input).summernote({
|
||||
placeholder,
|
||||
callbacks: {
|
||||
onKeydown(e) {
|
||||
if (popupShown) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
onKeyup(e) {
|
||||
if (popupShown) {
|
||||
e.preventDefault();
|
||||
}
|
||||
},
|
||||
onInit(object) {
|
||||
const originalInput = this;
|
||||
const setAutocomplete = function(jEditor) {
|
||||
if (jEditor !== undefined) {
|
||||
jEditor.escapeableTextComplete(mentions).on({
|
||||
'textComplete:show'() {
|
||||
popupShown = true;
|
||||
},
|
||||
'textComplete:hide'() {
|
||||
popupShown = false;
|
||||
},
|
||||
});
|
||||
}
|
||||
};
|
||||
$(originalInput).on('submitted', function() {
|
||||
// resetCommentInput has been called
|
||||
// when comment is submitted, the original textarea will be set to '', so shall we
|
||||
if (!this.value) {
|
||||
const sn = getSummernote(this);
|
||||
sn && sn.summernote('code', '');
|
||||
@@ -201,7 +123,9 @@ Template.editor.onRendered(() => {
|
||||
});
|
||||
const jEditor = object && object.editable;
|
||||
const toolbar = object && object.toolbar;
|
||||
setAutocomplete(jEditor);
|
||||
if (jEditor !== undefined) {
|
||||
jEditor.escapeableTextComplete(mentions);
|
||||
}
|
||||
if (toolbar !== undefined) {
|
||||
const fBtn = toolbar.find('.btn-fullscreen');
|
||||
fBtn.on('click', function() {
|
||||
@@ -211,6 +135,7 @@ Template.editor.onRendered(() => {
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
onImageUpload(files) {
|
||||
const $summernote = getSummernote(this);
|
||||
if (files && files.length > 0) {
|
||||
@@ -289,6 +214,12 @@ Template.editor.onRendered(() => {
|
||||
const thisNote = this;
|
||||
const updatePastedText = function(object) {
|
||||
const someNote = getSummernote(object);
|
||||
// Fix Pasting text into a card is adding a line before and after
|
||||
// (and multiplies by pasting more) by changing paste "p" to "br".
|
||||
// Fixes https://github.com/wekan/wekan/2890 .
|
||||
// == Fix Start ==
|
||||
someNote.execCommand('defaultParagraphSeparator', false, 'br');
|
||||
// == Fix End ==
|
||||
const original = someNote.summernote('code');
|
||||
const cleaned = cleanPastedHTML(original); //this is where to call whatever clean function you want. I have mine in a different file, called CleanPastedHTML.
|
||||
someNote.summernote('code', ''); //clear original
|
||||
@@ -331,6 +262,8 @@ Template.editor.onRendered(() => {
|
||||
}
|
||||
});
|
||||
|
||||
import sanitizeXss from 'xss';
|
||||
|
||||
// XXX I believe we should compute a HTML rendered field on the server that
|
||||
// would handle markdown and user mentions. We can simply have two
|
||||
// fields, one source, and one compiled version (in HTML) and send only the
|
||||
@@ -352,7 +285,7 @@ Blaze.Template.registerHelper(
|
||||
}
|
||||
return member;
|
||||
});
|
||||
const mentionRegex = /\B@(?:(?:"([\w.\s]*)")|([\w.]+))/gi; // including space in username
|
||||
const mentionRegex = /\B@([\w.]*)/gi;
|
||||
|
||||
let currentMention;
|
||||
while ((currentMention = mentionRegex.exec(content)) !== null) {
|
||||
@@ -368,7 +301,12 @@ Blaze.Template.registerHelper(
|
||||
if (knowedUser.userId === Meteor.userId()) {
|
||||
linkClass += ' me';
|
||||
}
|
||||
const link = HTML.A(
|
||||
// This @user mention link generation did open same Wekan
|
||||
// window in new tab, so now A is changed to U so it's
|
||||
// underlined and there is no link popup. This way also
|
||||
// text can be selected more easily.
|
||||
//const link = HTML.A(
|
||||
const link = HTML.U(
|
||||
{
|
||||
class: linkClass,
|
||||
// XXX Hack. Since we stringify this render function result below with
|
||||
@@ -376,16 +314,17 @@ Blaze.Template.registerHelper(
|
||||
// `userId` to the popup as usual, and we need to store it in the DOM
|
||||
// using a data attribute.
|
||||
'data-userId': knowedUser.userId,
|
||||
[ASIS]: 'true',
|
||||
},
|
||||
linkValue,
|
||||
);
|
||||
|
||||
content = content.replace(fullMention, Blaze.toHTML(link));
|
||||
}
|
||||
|
||||
return HTML.Raw(sanitizeXss(content));
|
||||
}),
|
||||
);
|
||||
|
||||
Template.viewer.events({
|
||||
// Viewer sometimes have click-able wrapper around them (for instance to edit
|
||||
// the corresponding text). Clicking a link shouldn't fire these actions, stop
|
||||
@@ -397,10 +336,7 @@ Template.viewer.events({
|
||||
Popup.open('member').call({ userId }, event, templateInstance);
|
||||
} else {
|
||||
const href = event.currentTarget.href;
|
||||
const child = event.currentTarget.firstElementChild;
|
||||
if (child && child.tagName === 'IMG') {
|
||||
prevent = false;
|
||||
} else if (href) {
|
||||
if (href) {
|
||||
window.open(href, '_blank');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ template(name="header")
|
||||
a(href="{{pathFor 'home'}}")
|
||||
span.fa.fa-home
|
||||
| {{_ 'all-boards'}}
|
||||
li.separator -
|
||||
li
|
||||
a(href="{{pathFor 'public'}}")
|
||||
span.fa.fa-globe
|
||||
| {{_ 'public'}}
|
||||
each currentUser.starredBoards
|
||||
li.separator -
|
||||
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
|
||||
@@ -35,6 +40,8 @@ template(name="header")
|
||||
a#header-new-board-icon.js-create-board
|
||||
i.fa.fa-plus(title="Create a new board")
|
||||
|
||||
+notifications
|
||||
|
||||
+headerUserBar
|
||||
|
||||
#header(class=currentBoard.colorClass)
|
||||
|
||||
@@ -99,7 +99,7 @@
|
||||
height: 28px
|
||||
font-size: 12px
|
||||
display: flex
|
||||
z-index: 17
|
||||
z-index: 21
|
||||
|
||||
#header-user-bar,
|
||||
#header-new-board-icon,
|
||||
@@ -127,7 +127,7 @@
|
||||
&.current
|
||||
color: darken(white, 5%)
|
||||
|
||||
&:first-child .fa-home
|
||||
&:first-child .fa-home,&:nth-child(3) .fa-globe
|
||||
margin-right: 5px
|
||||
|
||||
a.js-create-board
|
||||
@@ -218,6 +218,9 @@
|
||||
padding: 10px
|
||||
margin: -10px 0 -10px -10px
|
||||
|
||||
.announcement .viewer
|
||||
display: inline-block
|
||||
|
||||
.announcement,
|
||||
.offline-warning
|
||||
width: 100%
|
||||
|
||||
@@ -31,6 +31,11 @@ Template.userFormsLayout.onCreated(function() {
|
||||
return this.stop();
|
||||
},
|
||||
});
|
||||
Meteor.call('isPasswordLoginDisabled', (_, result) => {
|
||||
if (result) {
|
||||
$('.at-pwd-form').hide();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.userFormsLayout.onRendered(() => {
|
||||
@@ -73,6 +78,8 @@ Template.userFormsLayout.helpers({
|
||||
name = 'Igbo';
|
||||
} else if (lang.name === 'oc') {
|
||||
name = 'Occitan';
|
||||
} else if (lang.name === '繁体中文(台湾)') {
|
||||
name = '繁體中文(台灣)';
|
||||
}
|
||||
return { tag, name };
|
||||
}).sort(function(a, b) {
|
||||
|
||||
@@ -135,6 +135,10 @@ $popupWidth = 300px
|
||||
margin-bottom: 8px
|
||||
|
||||
.pop-over-list
|
||||
li
|
||||
display: block
|
||||
clear: both
|
||||
|
||||
li > a
|
||||
clear: both
|
||||
cursor: pointer
|
||||
@@ -316,6 +320,7 @@ $popupWidth = 300px
|
||||
input[type="file"]
|
||||
margin: 4px 0 12px
|
||||
width: 100%
|
||||
box-sizing: border-box
|
||||
|
||||
.pop-over-list
|
||||
li > a
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
template(name='notification')
|
||||
li.notification(class="{{#if read}}read{{/if}}")
|
||||
.read-status
|
||||
.materialCheckBox(class="{{#if read}}is-checked{{/if}}")
|
||||
+notificationIcon(activityData)
|
||||
.details
|
||||
+activity(activity=activityData mode='none')
|
||||
if read
|
||||
.remove
|
||||
a.fa.fa-trash
|
||||
@@ -0,0 +1,28 @@
|
||||
Template.notification.events({
|
||||
'click .read-status .materialCheckBox'() {
|
||||
const update = {};
|
||||
update[`profile.notifications.${this.index}.read`] = this.read
|
||||
? null
|
||||
: Date.now();
|
||||
Users.update(Meteor.userId(), { $set: update });
|
||||
},
|
||||
'click .remove a'() {
|
||||
Meteor.user().removeNotification(this.activityData._id);
|
||||
},
|
||||
});
|
||||
|
||||
Template.notification.helpers({
|
||||
mode: 'board',
|
||||
isOfActivityType(activityId, type) {
|
||||
const activity = Activities.findOne(activityId);
|
||||
return activity && activity.activityType === type;
|
||||
},
|
||||
activityType(activityId) {
|
||||
const activity = Activities.findOne(activityId);
|
||||
return activity ? activity.activityType : '';
|
||||
},
|
||||
activityUser(activityId) {
|
||||
const activity = Activities.findOne(activityId);
|
||||
return activity && activity.userId;
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,57 @@
|
||||
#notifications-drawer
|
||||
&.show-read .notification.read
|
||||
display: flex
|
||||
|
||||
.notification
|
||||
display: flex
|
||||
float: none
|
||||
padding: 12px 8px 8px
|
||||
color: black
|
||||
border-bottom: 1px solid #dbdbdb
|
||||
|
||||
&.read
|
||||
display: none
|
||||
|
||||
.read-status
|
||||
width: 30px
|
||||
|
||||
input
|
||||
width: 24px
|
||||
height: 24px
|
||||
|
||||
.activity-type
|
||||
margin: 16px 0 0
|
||||
width: 17px
|
||||
height: 17px
|
||||
font-size: 17px
|
||||
display: block
|
||||
color: #bbb
|
||||
|
||||
.details
|
||||
width: calc(100% - 30px)
|
||||
|
||||
.activity
|
||||
display: flex
|
||||
|
||||
.activity-desc
|
||||
width: 100%;
|
||||
|
||||
.activity-comment
|
||||
display: block
|
||||
width: 100%
|
||||
border-radius: 3px
|
||||
background: #fff
|
||||
text-decoration: none
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.2)
|
||||
margin-top: 5px
|
||||
padding: 5px
|
||||
|
||||
.activity-meta
|
||||
display: block
|
||||
font-size: 0.8em
|
||||
color: #999
|
||||
font-style: italic
|
||||
|
||||
.remove
|
||||
a:hover
|
||||
color #eb4646 !important
|
||||
@@ -0,0 +1,53 @@
|
||||
template(name='notificationIcon')
|
||||
if($in activityType 'deleteAttachment' 'addAttachment')
|
||||
i.fa.fa-paperclip.activity-type(title="attachment")
|
||||
else if($in activityType 'createBoard' 'importBoard')
|
||||
i.fa.fa-chalkboard.activity-type(title="board")
|
||||
|
||||
else if($in activityType 'createCard' 'importCard' 'moveCard')
|
||||
+cardNotificationIcon
|
||||
else if($in activityType 'moveCardBoard' 'archivedCard' 'restoredCard')
|
||||
+cardNotificationIcon
|
||||
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
|
||||
//- DRY and consistant
|
||||
|
||||
else if($in activityType 'addChecklist' 'removedChecklist' 'completeChecklist')
|
||||
+checklistNotificationIcon
|
||||
else if($in activityType 'uncompleteChecklist')
|
||||
+checklistNotificationIcon
|
||||
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
|
||||
//- DRY and consistant
|
||||
|
||||
else if($in activityType 'checkedItem' 'uncheckedItem' 'addChecklistItem' 'removedChecklistItem')
|
||||
i.fa.fa-check-square.activity-type(title="checklist item")
|
||||
else if($in activityType 'addComment')
|
||||
i.fa.fa-comment-o.activity-type(title="comment")
|
||||
else if($in activityType 'createCustomField' 'setCustomField' 'unsetCustomField')
|
||||
i.fa.fa-code.activity-type(title="custom field")
|
||||
else if($in activityType 'addedLabel' 'removedLabel')
|
||||
i.fa.fa-tag.activity-type(title="label")
|
||||
|
||||
else if($in activityType 'createList' 'removeList' 'archivedList')
|
||||
+listNotificationIcon
|
||||
else if($in activityType 'importList')
|
||||
+listNotificationIcon
|
||||
//- $in can only handle up to 3 cases so we have to break this case over 2 cases... use a simple template to keep it
|
||||
//- DRY and consistant
|
||||
|
||||
//- elswhere in the app we use fa-trello to indicate lists...
|
||||
//- i personally like fa-columns a bit better
|
||||
else if($in activityType 'unjoinMember' 'addBoardMember' 'joinMember' 'removeBoardMember')
|
||||
i.fa.fa-user.activity-type(title="member")
|
||||
else if($in activityType 'createSwimlane' 'archivedSwimlane')
|
||||
i.fa.fa-th-large.activity-type(title="swimlane")
|
||||
else
|
||||
i.fa.fa-bug.activity-type(title="can't find icon for #{activityType}")
|
||||
|
||||
template(name='cardNotificationIcon')
|
||||
i.fa.fa-clone.activity-type(title="card")
|
||||
|
||||
template(name='checklistNotificationIcon')
|
||||
i.fa.fa-list.activity-type(title="checklist")
|
||||
|
||||
template(name='listNotificationIcon')
|
||||
i.fa.fa-columns.activity-type(title="list")
|
||||
@@ -0,0 +1,5 @@
|
||||
template(name='notifications')
|
||||
#notifications.board-header-btns.right
|
||||
a.notifications-drawer-toggle.fa.fa-bell(class="{{#if $gt unreadNotifications 0}}alert{{/if}}")
|
||||
if $.Session.get 'showNotificationsDrawer'
|
||||
+notificationsDrawer(unreadNotifications=unreadNotifications)
|
||||
@@ -0,0 +1,32 @@
|
||||
// this hides the notifications drawer if anyone clicks off of the panel
|
||||
Template.body.events({
|
||||
click(event) {
|
||||
if (
|
||||
!$(event.target).is('#notifications *') &&
|
||||
Session.get('showNotificationsDrawer')
|
||||
) {
|
||||
toggleNotificationsDrawer();
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.notifications.helpers({
|
||||
unreadNotifications() {
|
||||
const notifications = Users.findOne(Meteor.userId()).notifications();
|
||||
const unreadNotifications = _.filter(notifications, v => !v.read);
|
||||
return unreadNotifications.length;
|
||||
},
|
||||
});
|
||||
|
||||
Template.notifications.events({
|
||||
'click .notifications-drawer-toggle'() {
|
||||
toggleNotificationsDrawer();
|
||||
},
|
||||
});
|
||||
|
||||
export function toggleNotificationsDrawer() {
|
||||
Session.set(
|
||||
'showNotificationsDrawer',
|
||||
!Session.get('showNotificationsDrawer'),
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#notifications
|
||||
position: relative
|
||||
|
||||
.notifications-drawer-toggle
|
||||
display: block
|
||||
line-height: 28px
|
||||
color: #f2f2f2
|
||||
margin: 0 10px
|
||||
width: 28px
|
||||
height: 28px
|
||||
text-align: center
|
||||
border: 0
|
||||
padding: 0
|
||||
|
||||
&.alert
|
||||
background-color: #eb4646;
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
template(name='notificationsDrawer')
|
||||
section#notifications-drawer(class="{{#if $.Session.get 'showReadNotifications'}}show-read{{/if}}")
|
||||
.header
|
||||
if $.Session.get 'showReadNotifications'
|
||||
a.toggle-read {{_ 'filter-by-unread'}}
|
||||
else
|
||||
a.toggle-read {{_ 'view-all'}}
|
||||
h5 {{_ 'notifications'}}
|
||||
if($gt unreadNotifications 0)
|
||||
|(#{unreadNotifications})
|
||||
a.fa.fa-times-thin.close
|
||||
ul.notifications
|
||||
each transformedProfile.notifications
|
||||
+notification(activityData=activity index=dbIndex read=read)
|
||||
if($gt unreadNotifications 0)
|
||||
a.all-read {{_ 'mark-all-as-read'}}
|
||||
if ($and ($.Session.get 'showReadNotifications') ($gt readNotifications 0))
|
||||
a.remove-read
|
||||
i.fa.fa-trash
|
||||
| {{_ 'remove-all-read'}}
|
||||
@@ -0,0 +1,53 @@
|
||||
import { toggleNotificationsDrawer } from './notifications.js';
|
||||
|
||||
Template.notificationsDrawer.onCreated(function() {
|
||||
Meteor.subscribe('notificationActivities');
|
||||
Meteor.subscribe('notificationCards');
|
||||
Meteor.subscribe('notificationUsers');
|
||||
Meteor.subscribe('notificationsAttachments');
|
||||
Meteor.subscribe('notificationChecklistItems');
|
||||
Meteor.subscribe('notificationChecklists');
|
||||
Meteor.subscribe('notificationComments');
|
||||
Meteor.subscribe('notificationLists');
|
||||
Meteor.subscribe('notificationSwimlanes');
|
||||
});
|
||||
|
||||
Template.notificationsDrawer.helpers({
|
||||
transformedProfile() {
|
||||
return Users.findOne(Meteor.userId());
|
||||
},
|
||||
readNotifications() {
|
||||
const readNotifications = _.filter(
|
||||
Meteor.user().profile.notifications,
|
||||
v => !!v.read,
|
||||
);
|
||||
return readNotifications.length;
|
||||
},
|
||||
});
|
||||
|
||||
Template.notificationsDrawer.events({
|
||||
'click .all-read'() {
|
||||
const notifications = Meteor.user().profile.notifications;
|
||||
for (const index in notifications) {
|
||||
if (notifications.hasOwnProperty(index) && !notifications[index].read) {
|
||||
const update = {};
|
||||
update[`profile.notifications.${index}.read`] = Date.now();
|
||||
Users.update(Meteor.userId(), { $set: update });
|
||||
}
|
||||
}
|
||||
},
|
||||
'click .close'() {
|
||||
toggleNotificationsDrawer();
|
||||
},
|
||||
'click .toggle-read'() {
|
||||
Session.set('showReadNotifications', !Session.get('showReadNotifications'));
|
||||
},
|
||||
'click .remove-read'() {
|
||||
const user = Meteor.user();
|
||||
for (const notification of user.profile.notifications) {
|
||||
if (notification.read) {
|
||||
user.removeNotification(notification.activity);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
belize = #2980b9
|
||||
|
||||
section#notifications-drawer
|
||||
position: fixed
|
||||
top: 28px
|
||||
right: 0
|
||||
width: 400px
|
||||
background-color: #fafafa
|
||||
box-shadow: 0 1px 2px rgba(0,0,0,0.15)
|
||||
border-radius: 2px
|
||||
max-height: calc(100vh - 28px - 36px)
|
||||
color: black
|
||||
padding-top 36px
|
||||
|
||||
a:hover
|
||||
color: belize !important
|
||||
|
||||
.header
|
||||
position: fixed
|
||||
top 28px
|
||||
right 0
|
||||
width calc(400px - 32px)
|
||||
padding: 8px 16px
|
||||
background: #ededed
|
||||
border-bottom: 1px solid #dbdbdb
|
||||
z-index 2
|
||||
|
||||
.toggle-read
|
||||
position absolute
|
||||
left 16px
|
||||
top calc(50% - 8px)
|
||||
color belize
|
||||
|
||||
h5
|
||||
text-align: center
|
||||
margin: 0
|
||||
|
||||
.close
|
||||
position: absolute
|
||||
top: calc(50% - 12px)
|
||||
right: 12px
|
||||
font-size: 24px
|
||||
height: 24px
|
||||
line-height: 24px
|
||||
opacity 1
|
||||
|
||||
.all-read,
|
||||
.remove-read
|
||||
color belize
|
||||
background-color: #fafafa
|
||||
margin 8px 16px 12px
|
||||
display inline-block
|
||||
|
||||
.remove-read
|
||||
float right
|
||||
|
||||
&:hover
|
||||
color #eb4646 !important
|
||||
|
||||
i.fa
|
||||
color inherit
|
||||
|
||||
|
||||
ul.notifications
|
||||
display: block
|
||||
padding: 0px 16px
|
||||
margin: 0
|
||||
height: calc(100vh - 102px)
|
||||
overflow-y: scroll
|
||||
@@ -1,29 +1,42 @@
|
||||
template(name="boardActions")
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-move-card-to'}}
|
||||
div.trigger-dropdown
|
||||
select(id="move-gen-action")
|
||||
option(value="top") {{_'r-top-of'}}
|
||||
option(value="bottom") {{_'r-bottom-of'}}
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-its-list'}}
|
||||
div.trigger-button.js-add-gen-move-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-move-card-to'}}
|
||||
div.trigger-dropdown
|
||||
select(id="move-spec-action")
|
||||
option(value="top") {{_'r-top-of'}}
|
||||
option(value="bottom") {{_'r-bottom-of'}}
|
||||
div.trigger-text
|
||||
| {{_'r-list'}}
|
||||
div.trigger-text
|
||||
| {{_'r-the-board'}}
|
||||
div.trigger-dropdown
|
||||
select(id="board-id")
|
||||
each boards
|
||||
if $eq _id currentBoard._id
|
||||
option(value="{{_id}}" selected) {{_ 'current'}}
|
||||
else
|
||||
option(value="{{_id}}") {{title}}
|
||||
div.trigger-text
|
||||
| {{_'r-in-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="listName",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
| {{_'r-in-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="swimlaneName",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-button.js-add-spec-move-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
@@ -33,14 +46,14 @@ template(name="boardActions")
|
||||
select(id="arch-action")
|
||||
option(value="archive") {{_'r-archive'}}
|
||||
option(value="unarchive") {{_'r-unarchive'}}
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-card'}}
|
||||
div.trigger-button.js-add-arch-action.js-goto-rules
|
||||
i.fa.fa-plus
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-add-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="swimlane-name",type=text,placeholder="{{_'r-name'}}")
|
||||
@@ -49,15 +62,15 @@ template(name="boardActions")
|
||||
|
||||
div.trigger-item
|
||||
div.trigger-content
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-create-card'}}
|
||||
div.trigger-dropdown
|
||||
input(id="card-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-in-list'}}
|
||||
div.trigger-dropdown
|
||||
input(id="list-name",type=text,placeholder="{{_'r-name'}}")
|
||||
div.trigger-text
|
||||
div.trigger-text
|
||||
| {{_'r-in-swimlane'}}
|
||||
div.trigger-dropdown
|
||||
input(id="swimlane-name2",type=text,placeholder="{{_'r-name'}}")
|
||||
@@ -65,8 +78,8 @@ template(name="boardActions")
|
||||
i.fa.fa-plus
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,22 @@
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
|
||||
boards() {
|
||||
const boards = Boards.find(
|
||||
{
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
_id: {
|
||||
$ne: Meteor.user().getTemplatesBoardId(),
|
||||
},
|
||||
},
|
||||
{
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
return boards;
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
@@ -52,15 +68,18 @@ BlazeComponent.extendComponent({
|
||||
const ruleName = this.data().ruleName.get();
|
||||
const trigger = this.data().triggerVar.get();
|
||||
const actionSelected = this.find('#move-spec-action').value;
|
||||
const listTitle = this.find('#listName').value;
|
||||
const swimlaneName = this.find('#swimlaneName').value;
|
||||
const listName = this.find('#listName').value;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const destBoardId = this.find('#board-id').value;
|
||||
const desc = Utils.getTriggerActionDesc(event, this);
|
||||
if (actionSelected === 'top') {
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToTop',
|
||||
listTitle,
|
||||
boardId,
|
||||
listName,
|
||||
swimlaneName,
|
||||
boardId: destBoardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
@@ -74,8 +93,9 @@ BlazeComponent.extendComponent({
|
||||
const triggerId = Triggers.insert(trigger);
|
||||
const actionId = Actions.insert({
|
||||
actionType: 'moveCardToBottom',
|
||||
listTitle,
|
||||
boardId,
|
||||
listName,
|
||||
swimlaneName,
|
||||
boardId: destBoardId,
|
||||
desc,
|
||||
});
|
||||
Rules.insert({
|
||||
|
||||
@@ -4,12 +4,16 @@ template(name='information')
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-title
|
||||
span {{_ 'info'}}
|
||||
span
|
||||
i.fa.fa-info-circle
|
||||
| {{_ 'info'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="information-display") {{_ 'info'}}
|
||||
a.js-setting-menu(data-id="information-display")
|
||||
i.fa.fa-info-circle
|
||||
| {{_ 'info'}}
|
||||
.main-body
|
||||
+statistics
|
||||
|
||||
|
||||
@@ -5,16 +5,22 @@ template(name="people")
|
||||
else
|
||||
.content-title.ext-box
|
||||
.ext-box-left
|
||||
span {{_ 'people'}}
|
||||
span
|
||||
i.fa.fa-users
|
||||
| {{_ 'people'}}
|
||||
input#searchInput(placeholder="{{_ 'search'}}")
|
||||
button#searchButton {{_ 'search'}}
|
||||
button#searchButton
|
||||
i.fa.fa-search
|
||||
| {{_ 'search'}}
|
||||
.ext-box-right
|
||||
span {{_ 'people-number'}} #{peopleNumber}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="people-setting") {{_ 'people'}}
|
||||
a.js-setting-menu(data-id="people-setting")
|
||||
i.fa.fa-users
|
||||
| {{_ 'people'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
@@ -34,9 +40,15 @@ template(name="peopleGeneral")
|
||||
th {{_ 'active'}}
|
||||
th {{_ 'authentication-method'}}
|
||||
th
|
||||
+newUserRow
|
||||
each user in peopleList
|
||||
+peopleRow(userId=user._id)
|
||||
|
||||
template(name="newUserRow")
|
||||
a.new-user
|
||||
i.fa.fa-edit
|
||||
| {{_ 'new'}}
|
||||
|
||||
template(name="peopleRow")
|
||||
tr
|
||||
if userData.loginDisabled
|
||||
@@ -90,6 +102,7 @@ template(name="peopleRow")
|
||||
td {{_ userData.authenticationMethod }}
|
||||
td
|
||||
a.edit-user
|
||||
i.fa.fa-edit
|
||||
| {{_ 'edit'}}
|
||||
|
||||
template(name="editUserPopup")
|
||||
@@ -97,7 +110,7 @@ template(name="editUserPopup")
|
||||
label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname autofocus)
|
||||
input.js-profile-fullname(type="text" value=user.profile.fullname)
|
||||
label
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
@@ -141,3 +154,49 @@ template(name="editUserPopup")
|
||||
// div
|
||||
// input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
|
||||
|
||||
template(name="newUserPopup")
|
||||
form
|
||||
//label.hide.userId(type="text" value=user._id)
|
||||
label
|
||||
| {{_ 'fullname'}}
|
||||
input.js-profile-fullname(type="text" value="")
|
||||
label
|
||||
| {{_ 'username'}}
|
||||
span.error.hide.username-taken
|
||||
| {{_ 'error-username-taken'}}
|
||||
//if isLdap
|
||||
// input.js-profile-username(type="text" value=user.username readonly)
|
||||
//else
|
||||
input.js-profile-username(type="text" value="")
|
||||
label
|
||||
| {{_ 'email'}}
|
||||
span.error.hide.email-taken
|
||||
| {{_ 'error-email-taken'}}
|
||||
//if isLdap
|
||||
// input.js-profile-email(type="email" value="{{user.emails.[0].address}}" readonly)
|
||||
//else
|
||||
input.js-profile-email(type="email" value="")
|
||||
label
|
||||
| {{_ 'admin'}}
|
||||
select.select-role.js-profile-isadmin
|
||||
option(value="false" selected="selected") {{_ 'no'}}
|
||||
option(value="true") {{_ 'yes'}}
|
||||
label
|
||||
| {{_ 'active'}}
|
||||
select.select-active.js-profile-isactive
|
||||
option(value="false" selected="selected") {{_ 'yes'}}
|
||||
option(value="true") {{_ 'no'}}
|
||||
label
|
||||
| {{_ 'authentication-type'}}
|
||||
select.select-authenticationMethod.js-authenticationMethod
|
||||
each authentications
|
||||
if isSelected value
|
||||
option(value="{{value}}" selected) {{_ value}}
|
||||
else
|
||||
option(value="{{value}}") {{_ value}}
|
||||
hr
|
||||
label
|
||||
| {{_ 'password'}}
|
||||
input.js-profile-password(type="password")
|
||||
div.buttonsContainer
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
@@ -39,6 +39,9 @@ BlazeComponent.extendComponent({
|
||||
this.filterPeople();
|
||||
}
|
||||
},
|
||||
'click #newUserButton'() {
|
||||
Popup.open('newUser');
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
@@ -141,6 +144,47 @@ Template.editUserPopup.helpers({
|
||||
},
|
||||
});
|
||||
|
||||
Template.newUserPopup.onCreated(function() {
|
||||
this.authenticationMethods = new ReactiveVar([]);
|
||||
this.errorMessage = new ReactiveVar('');
|
||||
|
||||
Meteor.call('getAuthenticationsEnabled', (_, result) => {
|
||||
if (result) {
|
||||
// TODO : add a management of different languages
|
||||
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
|
||||
this.authenticationMethods.set([
|
||||
{ value: 'password' },
|
||||
// Gets only the authentication methods availables
|
||||
...Object.entries(result)
|
||||
.filter(e => e[1])
|
||||
.map(e => ({ value: e[0] })),
|
||||
]);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Template.newUserPopup.helpers({
|
||||
//user() {
|
||||
// return Users.findOne(this.userId);
|
||||
//},
|
||||
authentications() {
|
||||
return Template.instance().authenticationMethods.get();
|
||||
},
|
||||
//isSelected(match) {
|
||||
// const userId = Template.instance().data.userId;
|
||||
// const selected = Users.findOne(userId).authenticationMethod;
|
||||
// return selected === match;
|
||||
//},
|
||||
//isLdap() {
|
||||
// const userId = Template.instance().data.userId;
|
||||
// const selected = Users.findOne(userId).authenticationMethod;
|
||||
// return selected === 'ldap';
|
||||
//},
|
||||
errorMessage() {
|
||||
return Template.instance().errorMessage.get();
|
||||
},
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {},
|
||||
user() {
|
||||
@@ -155,6 +199,16 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('peopleRow');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click a.new-user': Popup.open('newUser'),
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('newUserRow');
|
||||
|
||||
Template.editUserPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
@@ -248,3 +302,44 @@ Template.editUserPopup.events({
|
||||
Popup.close();
|
||||
}),
|
||||
});
|
||||
|
||||
Template.newUserPopup.events({
|
||||
submit(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const fullname = templateInstance.find('.js-profile-fullname').value.trim();
|
||||
const username = templateInstance.find('.js-profile-username').value.trim();
|
||||
const password = templateInstance.find('.js-profile-password').value;
|
||||
const isAdmin = templateInstance.find('.js-profile-isadmin').value.trim();
|
||||
const isActive = templateInstance.find('.js-profile-isactive').value.trim();
|
||||
const email = templateInstance.find('.js-profile-email').value.trim();
|
||||
|
||||
Meteor.call(
|
||||
'setCreateUser',
|
||||
fullname,
|
||||
username,
|
||||
password,
|
||||
isAdmin,
|
||||
isActive,
|
||||
email.toLowerCase(),
|
||||
function(error) {
|
||||
const usernameMessageElement = templateInstance.$('.username-taken');
|
||||
const emailMessageElement = templateInstance.$('.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();
|
||||
}
|
||||
},
|
||||
);
|
||||
Popup.close();
|
||||
},
|
||||
});
|
||||
@@ -33,7 +33,7 @@ table
|
||||
padding: 0;
|
||||
|
||||
button
|
||||
min-width: 60px;
|
||||
min-width: 90px;
|
||||
|
||||
.content-wrapper
|
||||
margin-top: 10px
|
||||
|
||||
@@ -4,22 +4,35 @@ template(name="setting")
|
||||
| {{_ 'error-notAuthorized'}}
|
||||
else
|
||||
.content-title
|
||||
i.fa.fa-cog
|
||||
span {{_ 'settings'}}
|
||||
.content-body
|
||||
.side-menu
|
||||
ul
|
||||
li.active
|
||||
a.js-setting-menu(data-id="registration-setting") {{_ 'registration'}}
|
||||
a.js-setting-menu(data-id="registration-setting")
|
||||
i.fa.fa-sign-in
|
||||
| {{_ 'registration'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="email-setting") {{_ 'email'}}
|
||||
a.js-setting-menu(data-id="email-setting")
|
||||
i.fa.fa-envelope
|
||||
| {{_ 'email'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="account-setting") {{_ 'accounts'}}
|
||||
a.js-setting-menu(data-id="account-setting")
|
||||
i.fa.fa-users
|
||||
| {{_ 'accounts'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="announcement-setting") {{_ 'admin-announcement'}}
|
||||
a.js-setting-menu(data-id="announcement-setting")
|
||||
i.fa.fa-bullhorn
|
||||
| {{_ 'admin-announcement'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="layout-setting") {{_ 'layout'}}
|
||||
a.js-setting-menu(data-id="layout-setting")
|
||||
i.fa.fa-object-group
|
||||
| {{_ 'layout'}}
|
||||
li
|
||||
a.js-setting-menu(data-id="webhook-setting") {{_ 'global-webhook'}}
|
||||
a.js-setting-menu(data-id="webhook-setting")
|
||||
i.fa.fa-globe
|
||||
| {{_ 'global-webhook'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
+spinner
|
||||
@@ -171,12 +184,6 @@ template(name='layoutSettings')
|
||||
.title {{_ 'custom-product-name'}}
|
||||
.form-group
|
||||
input.wekan-form-control#product-name(type="text", placeholder="" value="{{currentSetting.productName}}")
|
||||
li.layout-form
|
||||
.title {{_ 'add-custom-html-after-body-start'}}
|
||||
textarea#customHTMLafterBodyStart.wekan-form-control= currentSetting.customHTMLafterBodyStart
|
||||
li.layout-form
|
||||
.title {{_ 'add-custom-html-before-body-end'}}
|
||||
textarea#customHTMLbeforeBodyEnd.wekan-form-control= currentSetting.customHTMLbeforeBodyEnd
|
||||
li
|
||||
button.js-save-layout.primary {{_ 'save'}}
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ BlazeComponent.extendComponent({
|
||||
'members.isAdmin': true,
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -171,20 +171,12 @@ BlazeComponent.extendComponent({
|
||||
const displayAuthenticationMethod =
|
||||
$('input[name=displayAuthenticationMethod]:checked').val() === 'true';
|
||||
const defaultAuthenticationMethod = $('#defaultAuthenticationMethod').val();
|
||||
const customHTMLafterBodyStart = $('#customHTMLafterBodyStart')
|
||||
.val()
|
||||
.trim();
|
||||
const customHTMLbeforeBodyEnd = $('#customHTMLbeforeBodyEnd')
|
||||
.val()
|
||||
.trim();
|
||||
|
||||
try {
|
||||
Settings.update(Settings.findOne()._id, {
|
||||
$set: {
|
||||
productName,
|
||||
hideLogo: hideLogoChange,
|
||||
customHTMLafterBodyStart,
|
||||
customHTMLbeforeBodyEnd,
|
||||
displayAuthenticationMethod,
|
||||
defaultAuthenticationMethod,
|
||||
},
|
||||
|
||||
@@ -41,15 +41,18 @@
|
||||
&:hover
|
||||
background #fff
|
||||
box-shadow 0 1px 2px rgba(0,0,0,0.15);
|
||||
|
||||
a
|
||||
@extends .flex
|
||||
padding: 1rem 0 1rem 1rem
|
||||
width: 100% - 5rem
|
||||
|
||||
|
||||
span
|
||||
font-size: 13px
|
||||
|
||||
i
|
||||
margin-right: 20px
|
||||
|
||||
.main-body
|
||||
padding: 0.1em 1em
|
||||
-webkit-user-select: text // Safari 3.1+
|
||||
|
||||
@@ -37,11 +37,12 @@ template(name='homeSidebar')
|
||||
template(name="membersWidget")
|
||||
.board-widget.board-widget-members
|
||||
h3
|
||||
i.fa.fa-user
|
||||
i.fa.fa-users
|
||||
| {{_ 'members'}}
|
||||
unless currentUser.isCommentOnly
|
||||
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right
|
||||
i.board-header-btn-icon.fa.fa-cog
|
||||
unless currentUser.isWorker
|
||||
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right
|
||||
i.board-header-btn-icon.fa.fa-cog
|
||||
|
||||
.board-widget-content
|
||||
each currentBoard.activeMembers
|
||||
@@ -71,6 +72,108 @@ template(name="boardChangeColorPopup")
|
||||
if isSelected
|
||||
i.fa.fa-check
|
||||
|
||||
template(name="boardCardSettingsPopup")
|
||||
form.board-card-settings
|
||||
h3 {{_ 'show-on-card'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-receiveddate(class="{{#if allowsReceivedDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsReceivedDate}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-sign-out
|
||||
| {{_ 'card-received'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-startdate(class="{{#if allowsStartDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsStartDate}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-hourglass-start
|
||||
| {{_ 'card-start'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-duedate(class="{{#if allowsDueDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDueDate}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-sign-in
|
||||
| {{_ 'card-due'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-enddate(class="{{#if allowsEndDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsEndDate}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-hourglass-end
|
||||
| {{_ 'card-end'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-members(class="{{#if allowsMembers}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsMembers}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-users
|
||||
| {{_ 'members'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-assignee(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-user
|
||||
| {{_ 'assignee'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-assigned-by(class="{{#if allowsAssignedBy}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAssignedBy}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-shopping-cart
|
||||
| {{_ 'assigned-by'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-requested-by(class="{{#if allowsRequestedBy}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsRequestedBy}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-user-plus
|
||||
| {{_ 'requested-by'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-labels(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-tags
|
||||
| {{_ 'labels'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-title(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-align-left
|
||||
| {{_ 'description'}}
|
||||
| {{_ 'title'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-text(class="{{#if allowsDescriptionText}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionText}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-align-left
|
||||
| {{_ 'description'}}
|
||||
| {{_ 'custom-field-text'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-checklists(class="{{#if allowsChecklists}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsChecklists}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-check
|
||||
| {{_ 'checklists'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtasks'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-attachments(class="{{#if allowsAttachments}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAttachments}}is-checked{{/if}}")
|
||||
span
|
||||
i.fa.fa-paperclip
|
||||
| {{_ 'attachments'}}
|
||||
//div.check-div
|
||||
// a.flex.js-field-has-comments(class="{{#if allowsComments}}is-checked{{/if}}")
|
||||
// .materialCheckBox(class="{{#if allowsComments}}is-checked{{/if}}")
|
||||
// span
|
||||
// i.fa.fa-comment-o
|
||||
// | {{_ 'comment'}}
|
||||
//div.check-div
|
||||
// a.flex.js-field-has-activities(class="{{#if allowsActivities}}is-checked{{/if}}")
|
||||
// .materialCheckBox(class="{{#if allowsActivities}}is-checked{{/if}}")
|
||||
// span
|
||||
// i.fa.fa-history
|
||||
// | {{_ 'activities'}}
|
||||
|
||||
template(name="boardSubtaskSettingsPopup")
|
||||
form.board-subtask-settings
|
||||
h3 {{_ 'show-parent-in-minicard'}}
|
||||
@@ -130,7 +233,9 @@ template(name="chooseBoardSource")
|
||||
|
||||
template(name="archiveBoardPopup")
|
||||
p {{_ 'close-board-pop'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
|
||||
button.js-confirm.negate.full(type="submit")
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive'}}
|
||||
|
||||
template(name="outgoingWebhooksPopup")
|
||||
each integrations
|
||||
@@ -140,7 +245,7 @@ template(name="outgoingWebhooksPopup")
|
||||
b
|
||||
.materialCheckBox(class="{{#unless enabled}}is-checked{{/unless}}")
|
||||
input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" value=title)
|
||||
input.js-outgoing-webhooks-url(type="text" name="url" value=url autofocus)
|
||||
input.js-outgoing-webhooks-url(type="text" name="url" value=url)
|
||||
input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" value=token name="token")
|
||||
select.js-outgoing-webhooks-type(name="type")
|
||||
each _type in types
|
||||
@@ -152,7 +257,7 @@ template(name="outgoingWebhooksPopup")
|
||||
input(type="hidden" value=_id name="id")
|
||||
input.primary.wide(type="submit" value="{{_ 'save'}}")
|
||||
form.integration-form
|
||||
input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" autofocus)
|
||||
input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title")
|
||||
input.js-outgoing-webhooks-url(placeholder="{{_ 'URL' }}" type="text" name="url")
|
||||
input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" name="token")
|
||||
select.js-outgoing-webhooks-type(name="type")
|
||||
@@ -162,38 +267,98 @@ template(name="outgoingWebhooksPopup")
|
||||
|
||||
template(name="boardMenuPopup")
|
||||
ul.pop-over-list
|
||||
li: a.js-custom-fields {{_ 'custom-fields'}}
|
||||
li: a.js-open-archives {{_ 'archived-items'}}
|
||||
li
|
||||
a.js-open-rules-view(title="{{_ 'rules'}}")
|
||||
i.fa.fa-magic
|
||||
| {{_ 'rules'}}
|
||||
li
|
||||
a.js-custom-fields
|
||||
i.fa.fa-list-alt
|
||||
| {{_ 'custom-fields'}}
|
||||
li
|
||||
a.js-open-archives
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archived-items'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li: a.js-change-board-color {{_ 'board-change-color'}}
|
||||
li
|
||||
a.js-change-board-color
|
||||
i.fa.fa-paint-brush
|
||||
| {{_ 'board-change-color'}}
|
||||
|
||||
//-
|
||||
XXX Language should be handled by sandstorm, but for now display a
|
||||
language selection link in the board menu. This link is normally present
|
||||
in the header bar that is not displayed on sandstorm.
|
||||
if isSandstorm
|
||||
li: a.js-change-language {{_ 'language'}}
|
||||
li
|
||||
a.js-change-language
|
||||
i.fa.fa-flag
|
||||
| {{_ 'language'}}
|
||||
unless isSandstorm
|
||||
if currentUser.isBoardAdmin
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
li: a.js-archive-board {{_ 'archive-board'}}
|
||||
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-subtask-settings {{_ 'subtask-settings'}}
|
||||
if withApi
|
||||
li
|
||||
a(href="{{exportUrl}}", download="{{exportFilename}}")
|
||||
i.fa.fa-share-alt
|
||||
| {{_ 'export-board'}}
|
||||
li
|
||||
a.js-outgoing-webhooks
|
||||
i.fa.fa-globe
|
||||
| {{_ 'outgoing-webhooks'}}
|
||||
li
|
||||
a.js-card-settings
|
||||
i.fa.fa-id-card-o
|
||||
| {{_ 'card-settings'}}
|
||||
li
|
||||
a.js-subtask-settings
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtask-settings'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-archive-board
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-board'}}
|
||||
|
||||
if isSandstorm
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
|
||||
li: a.js-import-board {{_ 'import-board-c'}}
|
||||
li: a.js-archive-board {{_ 'archive-board'}}
|
||||
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
|
||||
if withApi
|
||||
li
|
||||
a(href="{{exportUrl}}", download="{{exportFilename}}")
|
||||
i.fa.fa-share-alt
|
||||
i.fa.fa-sign-out
|
||||
| {{_ 'export-board'}}
|
||||
li
|
||||
a.js-import-board
|
||||
i.fa.fa-share-alt
|
||||
i.fa.fa-sign-in
|
||||
| {{_ 'import-board-c'}}
|
||||
li
|
||||
a.js-archive-board
|
||||
i.fa.fa-arrow-right
|
||||
i.fa.fa-archive
|
||||
| {{_ 'archive-board'}}
|
||||
li
|
||||
a.js-outgoing-webhooks
|
||||
i.fa.fa-globe
|
||||
| {{_ 'outgoing-webhooks'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-subtask-settings {{_ 'subtask-settings'}}
|
||||
li
|
||||
a.js-card-settings
|
||||
i.fa.fa-id-card-o
|
||||
| {{_ 'card-settings'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-subtask-settings
|
||||
i.fa.fa-sitemap
|
||||
| {{_ 'subtask-settings'}}
|
||||
|
||||
template(name="labelsWidget")
|
||||
.board-widget.board-widget-labels
|
||||
@@ -203,7 +368,7 @@ template(name="labelsWidget")
|
||||
.board-widget-content
|
||||
each currentBoard.labels
|
||||
a.card-label(class="card-label-{{color}}"
|
||||
class="{{#if currentUser.isNotCommentOnly}}js-label{{/if}}")
|
||||
class="{{#if currentUser.isNotCommentOnly}}{{#if currentUser.isNotWorker}}js-label{{/if}}{{/if}}")
|
||||
span.card-label-name
|
||||
+viewer
|
||||
= name
|
||||
@@ -232,12 +397,12 @@ template(name="memberPopup")
|
||||
a.js-change-role
|
||||
| {{_ 'change-permissions'}}
|
||||
span.quiet (#{memberType})
|
||||
li
|
||||
if $eq currentUser._id userId
|
||||
a.js-leave-member {{_ 'leave-board'}}
|
||||
else if currentUser.isBoardAdmin
|
||||
a.js-remove-member {{_ 'remove-from-board'}}
|
||||
|
||||
unless currentUser.isWorker
|
||||
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}}
|
||||
@@ -301,6 +466,12 @@ template(name="changePermissionsPopup")
|
||||
if isCommentOnly
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'comment-only-desc'}}
|
||||
li
|
||||
a(class="{{#if isLastAdmin}}disabled{{else}}js-set-worker{{/if}}")
|
||||
| {{_ 'worker'}}
|
||||
if isWorker
|
||||
i.fa.fa-check
|
||||
span.sub-name {{_ 'worker-desc'}}
|
||||
if isLastAdmin
|
||||
hr
|
||||
p.quiet.bottom {{_ 'last-admin-desc'}}
|
||||
@@ -161,10 +161,13 @@ Template.memberPopup.helpers({
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
const commentOnly = currentBoard.hasCommentOnly(this.userId);
|
||||
const noComments = currentBoard.hasNoComments(this.userId);
|
||||
const worker = currentBoard.hasWorker(this.userId);
|
||||
if (commentOnly) {
|
||||
return TAPi18n.__('comment-only').toLowerCase();
|
||||
} else if (noComments) {
|
||||
return TAPi18n.__('no-comments').toLowerCase();
|
||||
} else if (worker) {
|
||||
return TAPi18n.__('worker').toLowerCase();
|
||||
} else {
|
||||
return TAPi18n.__(type).toLowerCase();
|
||||
}
|
||||
@@ -179,6 +182,10 @@ Template.memberPopup.helpers({
|
||||
|
||||
Template.boardMenuPopup.events({
|
||||
'click .js-rename-board': Popup.open('boardChangeTitle'),
|
||||
'click .js-open-rules-view'() {
|
||||
Modal.openWide('rulesMain');
|
||||
Popup.close();
|
||||
},
|
||||
'click .js-custom-fields'() {
|
||||
Sidebar.setView('customFields');
|
||||
Popup.close();
|
||||
@@ -205,9 +212,20 @@ Template.boardMenuPopup.events({
|
||||
'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'),
|
||||
'click .js-import-board': Popup.open('chooseBoardSource'),
|
||||
'click .js-subtask-settings': Popup.open('boardSubtaskSettings'),
|
||||
'click .js-card-settings': Popup.open('boardCardSettings'),
|
||||
});
|
||||
|
||||
Template.boardMenuPopup.onCreated(function() {
|
||||
this.apiEnabled = new ReactiveVar(false);
|
||||
Meteor.call('_isApiEnabled', (e, result) => {
|
||||
this.apiEnabled.set(result);
|
||||
});
|
||||
});
|
||||
|
||||
Template.boardMenuPopup.helpers({
|
||||
withApi() {
|
||||
return Template.instance().apiEnabled.get();
|
||||
},
|
||||
exportUrl() {
|
||||
const params = {
|
||||
boardId: Session.get('currentBoard'),
|
||||
@@ -267,6 +285,14 @@ Template.membersWidget.helpers({
|
||||
const user = Meteor.user();
|
||||
return user && user.isInvitedTo(Session.get('currentBoard'));
|
||||
},
|
||||
isWorker() {
|
||||
const user = Meteor.user();
|
||||
if (user) {
|
||||
return Meteor.call(Boards.hasWorker(user.memberId));
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.membersWidget.events({
|
||||
@@ -461,6 +487,10 @@ BlazeComponent.extendComponent({
|
||||
return this.currentBoard.allowsSubtasks;
|
||||
},
|
||||
|
||||
allowsReceivedDate() {
|
||||
return this.currentBoard.allowsReceivedDate;
|
||||
},
|
||||
|
||||
isBoardSelected() {
|
||||
return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
|
||||
},
|
||||
@@ -479,7 +509,7 @@ BlazeComponent.extendComponent({
|
||||
'members.userId': Meteor.userId(),
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
},
|
||||
@@ -574,6 +604,359 @@ BlazeComponent.extendComponent({
|
||||
},
|
||||
}).register('boardSubtaskSettingsPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
},
|
||||
|
||||
allowsReceivedDate() {
|
||||
return this.currentBoard.allowsReceivedDate;
|
||||
},
|
||||
|
||||
allowsStartDate() {
|
||||
return this.currentBoard.allowsStartDate;
|
||||
},
|
||||
|
||||
allowsDueDate() {
|
||||
return this.currentBoard.allowsDueDate;
|
||||
},
|
||||
|
||||
allowsEndDate() {
|
||||
return this.currentBoard.allowsEndDate;
|
||||
},
|
||||
|
||||
allowsSubtasks() {
|
||||
return this.currentBoard.allowsSubtasks;
|
||||
},
|
||||
|
||||
allowsMembers() {
|
||||
return this.currentBoard.allowsMembers;
|
||||
},
|
||||
|
||||
allowsAssignee() {
|
||||
return this.currentBoard.allowsAssignee;
|
||||
},
|
||||
|
||||
allowsAssignedBy() {
|
||||
return this.currentBoard.allowsAssignedBy;
|
||||
},
|
||||
|
||||
allowsRequestedBy() {
|
||||
return this.currentBoard.allowsRequestedBy;
|
||||
},
|
||||
|
||||
allowsLabels() {
|
||||
return this.currentBoard.allowsLabels;
|
||||
},
|
||||
|
||||
allowsChecklists() {
|
||||
return this.currentBoard.allowsChecklists;
|
||||
},
|
||||
|
||||
allowsAttachments() {
|
||||
return this.currentBoard.allowsAttachments;
|
||||
},
|
||||
|
||||
allowsComments() {
|
||||
return this.currentBoard.allowsComments;
|
||||
},
|
||||
|
||||
allowsDescriptionTitle() {
|
||||
return this.currentBoard.allowsDescriptionTitle;
|
||||
},
|
||||
|
||||
allowsDescriptionText() {
|
||||
return this.currentBoard.allowsDescriptionText;
|
||||
},
|
||||
|
||||
isBoardSelected() {
|
||||
return this.currentBoard.dateSettingsDefaultBoardID;
|
||||
},
|
||||
|
||||
isNullBoardSelected() {
|
||||
return (
|
||||
this.currentBoard.dateSettingsDefaultBoardId === null ||
|
||||
this.currentBoard.dateSettingsDefaultBoardId === undefined
|
||||
);
|
||||
},
|
||||
|
||||
boards() {
|
||||
return Boards.find(
|
||||
{
|
||||
archived: false,
|
||||
'members.userId': Meteor.userId(),
|
||||
},
|
||||
{
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
lists() {
|
||||
return Lists.find(
|
||||
{
|
||||
boardId: this.currentBoard._id,
|
||||
archived: false,
|
||||
},
|
||||
{
|
||||
sort: ['title'],
|
||||
},
|
||||
);
|
||||
},
|
||||
|
||||
hasLists() {
|
||||
return this.lists().count() > 0;
|
||||
},
|
||||
|
||||
isListSelected() {
|
||||
return (
|
||||
this.currentBoard.dateSettingsDefaultBoardId === this.currentData()._id
|
||||
);
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-field-has-receiveddate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsReceivedDate = !this.currentBoard
|
||||
.allowsReceivedDate;
|
||||
this.currentBoard.setAllowsReceivedDate(
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
$(`.js-field-has-receiveddate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
$('.js-field-has-receiveddate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-startdate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsStartDate = !this.currentBoard
|
||||
.allowsStartDate;
|
||||
this.currentBoard.setAllowsStartDate(
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
$(`.js-field-has-startdate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
$('.js-field-has-startdate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-enddate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsEndDate = !this.currentBoard.allowsEndDate;
|
||||
this.currentBoard.setAllowsEndDate(this.currentBoard.allowsEndDate);
|
||||
$(`.js-field-has-enddate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsEndDate,
|
||||
);
|
||||
$('.js-field-has-enddate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsEndDate,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-duedate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsDueDate = !this.currentBoard.allowsDueDate;
|
||||
this.currentBoard.setAllowsDueDate(this.currentBoard.allowsDueDate);
|
||||
$(`.js-field-has-duedate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDueDate,
|
||||
);
|
||||
$('.js-field-has-duedate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDueDate,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-subtasks'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
|
||||
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
|
||||
$(`.js-field-has-subtasks ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
$('.js-field-has-subtasks').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-members'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsMembers = !this.currentBoard.allowsMembers;
|
||||
this.currentBoard.setAllowsMembers(this.currentBoard.allowsMembers);
|
||||
$(`.js-field-has-members ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsMembers,
|
||||
);
|
||||
$('.js-field-has-members').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsMembers,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-assignee'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsAssignee = !this.currentBoard.allowsAssignee;
|
||||
this.currentBoard.setAllowsAssignee(this.currentBoard.allowsAssignee);
|
||||
$(`.js-field-has-assignee ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignee,
|
||||
);
|
||||
$('.js-field-has-assignee').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignee,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-assigned-by'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsAssignedBy = !this.currentBoard
|
||||
.allowsAssignedBy;
|
||||
this.currentBoard.setAllowsAssignedBy(
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
$(`.js-field-has-assigned-by ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
$('.js-field-has-assigned-by').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-requested-by'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsRequestedBy = !this.currentBoard
|
||||
.allowsRequestedBy;
|
||||
this.currentBoard.setAllowsRequestedBy(
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
$(`.js-field-has-requested-by ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
$('.js-field-has-requested-by').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-labels'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsLabels = !this.currentBoard.allowsLabels;
|
||||
this.currentBoard.setAllowsLabels(this.currentBoard.allowsLabels);
|
||||
$(`.js-field-has-labels ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignee,
|
||||
);
|
||||
$('.js-field-has-labels').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsLabels,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-description-title'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsDescriptionTitle = !this.currentBoard
|
||||
.allowsDescriptionTitle;
|
||||
this.currentBoard.setAllowsDescriptionTitle(
|
||||
this.currentBoard.allowsDescriptionTitle,
|
||||
);
|
||||
$(`.js-field-has-description-title ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDescriptionTitle,
|
||||
);
|
||||
$('.js-field-has-description-title').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDescriptionTitle,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-description-text'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsDescriptionText = !this.currentBoard
|
||||
.allowsDescriptionText;
|
||||
this.currentBoard.setAllowsDescriptionText(
|
||||
this.currentBoard.allowsDescriptionText,
|
||||
);
|
||||
$(`.js-field-has-description-text ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDescriptionText,
|
||||
);
|
||||
$('.js-field-has-description-text').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDescriptionText,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-checklists'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsChecklists = !this.currentBoard
|
||||
.allowsChecklists;
|
||||
this.currentBoard.setAllowsChecklists(
|
||||
this.currentBoard.allowsChecklists,
|
||||
);
|
||||
$(`.js-field-has-checklists ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsChecklists,
|
||||
);
|
||||
$('.js-field-has-checklists').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsChecklists,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-attachments'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsAttachments = !this.currentBoard
|
||||
.allowsAttachments;
|
||||
this.currentBoard.setAllowsAttachments(
|
||||
this.currentBoard.allowsAttachments,
|
||||
);
|
||||
$(`.js-field-has-attachments ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAttachments,
|
||||
);
|
||||
$('.js-field-has-attachments').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAttachments,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-comments'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsComments = !this.currentBoard.allowsComments;
|
||||
this.currentBoard.setAllowsComments(this.currentBoard.allowsComments);
|
||||
$(`.js-field-has-comments ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsComments,
|
||||
);
|
||||
$('.js-field-has-comments').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsComments,
|
||||
);
|
||||
},
|
||||
'click .js-field-has-activities'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsActivities = !this.currentBoard
|
||||
.allowsActivities;
|
||||
this.currentBoard.setAllowsActivities(
|
||||
this.currentBoard.allowsActivities,
|
||||
);
|
||||
$(`.js-field-has-activities ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsActivities,
|
||||
);
|
||||
$('.js-field-has-activities').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsActivities,
|
||||
);
|
||||
},
|
||||
},
|
||||
];
|
||||
},
|
||||
}).register('boardCardSettingsPopup');
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
@@ -644,7 +1027,7 @@ BlazeComponent.extendComponent({
|
||||
}).register('addMemberPopup');
|
||||
|
||||
Template.changePermissionsPopup.events({
|
||||
'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only'(
|
||||
'click .js-set-admin, click .js-set-normal, click .js-set-no-comments, click .js-set-comment-only, click .js-set-worker'(
|
||||
event,
|
||||
) {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
@@ -654,11 +1037,13 @@ Template.changePermissionsPopup.events({
|
||||
'js-set-comment-only',
|
||||
);
|
||||
const isNoComments = $(event.currentTarget).hasClass('js-set-no-comments');
|
||||
const isWorker = $(event.currentTarget).hasClass('js-set-worker');
|
||||
currentBoard.setMemberPermission(
|
||||
memberId,
|
||||
isAdmin,
|
||||
isNoComments,
|
||||
isCommentOnly,
|
||||
isWorker,
|
||||
);
|
||||
Popup.back(1);
|
||||
},
|
||||
@@ -675,7 +1060,8 @@ Template.changePermissionsPopup.helpers({
|
||||
return (
|
||||
!currentBoard.hasAdmin(this.userId) &&
|
||||
!currentBoard.hasNoComments(this.userId) &&
|
||||
!currentBoard.hasCommentOnly(this.userId)
|
||||
!currentBoard.hasCommentOnly(this.userId) &&
|
||||
!currentBoard.hasWorker(this.userId)
|
||||
);
|
||||
},
|
||||
|
||||
@@ -695,6 +1081,13 @@ Template.changePermissionsPopup.helpers({
|
||||
);
|
||||
},
|
||||
|
||||
isWorker() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return (
|
||||
!currentBoard.hasAdmin(this.userId) && currentBoard.hasWorker(this.userId)
|
||||
);
|
||||
},
|
||||
|
||||
isLastAdmin() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return (
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
color: darken(white, 40%)
|
||||
|
||||
.board-sidebar
|
||||
width: 248px
|
||||
width: 548px
|
||||
right: -@width
|
||||
transition: top .1s, right .1s, width .1s
|
||||
|
||||
|
||||
@@ -2,54 +2,60 @@ template(name="archivesSidebar")
|
||||
if isArchiveReady.get
|
||||
+basicTabs(tabs=tabs)
|
||||
+tabContent(slug="cards")
|
||||
p.quiet
|
||||
a.js-restore-all-cards {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-cards {{_ 'delete-all'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-cards {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-cards {{_ 'delete-all'}}
|
||||
each archivedCards
|
||||
.minicard-wrapper.js-minicard
|
||||
+minicard(this)
|
||||
if currentUser.isBoardMember
|
||||
p.quiet
|
||||
a.js-restore-card {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-card {{_ 'delete'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-card {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-card {{_ 'delete'}}
|
||||
if cardIsInArchivedList
|
||||
p.quiet.small ({{_ 'warn-list-archived'}})
|
||||
else
|
||||
p.no-items-message {{_ 'no-archived-cards'}}
|
||||
|
||||
+tabContent(slug="lists")
|
||||
p.quiet
|
||||
a.js-restore-all-lists {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-lists {{_ 'delete-all'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-lists {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-lists {{_ 'delete-all'}}
|
||||
ul.archived-lists
|
||||
each archivedLists
|
||||
li.archived-lists-item
|
||||
= title
|
||||
if currentUser.isBoardMember
|
||||
p.quiet
|
||||
a.js-restore-list {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-list {{_ 'delete'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-list {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-list {{_ 'delete'}}
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-lists'}}
|
||||
|
||||
+tabContent(slug="swimlanes")
|
||||
p.quiet
|
||||
a.js-restore-all-swimlanes {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-swimlanes {{_ 'delete-all'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-all-swimlanes {{_ 'restore-all'}}
|
||||
| -
|
||||
a.js-delete-all-swimlanes {{_ 'delete-all'}}
|
||||
ul.archived-lists
|
||||
each archivedSwimlanes
|
||||
li.archived-lists-item
|
||||
= title
|
||||
if currentUser.isBoardMember
|
||||
p.quiet
|
||||
a.js-restore-swimlane {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-swimlane {{_ 'delete'}}
|
||||
unless isWorker
|
||||
p.quiet
|
||||
a.js-restore-swimlane {{_ 'restore'}}
|
||||
| -
|
||||
a.js-delete-swimlane {{_ 'delete'}}
|
||||
else
|
||||
li.no-items-message {{_ 'no-archived-swimlanes'}}
|
||||
else
|
||||
|
||||
@@ -139,3 +139,12 @@ BlazeComponent.extendComponent({
|
||||
];
|
||||
},
|
||||
}).register('archivesSidebar');
|
||||
|
||||
Template.archivesSidebar.helpers({
|
||||
isWorker() {
|
||||
const currentBoard = Boards.findOne(Session.get('currentBoard'));
|
||||
return (
|
||||
!currentBoard.hasAdmin(this.userId) && currentBoard.hasWorker(this.userId)
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -45,6 +45,24 @@ template(name="filterSidebar")
|
||||
if Filter.members.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.assignees.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-assignee-filter
|
||||
span.sidebar-list-item-description
|
||||
| {{_ 'filter-no-assignee'}}
|
||||
if Filter.assignees.isSelected undefined
|
||||
i.fa.fa-check
|
||||
each currentBoard.activeMembers
|
||||
with getUser userId
|
||||
li(class="{{#if Filter.assignees.isSelected _id}}active{{/if}}")
|
||||
a.name.js-toggle-assignee-filter
|
||||
+userAvatar(userId=this._id)
|
||||
span.sidebar-list-item-description
|
||||
= profile.fullname
|
||||
| (<span class="username">{{ username }}</span>)
|
||||
if Filter.assignees.isSelected _id
|
||||
i.fa.fa-check
|
||||
hr
|
||||
ul.sidebar-list
|
||||
li(class="{{#if Filter.customFields.isSelected undefined}}active{{/if}}")
|
||||
a.name.js-toggle-custom-fields-filter
|
||||
@@ -117,13 +135,14 @@ template(name="multiselectionSidebar")
|
||||
i.fa.fa-check
|
||||
else if someSelectedElementHave 'member' _id
|
||||
i.fa.fa-ellipsis-h
|
||||
hr
|
||||
a.sidebar-btn.js-move-selection
|
||||
i.fa.fa-share
|
||||
span {{_ 'move-selection'}}
|
||||
a.sidebar-btn.js-archive-selection
|
||||
i.fa.fa-archive
|
||||
span {{_ 'archive-selection'}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
a.sidebar-btn.js-move-selection
|
||||
i.fa.fa-share
|
||||
span {{_ 'move-selection'}}
|
||||
a.sidebar-btn.js-archive-selection
|
||||
i.fa.fa-archive
|
||||
span {{_ 'archive-selection'}}
|
||||
|
||||
template(name="disambiguateMultiLabelPopup")
|
||||
p {{_ 'what-to-do'}}
|
||||
|
||||
@@ -18,6 +18,11 @@ BlazeComponent.extendComponent({
|
||||
Filter.members.toggle(this.currentData()._id);
|
||||
Filter.resetExceptions();
|
||||
},
|
||||
'click .js-toggle-assignee-filter'(evt) {
|
||||
evt.preventDefault();
|
||||
Filter.assignees.toggle(this.currentData()._id);
|
||||
Filter.resetExceptions();
|
||||
},
|
||||
'click .js-toggle-archive-filter'(evt) {
|
||||
evt.preventDefault();
|
||||
Filter.archive.toggle(this.currentData()._id);
|
||||
|
||||
@@ -43,19 +43,20 @@ template(name="listsGroup")
|
||||
+addListForm
|
||||
|
||||
template(name="addListForm")
|
||||
.list.list-composer.js-list-composer(class="{{#if isMiniScreen}}mini-list{{/if}}")
|
||||
.list-header-add
|
||||
+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'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
unless currentBoard.isTemplateBoard
|
||||
span.quiet
|
||||
| {{_ 'or'}}
|
||||
a.js-list-template {{_ 'template'}}
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-list'}}
|
||||
unless currentUser.isWorker
|
||||
.list.list-composer.js-list-composer(class="{{#if isMiniScreen}}mini-list{{/if}}")
|
||||
.list-header-add
|
||||
+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'}}
|
||||
unless currentBoard.isTemplatesBoard
|
||||
unless currentBoard.isTemplateBoard
|
||||
span.quiet
|
||||
| {{_ 'or'}}
|
||||
a.js-list-template {{_ 'template'}}
|
||||
else
|
||||
a.open-list-composer.js-open-inlined-form
|
||||
i.fa.fa-plus
|
||||
| {{_ 'add-list'}}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Cookies } from 'meteor/ostrio:cookies';
|
||||
const cookies = new Cookies();
|
||||
const { calculateIndex, enableClickOnTouch } = Utils;
|
||||
const { calculateIndex } = Utils;
|
||||
|
||||
function currentListIsInThisSwimlane(swimlaneId) {
|
||||
const currentList = Lists.findOne(Session.get('currentList'));
|
||||
@@ -87,14 +87,12 @@ function initSortable(boardComponent, $listsDom) {
|
||||
},
|
||||
});
|
||||
|
||||
// ugly touch event hotfix
|
||||
enableClickOnTouch('.js-list:not(.js-list-composer)');
|
||||
|
||||
function userIsMember() {
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,23 +108,23 @@ function initSortable(boardComponent, $listsDom) {
|
||||
showDesktopDragHandles = false;
|
||||
}
|
||||
|
||||
if (!Utils.isMiniScreen() && showDesktopDragHandles) {
|
||||
if (Utils.isMiniScreen() || showDesktopDragHandles) {
|
||||
$listsDom.sortable({
|
||||
handle: '.js-list-handle',
|
||||
});
|
||||
} else {
|
||||
} else if (!Utils.isMiniScreen() && !showDesktopDragHandles) {
|
||||
$listsDom.sortable({
|
||||
handle: '.js-list-header',
|
||||
});
|
||||
}
|
||||
|
||||
const $listDom = $listsDom;
|
||||
if ($listDom.data('sortable')) {
|
||||
if ($listDom.data('uiSortable') || $listDom.data('sortable')) {
|
||||
$listsDom.sortable(
|
||||
'option',
|
||||
'disabled',
|
||||
// Disable drag-dropping when user is not member
|
||||
!userIsMember(),
|
||||
// Disable drag-dropping when user is not member/is worker
|
||||
!userIsMember() || Meteor.user().isWorker(),
|
||||
// Not disable drag-dropping while in multi-selection mode
|
||||
// MultiSelection.isActive() || !userIsMember(),
|
||||
);
|
||||
@@ -187,8 +185,7 @@ BlazeComponent.extendComponent({
|
||||
}
|
||||
|
||||
const noDragInside = ['a', 'input', 'textarea', 'p'].concat(
|
||||
Utils.isMiniScreen() ||
|
||||
(!Utils.isMiniScreen() && showDesktopDragHandles)
|
||||
Utils.isMiniScreen() || showDesktopDragHandles
|
||||
? ['.js-list-handle', '.js-swimlane-header-handle']
|
||||
: ['.js-list-header'],
|
||||
);
|
||||
@@ -282,7 +279,8 @@ Template.swimlane.helpers({
|
||||
return (
|
||||
Meteor.user() &&
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly()
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -73,6 +73,7 @@ template(name="cardMemberPopup")
|
||||
p.quiet @{{ user.username }}
|
||||
ul.pop-over-list
|
||||
if currentUser.isNotCommentOnly
|
||||
if currentUser.isNotWorker
|
||||
li: a.js-remove-member {{_ 'remove-member-from-card'}}
|
||||
|
||||
if $eq currentUser._id user._id
|
||||
|
||||
@@ -13,21 +13,46 @@ template(name="headerUserBar")
|
||||
template(name="memberMenuPopup")
|
||||
ul.pop-over-list
|
||||
with currentUser
|
||||
li: a.js-edit-profile {{_ 'edit-profile'}}
|
||||
li: a.js-change-settings {{_ 'change-settings'}}
|
||||
li: a.js-change-avatar {{_ 'edit-avatar'}}
|
||||
li
|
||||
a.js-edit-profile
|
||||
i.fa.fa-user
|
||||
| {{_ 'edit-profile'}}
|
||||
li
|
||||
a.js-change-settings
|
||||
i.fa.fa-cog
|
||||
| {{_ 'change-settings'}}
|
||||
li
|
||||
a.js-change-avatar
|
||||
i.fa.fa-picture-o
|
||||
| {{_ 'edit-avatar'}}
|
||||
unless isSandstorm
|
||||
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
|
||||
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
|
||||
li
|
||||
a.js-change-password
|
||||
i.fa.fa-key
|
||||
| {{_ 'changePasswordPopup-title'}}
|
||||
li
|
||||
a.js-change-language
|
||||
i.fa.fa-flag
|
||||
| {{_ 'changeLanguagePopup-title'}}
|
||||
if currentUser.isAdmin
|
||||
li: a.js-go-setting(href="{{pathFor 'setting'}}") {{_ 'admin-panel'}}
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}") {{_ 'templates'}}
|
||||
li
|
||||
a.js-go-setting(href="{{pathFor 'setting'}}")
|
||||
i.fa.fa-lock
|
||||
| {{_ 'admin-panel'}}
|
||||
unless currentUser.isWorker
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li
|
||||
a(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
|
||||
i.fa.fa-clone
|
||||
| {{_ 'templates'}}
|
||||
unless isSandstorm
|
||||
hr
|
||||
ul.pop-over-list
|
||||
li: a.js-logout {{_ 'log-out'}}
|
||||
li
|
||||
a.js-logout
|
||||
i.fa.fa-sign-out
|
||||
| {{_ 'log-out'}}
|
||||
|
||||
template(name="editProfilePopup")
|
||||
form
|
||||
@@ -73,23 +98,36 @@ template(name="changeLanguagePopup")
|
||||
|
||||
template(name="changeSettingsPopup")
|
||||
ul.pop-over-list
|
||||
li
|
||||
a.js-toggle-system-messages
|
||||
| {{_ 'hide-system-messages'}}
|
||||
if hiddenSystemMessages
|
||||
i.fa.fa-check
|
||||
//li
|
||||
// a.js-toggle-system-messages
|
||||
// i.fa.fa-comments-o
|
||||
// | {{_ 'hide-system-messages'}}
|
||||
// if hiddenSystemMessages
|
||||
// i.fa.fa-check
|
||||
li
|
||||
a.js-toggle-desktop-drag-handles
|
||||
i.fa.fa-arrows
|
||||
| {{_ 'show-desktop-drag-handles'}}
|
||||
if showDesktopDragHandles
|
||||
i.fa.fa-check
|
||||
li
|
||||
label.bold
|
||||
| {{_ 'show-cards-minimum-count'}}
|
||||
input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="0" max="99" onkeydown="return false")
|
||||
input.js-apply-show-cards-at.left(type="submit" value="{{_ 'apply'}}")
|
||||
|
||||
unless currentUser.isWorker
|
||||
li
|
||||
label.bold.clear
|
||||
i.fa.fa-sort-numeric-asc
|
||||
| {{_ 'show-cards-minimum-count'}}
|
||||
input#show-cards-count-at.inline-input.left(type="number" value="#{showCardsCountAt}" min="0" max="99" onkeydown="return false")
|
||||
label.bold.clear
|
||||
i.fa.fa-calendar
|
||||
| {{_ 'start-day-of-week'}}
|
||||
select#start-day-of-week.inline-input.left
|
||||
each day in weekDays startDayOfWeek
|
||||
if day.isSelected
|
||||
option(selected="true", value="#{day.value}") #{day.name}
|
||||
else
|
||||
option(value="#{day.value}") #{day.name}
|
||||
input.js-apply-user-settings.left(type="submit" value="{{_ 'apply'}}")
|
||||
|
||||
template(name="userDeletePopup")
|
||||
p {{_ 'delete-user-confirm-popup'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
|
||||
unless currentUser.isWorker
|
||||
p {{_ 'delete-user-confirm-popup'}}
|
||||
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
|
||||
@@ -45,13 +45,31 @@ Template.memberMenuPopup.events({
|
||||
|
||||
Template.editProfilePopup.helpers({
|
||||
allowEmailChange() {
|
||||
return AccountSettings.findOne('accounts-allowEmailChange').booleanValue;
|
||||
Meteor.call('AccountSettings.allowEmailChange', (_, result) => {
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
allowUserNameChange() {
|
||||
return AccountSettings.findOne('accounts-allowUserNameChange').booleanValue;
|
||||
Meteor.call('AccountSettings.allowUserNameChange', (_, result) => {
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
allowUserDelete() {
|
||||
return AccountSettings.findOne('accounts-allowUserDelete').booleanValue;
|
||||
Meteor.call('AccountSettings.allowUserDelete', (_, result) => {
|
||||
if (result) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -148,6 +166,8 @@ Template.changeLanguagePopup.helpers({
|
||||
name = 'Igbo';
|
||||
} else if (lang.name === 'oc') {
|
||||
name = 'Occitan';
|
||||
} else if (lang.name === '繁体中文(台湾)') {
|
||||
name = '繁體中文(台灣)';
|
||||
}
|
||||
return { tag, name };
|
||||
}).sort(function(a, b) {
|
||||
@@ -204,6 +224,27 @@ Template.changeSettingsPopup.helpers({
|
||||
return cookies.get('limitToShowCardsCount');
|
||||
}
|
||||
},
|
||||
weekDays(startDay) {
|
||||
return [
|
||||
TAPi18n.__('sunday'),
|
||||
TAPi18n.__('monday'),
|
||||
TAPi18n.__('tuesday'),
|
||||
TAPi18n.__('wednesday'),
|
||||
TAPi18n.__('thursday'),
|
||||
TAPi18n.__('friday'),
|
||||
TAPi18n.__('saturday'),
|
||||
].map(function(day, index) {
|
||||
return { name: day, value: index, isSelected: index === startDay };
|
||||
});
|
||||
},
|
||||
startDayOfWeek() {
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return currentUser.getStartDayOfWeek();
|
||||
} else {
|
||||
return cookies.get('startDayOfWeek');
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
Template.changeSettingsPopup.events({
|
||||
@@ -227,20 +268,31 @@ Template.changeSettingsPopup.events({
|
||||
cookies.set('hasHiddenSystemMessages', 'true');
|
||||
}
|
||||
},
|
||||
'click .js-apply-show-cards-at'(event, templateInstance) {
|
||||
'click .js-apply-user-settings'(event, templateInstance) {
|
||||
event.preventDefault();
|
||||
const minLimit = parseInt(
|
||||
templateInstance.$('#show-cards-count-at').val(),
|
||||
10,
|
||||
);
|
||||
const startDay = parseInt(
|
||||
templateInstance.$('#start-day-of-week').val(),
|
||||
10,
|
||||
);
|
||||
const currentUser = Meteor.user();
|
||||
if (!isNaN(minLimit)) {
|
||||
currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
Meteor.call('changeLimitToShowCardsCount', minLimit);
|
||||
} else {
|
||||
cookies.set('limitToShowCardsCount', minLimit);
|
||||
}
|
||||
Popup.back();
|
||||
}
|
||||
if (!isNaN(startDay)) {
|
||||
if (currentUser) {
|
||||
Meteor.call('changeStartDayOfWeek', startDay);
|
||||
} else {
|
||||
cookies.set('startDayOfWeek', startDay);
|
||||
}
|
||||
}
|
||||
Popup.back();
|
||||
},
|
||||
});
|
||||
@@ -10,12 +10,22 @@ DatePicker = BlazeComponent.extendComponent({
|
||||
this.defaultTime = defaultTime;
|
||||
},
|
||||
|
||||
startDayOfWeek() {
|
||||
const currentUser = Meteor.user();
|
||||
if (currentUser) {
|
||||
return currentUser.getStartDayOfWeek();
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
const $picker = this.$('.js-datepicker')
|
||||
.datepicker({
|
||||
todayHighlight: true,
|
||||
todayBtn: 'linked',
|
||||
language: TAPi18n.getLanguage(),
|
||||
weekStart: this.startDayOfWeek(),
|
||||
})
|
||||
.on(
|
||||
'changeDate',
|
||||
|
||||
@@ -459,13 +459,21 @@ Filter = {
|
||||
// before changing the schema.
|
||||
labelIds: new SetFilter(),
|
||||
members: new SetFilter(),
|
||||
assignees: new SetFilter(),
|
||||
archive: new SetFilter(),
|
||||
hideEmpty: new SetFilter(),
|
||||
customFields: new SetFilter('_id'),
|
||||
advanced: new AdvancedFilter(),
|
||||
lists: new AdvancedFilter(), // we need the ability to filter list by name as well
|
||||
|
||||
_fields: ['labelIds', 'members', 'archive', 'hideEmpty', 'customFields'],
|
||||
_fields: [
|
||||
'labelIds',
|
||||
'members',
|
||||
'assignees',
|
||||
'archive',
|
||||
'hideEmpty',
|
||||
'customFields',
|
||||
],
|
||||
|
||||
// We don't filter cards that have been added after the last filter change. To
|
||||
// implement this we keep the id of these cards in this `_exceptions` fields
|
||||
|
||||
@@ -70,6 +70,30 @@ Mousetrap.bind('space', evt => {
|
||||
}
|
||||
});
|
||||
|
||||
// XXX This shortcut should also work when hovering over a card in board view
|
||||
Mousetrap.bind('c', evt => {
|
||||
if (!Session.get('currentCard')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const currentUserId = Meteor.userId();
|
||||
if (currentUserId === null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
Meteor.user().isBoardMember() &&
|
||||
!Meteor.user().isCommentOnly() &&
|
||||
!Meteor.user().isWorker()
|
||||
) {
|
||||
const card = Cards.findOne(Session.get('currentCard'));
|
||||
card.archive();
|
||||
// We should prevent scrolling in card when spacebar is clicked
|
||||
// This should do it according to Mousetrap docs, but it doesn't
|
||||
evt.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
Template.keyboardShortcuts.helpers({
|
||||
mapping: [
|
||||
{
|
||||
@@ -104,5 +128,9 @@ Template.keyboardShortcuts.helpers({
|
||||
keys: ['SPACE'],
|
||||
action: 'shortcut-assign-self',
|
||||
},
|
||||
{
|
||||
keys: ['C'],
|
||||
action: 'archive-card',
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -48,6 +48,11 @@ $.fn.escapeableTextComplete = function(strategies, options, ...otherArgs) {
|
||||
return this;
|
||||
};
|
||||
|
||||
EscapeActions.register('textcomplete', () => {}, () => dropdownMenuIsOpened, {
|
||||
noClickEscapeOn: '.textcomplete-dropdown',
|
||||
});
|
||||
EscapeActions.register(
|
||||
'textcomplete',
|
||||
() => {},
|
||||
() => dropdownMenuIsOpened,
|
||||
{
|
||||
noClickEscapeOn: '.textcomplete-dropdown',
|
||||
},
|
||||
);
|
||||
@@ -147,8 +147,38 @@ Utils = {
|
||||
// in a small window (even on desktop), Wekan run in compact mode.
|
||||
// we can easily debug with a small window of desktop browser. :-)
|
||||
isMiniScreen() {
|
||||
// OLD WINDOW WIDTH DETECTION:
|
||||
this.windowResizeDep.depend();
|
||||
return $(window).width() <= 800;
|
||||
|
||||
// NEW TOUCH DEVICE DETECTION:
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent
|
||||
|
||||
/*
|
||||
var hasTouchScreen = false;
|
||||
if ("maxTouchPoints" in navigator) {
|
||||
hasTouchScreen = navigator.maxTouchPoints > 0;
|
||||
} else if ("msMaxTouchPoints" in navigator) {
|
||||
hasTouchScreen = navigator.msMaxTouchPoints > 0;
|
||||
} else {
|
||||
var mQ = window.matchMedia && matchMedia("(pointer:coarse)");
|
||||
if (mQ && mQ.media === "(pointer:coarse)") {
|
||||
hasTouchScreen = !!mQ.matches;
|
||||
} else if ('orientation' in window) {
|
||||
hasTouchScreen = true; // deprecated, but good fallback
|
||||
} else {
|
||||
// Only as a last resort, fall back to user agent sniffing
|
||||
var UA = navigator.userAgent;
|
||||
hasTouchScreen = (
|
||||
/\b(BlackBerry|webOS|iPhone|IEMobile)\b/i.test(UA) ||
|
||||
/\b(Android|Windows Phone|iPad|iPod)\b/i.test(UA)
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
//if (hasTouchScreen)
|
||||
// document.getElementById("exampleButton").style.padding="1em";
|
||||
//return false;
|
||||
},
|
||||
|
||||
calculateIndexData(prevData, nextData, nItems = 1) {
|
||||
|
||||
+7
-3
@@ -38,9 +38,13 @@ AccountsTemplates.configure({
|
||||
},
|
||||
});
|
||||
|
||||
['signIn', 'signUp', 'resetPwd', 'forgotPwd', 'enrollAccount'].forEach(
|
||||
routeName => AccountsTemplates.configureRoute(routeName),
|
||||
);
|
||||
[
|
||||
'signIn',
|
||||
'signUp',
|
||||
'resetPwd',
|
||||
'forgotPwd',
|
||||
'enrollAccount',
|
||||
].forEach(routeName => AccountsTemplates.configureRoute(routeName));
|
||||
|
||||
// We display the form to change the password in a popup window that already
|
||||
// have a title, so we unset the title automatically displayed by useraccounts.
|
||||
|
||||
@@ -26,6 +26,27 @@ FlowRouter.route('/', {
|
||||
},
|
||||
});
|
||||
|
||||
FlowRouter.route('/public', {
|
||||
name: 'public',
|
||||
triggersEnter: [AccountsTemplates.ensureSignedIn],
|
||||
action() {
|
||||
Session.set('currentBoard', null);
|
||||
Session.set('currentList', null);
|
||||
Session.set('currentCard', null);
|
||||
|
||||
Filter.reset();
|
||||
EscapeActions.executeAll();
|
||||
|
||||
Utils.manageCustomUI();
|
||||
Utils.manageMatomo();
|
||||
|
||||
BlazeLayout.render('defaultLayout', {
|
||||
headerBar: 'boardListHeaderBar',
|
||||
content: 'boardList',
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
FlowRouter.route('/b/:id/:slug', {
|
||||
name: 'board',
|
||||
action(params) {
|
||||
|
||||
+47
-5
@@ -38,7 +38,7 @@ version: '2'
|
||||
# sudo service docker start
|
||||
# ----------------------------------------------------------------------------------
|
||||
# ==== USAGE OF THIS docker-compose.yml ====
|
||||
# 1) For seeing does Wekan work, try this and check with your webbroser:
|
||||
# 1) For seeing does Wekan work, try this and check with your web browser:
|
||||
# docker-compose up
|
||||
# 2) Stop Wekan and start Wekan in background:
|
||||
# docker-compose stop
|
||||
@@ -93,14 +93,14 @@ services:
|
||||
#-------------------------------------------------------------------------------------
|
||||
# ==== MONGODB AND METEOR VERSION ====
|
||||
# a) For Wekan Meteor 1.8.x version at master branch, use mongo 4.x
|
||||
image: mongo:4.0.12
|
||||
image: mongo:latest
|
||||
# b) For Wekan Meteor 1.6.x version at devel branch.
|
||||
# Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
|
||||
#image: mongo:3.2.21
|
||||
#-------------------------------------------------------------------------------------
|
||||
container_name: wekan-db
|
||||
restart: always
|
||||
command: mongod --smallfiles --oplogSize 128
|
||||
command: mongod --oplogSize 128
|
||||
networks:
|
||||
- wekan-tier
|
||||
expose:
|
||||
@@ -238,7 +238,12 @@ services:
|
||||
#---------------------------------------------------------------
|
||||
# ==== RICH TEXT EDITOR IN CARD COMMENTS ====
|
||||
# https://github.com/wekan/wekan/pull/2560
|
||||
- RICHER_CARD_COMMENT_EDITOR=true
|
||||
- RICHER_CARD_COMMENT_EDITOR=false
|
||||
#---------------------------------------------------------------
|
||||
# ==== MOUSE SCROLL ====
|
||||
# https://github.com/wekan/wekan/issues/2949
|
||||
- SCROLLINERTIA=0
|
||||
- SCROLLAMOUNT=auto
|
||||
#---------------------------------------------------------------
|
||||
# ==== CARD OPENED, SEND WEBHOOK MESSAGE ====
|
||||
# https://github.com/wekan/wekan/issues/2518
|
||||
@@ -249,6 +254,11 @@ services:
|
||||
#-MAX_IMAGE_PIXEL=1024
|
||||
#-IMAGE_COMPRESS_RATIO=80
|
||||
#---------------------------------------------------------------
|
||||
# ==== NOTIFICATION TRAY AFTER READ DAYS BEFORE REMOVE =====
|
||||
# Number of days after a notification is read before we remove it.
|
||||
# Default: 2
|
||||
#- NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE=2
|
||||
#---------------------------------------------------------------
|
||||
# ==== BIGEVENTS DUE ETC NOTIFICATIONS =====
|
||||
# https://github.com/wekan/wekan/pull/2541
|
||||
# Introduced a system env var BIGEVENTS_PATTERN default as "NONE",
|
||||
@@ -342,6 +352,31 @@ services:
|
||||
# Tthe claim name you want to map to the email field:
|
||||
#- OAUTH2_EMAIL_MAP=email
|
||||
#-----------------------------------------------------------------
|
||||
# ==== OAUTH2 Nextcloud ====
|
||||
# 1) Register the application with Nextcloud: https://your.nextcloud/settings/admin/security
|
||||
# Make sure you capture the application ID as well as generate a secret key.
|
||||
# 2) Configure the environment variables. This differs slightly
|
||||
# by installation type, but make sure you have the following:
|
||||
#- OAUTH2_ENABLED=true
|
||||
# OAuth2 login style: popup or redirect.
|
||||
#- OAUTH2_LOGIN_STYLE=redirect
|
||||
# Application GUID captured during app registration:
|
||||
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
|
||||
# Secret key generated during app registration:
|
||||
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
|
||||
#- OAUTH2_SERVER_URL=https://your-nextcloud.tld
|
||||
#- OAUTH2_AUTH_ENDPOINT=/index.php/apps/oauth2/authorize
|
||||
#- OAUTH2_USERINFO_ENDPOINT=/ocs/v2.php/cloud/user?format=json
|
||||
#- OAUTH2_TOKEN_ENDPOINT=/index.php/apps/oauth2/api/v1/token
|
||||
# The claim name you want to map to the unique ID field:
|
||||
#- OAUTH2_ID_MAP=id
|
||||
# The claim name you want to map to the username field:
|
||||
#- OAUTH2_USERNAME_MAP=id
|
||||
# The claim name you want to map to the full name field:
|
||||
#- OAUTH2_FULLNAME_MAP=display-name
|
||||
# Tthe claim name you want to map to the email field:
|
||||
#- OAUTH2_EMAIL_MAP=email
|
||||
#-----------------------------------------------------------------
|
||||
# ==== OAUTH2 KEYCLOAK ====
|
||||
# https://github.com/wekan/wekan/wiki/Keycloak <== MAPPING INFO, REQUIRED
|
||||
#- OAUTH2_ENABLED=true
|
||||
@@ -479,18 +514,22 @@ services:
|
||||
# The limit number of entries (0=unlimited)
|
||||
#- LDAP_SEARCH_SIZE_LIMIT=0
|
||||
#
|
||||
# Enable group filtering
|
||||
# Enable group filtering. Note the authenticated ldap user must be able to query all relevant group data with own login data from ldap.
|
||||
#- LDAP_GROUP_FILTER_ENABLE=false
|
||||
#
|
||||
# The object class for filtering. Example: group
|
||||
#- LDAP_GROUP_FILTER_OBJECTCLASS=
|
||||
#
|
||||
# The attribute of a group identifying it. Example: cn
|
||||
#- LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=
|
||||
#
|
||||
# The attribute inside a group object listing its members. Example: member
|
||||
#- LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=
|
||||
#
|
||||
# The format of the value of LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE. Example: 'dn' if the users dn ist saved as value into the attribute.
|
||||
#- LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=
|
||||
#
|
||||
# The group name (id) that matches all users.
|
||||
#- LDAP_GROUP_FILTER_GROUP_NAME=
|
||||
#
|
||||
# LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier). Example: guid
|
||||
@@ -559,6 +598,9 @@ services:
|
||||
# example : LOGOUT_ON_MINUTES=55
|
||||
#- LOGOUT_ON_MINUTES=
|
||||
#-------------------------------------------------------------------
|
||||
# Hide password login form
|
||||
# - PASSWORD_LOGIN_ENABLED=true
|
||||
#-------------------------------------------------------------------
|
||||
depends_on:
|
||||
- wekandb
|
||||
|
||||
|
||||
@@ -451,14 +451,14 @@ FS.HTTP.Handlers.Get = function (ref) {
|
||||
if(userAgent.indexOf('msie') >= 0 || userAgent.indexOf('trident') >= 0 || userAgent.indexOf('chrome') >= 0) {
|
||||
ref.filename = encodeURIComponent(ref.filename);
|
||||
} else if(userAgent.indexOf('firefox') >= 0) {
|
||||
ref.filename = new Buffer(ref.filename).toString('binary');
|
||||
ref.filename = Buffer.from(ref.filename).toString('binary');
|
||||
} else {
|
||||
/* safari*/
|
||||
ref.filename = new Buffer(ref.filename).toString('binary');
|
||||
}
|
||||
ref.filename = Buffer.from(ref.filename).toString('binary');
|
||||
}
|
||||
} catch (ex){
|
||||
ref.filename = 'tempfix';
|
||||
}
|
||||
}
|
||||
return originalHandler.call(this, ref);
|
||||
};
|
||||
// 221
|
||||
|
||||
@@ -56,3 +56,10 @@ mongodb-replicaset:
|
||||
This section controls the scale of the MongoDB redundant Replica Set.
|
||||
|
||||
**replicas:** This is the number of MongoDB instances to include in the set. You can set this to 1 for a single server - this will still allow you to scale-up later with a helm upgrade.
|
||||
|
||||
### Install OCP route
|
||||
If you use this chart to deploy Wekan on an OCP cluster, you can create route instead of ingress with following command:
|
||||
|
||||
``` bash
|
||||
$ helm template --set route.enabled=true,ingress.enabled=false values.yaml . | oc apply -f-
|
||||
```
|
||||
@@ -37,6 +37,12 @@ spec:
|
||||
value: {{ .Values.root_url | default "https://wekan.local" | quote }}
|
||||
- name: MONGO_URL
|
||||
value: "{{ template "mongodb-replicaset.url" . }}"
|
||||
{{- range $key := .Values.env }}
|
||||
{{- if .value }}
|
||||
- name: {{ .name }}
|
||||
value: {{ .value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
{{- if .Values.route.enabled -}}
|
||||
{{- $fullName := include "wekan.fullname" . -}}
|
||||
apiVersion: route.openshift.io/v1
|
||||
kind: Route
|
||||
metadata:
|
||||
annotations:
|
||||
haproxy.router.openshift.io/timeout: 4m
|
||||
openshift.io/host.generated: "true"
|
||||
labels:
|
||||
app: {{ template "wekan.name" . }}
|
||||
service: {{ template "wekan.name" . }}
|
||||
name: {{ template "wekan.name" . }}
|
||||
spec:
|
||||
port:
|
||||
targetPort: http
|
||||
tls:
|
||||
termination: edge
|
||||
to:
|
||||
kind: Service
|
||||
name: {{ template "wekan.name" . }}
|
||||
weight: 100
|
||||
wildcardPolicy: None
|
||||
{{- end }}
|
||||
@@ -2,6 +2,10 @@
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
{{- if .Values.serviceAccounts.annotations }}
|
||||
annotations:
|
||||
{{ .Values.serviceAccounts.annotations | indent 4}}
|
||||
{{- end }}
|
||||
labels:
|
||||
app: {{ template "wekan.name" . }}
|
||||
chart: {{ template "wekan.chart" . }}
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
serviceAccounts:
|
||||
create: true
|
||||
name: ""
|
||||
annotations: ""
|
||||
|
||||
## Wekan image configuration
|
||||
##
|
||||
@@ -29,7 +30,9 @@ credentials:
|
||||
|
||||
## Specify additional environmental variables for the Deployment
|
||||
##
|
||||
env: {}
|
||||
env:
|
||||
- name: ""
|
||||
value: ""
|
||||
|
||||
service:
|
||||
type: NodePort
|
||||
@@ -59,7 +62,10 @@ ingress:
|
||||
# hosts:
|
||||
# - wekan-example.local
|
||||
|
||||
resources:
|
||||
route:
|
||||
enabled: false
|
||||
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
cpu: 300m
|
||||
|
||||
+62
-31
@@ -64,7 +64,7 @@
|
||||
"activity-unchecked-item": "ازالة تحقق %s من قائمة التحقق %s من %s",
|
||||
"activity-checklist-added": "أضاف قائمة تحقق إلى %s",
|
||||
"activity-checklist-removed": "ازالة قائمة التحقق من %s",
|
||||
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
|
||||
"activity-checklist-completed": "completed checklist %s of %s",
|
||||
"activity-checklist-uncompleted": "لم يتم انجاز قائمة التحقق %s من %s",
|
||||
"activity-checklist-item-added": "تم اضافة عنصر قائمة التحقق الى '%s' في %s",
|
||||
"activity-checklist-item-removed": "تم ازالة عنصر قائمة التحقق الى '%s' في %s",
|
||||
@@ -74,12 +74,12 @@
|
||||
"activity-checklist-completed-card": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
|
||||
"activity-checklist-uncompleted-card": "uncompleted the checklist %s",
|
||||
"activity-editComment": "edited comment %s",
|
||||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-deleteComment": "تعليق محذوف %s",
|
||||
"add-attachment": "إضافة مرفق",
|
||||
"add-board": "إضافة لوحة",
|
||||
"add-card": "إضافة بطاقة",
|
||||
"add-swimlane": "Add Swimlane",
|
||||
"add-subtask": "Add Subtask",
|
||||
"add-subtask": "إضافة مهمة فرعية",
|
||||
"add-checklist": "إضافة قائمة تدقيق",
|
||||
"add-checklist-item": "إضافة عنصر إلى قائمة التحقق",
|
||||
"add-cover": "إضافة غلاف",
|
||||
@@ -111,8 +111,8 @@
|
||||
"restore-board": "استعادة اللوحة",
|
||||
"no-archived-boards": "لا توجد لوحات في الأرشيف.",
|
||||
"archives": "أرشيف",
|
||||
"template": "Template",
|
||||
"templates": "Templates",
|
||||
"template": "نموذج",
|
||||
"templates": "نماذج",
|
||||
"assign-member": "تعيين عضو",
|
||||
"attached": "أُرفق)",
|
||||
"attachment": "مرفق",
|
||||
@@ -152,6 +152,8 @@
|
||||
"card-spent": "امضى وقتا",
|
||||
"card-edit-attachments": "تعديل المرفقات",
|
||||
"card-edit-custom-fields": "تعديل الحقل المعدل",
|
||||
"card-start-voting": "ابدأ التصويت",
|
||||
"card-cancel-voting": "حذف التصويت وجميع الأصوات",
|
||||
"card-edit-labels": "تعديل العلامات",
|
||||
"card-edit-members": "تعديل الأعضاء",
|
||||
"card-labels-title": "تعديل علامات البطاقة.",
|
||||
@@ -161,6 +163,14 @@
|
||||
"cardAttachmentsPopup-title": "إرفاق من",
|
||||
"cardCustomField-datePopup-title": "تغير التاريخ",
|
||||
"cardCustomFieldsPopup-title": "تعديل الحقل المعدل",
|
||||
"cardStartVotingPopup-title": "ابدأ تصويت",
|
||||
"positiveVoteMembersPopup-title": "Proponents",
|
||||
"negativeVoteMembersPopup-title": "Opponents",
|
||||
"allowNonBoardMembers": "Allow anonymous vote on public board",
|
||||
"vote-question": "Voting question",
|
||||
"vote-public": "Show who voted what",
|
||||
"vote-for-it": "مع",
|
||||
"vote-against": "ضد",
|
||||
"cardDeletePopup-title": "حذف البطاقة ?",
|
||||
"cardDetailsActionsPopup-title": "إجراءات على البطاقة",
|
||||
"cardLabelsPopup-title": "علامات",
|
||||
@@ -183,7 +193,7 @@
|
||||
"changePasswordPopup-title": "تغيير كلمة المرور",
|
||||
"changePermissionsPopup-title": "تعديل الصلاحيات",
|
||||
"changeSettingsPopup-title": "تغيير الاعدادات",
|
||||
"subtasks": "Subtasks",
|
||||
"subtasks": "المهمات الفرعية",
|
||||
"checklists": "قوائم التّدقيق",
|
||||
"click-to-star": "اضغط لإضافة اللوحة للمفضلة.",
|
||||
"click-to-unstar": "اضغط لحذف اللوحة من المفضلة.",
|
||||
@@ -194,9 +204,9 @@
|
||||
"color-black": "black",
|
||||
"color-blue": "blue",
|
||||
"color-crimson": "crimson",
|
||||
"color-darkgreen": "darkgreen",
|
||||
"color-gold": "gold",
|
||||
"color-gray": "gray",
|
||||
"color-darkgreen": "اخضر غامق",
|
||||
"color-gold": "ذهبي",
|
||||
"color-gray": "رمادي",
|
||||
"color-green": "green",
|
||||
"color-indigo": "indigo",
|
||||
"color-lime": "lime",
|
||||
@@ -211,17 +221,17 @@
|
||||
"color-purple": "purple",
|
||||
"color-red": "red",
|
||||
"color-saddlebrown": "saddlebrown",
|
||||
"color-silver": "silver",
|
||||
"color-silver": "فضي",
|
||||
"color-sky": "sky",
|
||||
"color-slateblue": "slateblue",
|
||||
"color-white": "white",
|
||||
"color-white": "أبيض",
|
||||
"color-yellow": "yellow",
|
||||
"unset-color": "Unset",
|
||||
"comment": "تعليق",
|
||||
"comment-placeholder": "أكتب تعليق",
|
||||
"comment-only": "التعليق فقط",
|
||||
"comment-only-desc": "يمكن التعليق على بطاقات فقط.",
|
||||
"no-comments": "No comments",
|
||||
"no-comments": "لا يوجد تعليقات",
|
||||
"no-comments-desc": "Can not see comments and activities.",
|
||||
"worker": "Worker",
|
||||
"worker-desc": "Can only move cards, assign itself to card and comment.",
|
||||
@@ -239,8 +249,8 @@
|
||||
"createBoardPopup-title": "إنشاء لوحة",
|
||||
"chooseBoardSourcePopup-title": "استيراد لوحة",
|
||||
"createLabelPopup-title": "إنشاء علامة",
|
||||
"createCustomField": "Create Field",
|
||||
"createCustomFieldPopup-title": "Create Field",
|
||||
"createCustomField": "انشاء حقل",
|
||||
"createCustomFieldPopup-title": "انشاء حقل",
|
||||
"current": "الحالي",
|
||||
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
|
||||
"custom-field-checkbox": "Checkbox",
|
||||
@@ -250,8 +260,8 @@
|
||||
"custom-field-dropdown-options": "List Options",
|
||||
"custom-field-dropdown-options-placeholder": "Press enter to add more options",
|
||||
"custom-field-dropdown-unknown": "(unknown)",
|
||||
"custom-field-number": "Number",
|
||||
"custom-field-text": "Text",
|
||||
"custom-field-number": "رقم",
|
||||
"custom-field-text": "نص",
|
||||
"custom-fields": "Custom Fields",
|
||||
"date": "تاريخ",
|
||||
"decline": "Decline",
|
||||
@@ -319,6 +329,7 @@
|
||||
"filter-clear": "مسح التصفية",
|
||||
"filter-no-label": "لا يوجد ملصق",
|
||||
"filter-no-member": "ليس هناك أي عضو",
|
||||
"filter-no-assignee": "No assignee",
|
||||
"filter-no-custom-fields": "No Custom Fields",
|
||||
"filter-show-archive": "Show archived lists",
|
||||
"filter-hide-empty": "Hide empty lists",
|
||||
@@ -333,13 +344,11 @@
|
||||
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
|
||||
"home": "الرئيسية",
|
||||
"import": "Import",
|
||||
"link": "Link",
|
||||
"link": "رابط",
|
||||
"import-board": "استيراد لوحة",
|
||||
"import-board-c": "استيراد لوحة",
|
||||
"import-board-title-trello": "Import board from Trello",
|
||||
"import-board-title-wekan": "Import board from previous export",
|
||||
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
|
||||
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
|
||||
"from-trello": "من تريلو",
|
||||
"from-wekan": "From previous export",
|
||||
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
|
||||
@@ -440,7 +449,7 @@
|
||||
"save": "حفظ",
|
||||
"search": "بحث",
|
||||
"rules": "Rules",
|
||||
"search-cards": "Search from card/list titles and descriptions on this board",
|
||||
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
|
||||
"search-example": "Text to search for?",
|
||||
"select-color": "اختيار اللون",
|
||||
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
|
||||
@@ -466,15 +475,15 @@
|
||||
"this-board": "هذه اللوحة",
|
||||
"this-card": "هذه البطاقة",
|
||||
"spent-time-hours": "Spent time (hours)",
|
||||
"overtime-hours": "Overtime (hours)",
|
||||
"overtime": "Overtime",
|
||||
"overtime-hours": "وقت اضافي (ساعات)",
|
||||
"overtime": "وقت اضافي",
|
||||
"has-overtime-cards": "Has overtime cards",
|
||||
"has-spenttime-cards": "Has spent time cards",
|
||||
"time": "الوقت",
|
||||
"title": "عنوان",
|
||||
"tracking": "تتبع",
|
||||
"tracking-info": "You will be notified of any changes to those cards you are involved as creator or member.",
|
||||
"type": "Type",
|
||||
"type": "النوع",
|
||||
"unassign-member": "إلغاء تعيين العضو",
|
||||
"unsaved-description": "لديك وصف غير محفوظ",
|
||||
"unwatch": "غير مُشاهد",
|
||||
@@ -548,7 +557,7 @@
|
||||
"OS_Totalmem": "الذاكرة الكلية لنظام التشغيل",
|
||||
"OS_Type": "نوع نظام التشغيل",
|
||||
"OS_Uptime": "مدة تشغيل نظام التشغيل",
|
||||
"days": "days",
|
||||
"days": "أيام",
|
||||
"hours": "الساعات",
|
||||
"minutes": "الدقائق",
|
||||
"seconds": "الثواني",
|
||||
@@ -562,17 +571,17 @@
|
||||
"accounts-allowUserNameChange": "Allow Username Change",
|
||||
"createdAt": "Created at",
|
||||
"verified": "Verified",
|
||||
"active": "Active",
|
||||
"active": "نشط",
|
||||
"card-received": "Received",
|
||||
"card-received-on": "Received on",
|
||||
"card-end": "End",
|
||||
"card-end-on": "Ends on",
|
||||
"editCardReceivedDatePopup-title": "Change received date",
|
||||
"editCardEndDatePopup-title": "Change end date",
|
||||
"setCardColorPopup-title": "Set color",
|
||||
"setCardActionsColorPopup-title": "Choose a color",
|
||||
"setSwimlaneColorPopup-title": "Choose a color",
|
||||
"setListColorPopup-title": "Choose a color",
|
||||
"setCardColorPopup-title": "حدد اللون",
|
||||
"setCardActionsColorPopup-title": "اختر لوناً",
|
||||
"setSwimlaneColorPopup-title": "اختر لوناً",
|
||||
"setListColorPopup-title": "اختر لوناً",
|
||||
"assigned-by": "Assigned By",
|
||||
"requested-by": "Requested By",
|
||||
"board-delete-notice": "Deleting is permanent. You will lose all lists, cards and actions associated with this board.",
|
||||
@@ -583,8 +592,9 @@
|
||||
"default": "Default",
|
||||
"queue": "Queue",
|
||||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"show-subtasks-field": "Cards can have subtasks",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
"deposit-subtasks-list": "Landing list for subtasks deposited here:",
|
||||
"show-parent-in-minicard": "Show parent in minicard:",
|
||||
@@ -664,6 +674,7 @@
|
||||
"r-of-checklist": "of checklist",
|
||||
"r-send-email": "Send an email",
|
||||
"r-to": "to",
|
||||
"r-of": "of",
|
||||
"r-subject": "subject",
|
||||
"r-rule-details": "Rule details",
|
||||
"r-d-move-to-top-gen": "Move card to top of its list",
|
||||
@@ -753,5 +764,25 @@
|
||||
"hide-minicard-label-text": "Hide minicard label text",
|
||||
"show-desktop-drag-handles": "Show desktop drag handles",
|
||||
"assignee": "Assignee",
|
||||
"cardAssigneesPopup-title": "Assignee"
|
||||
"cardAssigneesPopup-title": "Assignee",
|
||||
"addmore-detail": "Add a more detailed description",
|
||||
"show-on-card": "Show on Card",
|
||||
"new": "New",
|
||||
"editUserPopup-title": "Edit User",
|
||||
"newUserPopup-title": "New User",
|
||||
"notifications": "Notifications",
|
||||
"view-all": "View All",
|
||||
"filter-by-unread": "Filter by Unread",
|
||||
"mark-all-as-read": "Mark all as read",
|
||||
"remove-all-read": "Remove all read",
|
||||
"allow-rename": "Allow Rename",
|
||||
"allowRenamePopup-title": "Allow Rename",
|
||||
"start-day-of-week": "Set day of the week start",
|
||||
"monday": "Monday",
|
||||
"tuesday": "Tuesday",
|
||||
"wednesday": "Wednesday",
|
||||
"thursday": "Thursday",
|
||||
"friday": "Friday",
|
||||
"saturday": "Saturday",
|
||||
"sunday": "Sunday"
|
||||
}
|
||||
+37
-6
@@ -64,7 +64,7 @@
|
||||
"activity-unchecked-item": "размаркира %s от списък със задачи %s на %s",
|
||||
"activity-checklist-added": "добави списък със задачи към %s",
|
||||
"activity-checklist-removed": "премахна списък със задачи от %s",
|
||||
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
|
||||
"activity-checklist-completed": "completed checklist %s of %s",
|
||||
"activity-checklist-uncompleted": "\"отзавърши\" чеклистта %s в %s",
|
||||
"activity-checklist-item-added": "добави точка към '%s' в/във %s",
|
||||
"activity-checklist-item-removed": "премахна точка от '%s' в %s",
|
||||
@@ -152,6 +152,8 @@
|
||||
"card-spent": "Изработено време",
|
||||
"card-edit-attachments": "Промени прикачените файлове",
|
||||
"card-edit-custom-fields": "Промени собствените полета",
|
||||
"card-start-voting": "Start voting",
|
||||
"card-cancel-voting": "Delete voting and all votes",
|
||||
"card-edit-labels": "Промени етикетите",
|
||||
"card-edit-members": "Промени членовете",
|
||||
"card-labels-title": "Промени етикетите за картата.",
|
||||
@@ -161,6 +163,14 @@
|
||||
"cardAttachmentsPopup-title": "Прикачи от",
|
||||
"cardCustomField-datePopup-title": "Промени датата",
|
||||
"cardCustomFieldsPopup-title": "Промени собствените полета",
|
||||
"cardStartVotingPopup-title": "Start a vote",
|
||||
"positiveVoteMembersPopup-title": "Proponents",
|
||||
"negativeVoteMembersPopup-title": "Opponents",
|
||||
"allowNonBoardMembers": "Allow anonymous vote on public board",
|
||||
"vote-question": "Voting question",
|
||||
"vote-public": "Show who voted what",
|
||||
"vote-for-it": "for it",
|
||||
"vote-against": "against",
|
||||
"cardDeletePopup-title": "Желаете да изтриете картата?",
|
||||
"cardDetailsActionsPopup-title": "Опции",
|
||||
"cardLabelsPopup-title": "Етикети",
|
||||
@@ -319,6 +329,7 @@
|
||||
"filter-clear": "Премахване на филтрите",
|
||||
"filter-no-label": "без етикет",
|
||||
"filter-no-member": "без член",
|
||||
"filter-no-assignee": "No assignee",
|
||||
"filter-no-custom-fields": "Няма Собствени полета",
|
||||
"filter-show-archive": "Show archived lists",
|
||||
"filter-hide-empty": "Hide empty lists",
|
||||
@@ -338,8 +349,6 @@
|
||||
"import-board-c": "Импортирай Табло",
|
||||
"import-board-title-trello": "Импорт на табло от Trello",
|
||||
"import-board-title-wekan": "Import board from previous export",
|
||||
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
|
||||
"import-sandstorm-warning": "Импортирането ще изтрие всичката налична информация в таблото и ще я замени с нова.",
|
||||
"from-trello": "От Trello",
|
||||
"from-wekan": "From previous export",
|
||||
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
|
||||
@@ -440,7 +449,7 @@
|
||||
"save": "Запази",
|
||||
"search": "Търсене",
|
||||
"rules": "Правила",
|
||||
"search-cards": "Search from card/list titles and descriptions on this board",
|
||||
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
|
||||
"search-example": "Text to search for?",
|
||||
"select-color": "Избери цвят",
|
||||
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
|
||||
@@ -583,8 +592,9 @@
|
||||
"default": "по подразбиране",
|
||||
"queue": "Опашка",
|
||||
"subtask-settings": "Настройки на Подзадачите",
|
||||
"card-settings": "Card Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Настройки за Подзадачите за това Табло",
|
||||
"show-subtasks-field": "Картата може да има подзадачи",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
"deposit-subtasks-list": "Landing list for subtasks deposited here:",
|
||||
"show-parent-in-minicard": "Show parent in minicard:",
|
||||
@@ -664,6 +674,7 @@
|
||||
"r-of-checklist": "of checklist",
|
||||
"r-send-email": "Send an email",
|
||||
"r-to": "to",
|
||||
"r-of": "of",
|
||||
"r-subject": "subject",
|
||||
"r-rule-details": "Детайли за правилото",
|
||||
"r-d-move-to-top-gen": "Move card to top of its list",
|
||||
@@ -753,5 +764,25 @@
|
||||
"hide-minicard-label-text": "Hide minicard label text",
|
||||
"show-desktop-drag-handles": "Show desktop drag handles",
|
||||
"assignee": "Assignee",
|
||||
"cardAssigneesPopup-title": "Assignee"
|
||||
"cardAssigneesPopup-title": "Assignee",
|
||||
"addmore-detail": "Add a more detailed description",
|
||||
"show-on-card": "Show on Card",
|
||||
"new": "New",
|
||||
"editUserPopup-title": "Edit User",
|
||||
"newUserPopup-title": "New User",
|
||||
"notifications": "Notifications",
|
||||
"view-all": "View All",
|
||||
"filter-by-unread": "Filter by Unread",
|
||||
"mark-all-as-read": "Mark all as read",
|
||||
"remove-all-read": "Remove all read",
|
||||
"allow-rename": "Allow Rename",
|
||||
"allowRenamePopup-title": "Allow Rename",
|
||||
"start-day-of-week": "Set day of the week start",
|
||||
"monday": "Monday",
|
||||
"tuesday": "Tuesday",
|
||||
"wednesday": "Wednesday",
|
||||
"thursday": "Thursday",
|
||||
"friday": "Friday",
|
||||
"saturday": "Saturday",
|
||||
"sunday": "Sunday"
|
||||
}
|
||||
+37
-6
@@ -64,7 +64,7 @@
|
||||
"activity-unchecked-item": "unchecked %s in checklist %s of %s",
|
||||
"activity-checklist-added": "added checklist to %s",
|
||||
"activity-checklist-removed": "removed a checklist from %s",
|
||||
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
|
||||
"activity-checklist-completed": "completed checklist %s of %s",
|
||||
"activity-checklist-uncompleted": "uncompleted the checklist %s of %s",
|
||||
"activity-checklist-item-added": "added checklist item to '%s' in %s",
|
||||
"activity-checklist-item-removed": "removed a checklist item from '%s' in %s",
|
||||
@@ -152,6 +152,8 @@
|
||||
"card-spent": "Spent Time",
|
||||
"card-edit-attachments": "Edit attachments",
|
||||
"card-edit-custom-fields": "Edit custom fields",
|
||||
"card-start-voting": "Start voting",
|
||||
"card-cancel-voting": "Delete voting and all votes",
|
||||
"card-edit-labels": "Edit labels",
|
||||
"card-edit-members": "Edit members",
|
||||
"card-labels-title": "Change the labels for the card.",
|
||||
@@ -161,6 +163,14 @@
|
||||
"cardAttachmentsPopup-title": "Attach From",
|
||||
"cardCustomField-datePopup-title": "Change date",
|
||||
"cardCustomFieldsPopup-title": "Edit custom fields",
|
||||
"cardStartVotingPopup-title": "Start a vote",
|
||||
"positiveVoteMembersPopup-title": "Proponents",
|
||||
"negativeVoteMembersPopup-title": "Opponents",
|
||||
"allowNonBoardMembers": "Allow anonymous vote on public board",
|
||||
"vote-question": "Voting question",
|
||||
"vote-public": "Show who voted what",
|
||||
"vote-for-it": "for it",
|
||||
"vote-against": "against",
|
||||
"cardDeletePopup-title": "Diverkañ ar gartenn ?",
|
||||
"cardDetailsActionsPopup-title": "Card Actions",
|
||||
"cardLabelsPopup-title": "Labels",
|
||||
@@ -319,6 +329,7 @@
|
||||
"filter-clear": "Clear filter",
|
||||
"filter-no-label": "No label",
|
||||
"filter-no-member": "No member",
|
||||
"filter-no-assignee": "No assignee",
|
||||
"filter-no-custom-fields": "No Custom Fields",
|
||||
"filter-show-archive": "Show archived lists",
|
||||
"filter-hide-empty": "Hide empty lists",
|
||||
@@ -338,8 +349,6 @@
|
||||
"import-board-c": "Import board",
|
||||
"import-board-title-trello": "Import board from Trello",
|
||||
"import-board-title-wekan": "Import board from previous export",
|
||||
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
|
||||
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
|
||||
"from-trello": "From Trello",
|
||||
"from-wekan": "From previous export",
|
||||
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
|
||||
@@ -440,7 +449,7 @@
|
||||
"save": "Save",
|
||||
"search": "Search",
|
||||
"rules": "Rules",
|
||||
"search-cards": "Search from card/list titles and descriptions on this board",
|
||||
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
|
||||
"search-example": "Text to search for?",
|
||||
"select-color": "Select Color",
|
||||
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
|
||||
@@ -583,8 +592,9 @@
|
||||
"default": "Default",
|
||||
"queue": "Queue",
|
||||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"show-subtasks-field": "Cards can have subtasks",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
"deposit-subtasks-list": "Landing list for subtasks deposited here:",
|
||||
"show-parent-in-minicard": "Show parent in minicard:",
|
||||
@@ -664,6 +674,7 @@
|
||||
"r-of-checklist": "of checklist",
|
||||
"r-send-email": "Send an email",
|
||||
"r-to": "to",
|
||||
"r-of": "of",
|
||||
"r-subject": "subject",
|
||||
"r-rule-details": "Rule details",
|
||||
"r-d-move-to-top-gen": "Move card to top of its list",
|
||||
@@ -753,5 +764,25 @@
|
||||
"hide-minicard-label-text": "Hide minicard label text",
|
||||
"show-desktop-drag-handles": "Show desktop drag handles",
|
||||
"assignee": "Assignee",
|
||||
"cardAssigneesPopup-title": "Assignee"
|
||||
"cardAssigneesPopup-title": "Assignee",
|
||||
"addmore-detail": "Add a more detailed description",
|
||||
"show-on-card": "Show on Card",
|
||||
"new": "New",
|
||||
"editUserPopup-title": "Edit User",
|
||||
"newUserPopup-title": "New User",
|
||||
"notifications": "Notifications",
|
||||
"view-all": "View All",
|
||||
"filter-by-unread": "Filter by Unread",
|
||||
"mark-all-as-read": "Mark all as read",
|
||||
"remove-all-read": "Remove all read",
|
||||
"allow-rename": "Allow Rename",
|
||||
"allowRenamePopup-title": "Allow Rename",
|
||||
"start-day-of-week": "Set day of the week start",
|
||||
"monday": "Monday",
|
||||
"tuesday": "Tuesday",
|
||||
"wednesday": "Wednesday",
|
||||
"thursday": "Thursday",
|
||||
"friday": "Friday",
|
||||
"saturday": "Saturday",
|
||||
"sunday": "Sunday"
|
||||
}
|
||||
Loaded 100 of 410 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user