Bläddra i källkod

Merge remote-tracking branch 'myorigin/master' into develop

Unknown 5 år sedan
förälder
incheckning
8bf13f43e8
100 ändrade filer med 1522 tillägg och 764 borttagningar
  1. 1 1
      .devcontainer/Dockerfile
  2. 1 1
      .future-snap/broken-snapcraft.yaml
  3. 1 1
      .future-snap/snapcraft.yaml
  4. 1 0
      .meteor/packages
  5. 10 9
      .meteor/versions
  6. 1 1
      .travis.yml
  7. 197 0
      CHANGELOG.md
  8. 1 1
      Dockerfile
  9. 2 2
      Dockerfile.arm64v8
  10. 1 1
      Stackerfile.yml
  11. 28 28
      client/components/activities/activities.jade
  12. 25 14
      client/components/activities/activities.js
  13. 10 10
      client/components/boards/boardHeader.jade
  14. 0 6
      client/components/boards/boardsList.js
  15. 8 2
      client/components/cards/cardDetails.jade
  16. 3 19
      client/components/cards/cardDetails.js
  17. 14 4
      client/components/cards/checklists.jade
  18. 16 0
      client/components/cards/checklists.js
  19. 16 0
      client/components/cards/checklists.styl
  20. 2 2
      client/components/cards/minicard.jade
  21. 8 1
      client/components/cards/minicard.styl
  22. 1 1
      client/components/rules/actions/cardActions.jade
  23. 2 1
      client/components/swimlanes/swimlaneHeader.jade
  24. 1 1
      client/components/swimlanes/swimlanes.js
  25. 13 5
      client/lib/utils.js
  26. 3 3
      docker-compose.yml
  27. 5 0
      find-replace.sh
  28. 2 1
      i18n/ar.i18n.json
  29. 2 1
      i18n/bg.i18n.json
  30. 2 1
      i18n/br.i18n.json
  31. 2 1
      i18n/ca.i18n.json
  32. 2 1
      i18n/cs.i18n.json
  33. 2 1
      i18n/da.i18n.json
  34. 3 2
      i18n/de.i18n.json
  35. 2 1
      i18n/el.i18n.json
  36. 2 1
      i18n/en-GB.i18n.json
  37. 2 1
      i18n/en.i18n.json
  38. 2 1
      i18n/eo.i18n.json
  39. 2 1
      i18n/es-AR.i18n.json
  40. 2 1
      i18n/es-CL.i18n.json
  41. 2 1
      i18n/es.i18n.json
  42. 2 1
      i18n/eu.i18n.json
  43. 10 9
      i18n/fa.i18n.json
  44. 2 1
      i18n/fi.i18n.json
  45. 2 1
      i18n/fr.i18n.json
  46. 2 1
      i18n/gl.i18n.json
  47. 2 1
      i18n/he.i18n.json
  48. 2 1
      i18n/hi.i18n.json
  49. 2 1
      i18n/hu.i18n.json
  50. 2 1
      i18n/hy.i18n.json
  51. 177 176
      i18n/id.i18n.json
  52. 2 1
      i18n/ig.i18n.json
  53. 4 3
      i18n/it.i18n.json
  54. 2 1
      i18n/ja.i18n.json
  55. 2 1
      i18n/ka.i18n.json
  56. 2 1
      i18n/km.i18n.json
  57. 2 1
      i18n/ko.i18n.json
  58. 2 1
      i18n/lv.i18n.json
  59. 2 1
      i18n/mk.i18n.json
  60. 2 1
      i18n/mn.i18n.json
  61. 2 1
      i18n/nb.i18n.json
  62. 4 3
      i18n/nl.i18n.json
  63. 2 1
      i18n/oc.i18n.json
  64. 2 1
      i18n/pl.i18n.json
  65. 2 1
      i18n/pt-BR.i18n.json
  66. 2 1
      i18n/pt.i18n.json
  67. 2 1
      i18n/ro.i18n.json
  68. 4 3
      i18n/ru.i18n.json
  69. 2 1
      i18n/sl.i18n.json
  70. 2 1
      i18n/sr.i18n.json
  71. 2 1
      i18n/sv.i18n.json
  72. 2 1
      i18n/sw.i18n.json
  73. 2 1
      i18n/ta.i18n.json
  74. 2 1
      i18n/th.i18n.json
  75. 26 25
      i18n/tr.i18n.json
  76. 2 1
      i18n/uk.i18n.json
  77. 2 1
      i18n/vi.i18n.json
  78. 4 3
      i18n/zh-CN.i18n.json
  79. 2 1
      i18n/zh-HK.i18n.json
  80. 2 1
      i18n/zh-TW.i18n.json
  81. 12 8
      models/boards.js
  82. 100 54
      models/cards.js
  83. 9 1
      models/checklistItems.js
  84. 5 7
      models/customFields.js
  85. 3 1
      models/export.js
  86. 30 24
      models/exporter.js
  87. 45 19
      models/users.js
  88. 14 3
      openapi/generate_openapi.py
  89. 2 16
      openshift/wekan.yml
  90. 540 191
      package-lock.json
  91. 18 19
      package.json
  92. 0 9
      packages/markdown/markdown.js
  93. 3 4
      packages/markdown/marked/package-lock.json
  94. 3 0
      packages/markdown/marked/package.json
  95. 11 7
      packages/markdown/package.js
  96. 5 0
      packages/markdown/src/checkNpmVersions.js
  97. 9 0
      packages/markdown/src/markdown.js
  98. 18 0
      packages/markdown/src/template-integration.js
  99. 0 16
      packages/markdown/template-integration.js
  100. 2 2
      packages/wekan-accounts-cas/cas_server.js

+ 1 - 1
.devcontainer/Dockerfile

@@ -6,7 +6,7 @@ ENV DEBIAN_FRONTEND=noninteractive
 
 
 ENV \
 ENV \
     DEBUG=false \
     DEBUG=false \
-    NODE_VERSION=12.18.0 \
+    NODE_VERSION=12.18.2 \
     METEOR_RELEASE=1.10.2 \
     METEOR_RELEASE=1.10.2 \
     USE_EDGE=false \
     USE_EDGE=false \
     METEOR_EDGE=1.5-beta.17 \
     METEOR_EDGE=1.5-beta.17 \

+ 1 - 1
.future-snap/broken-snapcraft.yaml

@@ -81,7 +81,7 @@ parts:
     wekan:
     wekan:
         source: .
         source: .
         plugin: nodejs
         plugin: nodejs
-        node-engine: 12.18.0
+        node-engine: 12.18.2
         node-packages:
         node-packages:
             - node-gyp
             - node-gyp
             - node-pre-gyp
             - node-pre-gyp

+ 1 - 1
.future-snap/snapcraft.yaml

@@ -83,7 +83,7 @@ parts:
     wekan:
     wekan:
         source: .
         source: .
         plugin: nodejs
         plugin: nodejs
-        node-engine: 12.18.0
+        node-engine: 12.18.2
         node-packages:
         node-packages:
             - node-gyp
             - node-gyp
             - node-pre-gyp
             - node-pre-gyp

+ 1 - 0
.meteor/packages

@@ -98,3 +98,4 @@ percolate:synced-cron
 easylogic:summernote
 easylogic:summernote
 cfs:filesystem
 cfs:filesystem
 ostrio:cookies
 ostrio:cookies
+tmeasday:check-npm-versions

+ 10 - 9
.meteor/versions

@@ -1,7 +1,7 @@
 3stack:presence@1.1.2
 3stack:presence@1.1.2
 accounts-base@1.6.0
 accounts-base@1.6.0
 accounts-oauth@1.2.0
 accounts-oauth@1.2.0
-accounts-password@1.6.0
+accounts-password@1.6.1
 aldeed:collection2@2.10.0
 aldeed:collection2@2.10.0
 aldeed:collection2-core@1.2.0
 aldeed:collection2-core@1.2.0
 aldeed:schema-deny@1.1.0
 aldeed:schema-deny@1.1.0
@@ -52,7 +52,7 @@ ddp@1.4.0
 ddp-client@2.3.3
 ddp-client@2.3.3
 ddp-common@1.4.0
 ddp-common@1.4.0
 ddp-rate-limiter@1.0.7
 ddp-rate-limiter@1.0.7
-ddp-server@2.3.1
+ddp-server@2.3.2
 deps@1.0.12
 deps@1.0.12
 diff-sequence@1.1.1
 diff-sequence@1.1.1
 dynamic-import@0.5.2
 dynamic-import@0.5.2
@@ -91,7 +91,7 @@ logging@1.1.20
 lucasantoniassi:accounts-lockout@1.0.0
 lucasantoniassi:accounts-lockout@1.0.0
 matb33:collection-hooks@0.9.1
 matb33:collection-hooks@0.9.1
 matteodem:easy-search@1.6.4
 matteodem:easy-search@1.6.4
-mdg:meteor-apm-agent@3.2.5
+mdg:meteor-apm-agent@3.2.6
 mdg:validation-error@0.5.1
 mdg:validation-error@0.5.1
 meteor@1.9.3
 meteor@1.9.3
 meteor-base@1.4.0
 meteor-base@1.4.0
@@ -101,7 +101,7 @@ meteorhacks:collection-utils@1.2.0
 meteorhacks:picker@1.0.3
 meteorhacks:picker@1.0.3
 meteorhacks:subs-manager@1.6.4
 meteorhacks:subs-manager@1.6.4
 meteorspark:util@0.2.0
 meteorspark:util@0.2.0
-minifier-css@1.5.0
+minifier-css@1.5.2
 minifier-js@2.6.0
 minifier-js@2.6.0
 minifiers@1.1.8-faster-rebuild.0
 minifiers@1.1.8-faster-rebuild.0
 minimongo@1.6.0
 minimongo@1.6.0
@@ -109,7 +109,7 @@ mobile-status-bar@1.1.0
 modern-browsers@0.1.5
 modern-browsers@0.1.5
 modules@0.15.0
 modules@0.15.0
 modules-runtime@0.12.0
 modules-runtime@0.12.0
-momentjs:moment@2.26.0
+momentjs:moment@2.27.0
 mongo@1.10.0
 mongo@1.10.0
 mongo-decimal@0.1.1
 mongo-decimal@0.1.1
 mongo-dev-server@1.1.0
 mongo-dev-server@1.1.0
@@ -162,14 +162,14 @@ simple:json-routes@2.1.0
 simple:rest-accounts-password@1.1.2
 simple:rest-accounts-password@1.1.2
 simple:rest-bearer-token-parser@1.0.1
 simple:rest-bearer-token-parser@1.0.1
 simple:rest-json-error-handler@1.0.1
 simple:rest-json-error-handler@1.0.1
-socket-stream-client@0.3.0
+socket-stream-client@0.3.1
 softwarerero:accounts-t9n@1.3.11
 softwarerero:accounts-t9n@1.3.11
 spacebars@1.0.15
 spacebars@1.0.15
 spacebars-compiler@1.1.3
 spacebars-compiler@1.1.3
 srp@1.1.0
 srp@1.1.0
 standard-minifier-css@1.6.0
 standard-minifier-css@1.6.0
 standard-minifier-js@2.6.0
 standard-minifier-js@2.6.0
-staringatlights:fast-render@3.2.0
+staringatlights:fast-render@3.3.0
 staringatlights:inject-data@2.3.0
 staringatlights:inject-data@2.3.0
 tap:i18n@1.8.2
 tap:i18n@1.8.2
 templates:tabs@2.3.0
 templates:tabs@2.3.0
@@ -177,11 +177,12 @@ templating@1.3.2
 templating-compiler@1.3.3
 templating-compiler@1.3.3
 templating-runtime@1.3.2
 templating-runtime@1.3.2
 templating-tools@1.1.2
 templating-tools@1.1.2
+tmeasday:check-npm-versions@0.3.2
 tracker@1.2.0
 tracker@1.2.0
 twbs:bootstrap@3.3.6
 twbs:bootstrap@3.3.6
 ui@1.0.13
 ui@1.0.13
 underscore@1.0.10
 underscore@1.0.10
-url@1.3.0
+url@1.3.1
 useraccounts:core@1.14.2
 useraccounts:core@1.14.2
 useraccounts:flow-routing@1.14.2
 useraccounts:flow-routing@1.14.2
 useraccounts:unstyled@1.14.2
 useraccounts:unstyled@1.14.2
@@ -191,7 +192,7 @@ webapp-hashing@1.0.9
 wekan-accounts-cas@0.1.0
 wekan-accounts-cas@0.1.0
 wekan-accounts-oidc@1.0.10
 wekan-accounts-oidc@1.0.10
 wekan-ldap@0.0.2
 wekan-ldap@0.0.2
-wekan-markdown@1.0.8
+wekan-markdown@1.0.9
 wekan-oidc@1.0.12
 wekan-oidc@1.0.12
 wekan-scrollbar@3.1.3
 wekan-scrollbar@3.1.3
 yasaricli:slugify@0.0.7
 yasaricli:slugify@0.0.7

+ 1 - 1
.travis.yml

@@ -3,7 +3,7 @@ sudo: required
 
 
 env:
 env:
   TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
   TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
-  TRAVIS_NODE_VERSION: 12.18.0
+  TRAVIS_NODE_VERSION: 12.18.2
   TRAVIS_NPM_VERSION: latest
   TRAVIS_NPM_VERSION: latest
 
 
 before_install:
 before_install:

+ 197 - 0
CHANGELOG.md

@@ -1,3 +1,200 @@
+# v4.20 2020-07-20 Wekan release
+
+This release adds the following updates:
+
+- Update dependencies [Part1](https://github.com/wekan/wekan/commit/419615bed43b6e9de4030193c47137a066b85bde) and
+  [Part2](https://github.com/wekan/wekan/commit/116372e11e09ce9b8376a8694553add595e02815).
+  Thanks to developers of dependencies and xet7.
+
+and fixes the following bugs:
+
+- [Change slug on card rename](https://github.com/wekan/wekan/pull/3214).
+  Thanks to NicoP-S.
+- [Add missing Wekan logo sizes for PWAs and Apps](https://github.com/wekan/wekan/commit/de28bf8569a7373a5d6fd60a4f413e76673adc26).
+  Thanks to xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.19 2020-07-18 Wekan release
+
+This release adds the following features:
+
+- [Add support for EdgeHTML browser (Microsoft Legacy Edge, not based on Chromium) by removing incompatible csv-stringify package.
+  CSV export will be fixed later](https://github.com/wekan/wekan/commit/b9a4b0b51d3692fcbb715b1afc875f21cd204ae5).
+  Thanks to xet7.
+
+and adds the following updates:
+
+- Update dependencies [Part1](https://github.com/wekan/wekan/commit/23ee93ca3d4ea161a93627a8e28e1ce93eea1bab),
+  [Part2](https://github.com/wekan/wekan/commit/6646d48ccbaf04c4935de35fe037eff3bd7fd469),
+  [Part3](https://github.com/wekan/wekan/commit/87cb4598f745a362aaac06b8b457198c40aaf61e),
+  [Part4](https://github.com/wekan/wekan/commit/f57ed2990f5c6e1af10d270b24c7092805711afe).
+  Thanks to developers of dependencies and xet7.
+
+and fixes the following bugs:
+
+- [Checklist Item PUT API: boolean cast on isFinished](https://github.com/wekan/wekan/pull/3211).
+  Thanks to Robert-Lebedeu.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.18 2020-07-10 Wekan release
+
+This release adds the following updates:
+
+- [Upgrade to Node 12.18.2](https://github.com/wekan/wekan/commit/6e4407ed9cb3c95a99e0dbbb4383324dd57d6be1).
+  Thanks to Node developers and xet7.
+- [Update dependencies](https://github.com/wekan/wekan/commit/05cd1247ab935f586d747743bb9cd79d23e0b1e6).
+  Thanks to dependency developers and xet7.
+
+and fixes the following bugs:
+
+- [All logged in users are now allowed to reorder boards by dragging at All Boards page and Public Boards page](https://github.com/wekan/wekan/commit/ba24c4e40c728d030504ed21ccf79247d0449e1b).
+  Thanks to xet7.
+- [Fix running meteor for dev in rebuild-wekan.sh](https://github.com/wekan/wekan/commit/a77cf56fbdaf0b74d8b97aa41b0a88fee85e3ee1).
+  Thanks to xet7.
+- [Fix start-wekan.bat](https://github.com/wekan/wekan/commit/0be1c00fccef8797a1b3612593a6623a9b465e0d) and
+  [Windows bundle install](https://github.com/wekan/wekan/wiki/Windows#a-bundle-with-windows-nodemongodb).
+  Thanks to xet7.
+- [Fix typo](https://github.com/wekan/wekan/pull/3197).
+  Thanks to Lua00808.
+- [Fix creating user misbehaving in some special case](https://github.com/wekan/wekan/pull/3206).
+  Thanks to salleman33.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.17 2020-06-18 Wekan release
+
+This release fixes the following bugs:
+
+- [Revert finding correct user changes that were made at Wekan v4.16](https://github.com/wekan/wekan/commit/5eb378452761ad1d6d67a491316007fdf6dfd689).
+  Thanks to xet7.
+- [Fix activities view on mobile devices](https://github.com/wekan/wekan/pull/3183).
+  Thanks to marc1006.
+- [Add back checks about can user export CSV/TSV](https://github.com/wekan/wekan/commit/afe00d02cddf016a3ccc1ed9a98a7f10d3339f26).
+  Thanks to marc1006 and xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.16 2020-06-17 Wekan release
+
+This release adds the following features:
+
+- [Add find-replace.sh script for development](https://github.com/wekan/wekan/commit/bda49ed60947e0438206b2f55119f5c5c132c734).
+  Thanks to xet7.
+
+and adds the following updates:
+
+- [Upgrade to Node 12.18.1](https://github.com/wekan/wekan/commit/b11ae567c9b2d16a115ea4f3f7f88e67d076f326).
+  Thanks to Node developers and xet7.
+
+and fixes the following bugs:
+
+- [OpenAPI: Fix jsdoc/operation matching](https://github.com/wekan/wekan/pull/3171).
+  Thanks to bentiss.
+- Fix finding corrent user [Part1](https://github.com/wekan/wekan/pull/3180) and
+  [Part2](https://github.com/wekan/wekan/commit/f245b6b7faa29b4f276527daca48c305fe9689c1).
+  Thanks to salleman33 and xet7.
+- [Try to prevent errors on CSV/TSV export](https://github.com/wekan/wekan/commit/b00db983c8506e0cdc9968e452c3c8025fc10776).
+  Thanks to xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.15 2020-06-16 Wekan release
+
+This release fixes the following bugs:
+
+- Fix lint errors [Part1](https://github.com/wekan/wekan/commit/f1587753cb0bba38e4b1df2e0300d3dc2826da72) and
+  [Part2](https://github.com/wekan/wekan/commit/e6629779f77676eadfe4465c407f0bee0ec64061).
+  Thanks to xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.14 2020-06-16 Wekan release
+
+This release adds the following new features:
+
+- [Add user option to hide finished checklist items. Strikethrough checked items](https://github.com/wekan/wekan/pull/3167).
+  Thanks to marc1006.
+- [Added the possibility to start a vote via API edit_card. And added some better visibility to see what was voted](https://github.com/wekan/wekan/pull/3170).
+  Thanks to NicoP-S.
+
+and adds the following updates:
+
+- [Update dependencies](https://github.com/wekan/wekan/commit/8f34cdc279602e97085e0a504f7716495349f83c).
+  Thanks to xet7.
+
+and fixes the following bugs:
+
+- [Fix infinite scrolling for activities](https://github.com/wekan/wekan/pull/3168).
+  Thanks to marc1006.
+- [Remove top and bottom margin for hidden checklist items](https://github.com/wekan/wekan/pull/3172).
+  Thanks to marc1006.
+- [Alignment and spacing of minicard labels](https://github.com/wekan/wekan/pull/3174).
+  Thanks to hgustafsson.
+- [Fix: Unable to delete a custom field in a board](https://github.com/wekan/wekan/commit/3b2b1087447bc8613baa8254bfec55e3d485bdc4).
+  Thanks to xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.13 2020-06-09 Wekan release
+
+This release adds the following updates:
+
+- [OpenShift template updates](https://github.com/wekan/wekan/pull/3158), Thanks to jimmyjones2:
+  1) Remove status fields (this is created by Kubernetes at run time)
+  2) The latest MongoDB by default available with OpenShift is 3.6
+  3) Change MongoDB service name to contain wekan to avoid potentially conflicting with other mongodb instances in the same project.
+
+and fixes the following bugs:
+
+- [Copy the labels only if the target board is different](https://github.com/wekan/wekan/pull/3154).
+  Thanks to marc1006.
+- [Fix condition whether a card is in list](https://github.com/wekan/wekan/pull/3165).
+  Thanks to marc1006.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
+# v4.12 2020-06-08 Wekan release
+
+This release fixes the following CRITICAL SECURITY VULNERABILITIES:
+
+- Fix XSS bug reported 2020-05-24 by [swsjona](https://twitter.com/swsjona):
+  [Part 1](https://github.com/wekan/wekan/commit/1f85b25549b50602380f1745f19e5fe44fe36d6f),
+  [Part 2](https://github.com/wekan/wekan/commit/fb44df981581354bf23a6928427ad2bf73c4550f),
+  [Part 3](https://github.com/wekan/wekan/commit/99f68f36b028d6c75acf2e5b83585b1acee65f97),
+  [Part 4](https://github.com/wekan/wekan/commit/8a622ec7c3043bf8f34399ef34563e6a9a19dcd8).
+  Logged in users could run javascript in input fields. This was partially fixed at v3.85,
+  but at some fields XSS was still possible. This affects at least Wekan versions v3.12-v4.12.
+  After this fix, Javascript in input fields is not executed.
+  Thanks to swsjona, marc1006 and xet7.
+
+and adds the following new features:
+
+- Change default view to Swimlanes:
+  [Part 1](https://github.com/wekan/wekan/commit/8c3322f9a93c321e8a2cc5cfcd4b1d6316a5fb7c),
+  [Part 2](https://github.com/wekan/wekan/commit/61e682470cdaef42cce2d74b41fb752cfc61848b),
+  [Part 3 Change dropdown order to Swimlanes/Lists/Calendar](https://github.com/wekan/wekan/commit/7f6d500cbec15496ae357b05b9df3f10e51ed1f1),
+  [Part 4.1. Public board default view to Swimlane. Part 4.2. When changing Public board
+  view (sets view cookie), also reload page so view is changed
+  immediately](https://github.com/wekan/wekan/commit/39519d1cc944c567837be0f88ab4a037e2144c61).
+  Thanks to xet7.
+- [Use markdown in Swimlane titles](https://github.com/wekan/wekan/commit/6b22f96313354b45b851b93c25aa392bbe346bdb).
+  Thanks to xet7.
+
+and adds the following updates:
+
+- [Update minifier-css](https://github.com/wekan/wekan/commit/cb1e91fee83eaad1e926c288c0abfc1e4f2a8bd4).
+  Thanks to xet7.
+
+and fixes the following bugs:
+
+- Fix indent [Part1](https://github.com/wekan/wekan/commit/415e94d187ffcb9a4afaecc5c6960a50a87ca7eb),
+  [Part 2](https://github.com/wekan/wekan/commit/96494bacf550cde65598e6d59199517f311aa33d).
+  Thanks to xet7.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
 # v4.11 2020-06-04 Wekan release
 # v4.11 2020-06-04 Wekan release
 
 
 This release adds the following new platforms:
 This release adds the following new platforms:

+ 1 - 1
Dockerfile

@@ -8,7 +8,7 @@ ARG DEBIAN_FRONTEND=noninteractive
 
 
 ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-essential git ca-certificates python3" \
 ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-essential git ca-certificates python3" \
     DEBUG=false \
     DEBUG=false \
-    NODE_VERSION=v12.18.0 \
+    NODE_VERSION=v12.18.2 \
     METEOR_RELEASE=1.10.2 \
     METEOR_RELEASE=1.10.2 \
     USE_EDGE=false \
     USE_EDGE=false \
     METEOR_EDGE=1.5-beta.17 \
     METEOR_EDGE=1.5-beta.17 \

+ 2 - 2
Dockerfile.arm64v8

@@ -4,7 +4,7 @@ FROM amd64/alpine:3.7 AS builder
 ENV QEMU_VERSION=v4.2.0-6 \
 ENV QEMU_VERSION=v4.2.0-6 \
     QEMU_ARCHITECTURE=aarch64 \
     QEMU_ARCHITECTURE=aarch64 \
     NODE_ARCHITECTURE=linux-arm64 \
     NODE_ARCHITECTURE=linux-arm64 \
-    NODE_VERSION=v12.18.0 \
+    NODE_VERSION=v12.18.2 \
     WEKAN_VERSION=3.96  \
     WEKAN_VERSION=3.96  \
     WEKAN_ARCHITECTURE=arm64
     WEKAN_ARCHITECTURE=arm64
 
 
@@ -40,7 +40,7 @@ LABEL maintainer="wekan"
 # Set the environment variables (defaults where required)
 # Set the environment variables (defaults where required)
 ENV QEMU_ARCHITECTURE=aarch64 \
 ENV QEMU_ARCHITECTURE=aarch64 \
     NODE_ARCHITECTURE=linux-arm64 \
     NODE_ARCHITECTURE=linux-arm64 \
-    NODE_VERSION=v12.18.0 \
+    NODE_VERSION=v12.18.2 \
     NODE_ENV=production \
     NODE_ENV=production \
     NPM_VERSION=latest \
     NPM_VERSION=latest \
     WITH_API=true \
     WITH_API=true \

+ 1 - 1
Stackerfile.yml

@@ -1,5 +1,5 @@
 appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
 appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
-appVersion: "v4.11.0"
+appVersion: "v4.20.0"
 files:
 files:
   userUploads:
   userUploads:
     - README.md
     - README.md

+ 28 - 28
client/components/activities/activities.jade

@@ -34,38 +34,38 @@ template(name="activity")
       //- board activity ------------------------------------------------------
       //- board activity ------------------------------------------------------
       if($eq mode 'board')
       if($eq mode 'board')
         if($eq activity.activityType 'createBoard')
         if($eq activity.activityType 'createBoard')
-          | {{_ 'activity-created' boardLabel}}.
+          | {{{_ 'activity-created' boardLabelLink}}}.
 
 
         if($eq activity.activityType 'importBoard')
         if($eq activity.activityType 'importBoard')
-          | {{{_ 'activity-imported-board' boardLabel sourceLink}}}.
+          | {{{_ 'activity-imported-board' boardLabelLink sourceLink}}}.
 
 
         if($eq activity.activityType 'addBoardMember')
         if($eq activity.activityType 'addBoardMember')
-          | {{{_ 'activity-added' memberLink boardLabel}}}.
+          | {{{_ 'activity-added' memberLink boardLabelLink}}}.
 
 
         if($eq activity.activityType 'removeBoardMember')
         if($eq activity.activityType 'removeBoardMember')
-          | {{{_ 'activity-excluded' memberLink boardLabel}}}.
+          | {{{_ 'activity-excluded' memberLink boardLabelLink}}}.
 
 
       //- card activity -------------------------------------------------------
       //- card activity -------------------------------------------------------
       if($eq activity.activityType 'createCard')
       if($eq activity.activityType 'createCard')
         if($eq mode 'card')
         if($eq mode 'card')
-          | {{{_ 'activity-added' cardLabel activity.listName}}}.
+          | {{{_ 'activity-added' cardLabelLink (sanitize activity.listName)}}}.
         else
         else
-          | {{{_ 'activity-added' cardLabel boardLabel}}}.
+          | {{{_ 'activity-added' cardLabelLink boardLabelLink}}}.
 
 
       if($eq activity.activityType 'importCard')
       if($eq activity.activityType 'importCard')
-        | {{{_ 'activity-imported' cardLink boardLabel sourceLink}}}.
+        | {{{_ 'activity-imported' cardLink boardLabelLink sourceLink}}}.
 
 
       if($eq activity.activityType 'moveCard')
       if($eq activity.activityType 'moveCard')
-        | {{{_ 'activity-moved' cardLabel activity.oldList.title activity.list.title}}}.
+        | {{{_ 'activity-moved' cardLabelLink (sanitize activity.oldList.title) (sanitize activity.list.title)}}}.
 
 
       if($eq activity.activityType 'moveCardBoard')
       if($eq activity.activityType 'moveCardBoard')
-        | {{{_ 'activity-moved' cardLink activity.oldBoardName activity.boardName}}}.
+        | {{{_ 'activity-moved' cardLink (sanitize activity.oldBoardName) (sanitize activity.boardName)}}}.
 
 
       if($eq activity.activityType 'archivedCard')
       if($eq activity.activityType 'archivedCard')
         | {{{_ 'activity-archived' cardLink}}}.
         | {{{_ 'activity-archived' cardLink}}}.
 
 
       if($eq activity.activityType 'restoredCard')
       if($eq activity.activityType 'restoredCard')
-        | {{{_ 'activity-sent' cardLink boardLabel}}}.
+        | {{{_ 'activity-sent' cardLink boardLabelLink}}}.
 
 
       //- checklist activity --------------------------------------------------
       //- checklist activity --------------------------------------------------
       if($eq activity.activityType 'addChecklist')
       if($eq activity.activityType 'addChecklist')
@@ -83,25 +83,25 @@ template(name="activity")
         | {{{_ 'activity-checklist-removed' cardLink}}}.
         | {{{_ 'activity-checklist-removed' cardLink}}}.
 
 
       if($eq activity.activityType 'completeChecklist')
       if($eq activity.activityType 'completeChecklist')
-        | {{{_ 'activity-checklist-completed' activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-checklist-completed' (sanitize activity.checklist.title) cardLink}}}.
 
 
       if($eq activity.activityType 'uncompleteChecklist')
       if($eq activity.activityType 'uncompleteChecklist')
-        | {{{_ 'activity-checklist-uncompleted' activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-checklist-uncompleted' (sanitize activity.checklist.title) cardLink}}}.
 
 
       if($eq activity.activityType 'checkedItem')
       if($eq activity.activityType 'checkedItem')
-        | {{{_ 'activity-checked-item' checkItem activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-checked-item' (sanitize checkItem) (sanitize activity.checklist.title) cardLink}}}.
 
 
       if($eq activity.activityType 'uncheckedItem')
       if($eq activity.activityType 'uncheckedItem')
-        | {{{_ 'activity-unchecked-item' checkItem activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-unchecked-item' (sanitize checkItem) (sanitize activity.checklist.title) cardLink}}}.
 
 
       if($eq activity.activityType 'addChecklistItem')
       if($eq activity.activityType 'addChecklistItem')
-        | {{{_ 'activity-checklist-item-added' activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-checklist-item-added' (sanitize activity.checklist.title) cardLink}}}.
         .activity-checklist(href="{{ activity.card.absoluteUrl }}")
         .activity-checklist(href="{{ activity.card.absoluteUrl }}")
           +viewer
           +viewer
             = activity.checklistItem.title
             = activity.checklistItem.title
 
 
       if($eq activity.activityType 'removedChecklistItem')
       if($eq activity.activityType 'removedChecklistItem')
-        | {{{_ 'activity-checklist-item-removed' activity.checklist.title cardLink}}}.
+        | {{{_ 'activity-checklist-item-removed' (sanitize activity.checklist.title) cardLink}}}.
 
 
       //- comment activity ----------------------------------------------------
       //- comment activity ----------------------------------------------------
       if($eq mode 'card')
       if($eq mode 'card')
@@ -143,31 +143,31 @@ template(name="activity")
           | {{_ 'activity-customfield-created' customField}}.
           | {{_ 'activity-customfield-created' customField}}.
 
 
         if($eq activity.activityType 'setCustomField')
         if($eq activity.activityType 'setCustomField')
-          | {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
+          | {{{_ 'activity-set-customfield' (sanitize lastCustomField) (sanitize lastCustomFieldValue) cardLink}}}.
 
 
         if($eq activity.activityType 'unsetCustomField')
         if($eq activity.activityType 'unsetCustomField')
-          | {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
+          | {{{_ 'activity-unset-customfield' (sanitize lastCustomField) cardLink}}}.
 
 
       //- label activity ------------------------------------------------------
       //- label activity ------------------------------------------------------
       if($eq activity.activityType 'addedLabel')
       if($eq activity.activityType 'addedLabel')
-        | {{{_ 'activity-added-label' lastLabel cardLink}}}.
+        | {{{_ 'activity-added-label' (sanitize lastLabel) cardLink}}}.
 
 
       if($eq activity.activityType 'removedLabel')
       if($eq activity.activityType 'removedLabel')
-        | {{{_ 'activity-removed-label' lastLabel cardLink}}}.
+        | {{{_ 'activity-removed-label' (sanitize lastLabel) cardLink}}}.
 
 
       //- list activity -------------------------------------------------------
       //- list activity -------------------------------------------------------
       if($neq mode 'card')
       if($neq mode 'card')
         if($eq activity.activityType 'createList')
         if($eq activity.activityType 'createList')
-          | {{{_ 'activity-added' listLabel boardLabel}}}.
+          | {{{_ 'activity-added' (sanitize listLabel) boardLabelLink}}}.
 
 
         if($eq activity.activityType 'importList')
         if($eq activity.activityType 'importList')
-          | {{{_ 'activity-imported' listLabel boardLabel sourceLink}}}.
+          | {{{_ 'activity-imported' (sanitize listLabel) boardLabelLink sourceLink}}}.
 
 
         if($eq activity.activityType 'removeList')
         if($eq activity.activityType 'removeList')
-          | {{{_ 'activity-removed' activity.title boardLabel}}}.
+          | {{{_ 'activity-removed' (sanitize activity.title) boardLabelLink}}}.
 
 
         if($eq activity.activityType 'archivedList')
         if($eq activity.activityType 'archivedList')
-          | {{_ 'activity-archived' listLabel}}.
+          | {{_ 'activity-archived' (sanitize listLabel)}}.
 
 
       //- member activity ----------------------------------------------------
       //- member activity ----------------------------------------------------
       if($eq activity.activityType 'joinMember')
       if($eq activity.activityType 'joinMember')
@@ -185,15 +185,15 @@ template(name="activity")
       //- swimlane activity --------------------------------------------------
       //- swimlane activity --------------------------------------------------
       if($neq mode 'card')
       if($neq mode 'card')
         if($eq activity.activityType 'createSwimlane')
         if($eq activity.activityType 'createSwimlane')
-          | {{{_ 'activity-added' activity.swimlane.title boardLabel}}}.
+          | {{_ 'activity-added' (sanitize activity.swimlane.title) boardLabelLink}}.
 
 
         if($eq activity.activityType 'archivedSwimlane')
         if($eq activity.activityType 'archivedSwimlane')
-          | {{_ 'activity-archived' activity.swimlane.title}}.
+          | {{_ 'activity-archived' (sanitize activity.swimlane.title)}}.
 
 
 
 
       //- I don't understand this part ----------------------------------------
       //- I don't understand this part ----------------------------------------
       if(currentData.timeKey)
       if(currentData.timeKey)
-        | {{{_ activity.activityType }}}
+        | {{_ activity.activityType }}
         = ' '
         = ' '
         i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
         i(title=currentData.timeValue).activity-meta {{ moment currentData.timeValue 'LLL' }}
         if (currentData.timeOldValue)
         if (currentData.timeOldValue)
@@ -203,6 +203,6 @@ template(name="activity")
             i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
             i(title=currentData.timeOldValue).activity-meta {{ moment currentData.timeOldValue 'LLL' }}
         = ' @'
         = ' @'
       else if(currentData.timeValue)
       else if(currentData.timeValue)
-        | {{{_ activity.activityType currentData.timeValue}}}
+        | {{_ activity.activityType currentData.timeValue}}
 
 
       span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}
       span(title=activity.createdAt).activity-meta {{ moment activity.createdAt }}

+ 25 - 14
client/components/activities/activities.js

@@ -1,3 +1,5 @@
+import sanitizeXss from 'xss';
+
 const activitiesPerPage = 20;
 const activitiesPerPage = 20;
 
 
 BlazeComponent.extendComponent({
 BlazeComponent.extendComponent({
@@ -5,8 +7,9 @@ BlazeComponent.extendComponent({
     // XXX Should we use ReactiveNumber?
     // XXX Should we use ReactiveNumber?
     this.page = new ReactiveVar(1);
     this.page = new ReactiveVar(1);
     this.loadNextPageLocked = false;
     this.loadNextPageLocked = false;
-    const sidebar = this.parentComponent(); // XXX for some reason not working
-    sidebar.callFirstWith(null, 'resetNextPeak');
+    // TODO is sidebar always available? E.g. on small screens/mobile devices
+    const sidebar = Sidebar;
+    sidebar && sidebar.callFirstWith(null, 'resetNextPeak');
     this.autorun(() => {
     this.autorun(() => {
       let mode = this.data().mode;
       let mode = this.data().mode;
       const capitalizedMode = Utils.capitalize(mode);
       const capitalizedMode = Utils.capitalize(mode);
@@ -27,6 +30,8 @@ BlazeComponent.extendComponent({
       this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
       this.subscribe('activities', mode, searchId, limit, hideSystem, () => {
         this.loadNextPageLocked = false;
         this.loadNextPageLocked = false;
 
 
+        // TODO the guard can be removed as soon as the TODO above is resolved
+        if (!sidebar) return;
         // If the sibear peak hasn't increased, that mean that there are no more
         // If the sibear peak hasn't increased, that mean that there are no more
         // activities, and we can stop calling new subscriptions.
         // activities, and we can stop calling new subscriptions.
         // XXX This is hacky! We need to know excatly and reactively how many
         // XXX This is hacky! We need to know excatly and reactively how many
@@ -41,23 +46,22 @@ BlazeComponent.extendComponent({
       });
       });
     });
     });
   },
   },
-}).register('activities');
-
-BlazeComponent.extendComponent({
   loadNextPage() {
   loadNextPage() {
     if (this.loadNextPageLocked === false) {
     if (this.loadNextPageLocked === false) {
       this.page.set(this.page.get() + 1);
       this.page.set(this.page.get() + 1);
       this.loadNextPageLocked = true;
       this.loadNextPageLocked = true;
     }
     }
   },
   },
+}).register('activities');
 
 
+BlazeComponent.extendComponent({
   checkItem() {
   checkItem() {
     const checkItemId = this.currentData().activity.checklistItemId;
     const checkItemId = this.currentData().activity.checklistItemId;
     const checkItem = ChecklistItems.findOne({ _id: checkItemId });
     const checkItem = ChecklistItems.findOne({ _id: checkItemId });
     return checkItem && checkItem.title;
     return checkItem && checkItem.title;
   },
   },
 
 
-  boardLabel() {
+  boardLabelLink() {
     const data = this.currentData();
     const data = this.currentData();
     if (data.mode !== 'board') {
     if (data.mode !== 'board') {
       return createBoardLink(data.activity.board(), data.activity.listName);
       return createBoardLink(data.activity.board(), data.activity.listName);
@@ -65,10 +69,10 @@ BlazeComponent.extendComponent({
     return TAPi18n.__('this-board');
     return TAPi18n.__('this-board');
   },
   },
 
 
-  cardLabel() {
+  cardLabelLink() {
     const data = this.currentData();
     const data = this.currentData();
     if (data.mode !== 'card') {
     if (data.mode !== 'card') {
-      return createCardLink(this.currentData().activity.card());
+      return createCardLink(data.activity.card());
     }
     }
     return TAPi18n.__('this-card');
     return TAPi18n.__('this-card');
   },
   },
@@ -134,11 +138,11 @@ BlazeComponent.extendComponent({
             {
             {
               href: source.url,
               href: source.url,
             },
             },
-            source.system,
+            sanitizeXss(source.system),
           ),
           ),
         );
         );
       } else {
       } else {
-        return source.system;
+        return sanitizeXss(source.system);
       }
       }
     }
     }
     return null;
     return null;
@@ -162,10 +166,10 @@ BlazeComponent.extendComponent({
               href: attachment.url({ download: true }),
               href: attachment.url({ download: true }),
               target: '_blank',
               target: '_blank',
             },
             },
-            attachment.name(),
+            sanitizeXss(attachment.name()),
           ),
           ),
         )) ||
         )) ||
-      this.currentData().activity.attachmentName
+      sanitizeXss(this.currentData().activity.attachmentName)
     );
     );
   },
   },
 
 
@@ -202,7 +206,14 @@ BlazeComponent.extendComponent({
   },
   },
 }).register('activity');
 }).register('activity');
 
 
+Template.activity.helpers({
+  sanitize(value) {
+    return sanitizeXss(value);
+  },
+});
+
 function createCardLink(card) {
 function createCardLink(card) {
+  if (!card) return '';
   return (
   return (
     card &&
     card &&
     Blaze.toHTML(
     Blaze.toHTML(
@@ -211,7 +222,7 @@ function createCardLink(card) {
           href: card.absoluteUrl(),
           href: card.absoluteUrl(),
           class: 'action-card',
           class: 'action-card',
         },
         },
-        card.title,
+        sanitizeXss(card.title),
       ),
       ),
     )
     )
   );
   );
@@ -228,7 +239,7 @@ function createBoardLink(board, list) {
           href: board.absoluteUrl(),
           href: board.absoluteUrl(),
           class: 'action-board',
           class: 'action-board',
         },
         },
-        text,
+        sanitizeXss(text),
       ),
       ),
     )
     )
   );
   );

+ 10 - 10
client/components/boards/boardHeader.jade

@@ -99,13 +99,13 @@ template(name="boardHeaderBar")
         a.board-header-btn.js-toggle-board-view(
         a.board-header-btn.js-toggle-board-view(
           title="{{_ 'board-view'}}")
           title="{{_ 'board-view'}}")
           i.fa.fa-caret-down
           i.fa.fa-caret-down
-          if $eq boardView 'board-view-lists'
-            i.fa.fa-trello
           if $eq boardView 'board-view-swimlanes'
           if $eq boardView 'board-view-swimlanes'
             i.fa.fa-th-large
             i.fa.fa-th-large
+          if $eq boardView 'board-view-lists'
+            i.fa.fa-trello
           if $eq boardView 'board-view-cal'
           if $eq boardView 'board-view-cal'
             i.fa.fa-calendar
             i.fa.fa-calendar
-          span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}
+          span {{#if boardView}}{{_ boardView}}{{else}}{{_ 'board-view-swimlanes'}}{{/if}}
 
 
       if canModifyBoard
       if canModifyBoard
         a.board-header-btn.js-multiselection-activate(
         a.board-header-btn.js-multiselection-activate(
@@ -172,13 +172,6 @@ template(name="boardChangeWatchPopup")
 
 
 template(name="boardChangeViewPopup")
 template(name="boardChangeViewPopup")
   ul.pop-over-list
   ul.pop-over-list
-    li
-      with "board-view-lists"
-        a.js-open-lists-view
-          i.fa.fa-trello.colorful
-          | {{_ 'board-view-lists'}}
-          if $eq Utils.boardView "board-view-lists"
-            i.fa.fa-check
     li
     li
       with "board-view-swimlanes"
       with "board-view-swimlanes"
         a.js-open-swimlanes-view
         a.js-open-swimlanes-view
@@ -186,6 +179,13 @@ template(name="boardChangeViewPopup")
           | {{_ 'board-view-swimlanes'}}
           | {{_ 'board-view-swimlanes'}}
           if $eq Utils.boardView "board-view-swimlanes"
           if $eq Utils.boardView "board-view-swimlanes"
             i.fa.fa-check
             i.fa.fa-check
+    li
+      with "board-view-lists"
+        a.js-open-lists-view
+          i.fa.fa-trello.colorful
+          | {{_ 'board-view-lists'}}
+          if $eq Utils.boardView "board-view-lists"
+            i.fa.fa-check
     li
     li
       with "board-view-cal"
       with "board-view-cal"
         a.js-open-cal-view
         a.js-open-cal-view

+ 0 - 6
client/components/boards/boardsList.js

@@ -25,10 +25,6 @@ BlazeComponent.extendComponent({
   },
   },
 
 
   onRendered() {
   onRendered() {
-    function userIsAllowedToMove() {
-      return Meteor.user();
-    }
-
     const itemsSelector = '.js-board:not(.placeholder)';
     const itemsSelector = '.js-board:not(.placeholder)';
 
 
     const $boards = this.$('.js-boards');
     const $boards = this.$('.js-boards');
@@ -77,8 +73,6 @@ BlazeComponent.extendComponent({
           handle: '.board-handle',
           handle: '.board-handle',
         });
         });
       }
       }
-
-      $boards.sortable('option', 'disabled', !userIsAllowedToMove());
     });
     });
   },
   },
 
 

+ 8 - 2
client/components/cards/cardDetails.jade

@@ -220,8 +220,14 @@ template(name="cardDetails")
       +viewer
       +viewer
         = getVoteQuestion
         = getVoteQuestion
       if showVotingButtons
       if showVotingButtons
-        button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}") {{_ 'vote-for-it'}}
-        button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}") {{_ 'vote-against'}}
+        button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}")
+          if voteState
+            i.fa.fa-thumbs-up
+          | {{_ 'vote-for-it'}}
+        button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}")
+          if $eq voteState false
+            i.fa.fa-thumbs-down
+          | {{_ 'vote-against'}}
 
 
     //- XXX We should use "editable" to avoid repetiting ourselves
     //- XXX We should use "editable" to avoid repetiting ourselves
     if canModifyCard
     if canModifyCard

+ 3 - 19
client/components/cards/cardDetails.js

@@ -38,22 +38,6 @@ BlazeComponent.extendComponent({
     Meteor.subscribe('unsaved-edits');
     Meteor.subscribe('unsaved-edits');
   },
   },
 
 
-  voteState() {
-    const card = this.currentData();
-    const userId = Meteor.userId();
-    let state;
-    if (card.vote) {
-      if (card.vote.positive) {
-        state = _.contains(card.vote.positive, userId);
-        if (state === true) return true;
-      }
-      if (card.vote.negative) {
-        state = _.contains(card.vote.negative, userId);
-        if (state === true) return false;
-      }
-    }
-    return null;
-  },
   isWatching() {
   isWatching() {
     const card = this.currentData();
     const card = this.currentData();
     return card.findWatcher(Meteor.userId());
     return card.findWatcher(Meteor.userId());
@@ -412,9 +396,9 @@ BlazeComponent.extendComponent({
           const forIt = $(e.target).hasClass('js-vote-positive');
           const forIt = $(e.target).hasClass('js-vote-positive');
           let newState = null;
           let newState = null;
           if (
           if (
-            this.voteState() === null ||
-            (this.voteState() === false && forIt) ||
-            (this.voteState() === true && !forIt)
+            this.data().voteState() === null ||
+            (this.data().voteState() === false && forIt) ||
+            (this.data().voteState() === true && !forIt)
           ) {
           ) {
             newState = forIt;
             newState = forIt;
           }
           }

+ 14 - 4
client/components/cards/checklists.jade

@@ -1,7 +1,17 @@
 template(name="checklists")
 template(name="checklists")
-  h3
-    i.fa.fa-check
-    | {{_ 'checklists'}}
+  .checklists-title
+    h3
+      i.fa.fa-check
+      | {{_ 'checklists'}}
+    if currentUser.isBoardMember
+      .material-toggle-switch
+        span.toggle-switch-title {{_ 'hide-checked-items'}}
+        if hideCheckedItems
+          input.toggle-switch(type="checkbox" id="toggleHideCheckedItemsButton" checked="checked")
+        else
+          input.toggle-switch(type="checkbox" id="toggleHideCheckedItemsButton")
+        label.toggle-label(for="toggleHideCheckedItemsButton")
+
   if toggleDeleteDialog.get
   if toggleDeleteDialog.get
     .board-overlay#card-details-overlay
     .board-overlay#card-details-overlay
     +checklistDeleteDialog(checklist = checklistToDelete)
     +checklistDeleteDialog(checklist = checklistToDelete)
@@ -86,7 +96,7 @@ template(name="checklistItems")
           | {{_ 'add-checklist-item'}}...
           | {{_ 'add-checklist-item'}}...
 
 
 template(name='checklistItemDetail')
 template(name='checklistItemDetail')
-  .js-checklist-item.checklist-item
+  .js-checklist-item.checklist-item(class="{{#if item.isFinished }}is-checked{{#if hideCheckedItems}} invisible{{/if}}{{/if}}")
     if canModifyCard
     if canModifyCard
       .check-box-container
       .check-box-container
         .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
         .check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")

+ 16 - 0
client/components/cards/checklists.js

@@ -193,6 +193,9 @@ BlazeComponent.extendComponent({
         }
         }
         this.toggleDeleteDialog.set(!this.toggleDeleteDialog.get());
         this.toggleDeleteDialog.set(!this.toggleDeleteDialog.get());
       },
       },
+      'click #toggleHideCheckedItemsButton'() {
+        Meteor.call('toggleHideCheckedItems');
+      },
     };
     };
 
 
     return [
     return [
@@ -211,6 +214,14 @@ BlazeComponent.extendComponent({
   },
   },
 }).register('checklists');
 }).register('checklists');
 
 
+Template.checklists.helpers({
+  hideCheckedItems() {
+    const currentUser = Meteor.user();
+    if (currentUser) return currentUser.hasHideCheckedItems();
+    return false;
+  },
+});
+
 Template.checklistDeleteDialog.onCreated(() => {
 Template.checklistDeleteDialog.onCreated(() => {
   const $cardDetails = this.$('.card-details');
   const $cardDetails = this.$('.card-details');
   this.scrollState = {
   this.scrollState = {
@@ -246,6 +257,11 @@ Template.checklistItemDetail.helpers({
       !Meteor.user().isWorker()
       !Meteor.user().isWorker()
     );
     );
   },
   },
+  hideCheckedItems() {
+    const user = Meteor.user();
+    if (user) return user.hasHideCheckedItems();
+    return false;
+  },
 });
 });
 
 
 BlazeComponent.extendComponent({
 BlazeComponent.extendComponent({

+ 16 - 0
client/components/cards/checklists.styl

@@ -16,6 +16,10 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
   &:hover
   &:hover
     color: inherit
     color: inherit
 
 
+.checklists-title
+  display: flex
+  justify-content: space-between
+
 .checklist-title
 .checklist-title
   .checkbox
   .checkbox
     float: left
     float: left
@@ -99,6 +103,17 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
   margin-top: 3px
   margin-top: 3px
   display: flex
   display: flex
   background: darken(white, 3%)
   background: darken(white, 3%)
+  opacity: 1
+  transition: height 0ms 400ms, opacity 400ms 0ms
+  height: auto
+  overflow: hidden
+
+  &.is-checked.invisible
+    opacity: 0
+    height: 0
+    transition: height 0ms 0ms, opacity 600ms 0ms
+    margin-top: 0
+    margin-bottom: 0
 
 
   &.placeholder
   &.placeholder
     background: darken(white, 20%)
     background: darken(white, 20%)
@@ -128,6 +143,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
     &.is-checked
     &.is-checked
       color: #8c8c8c
       color: #8c8c8c
       font-style: italic
       font-style: italic
+      text-decoration: line-through
     & .viewer
     & .viewer
       p
       p
         margin-bottom: 2px
         margin-bottom: 2px

+ 2 - 2
client/components/cards/minicard.jade

@@ -106,9 +106,9 @@ template(name="minicard")
           span.badge-icon.fa.fa-align-left
           span.badge-icon.fa.fa-align-left
       if getVoteQuestion
       if getVoteQuestion
         .badge.badge-state-image-only(title=getVoteQuestion)
         .badge.badge-state-image-only(title=getVoteQuestion)
-          span.badge-icon.fa.fa-thumbs-up
+          span.badge-icon.fa.fa-thumbs-up(class="{{#if voteState}}text-green{{/if}}")
           span.badge-text {{ voteCountPositive }}
           span.badge-text {{ voteCountPositive }}
-          span.badge-icon.fa.fa-thumbs-down
+          span.badge-icon.fa.fa-thumbs-down(class="{{#if $eq voteState false}}text-red{{/if}}")
           span.badge-text {{ voteCountNegative }}
           span.badge-text {{ voteCountNegative }}
       if attachments.count
       if attachments.count
         .badge
         .badge

+ 8 - 1
client/components/cards/minicard.styl

@@ -87,7 +87,9 @@
       width: 11px
       width: 11px
       height: @width
       height: @width
       border-radius: 2px
       border-radius: 2px
-      margin-left: 3px
+      margin-right: 3px
+      margin-bottom: 3px
+      
   .minicard-custom-fields
   .minicard-custom-fields
     display:block;
     display:block;
   .minicard-custom-field
   .minicard-custom-field
@@ -299,3 +301,8 @@ minicard-color(background, color...)
 
 
 .minicard-indigo
 .minicard-indigo
   minicard-color(#4b0082, #ffffff) //White text for better visibility
   minicard-color(#4b0082, #ffffff) //White text for better visibility
+
+.text-red
+  color:red
+.text-green
+  color:green

+ 1 - 1
client/components/rules/actions/cardActions.jade

@@ -75,7 +75,7 @@ template(name="cardActions")
         button.trigger-button.trigger-button-color.js-show-color-palette(
         button.trigger-button.trigger-button-color.js-show-color-palette(
           id="color-action"
           id="color-action"
           class="card-details-{{cardColorButton}}")
           class="card-details-{{cardColorButton}}")
-          | {{{_ cardColorButtonText }}}
+          | {{_ cardColorButtonText }}
     div.trigger-button.js-set-color-action.js-goto-rules
     div.trigger-button.js-set-color-action.js-goto-rules
       i.fa.fa-plus
       i.fa.fa-plus
 
 

+ 2 - 1
client/components/swimlanes/swimlaneHeader.jade

@@ -11,7 +11,8 @@ template(name="swimlaneHeader")
 template(name="swimlaneFixedHeader")
 template(name="swimlaneFixedHeader")
   .swimlane-header(
   .swimlane-header(
     class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
     class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
-    = title
+      +viewer
+        = title
   .swimlane-header-menu
   .swimlane-header-menu
     unless currentUser.isCommentOnly
     unless currentUser.isCommentOnly
       a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon
       a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon

+ 1 - 1
client/components/swimlanes/swimlanes.js

@@ -23,8 +23,8 @@ function currentCardIsInThisList(listId, swimlaneId) {
       currentCard.listId === listId &&
       currentCard.listId === listId &&
       currentCard.swimlaneId === swimlaneId
       currentCard.swimlaneId === swimlaneId
     );
     );
-  // Default view: board-view-lists
   else return currentCard && currentCard.listId === listId;
   else return currentCard && currentCard.listId === listId;
+
   // https://github.com/wekan/wekan/issues/1623
   // https://github.com/wekan/wekan/issues/1623
   // https://github.com/ChronikEwok/wekan/commit/cad9b20451bb6149bfb527a99b5001873b06c3de
   // https://github.com/ChronikEwok/wekan/commit/cad9b20451bb6149bfb527a99b5001873b06c3de
   // TODO: In public board, if you would like to switch between List/Swimlane view, you could
   // TODO: In public board, if you would like to switch between List/Swimlane view, you could

+ 13 - 5
client/lib/utils.js

@@ -6,12 +6,18 @@ Utils = {
     currentUser = Meteor.user();
     currentUser = Meteor.user();
     if (currentUser) {
     if (currentUser) {
       Meteor.user().setBoardView(view);
       Meteor.user().setBoardView(view);
-    } else if (view === 'board-view-lists') {
-      cookies.set('boardView', 'board-view-lists'); //true
     } else if (view === 'board-view-swimlanes') {
     } else if (view === 'board-view-swimlanes') {
       cookies.set('boardView', 'board-view-swimlanes'); //true
       cookies.set('boardView', 'board-view-swimlanes'); //true
+      location.reload();
+    } else if (view === 'board-view-lists') {
+      cookies.set('boardView', 'board-view-lists'); //true
+      location.reload();
     } else if (view === 'board-view-cal') {
     } else if (view === 'board-view-cal') {
       cookies.set('boardView', 'board-view-cal'); //true
       cookies.set('boardView', 'board-view-cal'); //true
+      location.reload();
+    } else {
+      cookies.set('boardView', 'board-view-swimlanes'); //true
+      location.reload();
     }
     }
   },
   },
 
 
@@ -24,14 +30,16 @@ Utils = {
     currentUser = Meteor.user();
     currentUser = Meteor.user();
     if (currentUser) {
     if (currentUser) {
       return (currentUser.profile || {}).boardView;
       return (currentUser.profile || {}).boardView;
-    } else if (cookies.get('boardView') === 'board-view-lists') {
-      return 'board-view-lists';
     } else if (cookies.get('boardView') === 'board-view-swimlanes') {
     } else if (cookies.get('boardView') === 'board-view-swimlanes') {
       return 'board-view-swimlanes';
       return 'board-view-swimlanes';
+    } else if (cookies.get('boardView') === 'board-view-lists') {
+      return 'board-view-lists';
     } else if (cookies.get('boardView') === 'board-view-cal') {
     } else if (cookies.get('boardView') === 'board-view-cal') {
       return 'board-view-cal';
       return 'board-view-cal';
     } else {
     } else {
-      return false;
+      cookies.set('boardView', 'board-view-swimlanes'); //true
+      location.reload();
+      return 'board-view-swimlanes';
     }
     }
   },
   },
 
 

+ 3 - 3
docker-compose.yml

@@ -115,11 +115,11 @@ services:
     # NOTE: Quay is currently not updated, use Docker Hub image below c)
     # NOTE: Quay is currently not updated, use Docker Hub image below c)
     # a) For Wekan Meteor 1.8.x version at master branch,
     # a) For Wekan Meteor 1.8.x version at master branch,
     #    using https://quay.io/wekan/wekan automatic builds
     #    using https://quay.io/wekan/wekan automatic builds
-    image: quay.io/wekan/wekan
+    #image: quay.io/wekan/wekan
     # b) Using specific Meteor 1.6.x version tag:
     # b) Using specific Meteor 1.6.x version tag:
     # image: quay.io/wekan/wekan:v1.95
     # image: quay.io/wekan/wekan:v1.95
     # c) Using Docker Hub automatic builds https://hub.docker.com/r/wekanteam/wekan
     # c) Using Docker Hub automatic builds https://hub.docker.com/r/wekanteam/wekan
-    #image: wekanteam/wekan
+    image: wekanteam/wekan
     # image: wekanteam/wekan:v2.99
     # image: wekanteam/wekan:v2.99
     #-------------------------------------------------------------------------------------
     #-------------------------------------------------------------------------------------
     container_name: wekan-app
     container_name: wekan-app
@@ -180,7 +180,7 @@ services:
       # that if you're using more than 1 instance of Wekan
       # that if you're using more than 1 instance of Wekan
       # (or any MeteorJS based tool) you're supposed to set
       # (or any MeteorJS based tool) you're supposed to set
       # MONGO_OPLOG_URL as an environment variable.
       # MONGO_OPLOG_URL as an environment variable.
-      # Without setting it, Meteor will perform a pull-and-diff
+      # Without setting it, Meteor will perform a poll-and-diff
       # update of it's dataset. With it, Meteor will update from
       # update of it's dataset. With it, Meteor will update from
       # the OPLOG. See here
       # the OPLOG. See here
       #   https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908
       #   https://blog.meteor.com/tuning-meteor-mongo-livedata-for-scalability-13fe9deb8908

+ 5 - 0
find-replace.sh

@@ -0,0 +1,5 @@
+
+# Recursive find/replace.
+# Syntax: ./find-replace.sh searchtext replacetext
+
+egrep -lRZ '$1' . | xargs -0 -l sed -i -e 's/$1/$2/g'

+ 2 - 1
i18n/ar.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/bg.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/br.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/ca.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/cs.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/da.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Afstemning",
   "voting": "Afstemning",
   "archived": "Arkiveret",
   "archived": "Arkiveret",
   "delete-linked-card-before-this-card": "Du kan ikke slette dette kort før der slettes sammenkædede kort som har",
   "delete-linked-card-before-this-card": "Du kan ikke slette dette kort før der slettes sammenkædede kort som har",
-  "delete-linked-cards-before-this-list": "Du kan ikke slette denne liste før der slettes sammenkædede kort, der peger til kort i denne liste"
+  "delete-linked-cards-before-this-list": "Du kan ikke slette denne liste før der slettes sammenkædede kort, der peger til kort i denne liste",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 3 - 2
i18n/de.i18n.json

@@ -807,6 +807,7 @@
   "last-activity": "Letzte Aktivität",
   "last-activity": "Letzte Aktivität",
   "voting": "Abstimunng",
   "voting": "Abstimunng",
   "archived": "Archiviert",
   "archived": "Archiviert",
-  "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-card-before-this-card": "Sie können diese Karte erst löschen, wenn Sie alle verbundenen Karten gelöscht haben.",
+  "delete-linked-cards-before-this-list": "Sie können diese Liste erst löschen, wenn Sie alle Karten gelöscht haben, die auf Karten in dieser Liste verweisen.",
+  "hide-checked-items": "Erledigte ausblenden"
 }
 }

+ 2 - 1
i18n/el.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/en-GB.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/en.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/eo.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/es-AR.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/es-CL.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/es.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Votar",
   "voting": "Votar",
   "archived": "Archivado",
   "archived": "Archivado",
   "delete-linked-card-before-this-card": "No puede borrar esta tarjeta antes de borrar la tarjeta enlazada que tiene",
   "delete-linked-card-before-this-card": "No puede borrar esta tarjeta antes de borrar la tarjeta enlazada que tiene",
-  "delete-linked-cards-before-this-list": "No puede borrar esta lista antes de borrar las tarjetas enlazadas que apuntan a tarjetas en esta lista"
+  "delete-linked-cards-before-this-list": "No puede borrar esta lista antes de borrar las tarjetas enlazadas que apuntan a tarjetas en esta lista",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/eu.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 10 - 9
i18n/fa.i18n.json

@@ -164,15 +164,15 @@
   "cardStartVotingPopup-title": "شروع به رای",
   "cardStartVotingPopup-title": "شروع به رای",
   "positiveVoteMembersPopup-title": "طرفداران",
   "positiveVoteMembersPopup-title": "طرفداران",
   "negativeVoteMembersPopup-title": "مخالفان",
   "negativeVoteMembersPopup-title": "مخالفان",
-  "card-edit-voting": "Edit voting",
-  "editVoteEndDatePopup-title": "Change vote end date",
-  "allowNonBoardMembers": "Allow all logged in users",
+  "card-edit-voting": "ویرایش رای",
+  "editVoteEndDatePopup-title": "تغییر تاریخ پایان رای گیری",
+  "allowNonBoardMembers": "اجازه دادن به همه کاربران وارد شده",
   "vote-question": "سوال رای گیری",
   "vote-question": "سوال رای گیری",
   "vote-public": "نمایش چه کسی به چه رای داده است",
   "vote-public": "نمایش چه کسی به چه رای داده است",
-  "vote-for-it": "for it",
+  "vote-for-it": "برای این",
   "vote-against": "بر خلاف",
   "vote-against": "بر خلاف",
-  "deleteVotePopup-title": "Delete vote?",
-  "vote-delete-pop": "Deleting is permanent. You will lose all actions associated with this vote.",
+  "deleteVotePopup-title": "رای حذف شود ؟",
+  "vote-delete-pop": "حذف کردن به صورت دائمی هست و قابل برگشت نیست.",
   "cardDeletePopup-title": "آیا می خواهید کارت را حذف کنید؟",
   "cardDeletePopup-title": "آیا می خواهید کارت را حذف کنید؟",
   "cardDetailsActionsPopup-title": "اعمال کارت",
   "cardDetailsActionsPopup-title": "اعمال کارت",
   "cardLabelsPopup-title": "برچسب ها",
   "cardLabelsPopup-title": "برچسب ها",
@@ -256,8 +256,8 @@
   "current": "جاری",
   "current": "جاری",
   "custom-field-delete-pop": "این اقدام فیلدشخصی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
   "custom-field-delete-pop": "این اقدام فیلدشخصی را بهمراه تمامی تاریخچه آن از کارت ها پاک می کند و برگشت پذیر نمی باشد",
   "custom-field-checkbox": "جعبه انتخابی",
   "custom-field-checkbox": "جعبه انتخابی",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "واحد پولی",
+  "custom-field-currency-option": "کد واحد پولی",
   "custom-field-date": "تاریخ",
   "custom-field-date": "تاریخ",
   "custom-field-dropdown": "لیست افتادنی",
   "custom-field-dropdown": "لیست افتادنی",
   "custom-field-dropdown-none": "(هیچ)",
   "custom-field-dropdown-none": "(هیچ)",
@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/fi.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Äänestys",
   "voting": "Äänestys",
   "archived": "Arkistoitu",
   "archived": "Arkistoitu",
   "delete-linked-card-before-this-card": "Et voi poistaa tätä korttia ennenkuin ensin poistat linkitetyn kortin jolla on",
   "delete-linked-card-before-this-card": "Et voi poistaa tätä korttia ennenkuin ensin poistat linkitetyn kortin jolla on",
-  "delete-linked-cards-before-this-list": "Et voi poistaa tätä listaa ennenkuin poistat linkitetyt kortit jotka osoittavat kortteihin tässä listassa"
+  "delete-linked-cards-before-this-list": "Et voi poistaa tätä listaa ennenkuin poistat linkitetyt kortit jotka osoittavat kortteihin tässä listassa",
+  "hide-checked-items": "Piilota ruksatut kohdat"
 }
 }

+ 2 - 1
i18n/fr.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Vote",
   "voting": "Vote",
   "archived": "Archivé",
   "archived": "Archivé",
   "delete-linked-card-before-this-card": "Vous ne pouvez pas supprimer cette carte avant d'avoir d'abord supprimé la carte liée qui a",
   "delete-linked-card-before-this-card": "Vous ne pouvez pas supprimer cette carte avant d'avoir d'abord supprimé la carte liée qui a",
-  "delete-linked-cards-before-this-list": "Vous ne pouvez pas supprimer cette liste avant d'avoir d'abord supprimé les cartes liées qui pointent vers des cartes de cette liste"
+  "delete-linked-cards-before-this-list": "Vous ne pouvez pas supprimer cette liste avant d'avoir d'abord supprimé les cartes liées qui pointent vers des cartes de cette liste",
+  "hide-checked-items": "Cacher les éléments cochés"
 }
 }

+ 2 - 1
i18n/gl.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/he.i18n.json

@@ -808,5 +808,6 @@
   "voting": "הצבעה",
   "voting": "הצבעה",
   "archived": "בארכיון",
   "archived": "בארכיון",
   "delete-linked-card-before-this-card": "לא ניתן למחוק את הכרטיס הזה לפני שמוחקים את הכרטיס המקושר שיש לו",
   "delete-linked-card-before-this-card": "לא ניתן למחוק את הכרטיס הזה לפני שמוחקים את הכרטיס המקושר שיש לו",
-  "delete-linked-cards-before-this-list": "לא ניתן למחוק את הרשימה הזו לפני שמוחקים את הכרטיסים שמצביעים לכרטיסים ברשימה הזו"
+  "delete-linked-cards-before-this-list": "לא ניתן למחוק את הרשימה הזו לפני שמוחקים את הכרטיסים שמצביעים לכרטיסים ברשימה הזו",
+  "hide-checked-items": "הסתרת הפריטים שסומנו"
 }
 }

+ 2 - 1
i18n/hi.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/hu.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/hy.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 177 - 176
i18n/id.i18n.json

@@ -1,7 +1,7 @@
 {
 {
   "accept": "Terima",
   "accept": "Terima",
-  "act-activity-notify": "Activity Notification",
-  "act-addAttachment": "added attachment __attachment__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
+  "act-activity-notify": "Pemeberitahuan Aktifitas",
+  "act-addAttachment": "ditambahkan lampiran __attachment__ di kartu __card__ pada daftar __list__ pada swimline __swimline__ pada papan __board__",
   "act-deleteAttachment": "deleted attachment __attachment__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-deleteAttachment": "deleted attachment __attachment__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-addSubtask": "added subtask __subtask__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-addSubtask": "added subtask __subtask__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-addLabel": "Added label __label__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-addLabel": "Added label __label__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
@@ -25,7 +25,7 @@
   "act-createCustomField": "created custom field __customField__ at board __board__",
   "act-createCustomField": "created custom field __customField__ at board __board__",
   "act-deleteCustomField": "deleted custom field __customField__ at board __board__",
   "act-deleteCustomField": "deleted custom field __customField__ at board __board__",
   "act-setCustomField": "edited custom field __customField__: __customFieldValue__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
   "act-setCustomField": "edited custom field __customField__: __customFieldValue__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
-  "act-createList": "added list __list__ to board __board__",
+  "act-createList": "ditambahkan daftar __list__ pada papan __board__",
   "act-addBoardMember": "added member __member__ to board __board__",
   "act-addBoardMember": "added member __member__ to board __board__",
   "act-archivedBoard": "Board __board__ moved to Archive",
   "act-archivedBoard": "Board __board__ moved to Archive",
   "act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
   "act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
@@ -98,7 +98,7 @@
   "and-n-other-card_plural": "Dan__menghitung__kartu lain",
   "and-n-other-card_plural": "Dan__menghitung__kartu lain",
   "apply": "Terapkan",
   "apply": "Terapkan",
   "app-is-offline": "Loading, please wait. Refreshing the page will cause data loss. If loading does not work, please check that server has not stopped.",
   "app-is-offline": "Loading, please wait. Refreshing the page will cause data loss. If loading does not work, please check that server has not stopped.",
-  "archive": "Move to Archive",
+  "archive": "Pindahlan ke Arsip",
   "archive-all": "Move All to Archive",
   "archive-all": "Move All to Archive",
   "archive-board": "Move Board to Archive",
   "archive-board": "Move Board to Archive",
   "archive-card": "Move Card to Archive",
   "archive-card": "Move Card to Archive",
@@ -108,11 +108,11 @@
   "archiveBoardPopup-title": "Move Board to Archive?",
   "archiveBoardPopup-title": "Move Board to Archive?",
   "archived-items": "Arsip",
   "archived-items": "Arsip",
   "archived-boards": "Boards in Archive",
   "archived-boards": "Boards in Archive",
-  "restore-board": "Restore Board",
-  "no-archived-boards": "No Boards in Archive.",
+  "restore-board": "Pulihkan Papan",
+  "no-archived-boards": "Tidak ada Papan pada Arsip",
   "archives": "Arsip",
   "archives": "Arsip",
-  "template": "Template",
-  "templates": "Templates",
+  "template": "Klise",
+  "templates": "Klise",
   "assign-member": "Tugaskan anggota",
   "assign-member": "Tugaskan anggota",
   "attached": "terlampir",
   "attached": "terlampir",
   "attachment": "Lampiran",
   "attachment": "Lampiran",
@@ -131,22 +131,22 @@
   "boardChangeTitlePopup-title": "Ganti Nama Panel",
   "boardChangeTitlePopup-title": "Ganti Nama Panel",
   "boardChangeVisibilityPopup-title": "Ubah Penampakan",
   "boardChangeVisibilityPopup-title": "Ubah Penampakan",
   "boardChangeWatchPopup-title": "Ubah Pengamatan",
   "boardChangeWatchPopup-title": "Ubah Pengamatan",
-  "boardMenuPopup-title": "Board Settings",
-  "boardChangeViewPopup-title": "Board View",
+  "boardMenuPopup-title": "Pengaturan Papan",
+  "boardChangeViewPopup-title": "Tampilan Papan",
   "boards": "Panel",
   "boards": "Panel",
-  "board-view": "Board View",
-  "board-view-cal": "Calendar",
+  "board-view": "Tampilan Papan",
+  "board-view-cal": "Kalender",
   "board-view-swimlanes": "Swimlanes",
   "board-view-swimlanes": "Swimlanes",
-  "board-view-collapse": "Collapse",
+  "board-view-collapse": "Ciutkan",
   "board-view-lists": "Daftar",
   "board-view-lists": "Daftar",
   "bucket-example": "Contohnya seperti “Bucket List” ",
   "bucket-example": "Contohnya seperti “Bucket List” ",
   "cancel": "Batal",
   "cancel": "Batal",
-  "card-archived": "This card is moved to Archive.",
-  "board-archived": "This board is moved to Archive.",
+  "card-archived": "Kartu ini telah dipindahkan ke Arsip",
+  "board-archived": "Kartu ini telah dipindahkan ke Arsip",
   "card-comments-title": "Kartu ini punya %s komentar",
   "card-comments-title": "Kartu ini punya %s komentar",
   "card-delete-notice": "Menghapus sama dengan permanen. Anda akan kehilangan semua aksi yang terhubung ke kartu ini",
   "card-delete-notice": "Menghapus sama dengan permanen. Anda akan kehilangan semua aksi yang terhubung ke kartu ini",
   "card-delete-pop": "Semua aksi akan dihapus dari aktivitas dan anda tidak bisa lagi buka kartu ini",
   "card-delete-pop": "Semua aksi akan dihapus dari aktivitas dan anda tidak bisa lagi buka kartu ini",
-  "card-delete-suggest-archive": "You can move a card to Archive to remove it from the board and preserve the activity.",
+  "card-delete-suggest-archive": "Kamu bisa memindahkan Kartu ke Arsip untuk menghapusnya dari Papan dan mempertahankan Aktifitas",
   "card-due": "Jatuh Tempo",
   "card-due": "Jatuh Tempo",
   "card-due-on": "Jatuh Tempo pada",
   "card-due-on": "Jatuh Tempo pada",
   "card-spent": "Spent Time",
   "card-spent": "Spent Time",
@@ -425,8 +425,8 @@
   "muted-info": "Anda tidak akan pernah dinotifikasi semua perubahan di panel ini",
   "muted-info": "Anda tidak akan pernah dinotifikasi semua perubahan di panel ini",
   "my-boards": "Panel saya",
   "my-boards": "Panel saya",
   "name": "Nama",
   "name": "Nama",
-  "no-archived-cards": "No cards in Archive.",
-  "no-archived-lists": "No lists in Archive.",
+  "no-archived-cards": "Tidak ada kartu di arsip.",
+  "no-archived-lists": "Tidak ada daftar di arsip.",
   "no-archived-swimlanes": "No swimlanes in Archive.",
   "no-archived-swimlanes": "No swimlanes in Archive.",
   "no-results": "Tidak ada hasil",
   "no-results": "Tidak ada hasil",
   "normal": "Normal",
   "normal": "Normal",
@@ -452,8 +452,8 @@
   "quick-access-description": "Beri bintang panel untuk menambah shortcut di papan ini",
   "quick-access-description": "Beri bintang panel untuk menambah shortcut di papan ini",
   "remove-cover": "Hapus Sampul",
   "remove-cover": "Hapus Sampul",
   "remove-from-board": "Hapus dari panel",
   "remove-from-board": "Hapus dari panel",
-  "remove-label": "Remove Label",
-  "listDeletePopup-title": "Delete List ?",
+  "remove-label": "Hapus Label",
+  "listDeletePopup-title": "Hapus Daftar ?",
   "remove-member": "Hapus Anggota",
   "remove-member": "Hapus Anggota",
   "remove-member-from-card": "Hapus dari Kartu",
   "remove-member-from-card": "Hapus dari Kartu",
   "remove-member-pop": "Hapus__nama__(__username__) dari __boardTitle__? Partisipan akan dihapus dari semua kartu di panel ini. Mereka akan diberi tahu",
   "remove-member-pop": "Hapus__nama__(__username__) dari __boardTitle__? Partisipan akan dihapus dari semua kartu di panel ini. Mereka akan diberi tahu",
@@ -463,21 +463,21 @@
   "restore": "Pulihkan",
   "restore": "Pulihkan",
   "save": "Simpan",
   "save": "Simpan",
   "search": "Cari",
   "search": "Cari",
-  "rules": "Rules",
-  "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",
-  "setWipLimitPopup-title": "Set WIP Limit",
+  "rules": "Peraturan",
+  "search-cards": "Cari dari judul kartu/daftar, deskripsi dan bidang khusus di papan ini",
+  "search-example": "Teks untuk dicari ?",
+  "select-color": "Pilih Warna",
+  "set-wip-limit-value": "Tetapkan batas untuk jumlah tugas maksimum dalam daftar ini",
+  "setWipLimitPopup-title": "Tetapkan Batas WIP ",
   "shortcut-assign-self": "Masukkan diri anda sendiri ke kartu ini",
   "shortcut-assign-self": "Masukkan diri anda sendiri ke kartu ini",
-  "shortcut-autocomplete-emoji": "Autocomplete emoji",
+  "shortcut-autocomplete-emoji": "Pelengkap Otomatis emoji",
   "shortcut-autocomplete-members": "Autocomplete partisipan",
   "shortcut-autocomplete-members": "Autocomplete partisipan",
   "shortcut-clear-filters": "Bersihkan semua saringan",
   "shortcut-clear-filters": "Bersihkan semua saringan",
   "shortcut-close-dialog": "Tutup Dialog",
   "shortcut-close-dialog": "Tutup Dialog",
   "shortcut-filter-my-cards": "Filter kartu saya",
   "shortcut-filter-my-cards": "Filter kartu saya",
   "shortcut-show-shortcuts": "Angkat naik shortcut daftar ini",
   "shortcut-show-shortcuts": "Angkat naik shortcut daftar ini",
-  "shortcut-toggle-filterbar": "Toggle Filter Sidebar",
-  "shortcut-toggle-sidebar": "Toggle Board Sidebar",
+  "shortcut-toggle-filterbar": "Toggle Filter Bilah Samping",
+  "shortcut-toggle-sidebar": "Toggle Papan Bilah Samping",
   "show-cards-minimum-count": "Tampilkan jumlah kartu jika daftar punya lebih dari ",
   "show-cards-minimum-count": "Tampilkan jumlah kartu jika daftar punya lebih dari ",
   "sidebar-open": "Buka Sidebar",
   "sidebar-open": "Buka Sidebar",
   "sidebar-close": "Tutup Sidebar",
   "sidebar-close": "Tutup Sidebar",
@@ -489,16 +489,16 @@
   "team": "Tim",
   "team": "Tim",
   "this-board": "Panel ini",
   "this-board": "Panel ini",
   "this-card": "Kartu ini",
   "this-card": "Kartu ini",
-  "spent-time-hours": "Spent time (hours)",
-  "overtime-hours": "Overtime (hours)",
-  "overtime": "Overtime",
-  "has-overtime-cards": "Has overtime cards",
+  "spent-time-hours": "Waktu yang dihabiskan (jam)",
+  "overtime-hours": "Lembur (jam)",
+  "overtime": "Lembur",
+  "has-overtime-cards": "Punya kartu lembur",
   "has-spenttime-cards": "Has spent time cards",
   "has-spenttime-cards": "Has spent time cards",
   "time": "Waktu",
   "time": "Waktu",
   "title": "Judul",
   "title": "Judul",
   "tracking": "Pelacakan",
   "tracking": "Pelacakan",
   "tracking-info": "Anda akan dinotifikasi semua perubahan di kartu tersebut diaman anda terlibat sebagai creator atau partisipan",
   "tracking-info": "Anda akan dinotifikasi semua perubahan di kartu tersebut diaman anda terlibat sebagai creator atau partisipan",
-  "type": "Type",
+  "type": "tipe",
   "unassign-member": "Tidak sertakan partisipan",
   "unassign-member": "Tidak sertakan partisipan",
   "unsaved-description": "Anda memiliki deskripsi yang belum disimpan.",
   "unsaved-description": "Anda memiliki deskripsi yang belum disimpan.",
   "unwatch": "Tidak mengamati",
   "unwatch": "Tidak mengamati",
@@ -515,11 +515,11 @@
   "welcome-swimlane": "Milestone 1",
   "welcome-swimlane": "Milestone 1",
   "welcome-list1": "Tingkat dasar",
   "welcome-list1": "Tingkat dasar",
   "welcome-list2": "Tingkat lanjut",
   "welcome-list2": "Tingkat lanjut",
-  "card-templates-swimlane": "Card Templates",
-  "list-templates-swimlane": "List Templates",
-  "board-templates-swimlane": "Board Templates",
+  "card-templates-swimlane": "Klise Kartu",
+  "list-templates-swimlane": "Klise Daftar",
+  "board-templates-swimlane": "Klise Papan",
   "what-to-do": "Apa yang mau Anda lakukan?",
   "what-to-do": "Apa yang mau Anda lakukan?",
-  "wipLimitErrorPopup-title": "Invalid WIP Limit",
+  "wipLimitErrorPopup-title": "Batas WIP tidak valid",
   "wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
   "wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
   "wipLimitErrorPopup-dialog-pt2": "Please move some tasks out of this list, or set a higher WIP limit.",
   "wipLimitErrorPopup-dialog-pt2": "Please move some tasks out of this list, or set a higher WIP limit.",
   "admin-panel": "Panel Admin",
   "admin-panel": "Panel Admin",
@@ -544,11 +544,11 @@
   "invitation-code": "Kode Undangan",
   "invitation-code": "Kode Undangan",
   "email-invite-register-subject": "__inviter__ mengirim undangan ke Anda",
   "email-invite-register-subject": "__inviter__ mengirim undangan ke Anda",
   "email-invite-register-text": "Dear __user__,\n\n__inviter__ invites you to kanban board for collaborations.\n\nPlease follow the link below:\n__url__\n\nAnd your invitation code is: __icode__\n\nThanks.",
   "email-invite-register-text": "Dear __user__,\n\n__inviter__ invites you to kanban board for collaborations.\n\nPlease follow the link below:\n__url__\n\nAnd your invitation code is: __icode__\n\nThanks.",
-  "email-smtp-test-subject": "SMTP Test Email",
+  "email-smtp-test-subject": "SMTP Tes Surel",
   "email-smtp-test-text": "You have successfully sent an email",
   "email-smtp-test-text": "You have successfully sent an email",
   "error-invitation-code-not-exist": "Kode undangan tidak ada",
   "error-invitation-code-not-exist": "Kode undangan tidak ada",
   "error-notAuthorized": "You are not authorized to view this page.",
   "error-notAuthorized": "You are not authorized to view this page.",
-  "webhook-title": "Webhook Name",
+  "webhook-title": "Nama Webhook",
   "webhook-token": "Token (Optional for Authentication)",
   "webhook-token": "Token (Optional for Authentication)",
   "outgoing-webhooks": "Outgoing Webhooks",
   "outgoing-webhooks": "Outgoing Webhooks",
   "bidirectional-webhooks": "Two-Way Webhooks",
   "bidirectional-webhooks": "Two-Way Webhooks",
@@ -558,10 +558,10 @@
   "global-webhook": "Global Webhooks",
   "global-webhook": "Global Webhooks",
   "new-outgoing-webhook": "New Outgoing Webhook",
   "new-outgoing-webhook": "New Outgoing Webhook",
   "no-name": "(Unknown)",
   "no-name": "(Unknown)",
-  "Node_version": "Node version",
-  "Meteor_version": "Meteor version",
-  "MongoDB_version": "MongoDB version",
-  "MongoDB_storage_engine": "MongoDB storage engine",
+  "Node_version": "Versi Node",
+  "Meteor_version": "Versi Meteor",
+  "MongoDB_version": "Versi MongoDB",
+  "MongoDB_storage_engine": "Mesin penyimpanan MongoDb",
   "MongoDB_Oplog_enabled": "MongoDB Oplog enabled",
   "MongoDB_Oplog_enabled": "MongoDB Oplog enabled",
   "OS_Arch": "OS Arch",
   "OS_Arch": "OS Arch",
   "OS_Cpus": "OS CPU Count",
   "OS_Cpus": "OS CPU Count",
@@ -572,44 +572,44 @@
   "OS_Totalmem": "OS Total Memory",
   "OS_Totalmem": "OS Total Memory",
   "OS_Type": "OS Type",
   "OS_Type": "OS Type",
   "OS_Uptime": "OS Uptime",
   "OS_Uptime": "OS Uptime",
-  "days": "days",
-  "hours": "hours",
-  "minutes": "minutes",
-  "seconds": "seconds",
+  "days": "hari",
+  "hours": "m",
+  "minutes": "menit",
+  "seconds": "detik",
   "show-field-on-card": "Show this field on card",
   "show-field-on-card": "Show this field on card",
   "automatically-field-on-card": "Auto create field to all cards",
   "automatically-field-on-card": "Auto create field to all cards",
   "showLabel-field-on-card": "Show field label on minicard",
   "showLabel-field-on-card": "Show field label on minicard",
-  "yes": "Yes",
-  "no": "No",
-  "accounts": "Accounts",
+  "yes": "Ya",
+  "no": "Tidak",
+  "accounts": "Akun",
   "accounts-allowEmailChange": "Allow Email Change",
   "accounts-allowEmailChange": "Allow Email Change",
   "accounts-allowUserNameChange": "Allow Username Change",
   "accounts-allowUserNameChange": "Allow Username Change",
-  "createdAt": "Created at",
-  "verified": "Verified",
-  "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",
-  "assigned-by": "Assigned By",
-  "requested-by": "Requested By",
+  "createdAt": "Dibuat pada",
+  "verified": "Terverifikasi",
+  "active": "Aktif",
+  "card-received": "Diterima",
+  "card-received-on": "Diterima pada",
+  "card-end": "Berakhir",
+  "card-end-on": "Berakhir pada",
+  "editCardReceivedDatePopup-title": "Ubah tanggal diterima",
+  "editCardEndDatePopup-title": "Ubah tanggal berakhir",
+  "setCardColorPopup-title": "Tetapkan warna",
+  "setCardActionsColorPopup-title": "Pilih warna",
+  "setSwimlaneColorPopup-title": "Pilih warna",
+  "setListColorPopup-title": "Pilih warna",
+  "assigned-by": "Ditandatangani Oleh",
+  "requested-by": "Diminta Oleh",
   "board-delete-notice": "Deleting is permanent. You will lose all lists, cards and actions associated with this board.",
   "board-delete-notice": "Deleting is permanent. You will lose all lists, cards and actions associated with this board.",
   "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
   "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
-  "boardDeletePopup-title": "Delete Board?",
-  "delete-board": "Delete Board",
+  "boardDeletePopup-title": "Hapus Papan?",
+  "delete-board": "Hapus Papan",
   "default-subtasks-board": "Subtasks for __board__ board",
   "default-subtasks-board": "Subtasks for __board__ board",
-  "default": "Default",
-  "queue": "Queue",
+  "default": "Standar",
+  "queue": "Antrian",
   "subtask-settings": "Subtasks Settings",
   "subtask-settings": "Subtasks Settings",
-  "card-settings": "Card Settings",
+  "card-settings": "Pengaturan Kartu",
   "boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
   "boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
-  "boardCardSettingsPopup-title": "Card Settings",
+  "boardCardSettingsPopup-title": "Pengaturan Kartu",
   "deposit-subtasks-board": "Deposit subtasks to this board:",
   "deposit-subtasks-board": "Deposit subtasks to this board:",
   "deposit-subtasks-list": "Landing list for subtasks deposited here:",
   "deposit-subtasks-list": "Landing list for subtasks deposited here:",
   "show-parent-in-minicard": "Show parent in minicard:",
   "show-parent-in-minicard": "Show parent in minicard:",
@@ -629,34 +629,34 @@
   "activity-delete-attach-card": "deleted an attachment",
   "activity-delete-attach-card": "deleted an attachment",
   "activity-set-customfield": "set custom field '%s' to '%s' in %s",
   "activity-set-customfield": "set custom field '%s' to '%s' in %s",
   "activity-unset-customfield": "unset custom field '%s' in %s",
   "activity-unset-customfield": "unset custom field '%s' in %s",
-  "r-rule": "Rule",
-  "r-add-trigger": "Add trigger",
-  "r-add-action": "Add action",
-  "r-board-rules": "Board rules",
-  "r-add-rule": "Add rule",
-  "r-view-rule": "View rule",
+  "r-rule": "Aturan",
+  "r-add-trigger": "Tambahkan pelatuk",
+  "r-add-action": "Tambahkan aksi",
+  "r-board-rules": "Aturan papan",
+  "r-add-rule": "Tambahkan aturan",
+  "r-view-rule": "Lihat aturan",
   "r-delete-rule": "Delete rule",
   "r-delete-rule": "Delete rule",
   "r-new-rule-name": "New rule title",
   "r-new-rule-name": "New rule title",
   "r-no-rules": "No rules",
   "r-no-rules": "No rules",
-  "r-when-a-card": "When a card",
-  "r-is": "is",
-  "r-is-moved": "is moved",
-  "r-added-to": "Added to",
-  "r-removed-from": "Removed from",
-  "r-the-board": "the board",
-  "r-list": "list",
-  "set-filter": "Set Filter",
-  "r-moved-to": "Moved to",
-  "r-moved-from": "Moved from",
-  "r-archived": "Moved to Archive",
-  "r-unarchived": "Restored from Archive",
-  "r-a-card": "a card",
-  "r-when-a-label-is": "When a label is",
-  "r-when-the-label": "When the label",
-  "r-list-name": "list name",
-  "r-when-a-member": "When a member is",
-  "r-when-the-member": "When the member",
-  "r-name": "name",
+  "r-when-a-card": "Ketika kartu",
+  "r-is": "adalah",
+  "r-is-moved": "dipindahkan",
+  "r-added-to": "Ditambahkan ke",
+  "r-removed-from": "Dihapus dari",
+  "r-the-board": "papan",
+  "r-list": "daftar",
+  "set-filter": "Atur Saringan",
+  "r-moved-to": "Dipindahkan ke",
+  "r-moved-from": "Dipindahkan dari",
+  "r-archived": "Dipindahkan ke Arsip",
+  "r-unarchived": "Dipulihkan dari Arsip",
+  "r-a-card": "Kartu",
+  "r-when-a-label-is": "Ketika label adalah",
+  "r-when-the-label": "Ketika label",
+  "r-list-name": "nama daftar",
+  "r-when-a-member": "Ketika anggota adalah",
+  "r-when-the-member": "Ketika anggota",
+  "r-name": "nama",
   "r-when-a-attach": "When an attachment",
   "r-when-a-attach": "When an attachment",
   "r-when-a-checklist": "When a checklist is",
   "r-when-a-checklist": "When a checklist is",
   "r-when-the-checklist": "When the checklist",
   "r-when-the-checklist": "When the checklist",
@@ -669,70 +669,70 @@
   "r-move-card-to": "Move card to",
   "r-move-card-to": "Move card to",
   "r-top-of": "Top of",
   "r-top-of": "Top of",
   "r-bottom-of": "Bottom of",
   "r-bottom-of": "Bottom of",
-  "r-its-list": "its list",
-  "r-archive": "Move to Archive",
-  "r-unarchive": "Restore from Archive",
-  "r-card": "card",
+  "r-its-list": "daftar ini",
+  "r-archive": "Pindahlan ke Arsip",
+  "r-unarchive": "Pulihkan dari Arsip",
+  "r-card": "Kartu",
   "r-add": "Tambah",
   "r-add": "Tambah",
-  "r-remove": "Remove",
+  "r-remove": "hapus",
   "r-label": "label",
   "r-label": "label",
-  "r-member": "member",
-  "r-remove-all": "Remove all members from the card",
-  "r-set-color": "Set color to",
+  "r-member": "anggota",
+  "r-remove-all": "Hapus semua anggota dari kartu",
+  "r-set-color": "Tetapkan warna ke",
   "r-checklist": "checklist",
   "r-checklist": "checklist",
   "r-check-all": "Check all",
   "r-check-all": "Check all",
   "r-uncheck-all": "Uncheck all",
   "r-uncheck-all": "Uncheck all",
   "r-items-check": "items of checklist",
   "r-items-check": "items of checklist",
   "r-check": "Check",
   "r-check": "Check",
   "r-uncheck": "Uncheck",
   "r-uncheck": "Uncheck",
-  "r-item": "item",
+  "r-item": "Item",
   "r-of-checklist": "of checklist",
   "r-of-checklist": "of checklist",
   "r-send-email": "Send an email",
   "r-send-email": "Send an email",
-  "r-to": "to",
-  "r-of": "of",
-  "r-subject": "subject",
+  "r-to": "kepada",
+  "r-of": "dari",
+  "r-subject": "Subyek",
   "r-rule-details": "Rule details",
   "r-rule-details": "Rule details",
   "r-d-move-to-top-gen": "Move card to top of its list",
   "r-d-move-to-top-gen": "Move card to top of its list",
   "r-d-move-to-top-spec": "Move card to top of list",
   "r-d-move-to-top-spec": "Move card to top of list",
   "r-d-move-to-bottom-gen": "Move card to bottom of its list",
   "r-d-move-to-bottom-gen": "Move card to bottom of its list",
   "r-d-move-to-bottom-spec": "Move card to bottom of list",
   "r-d-move-to-bottom-spec": "Move card to bottom of list",
-  "r-d-send-email": "Send email",
-  "r-d-send-email-to": "to",
-  "r-d-send-email-subject": "subject",
-  "r-d-send-email-message": "message",
-  "r-d-archive": "Move card to Archive",
-  "r-d-unarchive": "Restore card from Archive",
+  "r-d-send-email": "Kirim surel",
+  "r-d-send-email-to": "kepada",
+  "r-d-send-email-subject": "Subyek",
+  "r-d-send-email-message": "pesan",
+  "r-d-archive": "Pindahlan kartu ke Arsip",
+  "r-d-unarchive": "Pulihkan kartu dari Arsip",
   "r-d-add-label": "Tambahkan label",
   "r-d-add-label": "Tambahkan label",
-  "r-d-remove-label": "Remove label",
-  "r-create-card": "Create new card",
-  "r-in-list": "in list",
+  "r-d-remove-label": "Hapus label",
+  "r-create-card": "Buat kartu baru",
+  "r-in-list": "pada daftar",
   "r-in-swimlane": "in swimlane",
   "r-in-swimlane": "in swimlane",
-  "r-d-add-member": "Add member",
-  "r-d-remove-member": "Remove member",
-  "r-d-remove-all-member": "Remove all member",
+  "r-d-add-member": "Tambahkan anggota",
+  "r-d-remove-member": "Hapus anggota",
+  "r-d-remove-all-member": "Hapus semua anggota",
   "r-d-check-all": "Check all items of a list",
   "r-d-check-all": "Check all items of a list",
   "r-d-uncheck-all": "Uncheck all items of a list",
   "r-d-uncheck-all": "Uncheck all items of a list",
   "r-d-check-one": "Check item",
   "r-d-check-one": "Check item",
   "r-d-uncheck-one": "Uncheck item",
   "r-d-uncheck-one": "Uncheck item",
   "r-d-check-of-list": "of checklist",
   "r-d-check-of-list": "of checklist",
-  "r-d-add-checklist": "Add checklist",
-  "r-d-remove-checklist": "Remove checklist",
-  "r-by": "by",
-  "r-add-checklist": "Add checklist",
-  "r-with-items": "with items",
-  "r-items-list": "item1,item2,item3",
+  "r-d-add-checklist": "Tambahkan daftar periksa",
+  "r-d-remove-checklist": "Hapus daftar periksa",
+  "r-by": "oleh",
+  "r-add-checklist": "Tambahkan daftar periksa",
+  "r-with-items": "dengan item",
+  "r-items-list": "item 1, item2, item 3",
   "r-add-swimlane": "Add swimlane",
   "r-add-swimlane": "Add swimlane",
   "r-swimlane-name": "swimlane name",
   "r-swimlane-name": "swimlane name",
   "r-board-note": "Note: leave a field empty to match every possible value.",
   "r-board-note": "Note: leave a field empty to match every possible value.",
   "r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
   "r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
   "r-when-a-card-is-moved": "When a card is moved to another list",
   "r-when-a-card-is-moved": "When a card is moved to another list",
-  "r-set": "Set",
-  "r-update": "Update",
-  "r-datefield": "date field",
-  "r-df-start-at": "start",
-  "r-df-due-at": "due",
-  "r-df-end-at": "end",
-  "r-df-received-at": "received",
+  "r-set": "Tetapkan",
+  "r-update": "Ubah",
+  "r-datefield": "bidang tanggal",
+  "r-df-start-at": "mulai",
+  "r-df-due-at": "sampai",
+  "r-df-end-at": "berakhir",
+  "r-df-received-at": "diterima",
   "r-to-current-datetime": "to current date/time",
   "r-to-current-datetime": "to current date/time",
   "r-remove-value-from": "Remove value from",
   "r-remove-value-from": "Remove value from",
   "ldap": "LDAP",
   "ldap": "LDAP",
@@ -741,22 +741,22 @@
   "authentication-method": "Metode Autentikasi",
   "authentication-method": "Metode Autentikasi",
   "authentication-type": "Tipe Autentikasi",
   "authentication-type": "Tipe Autentikasi",
   "custom-product-name": "Custom Product Name",
   "custom-product-name": "Custom Product Name",
-  "layout": "Layout",
+  "layout": "Tata letak",
   "hide-logo": "Sembunyikan Logo",
   "hide-logo": "Sembunyikan Logo",
-  "add-custom-html-after-body-start": "Add Custom HTML after <body> start",
-  "add-custom-html-before-body-end": "Add Custom HTML before </body> end",
-  "error-undefined": "Something went wrong",
-  "error-ldap-login": "An error occurred while trying to login",
+  "add-custom-html-after-body-start": "Tambahkan HTML khusus setelah <body> mulai",
+  "add-custom-html-before-body-end": "Tambahkan HTML khusus sebelum </body> berakhir",
+  "error-undefined": "Ada yang salah",
+  "error-ldap-login": "Terjadi kesalahan saat mencoba masuk",
   "display-authentication-method": "Display Authentication Method",
   "display-authentication-method": "Display Authentication Method",
   "default-authentication-method": "Default Authentication Method",
   "default-authentication-method": "Default Authentication Method",
-  "duplicate-board": "Duplicate Board",
-  "people-number": "The number of people is:",
+  "duplicate-board": "Duplikat Papan",
+  "people-number": "Jumlah orang:",
   "swimlaneDeletePopup-title": "Delete Swimlane ?",
   "swimlaneDeletePopup-title": "Delete Swimlane ?",
   "swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
   "swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
-  "restore-all": "Restore all",
-  "delete-all": "Delete all",
-  "loading": "Loading, please wait.",
-  "previous_as": "last time was",
+  "restore-all": "Pulihkan semua",
+  "delete-all": "Hapus semua",
+  "loading": "Sedang memuat, harap tunggu.",
+  "previous_as": "terakhir kali adalah",
   "act-a-dueAt": "modified due time to \nWhen: __timeValue__\nWhere: __card__\n previous due was __timeOldValue__",
   "act-a-dueAt": "modified due time to \nWhen: __timeValue__\nWhere: __card__\n previous due was __timeOldValue__",
   "act-a-endAt": "modified ending time to __timeValue__ from (__timeOldValue__)",
   "act-a-endAt": "modified ending time to __timeValue__ from (__timeOldValue__)",
   "act-a-startAt": "modified starting time to __timeValue__ from (__timeOldValue__)",
   "act-a-startAt": "modified starting time to __timeValue__ from (__timeOldValue__)",
@@ -776,37 +776,38 @@
   "act-atUserComment": "You were mentioned in [__board__] __list__/__card__",
   "act-atUserComment": "You were mentioned in [__board__] __list__/__card__",
   "delete-user-confirm-popup": "Are you sure you want to delete this account? There is no undo.",
   "delete-user-confirm-popup": "Are you sure you want to delete this account? There is no undo.",
   "accounts-allowUserDelete": "Allow users to self delete their account",
   "accounts-allowUserDelete": "Allow users to self delete their account",
-  "hide-minicard-label-text": "Hide minicard label text",
-  "show-desktop-drag-handles": "Show desktop drag handles",
-  "assignee": "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",
+  "hide-minicard-label-text": "Sembunyikan teks label kartu mini",
+  "show-desktop-drag-handles": "Tampilkan gagang seret desktop",
+  "assignee": "Penerima tugas",
+  "cardAssigneesPopup-title": "Penerima tugas",
+  "addmore-detail": "Tambahkan deskripsi yang lebih rinci",
+  "show-on-card": "Tampilkan pada Kartu",
+  "new": "Baru",
+  "editUserPopup-title": "Ubah Pengguna",
+  "newUserPopup-title": "Pengguna Baru",
+  "notifications": "Pemberitahuan",
+  "view-all": "Lihat Semua",
+  "filter-by-unread": "Saring yang Belum Dibaca",
+  "mark-all-as-read": "Tandai semua telah dibaca",
+  "remove-all-read": "Hapus semua yang telah dibaca",
+  "allow-rename": "Ijinkan Ganti Nama",
+  "allowRenamePopup-title": "Ijinkan Ganti Nama",
+  "start-day-of-week": "Tetapkan hari dimulai dalam minggu",
+  "monday": "Senin",
+  "tuesday": "Selasa",
+  "wednesday": "Rabu",
+  "thursday": "Kamis",
+  "friday": "Jum'at",
+  "saturday": "Sabtu",
+  "sunday": "Minggu",
   "status": "Status",
   "status": "Status",
   "swimlane": "Swimlane",
   "swimlane": "Swimlane",
-  "owner": "Owner",
-  "last-modified-at": "Last modified at",
-  "last-activity": "Last activity",
-  "voting": "Voting",
-  "archived": "Archived",
-  "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "owner": "Pemilik",
+  "last-modified-at": "Terakhir diubah pada",
+  "last-activity": "Aktifitas terakhir",
+  "voting": "Pemungutan Suara",
+  "archived": "Diarsipkan",
+  "delete-linked-card-before-this-card": "Kamu tidak dapat menghapus kartu ini sebelum menghapus kartu tertaut yang telah",
+  "delete-linked-cards-before-this-list": "Kamu tidak dapat menghapus daftar ini sebelum menghapus kartu tertaut yang mengarah ke kartu dalam daftar ini",
+  "hide-checked-items": "Sembunyikan item yang dicentang"
 }
 }

+ 2 - 1
i18n/ig.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 4 - 3
i18n/it.i18n.json

@@ -256,8 +256,8 @@
   "current": "corrente",
   "current": "corrente",
   "custom-field-delete-pop": "Non potrai tornare indietro. Questa azione rimuoverà questo campo personalizzato da tutte le schede ed eliminerà ogni sua traccia.",
   "custom-field-delete-pop": "Non potrai tornare indietro. Questa azione rimuoverà questo campo personalizzato da tutte le schede ed eliminerà ogni sua traccia.",
   "custom-field-checkbox": "Casella di scelta",
   "custom-field-checkbox": "Casella di scelta",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "Valuta",
+  "custom-field-currency-option": "Codice Valuta",
   "custom-field-date": "Data",
   "custom-field-date": "Data",
   "custom-field-dropdown": "Lista a discesa",
   "custom-field-dropdown": "Lista a discesa",
   "custom-field-dropdown-none": "(niente)",
   "custom-field-dropdown-none": "(niente)",
@@ -808,5 +808,6 @@
   "voting": "Votazione",
   "voting": "Votazione",
   "archived": "Archiviato",
   "archived": "Archiviato",
   "delete-linked-card-before-this-card": "Non puoi eliminare questa scheda prima di avere eliminato una scheda collegata che ha",
   "delete-linked-card-before-this-card": "Non puoi eliminare questa scheda prima di avere eliminato una scheda collegata che ha",
-  "delete-linked-cards-before-this-list": "Non puoi eliminare questa lista prima di avere eliminato le schede collegate che puntano su schede in questa lista"
+  "delete-linked-cards-before-this-list": "Non puoi eliminare questa lista prima di avere eliminato le schede collegate che puntano su schede in questa lista",
+  "hide-checked-items": "Nascondi articoli controllati"
 }
 }

+ 2 - 1
i18n/ja.i18n.json

@@ -808,5 +808,6 @@
   "voting": "投票",
   "voting": "投票",
   "archived": "アーカイブ",
   "archived": "アーカイブ",
   "delete-linked-card-before-this-card": "カード内にある、リンクされているカードを削除しなければ、このカードは削除できません",
   "delete-linked-card-before-this-card": "カード内にある、リンクされているカードを削除しなければ、このカードは削除できません",
-  "delete-linked-cards-before-this-list": "リスト内にある、他のカードを参照しているカードを削除しなければ、このリストは削除できません"
+  "delete-linked-cards-before-this-list": "リスト内にある、他のカードを参照しているカードを削除しなければ、このリストは削除できません",
+  "hide-checked-items": "チェックした項目を隠す"
 }
 }

+ 2 - 1
i18n/ka.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/km.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/ko.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/lv.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/mk.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/mn.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/nb.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 4 - 3
i18n/nl.i18n.json

@@ -256,8 +256,8 @@
   "current": "Huidige",
   "current": "Huidige",
   "custom-field-delete-pop": "Er is geen herstelmogelijkheid. Deze actie zal dit maatwerkveld van alle kaarten verwijderen en de bijbehorende historie wissen.",
   "custom-field-delete-pop": "Er is geen herstelmogelijkheid. Deze actie zal dit maatwerkveld van alle kaarten verwijderen en de bijbehorende historie wissen.",
   "custom-field-checkbox": "Checkbox",
   "custom-field-checkbox": "Checkbox",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "Valuta",
+  "custom-field-currency-option": "Valuta Teken",
   "custom-field-date": "Datum",
   "custom-field-date": "Datum",
   "custom-field-dropdown": "Dropdown Lijst",
   "custom-field-dropdown": "Dropdown Lijst",
   "custom-field-dropdown-none": "(geen)",
   "custom-field-dropdown-none": "(geen)",
@@ -808,5 +808,6 @@
   "voting": "Stemmen",
   "voting": "Stemmen",
   "archived": "Gearchiveerd",
   "archived": "Gearchiveerd",
   "delete-linked-card-before-this-card": "Je kunt deze kaart niet verwijderen voordat de gekoppelde kaart is verwijderd ",
   "delete-linked-card-before-this-card": "Je kunt deze kaart niet verwijderen voordat de gekoppelde kaart is verwijderd ",
-  "delete-linked-cards-before-this-list": "Je kunt deze lijst niet verwijderen voordat de gekoppelde kaarten verwijderd zijn die verwijzen naar kaarten in deze lijst"
+  "delete-linked-cards-before-this-list": "Je kunt deze lijst niet verwijderen voordat de gekoppelde kaarten verwijderd zijn die verwijzen naar kaarten in deze lijst",
+  "hide-checked-items": "Verberg aangevinkte items"
 }
 }

+ 2 - 1
i18n/oc.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/pl.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Głosowanie",
   "voting": "Głosowanie",
   "archived": "Zarchiwizowany",
   "archived": "Zarchiwizowany",
   "delete-linked-card-before-this-card": "Nie możesz usunąć tej karty, dopóki nie usuniesz podpiętej karty, w której są",
   "delete-linked-card-before-this-card": "Nie możesz usunąć tej karty, dopóki nie usuniesz podpiętej karty, w której są",
-  "delete-linked-cards-before-this-list": "Nie możesz usunąć tej karty, dopóki nie usuniesz podpiętych kart, które wskazują na karty w tej liście"
+  "delete-linked-cards-before-this-list": "Nie możesz usunąć tej karty, dopóki nie usuniesz podpiętych kart, które wskazują na karty w tej liście",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/pt-BR.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Votação",
   "voting": "Votação",
   "archived": "Arquivado",
   "archived": "Arquivado",
   "delete-linked-card-before-this-card": "Você não pode excluir este cartão antes de excluir primeiro o cartão vinculado que possui",
   "delete-linked-card-before-this-card": "Você não pode excluir este cartão antes de excluir primeiro o cartão vinculado que possui",
-  "delete-linked-cards-before-this-list": "Você não pode excluir esta lista antes de excluir primeiro os cartões vinculados que estão apontando para os cartões nesta lista"
+  "delete-linked-cards-before-this-list": "Você não pode excluir esta lista antes de excluir primeiro os cartões vinculados que estão apontando para os cartões nesta lista",
+  "hide-checked-items": "Esconder itens marcados"
 }
 }

+ 2 - 1
i18n/pt.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Arquivado",
   "archived": "Arquivado",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/ro.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 4 - 3
i18n/ru.i18n.json

@@ -256,8 +256,8 @@
   "current": "текущий",
   "current": "текущий",
   "custom-field-delete-pop": "Отменить нельзя. Это удалит настраиваемое поле со всех карт и уничтожит его историю.",
   "custom-field-delete-pop": "Отменить нельзя. Это удалит настраиваемое поле со всех карт и уничтожит его историю.",
   "custom-field-checkbox": "Галочка",
   "custom-field-checkbox": "Галочка",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "Валюта",
+  "custom-field-currency-option": "Код валюты",
   "custom-field-date": "Дата",
   "custom-field-date": "Дата",
   "custom-field-dropdown": "Выпадающий список",
   "custom-field-dropdown": "Выпадающий список",
   "custom-field-dropdown-none": "(нет)",
   "custom-field-dropdown-none": "(нет)",
@@ -808,5 +808,6 @@
   "voting": "Голосование",
   "voting": "Голосование",
   "archived": "Архивировано",
   "archived": "Архивировано",
   "delete-linked-card-before-this-card": "Вы не можете удалить карточку, не удалив связанную c ней карточку, которая имеет ",
   "delete-linked-card-before-this-card": "Вы не можете удалить карточку, не удалив связанную c ней карточку, которая имеет ",
-  "delete-linked-cards-before-this-list": "Вы не можете удалить этот список, не удалив карточки, которые указывают на карточки в этом списке"
+  "delete-linked-cards-before-this-list": "Вы не можете удалить этот список, не удалив карточки, которые указывают на карточки в этом списке",
+  "hide-checked-items": "Спрятать отмеченные"
 }
 }

+ 2 - 1
i18n/sl.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/sr.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/sv.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Röstning",
   "voting": "Röstning",
   "archived": "Arkiverad",
   "archived": "Arkiverad",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/sw.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/ta.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/th.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 26 - 25
i18n/tr.i18n.json

@@ -256,8 +256,8 @@
   "current": "mevcut",
   "current": "mevcut",
   "custom-field-delete-pop": "Bunun geri dönüşü yoktur. Bu özel alan tüm kartlardan kaldırılıp tarihçesi yokedilecektir.",
   "custom-field-delete-pop": "Bunun geri dönüşü yoktur. Bu özel alan tüm kartlardan kaldırılıp tarihçesi yokedilecektir.",
   "custom-field-checkbox": "İşaret kutusu",
   "custom-field-checkbox": "İşaret kutusu",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "Para birimi",
+  "custom-field-currency-option": "Para birimi kodu",
   "custom-field-date": "Tarih",
   "custom-field-date": "Tarih",
   "custom-field-dropdown": "Açılır liste",
   "custom-field-dropdown": "Açılır liste",
   "custom-field-dropdown-none": "(hiçbiri)",
   "custom-field-dropdown-none": "(hiçbiri)",
@@ -319,12 +319,12 @@
   "error-username-taken": "Kullanıcı adı zaten alınmış",
   "error-username-taken": "Kullanıcı adı zaten alınmış",
   "error-email-taken": "Bu e-posta adresi daha önceden alınmış",
   "error-email-taken": "Bu e-posta adresi daha önceden alınmış",
   "export-board": "Panoyu dışarı aktar",
   "export-board": "Panoyu dışarı aktar",
-  "export-board-json": "Export board to JSON",
-  "export-board-csv": "Export board to CSV",
-  "export-board-tsv": "Export board to TSV",
-  "export-board-html": "Export board to HTML",
+  "export-board-json": "Panoyu JSON olarak dışarı aktar",
+  "export-board-csv": "Panoyu CSV olarak dışarı aktar",
+  "export-board-tsv": "Panoyu TSV olarak dışarı aktar",
+  "export-board-html": "Panoyu HTML olarak dışarı aktar",
   "exportBoardPopup-title": "Panoyu dışarı aktar",
   "exportBoardPopup-title": "Panoyu dışarı aktar",
-  "sort": "Sort",
+  "sort": "Sırala",
   "sort-desc": "Click to Sort List",
   "sort-desc": "Click to Sort List",
   "list-sort-by": "Sort the List By:",
   "list-sort-by": "Sort the List By:",
   "list-label-modifiedAt": "Son Erişim Zamanı...",
   "list-label-modifiedAt": "Son Erişim Zamanı...",
@@ -341,8 +341,8 @@
   "filter-no-member": "Üye yok",
   "filter-no-member": "Üye yok",
   "filter-no-assignee": "No assignee",
   "filter-no-assignee": "No assignee",
   "filter-no-custom-fields": "Hiç özel alan yok",
   "filter-no-custom-fields": "Hiç özel alan yok",
-  "filter-show-archive": "Show archived lists",
-  "filter-hide-empty": "Hide empty lists",
+  "filter-show-archive": "Arşivlenmiş listeleri göster",
+  "filter-hide-empty": "Boş listeleri gizle",
   "filter-on": "Filtre aktif",
   "filter-on": "Filtre aktif",
   "filter-on-desc": "Bu panodaki kartları filtreliyorsunuz. Fitreyi düzenlemek için tıklayın.",
   "filter-on-desc": "Bu panodaki kartları filtreliyorsunuz. Fitreyi düzenlemek için tıklayın.",
   "filter-to-selection": "Seçime göre filtreleme yap",
   "filter-to-selection": "Seçime göre filtreleme yap",
@@ -359,10 +359,10 @@
   "import-board-c": "Panoyu içe aktar",
   "import-board-c": "Panoyu içe aktar",
   "import-board-title-trello": "Trello'dan panoyu içeri aktar",
   "import-board-title-trello": "Trello'dan panoyu içeri aktar",
   "import-board-title-wekan": "Import board from previous export",
   "import-board-title-wekan": "Import board from previous export",
-  "import-board-title-csv": "Import board from CSV/TSV",
+  "import-board-title-csv": "CSV/TSV formatındaki panoyu içeri aktar",
   "from-trello": "Trello'dan",
   "from-trello": "Trello'dan",
   "from-wekan": "From previous export",
   "from-wekan": "From previous export",
-  "from-csv": "From CSV/TSV",
+  "from-csv": "CSV/TSV'den",
   "import-board-instruction-trello": "Trello panonuzda 'Menü'ye gidip 'Daha fazlası'na tıklayın, ardından 'Yazdır ve Çıktı Al'ı seçip 'JSON biçiminde çıktı al' diyerek çıkan metni buraya kopyalayın.",
   "import-board-instruction-trello": "Trello panonuzda 'Menü'ye gidip 'Daha fazlası'na tıklayın, ardından 'Yazdır ve Çıktı Al'ı seçip 'JSON biçiminde çıktı al' diyerek çıkan metni buraya kopyalayın.",
   "import-board-instruction-csv": "Paste in your Comma Separated Values(CSV)/ Tab Separated Values (TSV) .",
   "import-board-instruction-csv": "Paste in your Comma Separated Values(CSV)/ Tab Separated Values (TSV) .",
   "import-board-instruction-wekan": "In your board, go to 'Menu', then 'Export board', and copy the text in the downloaded file.",
   "import-board-instruction-wekan": "In your board, go to 'Menu', then 'Export board', and copy the text in the downloaded file.",
@@ -399,10 +399,10 @@
   "set-color-list": "Rengi Ayarla",
   "set-color-list": "Rengi Ayarla",
   "listActionPopup-title": "Liste İşlemleri",
   "listActionPopup-title": "Liste İşlemleri",
   "swimlaneActionPopup-title": "Kulvar İşlemleri",
   "swimlaneActionPopup-title": "Kulvar İşlemleri",
-  "swimlaneAddPopup-title": "Add a Swimlane below",
+  "swimlaneAddPopup-title": "Aşağı kulvar ekle",
   "listImportCardPopup-title": "Bir Trello kartını içeri aktar",
   "listImportCardPopup-title": "Bir Trello kartını içeri aktar",
   "listImportCardsTsvPopup-title": "Import Excel CSV/TSV",
   "listImportCardsTsvPopup-title": "Import Excel CSV/TSV",
-  "listMorePopup-title": "Daha",
+  "listMorePopup-title": "Daha fazla",
   "link-list": "Listeye doğrudan bağlantı",
   "link-list": "Listeye doğrudan bağlantı",
   "list-delete-pop": "Etkinlik akışınızdaki tüm eylemler geri kurtarılamaz şekilde kaldırılacak. Bu işlem geri alınamaz.",
   "list-delete-pop": "Etkinlik akışınızdaki tüm eylemler geri kurtarılamaz şekilde kaldırılacak. Bu işlem geri alınamaz.",
   "list-delete-suggest-archive": "You can move a list to Archive to remove it from the board and preserve the activity.",
   "list-delete-suggest-archive": "You can move a list to Archive to remove it from the board and preserve the activity.",
@@ -437,7 +437,7 @@
   "optional": "isteğe bağlı",
   "optional": "isteğe bağlı",
   "or": "veya",
   "or": "veya",
   "page-maybe-private": "Bu sayfa gizli olabilir. <a href='%s'>Oturum açarak</a> görmeyi deneyin.",
   "page-maybe-private": "Bu sayfa gizli olabilir. <a href='%s'>Oturum açarak</a> görmeyi deneyin.",
-  "page-not-found": "Sayda bulunamadı.",
+  "page-not-found": "Sayfa bulunamadı.",
   "password": "Parola",
   "password": "Parola",
   "paste-or-dragdrop": "Dosya eklemek için yapıştırabilir, veya (eğer resimse) sürükle bırak yapabilirsiniz",
   "paste-or-dragdrop": "Dosya eklemek için yapıştırabilir, veya (eğer resimse) sürükle bırak yapabilirsiniz",
   "participating": "Katılımcılar",
   "participating": "Katılımcılar",
@@ -448,8 +448,8 @@
   "private-desc": "Bu pano gizli. Sadece panoya ekli kişiler görüntüleyebilir ve düzenleyebilir.",
   "private-desc": "Bu pano gizli. Sadece panoya ekli kişiler görüntüleyebilir ve düzenleyebilir.",
   "profile": "Kullanıcı Sayfası",
   "profile": "Kullanıcı Sayfası",
   "public": "Genel",
   "public": "Genel",
-  "public-desc": "Bu pano genel. Bağlantı adresi ile herhangi bir kimseye görünür ve Google gibi arama motorlarında gösterilecektir. Panoyu, sadece eklenen kişiler düzenleyebilir.",
-  "quick-access-description": "Bu bara kısayol olarak bir pano eklemek için panoyu yıldızlamalısınız",
+  "public-desc": "Bu pano genel bir panodur. Bağlantıya sahip olan herkes panoyu görüntüleyebilir, ayrıca panonuz Google gibi arama motorlarında görünür. Panoyu, sadece panoya eklenen kişiler düzenleyebilir.",
+  "quick-access-description": "Yıldızladığınız panolar burada gözükür",
   "remove-cover": "Kapak Resmini Kaldır",
   "remove-cover": "Kapak Resmini Kaldır",
   "remove-from-board": "Panodan Kaldır",
   "remove-from-board": "Panodan Kaldır",
   "remove-label": "Etiketi Kaldır",
   "remove-label": "Etiketi Kaldır",
@@ -515,9 +515,9 @@
   "welcome-swimlane": "Kilometre taşı",
   "welcome-swimlane": "Kilometre taşı",
   "welcome-list1": "Temel",
   "welcome-list1": "Temel",
   "welcome-list2": "Gelişmiş",
   "welcome-list2": "Gelişmiş",
-  "card-templates-swimlane": "Card Templates",
-  "list-templates-swimlane": "List Templates",
-  "board-templates-swimlane": "Board Templates",
+  "card-templates-swimlane": "Kart şablonları",
+  "list-templates-swimlane": "Liste şablonları",
+  "board-templates-swimlane": "Pano şablonları",
   "what-to-do": "Ne yapmak istiyorsunuz?",
   "what-to-do": "Ne yapmak istiyorsunuz?",
   "wipLimitErrorPopup-title": "Geçersiz Devam Eden İş Sınırı",
   "wipLimitErrorPopup-title": "Geçersiz Devam Eden İş Sınırı",
   "wipLimitErrorPopup-dialog-pt1": "Bu listedeki iş sayısı belirlediğiniz sınırdan daha fazla.",
   "wipLimitErrorPopup-dialog-pt1": "Bu listedeki iş sayısı belirlediğiniz sınırdan daha fazla.",
@@ -559,8 +559,8 @@
   "new-outgoing-webhook": "Yeni Dışarı Giden Web Bağlantısı",
   "new-outgoing-webhook": "Yeni Dışarı Giden Web Bağlantısı",
   "no-name": "(Bilinmeyen)",
   "no-name": "(Bilinmeyen)",
   "Node_version": "Node sürümü",
   "Node_version": "Node sürümü",
-  "Meteor_version": "Meteor version",
-  "MongoDB_version": "MongoDB version",
+  "Meteor_version": "Meteor sürümü",
+  "MongoDB_version": "MongoDB sürümü",
   "MongoDB_storage_engine": "MongoDB storage engine",
   "MongoDB_storage_engine": "MongoDB storage engine",
   "MongoDB_Oplog_enabled": "MongoDB Oplog enabled",
   "MongoDB_Oplog_enabled": "MongoDB Oplog enabled",
   "OS_Arch": "İşletim Sistemi Mimarisi",
   "OS_Arch": "İşletim Sistemi Mimarisi",
@@ -603,13 +603,13 @@
   "delete-board-confirm-popup": "Tüm listeler, kartlar, etiketler ve etkinlikler silinecek ve pano içeriğini kurtaramayacaksınız. Geri dönüş yok.",
   "delete-board-confirm-popup": "Tüm listeler, kartlar, etiketler ve etkinlikler silinecek ve pano içeriğini kurtaramayacaksınız. Geri dönüş yok.",
   "boardDeletePopup-title": "Panoyu Sil?",
   "boardDeletePopup-title": "Panoyu Sil?",
   "delete-board": "Panoyu Sil",
   "delete-board": "Panoyu Sil",
-  "default-subtasks-board": "Subtasks for __board__ board",
+  "default-subtasks-board": "__board__ panosu için alt görevler",
   "default": "Varsayılan",
   "default": "Varsayılan",
   "queue": "Sıra",
   "queue": "Sıra",
   "subtask-settings": "Alt Görev ayarları",
   "subtask-settings": "Alt Görev ayarları",
-  "card-settings": "Card Settings",
+  "card-settings": "Kart ayarları",
   "boardSubtaskSettingsPopup-title": "Pano alt görev ayarları",
   "boardSubtaskSettingsPopup-title": "Pano alt görev ayarları",
-  "boardCardSettingsPopup-title": "Card Settings",
+  "boardCardSettingsPopup-title": "Kart ayarları",
   "deposit-subtasks-board": "Deposit subtasks to this board:",
   "deposit-subtasks-board": "Deposit subtasks to this board:",
   "deposit-subtasks-list": "Alt görevlerin açılacağı liste:",
   "deposit-subtasks-list": "Alt görevlerin açılacağı liste:",
   "show-parent-in-minicard": "Mini kart içinde üst kartı göster",
   "show-parent-in-minicard": "Mini kart içinde üst kartı göster",
@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/uk.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/vi.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 4 - 3
i18n/zh-CN.i18n.json

@@ -256,8 +256,8 @@
   "current": "当前",
   "current": "当前",
   "custom-field-delete-pop": "没有撤销,此动作将从所有卡片中移除自定义字段并销毁历史。",
   "custom-field-delete-pop": "没有撤销,此动作将从所有卡片中移除自定义字段并销毁历史。",
   "custom-field-checkbox": "选择框",
   "custom-field-checkbox": "选择框",
-  "custom-field-currency": "Currency",
-  "custom-field-currency-option": "Currency Code",
+  "custom-field-currency": "货币",
+  "custom-field-currency-option": "货币代码",
   "custom-field-date": "日期",
   "custom-field-date": "日期",
   "custom-field-dropdown": "下拉列表",
   "custom-field-dropdown": "下拉列表",
   "custom-field-dropdown-none": "(无)",
   "custom-field-dropdown-none": "(无)",
@@ -808,5 +808,6 @@
   "voting": "投票",
   "voting": "投票",
   "archived": "存档",
   "archived": "存档",
   "delete-linked-card-before-this-card": "在你首次删除卡片前你无法删除此选项卡片",
   "delete-linked-card-before-this-card": "在你首次删除卡片前你无法删除此选项卡片",
-  "delete-linked-cards-before-this-list": "在首先删除指向此列表中的卡的链接卡之前,不能删除此列表"
+  "delete-linked-cards-before-this-list": "在首先删除指向此列表中的卡的链接卡之前,不能删除此列表",
+  "hide-checked-items": "隐藏选中项"
 }
 }

+ 2 - 1
i18n/zh-HK.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 2 - 1
i18n/zh-TW.i18n.json

@@ -808,5 +808,6 @@
   "voting": "Voting",
   "voting": "Voting",
   "archived": "Archived",
   "archived": "Archived",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
   "delete-linked-card-before-this-card": "You can not delete this card before first deleting linked card that has",
-  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list"
+  "delete-linked-cards-before-this-list": "You can not delete this list before first deleting linked cards that are pointing to cards in this list",
+  "hide-checked-items": "Hide checked items"
 }
 }

+ 12 - 8
models/boards.js

@@ -18,18 +18,14 @@ Boards.attachSchema(
       type: String,
       type: String,
       // eslint-disable-next-line consistent-return
       // eslint-disable-next-line consistent-return
       autoValue() {
       autoValue() {
-        // XXX We need to improve slug management. Only the id should be necessary
-        // to identify a board in the code.
-        // XXX If the board title is updated, the slug should also be updated.
         // In some cases (Chinese and Japanese for instance) the `getSlug` function
         // In some cases (Chinese and Japanese for instance) the `getSlug` function
         // return an empty string. This is causes bugs in our application so we set
         // return an empty string. This is causes bugs in our application so we set
         // a default slug in this case.
         // a default slug in this case.
-        if (this.isInsert && !this.isSet) {
+        // Improvment would be to change client URL after slug is changed
+        const title = this.field('title');
+        if (title.isSet && !this.isSet) {
           let slug = 'board';
           let slug = 'board';
-          const title = this.field('title');
-          if (title.isSet) {
-            slug = getSlug(title.value) || slug;
-          }
+          slug = getSlug(title.value) || slug;
           return slug;
           return slug;
         }
         }
       },
       },
@@ -1219,6 +1215,14 @@ if (Meteor.isServer) {
     fetch: ['members'],
     fetch: ['members'],
   });
   });
 
 
+  // All logged in users are allowed to reorder boards by dragging at All Boards page and Public Boards page.
+  Boards.allow({
+    update(userId, board, fieldNames) {
+      return _.contains(fieldNames, 'sort');
+    },
+    fetch: [],
+  });
+
   // The number of users that have starred this board is managed by trusted code
   // The number of users that have starred this board is managed by trusted code
   // and the user is not allowed to update it
   // and the user is not allowed to update it
   Boards.deny({
   Boards.deny({

+ 100 - 54
models/cards.js

@@ -368,30 +368,36 @@ Cards.allow({
 
 
 Cards.helpers({
 Cards.helpers({
   copy(boardId, swimlaneId, listId) {
   copy(boardId, swimlaneId, listId) {
-    const oldBoard = Boards.findOne(this.boardId);
-    const oldBoardLabels = oldBoard.labels;
-    // Get old label names
-    const oldCardLabels = _.pluck(
-      _.filter(oldBoardLabels, label => {
-        return _.contains(this.labelIds, label._id);
-      }),
-      'name',
-    );
-
-    const newBoard = Boards.findOne(boardId);
-    const newBoardLabels = newBoard.labels;
-    const newCardLabels = _.pluck(
-      _.filter(newBoardLabels, label => {
-        return _.contains(oldCardLabels, label.name);
-      }),
-      '_id',
-    );
-
     const oldId = this._id;
     const oldId = this._id;
     const oldCard = Cards.findOne(oldId);
     const oldCard = Cards.findOne(oldId);
 
 
-    // Copy Custom Fields
-    if (oldBoard._id !== boardId) {
+    // we must only copy the labels and custom fields if the target board
+    // differs from the source board
+    if (this.boardId !== boardId) {
+      const oldBoard = Boards.findOne(this.boardId);
+      const oldBoardLabels = oldBoard.labels;
+
+      // Get old label names
+      const oldCardLabels = _.pluck(
+        _.filter(oldBoardLabels, label => {
+          return _.contains(this.labelIds, label._id);
+        }),
+        'name',
+      );
+
+      const newBoard = Boards.findOne(boardId);
+      const newBoardLabels = newBoard.labels;
+      const newCardLabels = _.pluck(
+        _.filter(newBoardLabels, label => {
+          return _.contains(oldCardLabels, label.name);
+        }),
+        '_id',
+      );
+      // now set the new label ids
+      delete this.labelIds;
+      this.labelIds = newCardLabels;
+
+      // Copy Custom Fields
       CustomFields.find({
       CustomFields.find({
         _id: {
         _id: {
           $in: oldCard.customFields.map(cf => {
           $in: oldCard.customFields.map(cf => {
@@ -404,8 +410,6 @@ Cards.helpers({
     }
     }
 
 
     delete this._id;
     delete this._id;
-    delete this.labelIds;
-    this.labelIds = newCardLabels;
     this.boardId = boardId;
     this.boardId = boardId;
     this.swimlaneId = swimlaneId;
     this.swimlaneId = swimlaneId;
     this.listId = listId;
     this.listId = listId;
@@ -1108,6 +1112,21 @@ Cards.helpers({
       return Users.find({ _id: { $in: this.vote.negative } });
       return Users.find({ _id: { $in: this.vote.negative } });
     return [];
     return [];
   },
   },
+  voteState() {
+    const userId = Meteor.userId();
+    let state;
+    if (this.vote) {
+      if (this.vote.positive) {
+        state = _.contains(this.vote.positive, userId);
+        if (state === true) return true;
+      }
+      if (this.vote.negative) {
+        state = _.contains(this.vote.negative, userId);
+        if (state === true) return false;
+      }
+    }
+    return null;
+  },
 
 
   getId() {
   getId() {
     if (this.isLinked()) {
     if (this.isLinked()) {
@@ -1298,8 +1317,40 @@ Cards.mutations({
   },
   },
 
 
   move(boardId, swimlaneId, listId, sort) {
   move(boardId, swimlaneId, listId, sort) {
-    // Copy Custom Fields
+    const mutatedFields = {
+      boardId,
+      swimlaneId,
+      listId,
+      sort,
+    };
+
+    // we must only copy the labels and custom fields if the target board
+    // differs from the source board
     if (this.boardId !== boardId) {
     if (this.boardId !== boardId) {
+      // Get label names
+      const oldBoard = Boards.findOne(this.boardId);
+      const oldBoardLabels = oldBoard.labels;
+      const oldCardLabels = _.pluck(
+        _.filter(oldBoardLabels, label => {
+          return _.contains(this.labelIds, label._id);
+        }),
+        'name',
+      );
+
+      const newBoard = Boards.findOne(boardId);
+      const newBoardLabels = newBoard.labels;
+      const newCardLabelIds = _.pluck(
+        _.filter(newBoardLabels, label => {
+          return label.name && _.contains(oldCardLabels, label.name);
+        }),
+        '_id',
+      );
+
+      Object.assign(mutatedFields, {
+        labelIds: newCardLabelIds,
+      });
+
+      // Copy custom fields
       CustomFields.find({
       CustomFields.find({
         _id: {
         _id: {
           $in: this.customFields.map(cf => {
           $in: this.customFields.map(cf => {
@@ -1311,33 +1362,6 @@ Cards.mutations({
       });
       });
     }
     }
 
 
-    // Get label names
-    const oldBoard = Boards.findOne(this.boardId);
-    const oldBoardLabels = oldBoard.labels;
-    const oldCardLabels = _.pluck(
-      _.filter(oldBoardLabels, label => {
-        return _.contains(this.labelIds, label._id);
-      }),
-      'name',
-    );
-
-    const newBoard = Boards.findOne(boardId);
-    const newBoardLabels = newBoard.labels;
-    const newCardLabelIds = _.pluck(
-      _.filter(newBoardLabels, label => {
-        return label.name && _.contains(oldCardLabels, label.name);
-      }),
-      '_id',
-    );
-
-    const mutatedFields = {
-      boardId,
-      swimlaneId,
-      listId,
-      sort,
-      labelIds: newCardLabelIds,
-    };
-
     Cards.update(this._id, {
     Cards.update(this._id, {
       $set: mutatedFields,
       $set: mutatedFields,
     });
     });
@@ -2169,7 +2193,7 @@ if (Meteor.isServer) {
             description: doc.description,
             description: doc.description,
             listId: doc.listId,
             listId: doc.listId,
             receivedAt: doc.receivedAt,
             receivedAt: doc.receivedAt,
-            startAt:doc.startAt,
+            startAt: doc.startAt,
             dueAt: doc.dueAt,
             dueAt: doc.dueAt,
             endAt: doc.endAt,
             endAt: doc.endAt,
             assignees: doc.assignees,
             assignees: doc.assignees,
@@ -2210,7 +2234,7 @@ if (Meteor.isServer) {
           title: doc.title,
           title: doc.title,
           description: doc.description,
           description: doc.description,
           receivedAt: doc.receivedAt,
           receivedAt: doc.receivedAt,
-          startAt:doc.startAt,
+          startAt: doc.startAt,
           dueAt: doc.dueAt,
           dueAt: doc.dueAt,
           endAt: doc.endAt,
           endAt: doc.endAt,
           assignees: doc.assignees,
           assignees: doc.assignees,
@@ -2365,6 +2389,10 @@ if (Meteor.isServer) {
    * @param {boolean} [isOverTime] the new isOverTime field of the card
    * @param {boolean} [isOverTime] the new isOverTime field of the card
    * @param {string} [customFields] the new customFields value of the card
    * @param {string} [customFields] the new customFields value of the card
    * @param {string} [color] the new color of the card
    * @param {string} [color] the new color of the card
+   * @param {Object} [vote] the vote object
+   * @param {string} vote.question the vote question
+   * @param {boolean} vote.public show who voted what
+   * @param {boolean} vote.allowNonBoardMembers allow all logged in users to vote?
    * @return_type {_id: string}
    * @return_type {_id: string}
    */
    */
   JsonRoutes.add(
   JsonRoutes.add(
@@ -2464,6 +2492,24 @@ if (Meteor.isServer) {
           { $set: { color: newColor } },
           { $set: { color: newColor } },
         );
         );
       }
       }
+      if (req.body.hasOwnProperty('vote')) {
+        const newVote = req.body.vote;
+        newVote.positive = [];
+        newVote.negative = [];
+        if (!newVote.hasOwnProperty('public')) newVote.public = false;
+        if (!newVote.hasOwnProperty('allowNonBoardMembers'))
+          newVote.allowNonBoardMembers = false;
+
+        Cards.direct.update(
+          {
+            _id: paramCardId,
+            listId: paramListId,
+            boardId: paramBoardId,
+            archived: false,
+          },
+          { $set: { vote: newVote } },
+        );
+      }
       if (req.body.hasOwnProperty('labelIds')) {
       if (req.body.hasOwnProperty('labelIds')) {
         let newlabelIds = req.body.labelIds;
         let newlabelIds = req.body.labelIds;
         if (_.isString(newlabelIds)) {
         if (_.isString(newlabelIds)) {
@@ -2703,7 +2749,7 @@ if (Meteor.isServer) {
    * @return_type [{_id: string,
    * @return_type [{_id: string,
    *                title: string,
    *                title: string,
    *                description: string,
    *                description: string,
-   *                listId: string
+   *                listId: string,
    *                swinlaneId: string}]
    *                swinlaneId: string}]
    */
    */
   JsonRoutes.add(
   JsonRoutes.add(

+ 9 - 1
models/checklistItems.js

@@ -302,10 +302,18 @@ if (Meteor.isServer) {
 
 
       const paramItemId = req.params.itemId;
       const paramItemId = req.params.itemId;
 
 
+      function isTrue(data) {
+        try {
+          return data.toLowerCase() === 'true';
+        } catch (error) {
+          return data;
+        }
+      }
+
       if (req.body.hasOwnProperty('isFinished')) {
       if (req.body.hasOwnProperty('isFinished')) {
         ChecklistItems.direct.update(
         ChecklistItems.direct.update(
           { _id: paramItemId },
           { _id: paramItemId },
-          { $set: { isFinished: req.body.isFinished } },
+          { $set: { isFinished: isTrue(req.body.isFinished) } },
         );
         );
       }
       }
       if (req.body.hasOwnProperty('title')) {
       if (req.body.hasOwnProperty('title')) {

+ 5 - 7
models/customFields.js

@@ -172,16 +172,14 @@ function customFieldDeletion(userId, doc) {
 function customFieldEdit(userId, doc) {
 function customFieldEdit(userId, doc) {
   const card = Cards.findOne(doc.cardId);
   const card = Cards.findOne(doc.cardId);
   const customFieldValue = Activities.findOne({ customFieldId: doc._id }).value;
   const customFieldValue = Activities.findOne({ customFieldId: doc._id }).value;
-  const boardId = card.boardId;
-  //boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId
   Activities.insert({
   Activities.insert({
     userId,
     userId,
     activityType: 'setCustomField',
     activityType: 'setCustomField',
-    boardId,
+    boardId: doc.boardIds[0], // We are creating a customField, it has only one boardId
     customFieldId: doc._id,
     customFieldId: doc._id,
     customFieldValue,
     customFieldValue,
-    listId: card.listId,
-    swimlaneId: card.swimlaneId,
+    listId: doc.listId,
+    swimlaneId: doc.swimlaneId,
   });
   });
 }
 }
 
 
@@ -206,8 +204,8 @@ if (Meteor.isServer) {
       Activities.remove({
       Activities.remove({
         customFieldId: doc._id,
         customFieldId: doc._id,
         boardId: modifier.$pull.boardIds,
         boardId: modifier.$pull.boardIds,
-        listId: card.listId,
-        swimlaneId: card.swimlaneId,
+        listId: doc.listId,
+        swimlaneId: doc.swimlaneId,
       });
       });
     } else if (_.contains(fieldNames, 'boardIds') && modifier.$push) {
     } else if (_.contains(fieldNames, 'boardIds') && modifier.$push) {
       Activities.insert({
       Activities.insert({

+ 3 - 1
models/export.js

@@ -85,7 +85,9 @@ if (Meteor.isServer) {
         ? exporter.buildCsv(params.query.delimiter)
         ? exporter.buildCsv(params.query.delimiter)
         : exporter.buildCsv();
         : exporter.buildCsv();
       res.writeHead(200, {
       res.writeHead(200, {
-        'Content-Length': body.length,
+        // Checking length does not work https://github.com/wekan/wekan/issues/3173
+        // so not using it here
+        //'Content-Length': body.length,
         'Content-Type': params.query.delimiter ? 'text/csv' : 'text/tsv',
         'Content-Type': params.query.delimiter ? 'text/csv' : 'text/tsv',
       });
       });
       res.write(body);
       res.write(body);

+ 30 - 24
models/exporter.js

@@ -1,7 +1,8 @@
-const stringify = require('csv-stringify');
+// const stringify = require('csv-stringify');
 
 
 // exporter maybe is broken since Gridfs introduced, add fs and path
 // exporter maybe is broken since Gridfs introduced, add fs and path
 export class Exporter {
 export class Exporter {
+  /*
   constructor(boardId) {
   constructor(boardId) {
     this._boardId = boardId;
     this._boardId = boardId;
   }
   }
@@ -240,29 +241,29 @@ export class Exporter {
       }
       }
       i++;
       i++;
     });
     });
-    /* TODO: Try to get translations working.
-             These currently only bring English translations.
-    TAPi18n.__('title'),
-    TAPi18n.__('description'),
-    TAPi18n.__('status'),
-    TAPi18n.__('swimlane'),
-    TAPi18n.__('owner'),
-    TAPi18n.__('requested-by'),
-    TAPi18n.__('assigned-by'),
-    TAPi18n.__('members'),
-    TAPi18n.__('assignee'),
-    TAPi18n.__('labels'),
-    TAPi18n.__('card-start'),
-    TAPi18n.__('card-due'),
-    TAPi18n.__('card-end'),
-    TAPi18n.__('overtime-hours'),
-    TAPi18n.__('spent-time-hours'),
-    TAPi18n.__('createdAt'),
-    TAPi18n.__('last-modified-at'),
-    TAPi18n.__('last-activity'),
-    TAPi18n.__('voting'),
-    TAPi18n.__('archived'),
-    */
+
+    // TODO: Try to get translations working.
+    //         These currently only bring English translations.
+    // TAPi18n.__('title'),
+    // TAPi18n.__('description'),
+    // TAPi18n.__('status'),
+    // TAPi18n.__('swimlane'),
+    // TAPi18n.__('owner'),
+    // TAPi18n.__('requested-by'),
+    // TAPi18n.__('assigned-by'),
+    // TAPi18n.__('members'),
+    // TAPi18n.__('assignee'),
+    // TAPi18n.__('labels'),
+    // TAPi18n.__('card-start'),
+    // TAPi18n.__('card-due'),
+    // TAPi18n.__('card-end'),
+    // TAPi18n.__('overtime-hours'),
+    // TAPi18n.__('spent-time-hours'),
+    // TAPi18n.__('createdAt'),
+    // TAPi18n.__('last-modified-at'),
+    // TAPi18n.__('last-activity'),
+    // TAPi18n.__('voting'),
+    // TAPi18n.__('archived'),
 
 
     const stringifier = stringify({
     const stringifier = stringify({
       header: true,
       header: true,
@@ -395,4 +396,9 @@ export class Exporter {
     const board = Boards.findOne(this._boardId);
     const board = Boards.findOne(this._boardId);
     return board && board.isVisibleBy(user);
     return board && board.isVisibleBy(user);
   }
   }
+*/
+
+  canExport(user) {
+    return false;
+  }
 }
 }

+ 45 - 19
models/users.js

@@ -95,7 +95,7 @@ Users.attachSchema(
       autoValue() {
       autoValue() {
         if (this.isInsert && !this.isSet) {
         if (this.isInsert && !this.isSet) {
           return {
           return {
-            boardView: 'board-view-lists',
+            boardView: 'board-view-swimlanes',
           };
           };
         }
         }
       },
       },
@@ -128,6 +128,13 @@ Users.attachSchema(
       type: Boolean,
       type: Boolean,
       optional: true,
       optional: true,
     },
     },
+    'profile.hideCheckedItems': {
+      /**
+       * does the user want to hide checked checklist items?
+       */
+      type: Boolean,
+      optional: true,
+    },
     'profile.hiddenSystemMessages': {
     'profile.hiddenSystemMessages': {
       /**
       /**
        * does the user want to hide system messages?
        * does the user want to hide system messages?
@@ -218,8 +225,8 @@ Users.attachSchema(
       type: String,
       type: String,
       optional: true,
       optional: true,
       allowedValues: [
       allowedValues: [
-        'board-view-lists',
         'board-view-swimlanes',
         'board-view-swimlanes',
+        'board-view-lists',
         'board-view-cal',
         'board-view-cal',
       ],
       ],
     },
     },
@@ -483,6 +490,11 @@ Users.helpers({
     return profile.showDesktopDragHandles || false;
     return profile.showDesktopDragHandles || false;
   },
   },
 
 
+  hasHideCheckedItems() {
+    const profile = this.profile || {};
+    return profile.hideCheckedItems || false;
+  },
+
   hasHiddenSystemMessages() {
   hasHiddenSystemMessages() {
     const profile = this.profile || {};
     const profile = this.profile || {};
     return profile.hiddenSystemMessages || false;
     return profile.hiddenSystemMessages || false;
@@ -612,6 +624,15 @@ Users.mutations({
     };
     };
   },
   },
 
 
+  toggleHideCheckedItems() {
+    const value = this.hasHideCheckedItems();
+    return {
+      $set: {
+        'profile.hideCheckedItems': !value,
+      },
+    };
+  },
+
   toggleSystem(value = false) {
   toggleSystem(value = false) {
     return {
     return {
       $set: {
       $set: {
@@ -690,6 +711,10 @@ Meteor.methods({
     const user = Meteor.user();
     const user = Meteor.user();
     user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
     user.toggleDesktopHandles(user.hasShowDesktopDragHandles());
   },
   },
+  toggleHideCheckedItems() {
+    const user = Meteor.user();
+    user.toggleHideCheckedItems();
+  },
   toggleSystemMessages() {
   toggleSystemMessages() {
     const user = Meteor.user();
     const user = Meteor.user();
     user.toggleSystem(user.hasHiddenSystemMessages());
     user.toggleSystem(user.hasHiddenSystemMessages());
@@ -903,7 +928,7 @@ if (Meteor.isServer) {
       user.profile = {
       user.profile = {
         initials,
         initials,
         fullname: user.services.oidc.fullname,
         fullname: user.services.oidc.fullname,
-        boardView: 'board-view-lists',
+        boardView: 'board-view-swimlanes',
       };
       };
       user.authenticationMethod = 'oauth2';
       user.authenticationMethod = 'oauth2';
 
 
@@ -921,7 +946,8 @@ if (Meteor.isServer) {
       existingUser.profile = user.profile;
       existingUser.profile = user.profile;
       existingUser.authenticationMethod = user.authenticationMethod;
       existingUser.authenticationMethod = user.authenticationMethod;
 
 
-      Meteor.users.remove({ _id: existingUser._id }); // remove existing record
+      Meteor.users.remove({ _id: user._id });
+      Meteor.users.remove({ _id: existingUser._id }); // is going to be created again
       return existingUser;
       return existingUser;
     }
     }
 
 
@@ -961,7 +987,7 @@ if (Meteor.isServer) {
       );
       );
     } else {
     } else {
       user.profile = { icode: options.profile.invitationcode };
       user.profile = { icode: options.profile.invitationcode };
-      user.profile.boardView = 'board-view-lists';
+      user.profile.boardView = 'board-view-swimlanes';
 
 
       // Deletes the invitation code after the user was created successfully.
       // Deletes the invitation code after the user was created successfully.
       setTimeout(
       setTimeout(
@@ -1109,10 +1135,10 @@ if (Meteor.isServer) {
         });
         });
         */
         */
 
 
-          const Future = require('fibers/future');
-          let future1 = new Future();
-          let future2 = new Future();
-          let future3 = new Future();
+        const Future = require('fibers/future');
+        let future1 = new Future();
+        let future2 = new Future();
+        let future3 = new Future();
         Boards.insert(
         Boards.insert(
           {
           {
             title: TAPi18n.__('templates'),
             title: TAPi18n.__('templates'),
@@ -1140,7 +1166,7 @@ if (Meteor.isServer) {
                 Users.update(fakeUserId.get(), {
                 Users.update(fakeUserId.get(), {
                   $set: { 'profile.cardTemplatesSwimlaneId': swimlaneId },
                   $set: { 'profile.cardTemplatesSwimlaneId': swimlaneId },
                 });
                 });
-                  future1.return();
+                future1.return();
               },
               },
             );
             );
 
 
@@ -1158,7 +1184,7 @@ if (Meteor.isServer) {
                 Users.update(fakeUserId.get(), {
                 Users.update(fakeUserId.get(), {
                   $set: { 'profile.listTemplatesSwimlaneId': swimlaneId },
                   $set: { 'profile.listTemplatesSwimlaneId': swimlaneId },
                 });
                 });
-                  future2.return();
+                future2.return();
               },
               },
             );
             );
 
 
@@ -1176,22 +1202,22 @@ if (Meteor.isServer) {
                 Users.update(fakeUserId.get(), {
                 Users.update(fakeUserId.get(), {
                   $set: { 'profile.boardTemplatesSwimlaneId': swimlaneId },
                   $set: { 'profile.boardTemplatesSwimlaneId': swimlaneId },
                 });
                 });
-                  future3.return();
+                future3.return();
               },
               },
             );
             );
           },
           },
         );
         );
-          // HACK
-          future1.wait();
-          future2.wait();
-          future3.wait();
+        // HACK
+        future1.wait();
+        future2.wait();
+        future3.wait();
       });
       });
     });
     });
   }
   }
 
 
-    Users.after.insert((userId, doc) => {
-        // HACK
-      doc = Users.findOne({_id: doc._id});
+  Users.after.insert((userId, doc) => {
+    // HACK
+    doc = Users.findOne({ _id: doc._id });
     if (doc.createdThroughApi) {
     if (doc.createdThroughApi) {
       // The admin user should be able to create a user despite disabling registration because
       // The admin user should be able to create a user despite disabling registration because
       // it is two different things (registration and creation).
       // it is two different things (registration and creation).

+ 14 - 3
openapi/generate_openapi.py

@@ -249,7 +249,10 @@ class EntryPoint(object):
 
 
                 if name.startswith('{'):
                 if name.startswith('{'):
                     param_type = name.strip('{}')
                     param_type = name.strip('{}')
-                    if param_type not in ['string', 'number', 'boolean', 'integer', 'array', 'file']:
+                    if param_type == 'Object':
+                        # hope for the best
+                        param_type = 'object'
+                    elif param_type not in ['string', 'number', 'boolean', 'integer', 'array', 'file']:
                         self.warn('unknown type {}\n allowed values: string, number, boolean, integer, array, file'.format(param_type))
                         self.warn('unknown type {}\n allowed values: string, number, boolean, integer, array, file'.format(param_type))
                     try:
                     try:
                         name, desc = desc.split(maxsplit=1)
                         name, desc = desc.split(maxsplit=1)
@@ -814,13 +817,21 @@ def parse_schemas(schemas_dir):
                                                        for d in data]
                                                        for d in data]
                                 entry_points.extend(schema_entry_points)
                                 entry_points.extend(schema_entry_points)
 
 
+                                end_of_previous_operation = -1
+
                                 # try to match JSDoc to the operations
                                 # try to match JSDoc to the operations
                                 for entry_point in schema_entry_points:
                                 for entry_point in schema_entry_points:
                                     operation = entry_point.method  # POST/GET/PUT/DELETE
                                     operation = entry_point.method  # POST/GET/PUT/DELETE
+
+                                    # find all jsdocs that end before the current operation,
+                                    # the last item in the list is the one we need
                                     jsdoc = [j for j in jsdocs
                                     jsdoc = [j for j in jsdocs
-                                             if j.loc.end.line + 1 == operation.loc.start.line]
+                                             if j.loc.end.line + 1 <= operation.loc.start.line and
+                                                j.loc.start.line > end_of_previous_operation]
                                     if bool(jsdoc):
                                     if bool(jsdoc):
-                                        entry_point.doc = jsdoc[0]
+                                        entry_point.doc = jsdoc[-1]
+
+                                    end_of_previous_operation = operation.loc.end.line
             except TypeError:
             except TypeError:
                 logger.warning(context.txt_for(statement))
                 logger.warning(context.txt_for(statement))
                 logger.error('{}:{}-{} can not parse {}'.format(path,
                 logger.error('{}:{}-{} can not parse {}'.format(path,

+ 2 - 16
openshift/wekan.yml

@@ -64,8 +64,6 @@ objects:
       name: "${WEKAN_SERVICE_NAME}"
       name: "${WEKAN_SERVICE_NAME}"
     sessionAffinity: None
     sessionAffinity: None
     type: ClusterIP
     type: ClusterIP
-  status:
-    loadBalancer: {}
 - apiVersion: v1
 - apiVersion: v1
   kind: Service
   kind: Service
   metadata:
   metadata:
@@ -86,8 +84,6 @@ objects:
       name: "${DATABASE_SERVICE_NAME}"
       name: "${DATABASE_SERVICE_NAME}"
     sessionAffinity: None
     sessionAffinity: None
     type: ClusterIP
     type: ClusterIP
-  status:
-    loadBalancer: {}
 - apiVersion: v1
 - apiVersion: v1
   kind: PersistentVolumeClaim
   kind: PersistentVolumeClaim
   metadata:
   metadata:
@@ -276,7 +272,6 @@ objects:
         lastTriggeredImage: ''
         lastTriggeredImage: ''
       type: ImageChange
       type: ImageChange
     - type: ConfigChange
     - type: ConfigChange
-  status: {}
 - apiVersion: route.openshift.io/v1
 - apiVersion: route.openshift.io/v1
   kind: Route
   kind: Route
   metadata:
   metadata:
@@ -297,15 +292,6 @@ objects:
       name: wekan
       name: wekan
       weight: 100
       weight: 100
     wildcardPolicy: None
     wildcardPolicy: None
-  status:
-    ingress:
-      - conditions:
-          - lastTransitionTime: '2018-08-28T14:45:21Z'
-            status: 'True'
-            type: Admitted
-        host: ${FQDN}
-        routerName: router
-        wildcardPolicy: None
 parameters:
 parameters:
 - description: The Fully Qualified Hostname (FQDN) of the application
 - description: The Fully Qualified Hostname (FQDN) of the application
   displayName: FQDN
   displayName: FQDN
@@ -323,7 +309,7 @@ parameters:
   displayName: Database Service Name
   displayName: Database Service Name
   name: DATABASE_SERVICE_NAME
   name: DATABASE_SERVICE_NAME
   required: true
   required: true
-  value: mongodb
+  value: wekan-mongodb
 - description: Username for MongoDB user that will be used for accessing the database.
 - description: Username for MongoDB user that will be used for accessing the database.
   displayName: MongoDB Connection Username
   displayName: MongoDB Connection Username
   from: user[A-Z0-9]{3}
   from: user[A-Z0-9]{3}
@@ -356,7 +342,7 @@ parameters:
   displayName: Version of MongoDB Image
   displayName: Version of MongoDB Image
   name: MONGODB_VERSION
   name: MONGODB_VERSION
   required: true
   required: true
-  value: '4.0.10'
+  value: '3.6'
 - name: WEKAN_SERVICE_NAME
 - name: WEKAN_SERVICE_NAME
   displayName: Wekan Service Name
   displayName: Wekan Service Name
   value: wekan
   value: wekan

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 540 - 191
package-lock.json


+ 18 - 19
package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "wekan",
   "name": "wekan",
-  "version": "v4.11.0",
+  "version": "v4.20.0",
   "description": "Open-Source kanban",
   "description": "Open-Source kanban",
   "private": true,
   "private": true,
   "scripts": {
   "scripts": {
@@ -45,37 +45,36 @@
     "eslint-config-meteor": "0.0.9",
     "eslint-config-meteor": "0.0.9",
     "eslint-config-prettier": "^3.6.0",
     "eslint-config-prettier": "^3.6.0",
     "eslint-import-resolver-meteor": "^0.4.0",
     "eslint-import-resolver-meteor": "^0.4.0",
-    "eslint-plugin-import": "^2.20.0",
+    "eslint-plugin-import": "^2.22.0",
     "eslint-plugin-meteor": "^5.1.0",
     "eslint-plugin-meteor": "^5.1.0",
-    "eslint-plugin-prettier": "^3.1.2",
+    "eslint-plugin-prettier": "^3.1.4",
     "lint-staged": "^7.3.0",
     "lint-staged": "^7.3.0",
     "pre-commit": "^1.2.2",
     "pre-commit": "^1.2.2",
     "prettier": "^1.19.1",
     "prettier": "^1.19.1",
     "prettier-eslint": "^9.0.2"
     "prettier-eslint": "^9.0.2"
   },
   },
   "dependencies": {
   "dependencies": {
-    "@babel/core": "^7.9.6",
-    "@babel/runtime": "^7.9.6",
+    "@babel/core": "^7.10.5",
+    "@babel/runtime": "^7.10.5",
     "@root/request": "^1.6.1",
     "@root/request": "^1.6.1",
-    "ajv": "^5.0.0",
+    "ajv": "^6.12.3",
     "babel-runtime": "^6.26.0",
     "babel-runtime": "^6.26.0",
-    "bcrypt": "^3.0.7",
-    "bson": "^4.0.3",
-    "bunyan": "^1.8.12",
-    "csv-stringify": "^5.5.0",
-    "es6-promise": "^4.2.4",
+    "bcrypt": "^5.0.0",
+    "bson": "^4.0.4",
+    "bunyan": "^2.0.4",
+    "es6-promise": "^4.2.8",
     "fibers": "^5.0.0",
     "fibers": "^5.0.0",
-    "flatted": "^2.0.1",
-    "gridfs-stream": "^0.5.3",
-    "jszip": "^3.4.0",
-    "ldapjs": "^1.0.2",
-    "meteor-node-stubs": "^0.4.1",
-    "mongodb": "^3.5.7",
+    "flatted": "^3.0.4",
+    "gridfs-stream": "^1.1.1",
+    "jszip": "^3.5.0",
+    "ldapjs": "^2.0.0",
+    "meteor-node-stubs": "^1.0.0",
+    "mongodb": "^3.5.9",
     "os": "^0.1.1",
     "os": "^0.1.1",
-    "page": "^1.11.5",
+    "page": "^1.11.6",
     "papaparse": "^5.2.0",
     "papaparse": "^5.2.0",
     "qs": "^6.9.4",
     "qs": "^6.9.4",
     "source-map-support": "^0.5.19",
     "source-map-support": "^0.5.19",
-    "xss": "^1.0.6"
+    "xss": "^1.0.7"
   }
   }
 }
 }

+ 0 - 9
packages/markdown/markdown.js

@@ -1,9 +0,0 @@
-var mark = marked;
-
-mark.setOptions({
-  gfm: true,
-  tables: true,
-  breaks: true
-});
-
-Markdown = mark;

+ 3 - 4
packages/markdown/marked/package-lock.json

@@ -2675,10 +2675,9 @@
       }
       }
     },
     },
     "lodash": {
     "lodash": {
-      "version": "4.17.14",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
-      "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==",
-      "dev": true
+      "version": "4.17.19",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.19.tgz",
+      "integrity": "sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ=="
     },
     },
     "loose-envify": {
     "loose-envify": {
       "version": "1.4.0",
       "version": "1.4.0",

+ 3 - 0
packages/markdown/marked/package.json

@@ -74,5 +74,8 @@
   },
   },
   "engines": {
   "engines": {
     "node": ">= 8.16.2"
     "node": ">= 8.16.2"
+  },
+  "dependencies": {
+    "lodash": "^4.17.19"
   }
   }
 }
 }

+ 11 - 7
packages/markdown/package.js

@@ -2,23 +2,27 @@
 
 
 Package.describe({
 Package.describe({
 	name: 'wekan-markdown',
 	name: 'wekan-markdown',
-	summary: "GitHub flavored markdown parser for Meteor based on marked.js",
-	version: "1.0.8",
-	git: "https://github.com/wekan/markdown.git"
+	summary: 'GitHub flavored markdown parser for Meteor based on marked.js',
+	version: '1.0.9',
+	git: 'https://github.com/wekan/markdown.git',
 });
 });
 
 
 // Before Meteor 0.9?
 // Before Meteor 0.9?
 if(!Package.onUse) Package.onUse = Package.on_use;
 if(!Package.onUse) Package.onUse = Package.on_use;
 
 
 Package.onUse(function (api) {
 Package.onUse(function (api) {
-	if(api.versionsFrom) api.versionsFrom('METEOR@0.9.0');
+	if(api.versionsFrom) api.versionsFrom('1.8.2');
 
 
 	api.use('templating');
 	api.use('templating');
+  api.use("ecmascript", ['server', 'client']);
 
 
 	api.add_files('marked/lib/marked.js', ['server', 'client']);
 	api.add_files('marked/lib/marked.js', ['server', 'client']);
-	api.add_files('markdown.js', ['server', 'client']);
+	api.add_files('src/markdown.js', ['server', 'client']);
 	api.export('Markdown', ['server', 'client']);
 	api.export('Markdown', ['server', 'client']);
 
 
-	api.use("ui", "client", {weak: true});
-	api.add_files("template-integration.js", "client");
+  api.use('ui', 'client', {weak: true});
+  api.use('tmeasday:check-npm-versions', 'client');
+
+  api.add_files('src/checkNpmVersions.js', 'client');
+	api.add_files('src/template-integration.js', 'client');
 });
 });

+ 5 - 0
packages/markdown/src/checkNpmVersions.js

@@ -0,0 +1,5 @@
+import { checkNpmVersions } from 'meteor/tmeasday:check-npm-versions';
+
+checkNpmVersions({
+    'xss': '1.0.6',
+}, 'my:xss');

+ 9 - 0
packages/markdown/src/markdown.js

@@ -0,0 +1,9 @@
+import marked from '../marked/lib/marked.js';
+
+marked.setOptions({
+  gfm: true,
+  tables: true,
+  breaks: true,
+});
+
+Markdown = marked;

+ 18 - 0
packages/markdown/src/template-integration.js

@@ -0,0 +1,18 @@
+import sanitizeXss from 'xss';
+
+if (Package.ui) {
+	const Template = Package.templating.Template;
+	const UI = Package.ui.UI;
+	const HTML = Package.htmljs.HTML;
+	const Blaze = Package.blaze.Blaze; // implied by `ui`
+
+	UI.registerHelper('markdown', new Template('markdown', function () {
+		const self = this;
+		let text = '';
+		if (self.templateContentBlock) {
+			text = Blaze._toText(self.templateContentBlock, HTML.TEXTMODE.STRING);
+		}
+
+      return HTML.Raw(sanitizeXss(Markdown(text)));
+	}));
+}

+ 0 - 16
packages/markdown/template-integration.js

@@ -1,16 +0,0 @@
-if (Package.ui) {
-	var Template = Package.templating.Template;
-	var UI = Package.ui.UI;
-	var HTML = Package.htmljs.HTML;
-	var Blaze = Package.blaze.Blaze; // implied by `ui`
-
-	UI.registerHelper('markdown', new Template('markdown', function () {
-		var self = this;
-		var text = "";
-		if(self.templateContentBlock) {
-			text = Blaze._toText(self.templateContentBlock, HTML.TEXTMODE.STRING);
-		}
-
-		return HTML.Raw(Markdown(text));
-	}));
-}

+ 2 - 2
packages/wekan-accounts-cas/cas_server.js

@@ -229,13 +229,13 @@ const casValidate = (req, ticket, token, service, callback) => {
   if (attrs.debug) {
   if (attrs.debug) {
     console.log(`CAS response : ${JSON.stringify(result)}`);
     console.log(`CAS response : ${JSON.stringify(result)}`);
   }
   }
-  let user = Meteor.users.findOne({ 'username': options.username });
+  let user = Users.findOne({ 'username': options.username });
   if (! user) {
   if (! user) {
     if (attrs.debug) {
     if (attrs.debug) {
       console.log(`Creating user account ${JSON.stringify(options)}`);
       console.log(`Creating user account ${JSON.stringify(options)}`);
     }
     }
     const userId = Accounts.insertUserDoc({}, options);
     const userId = Accounts.insertUserDoc({}, options);
-    user = Meteor.users.findOne(userId);
+    user = Users.findOne(userId);
   }
   }
   if (attrs.debug) {
   if (attrs.debug) {
     console.log(`Using user account ${JSON.stringify(user)}`);
     console.log(`Using user account ${JSON.stringify(user)}`);

Vissa filer visades inte eftersom för många filer har ändrats