Compare commits

...
147 Commits
Author SHA1 Message Date
Lauri Ojansivu 6cd92ab2c6 v3.97 2020-04-19 17:05:41 +03:00
Lauri Ojansivu e92ebe5151 Update ChangeLog. 2020-04-19 16:52:06 +03:00
Lauri Ojansivu 8cb838c0de Merge branch 'boeserwolf-feature-sortable-boards' 2020-04-19 16:31:12 +03:00
Lauri Ojansivu 6cae14d6e9 Merge branch 'feature-sortable-boards' of https://github.com/boeserwolf/wekan into boeserwolf-feature-sortable-boards 2020-04-19 16:30:27 +03:00
boeserwolf b42d8346cd Insert new boards at last position 2020-04-19 15:53:13 +03:00
boeserwolf 1a065ff351 Refactor variable names 2020-04-19 15:52:43 +03:00
boeserwolf 3565ff2700 Export sort field 2020-04-19 15:52:06 +03:00
boeserwolf e354715a9d Remove sorting by _id 2020-04-19 15:51:29 +03:00
Lauri Ojansivu e7002f417b Update translations. 2020-04-19 14:00:24 +03:00
boeserwolf ef5f38f431 Make boards sortable 2020-04-19 13:49:10 +03:00
boeserwolf b3efa71d13 Add move function to boards mutations 2020-04-19 13:49:10 +03:00
boeserwolf 10fcc19b7f Add sortDefault helper for sorting boards 2020-04-19 13:49:07 +03:00
Lauri Ojansivu 948f05fecb Update ChangeLog. 2020-04-19 12:23:29 +03:00
Lauri Ojansivu 927bb83813 Merge pull request #3025 from boeserwolf/master
Make linked card clickable
2020-04-19 12:14:48 +03:00
boeserwolf 9f396e9038 Add a migration to add a sort field to the boards model 2020-04-19 10:51:58 +03:00
boeserwolf 2400c91013 Add sort field to boards model 2020-04-19 10:48:44 +03:00
boeserwolf f583645744 Make linked card clickable 2020-04-19 10:33:41 +03:00
Lauri Ojansivu 42b3cff99f Update ChangeLog. 2020-04-17 22:14:09 +03:00
Lauri Ojansivu 960fe5163b Remove old warning from Sandstorm import board data loss, because bug has been already fixed.
Thanks to aputsiaq and xet7 !
2020-04-17 21:58:19 +03:00
Lauri Ojansivu 41665c079d Update ChangeLog. 2020-04-17 21:48:06 +03:00
Lauri Ojansivu 8a0defc988 Merge pull request #3024 from marc1006/card_layout_fix
Improve card layout on mobile devices
2020-04-17 21:38:50 +03:00
Marc Hartmayer d7e0350ecf Improve card layout on mobile devices 2020-04-17 19:49:43 +02:00
Lauri Ojansivu bf15fa988d Rename Dockerfile.amd64 back to Dockerfile, because automatic builds did not work.
Thanks to xet7 !
2020-04-17 18:34:41 +03:00
Lauri Ojansivu db2d59181c Update ChangeLog. 2020-04-17 10:21:41 +03:00
Lauri Ojansivu dcc9a0d498 Merge branch 'brokencode64-arm64-dockerfile' 2020-04-17 10:18:53 +03:00
Lauri Ojansivu 936dea591a Merge branch 'arm64-dockerfile' of https://github.com/brokencode64/wekan into brokencode64-arm64-dockerfile 2020-04-17 10:18:30 +03:00
Lauri Ojansivu cf7e5472ba Update translations. 2020-04-17 10:10:40 +03:00
Lauri Ojansivu 5c61119716 Update ChangeLog. 2020-04-17 10:08:45 +03:00
Lauri Ojansivu 3558d711ff Merge pull request #3020 from ckavili/master
oidc server is updated to work with OCP OAuth
2020-04-17 10:02:38 +03:00
thewoosterisroot 72c1c49da3 Adding dockerfiles for multi-arch builds and manifest. 2020-04-16 19:30:50 +02:00
Cansu Kavili 93f8ff946f updated with env and annotation parameters 2020-04-15 09:54:22 +02:00
Cansu Kavili 61d582ffd9 updated with env and annotation parameters 2020-04-15 09:52:34 +02:00
Cansu Kavili 60384be5ff add annotations if specified in values file 2020-04-15 09:50:30 +02:00
Cansu Kavili 8ac305778a Add env parameters if specified in values file 2020-04-15 09:50:07 +02:00
Lauri Ojansivu 5be93741ee Update ChangeLog. 2020-04-15 03:44:30 +03:00
Lauri Ojansivu c2f91baaf9 Merge pull request #3019 from devinsm/mobile-friendly-checklist
Allows for use of checklist on mobile
2020-04-15 03:40:14 +03:00
Devin McAllester 9df5c0e2de Allows for use of checklist on mobile 2020-04-14 17:05:58 -07:00
Lauri Ojansivu f1a9e30956 v3.96 2020-04-15 00:05:48 +03:00
Lauri Ojansivu 4b202aaa08 Update ChangeLog. 2020-04-14 23:43:38 +03:00
Lauri Ojansivu 5ef1a92366 Update translations. 2020-04-14 23:41:22 +03:00
Lauri Ojansivu 1a836969e1 Remove 1.8.x files because Sandstorm now uses newest Meteor.
Thanks to xet7 !
2020-04-14 23:01:21 +03:00
Lauri Ojansivu 079b3da6ef Merge pull request #3015 from boeserwolf/master
Fix <p> margin in card labels
2020-04-14 21:23:41 +03:00
Lauri Ojansivu 13563e20e7 Merge pull request #3014 from salleman33/master
hide password auth with PASSWORD_LOGIN_ENABLED variable
2020-04-14 21:23:10 +03:00
Allemand 4f1330c777 Update docker-compose.yml 2020-04-14 09:12:39 +02:00
Allemand 94b558cf43 Update start-wekan.sh 2020-04-14 09:09:38 +02:00
Allemand e22e24d917 Update start-wekan.bat 2020-04-14 09:07:49 +02:00
Allemand 55545a52ca Update wekan-help 2020-04-14 09:05:14 +02:00
Allemand e0cb5a0c7a Update config 2020-04-14 09:01:43 +02:00
Allemand efd3faf9ef Update sandstorm-pkgdef.capnp 2020-04-14 08:58:47 +02:00
Allemand 2fd577d2c0 Update docker-compose.yml 2020-04-14 08:56:52 +02:00
Allemand 659e8418f7 Update Dockerfile 2020-04-14 08:51:59 +02:00
Allemand 18610d2fe6 Update settings.js 2020-04-14 08:49:47 +02:00
Allemand 1389ed0fce Update layouts.js 2020-04-14 08:48:51 +02:00
boeserwolf c39364af83 Fix margin in card labels 2020-04-13 23:47:00 +02:00
salleman 3e817257ef hide password auth with PASSWORD_LOGIN_ENABLED variable 2020-04-13 21:06:27 +02:00
Lauri Ojansivu c5f782976b Update Sandstorm release script for newest Meteor and Node 12.x 2020-04-13 10:55:00 -04:00
Lauri Ojansivu b841f798f8 Merge pull request #3013 from salleman33/master
debug isBoardAdmin on main page
2020-04-13 17:48:16 +03:00
salleman 35ae07e2a6 debug isBoardAdmin on main page 2020-04-13 15:46:29 +02:00
Cansu Kavili 2c792363bf ocp hack added 2020-04-13 14:03:19 +02:00
Lauri Ojansivu a68ecc079d Update translations. 2020-04-13 02:12:10 +03:00
Lauri Ojansivu b2d546579c Fix capnp workaround to work with newest Meteor and Node 12.x.
Thanks to kentonv !
2020-04-13 02:09:46 +03:00
Lauri Ojansivu 4bc6ad3b4c v3.95 2020-04-12 18:07:38 +03:00
Lauri Ojansivu 7f558fede0 Update translations. 2020-04-12 17:45:33 +03:00
Lauri Ojansivu 544bc1d6ad Merge branch 'master' of https://github.com/NicoP-S/wekan 2020-04-12 16:58:08 +03:00
Lauri Ojansivu 89d25f52fa Update ChangeLog. 2020-04-12 16:55:26 +03:00
Lauri Ojansivu 2fd71d5be8 Merge pull request #3009 from juniormendonca/juniormendonca/gitpod-setup
Add gitpod config
2020-04-12 16:53:32 +03:00
Lauri Ojansivu dc643f3d43 Merge pull request #3010 from jtbairdsr/master
fix error in notifications cleanup cron
2020-04-12 16:50:19 +03:00
Lauri Ojansivu 4469b12203 Merge pull request #3012 from boeserwolf/master
Fix styling issue in notifications drawer
2020-04-12 16:42:09 +03:00
boeserwolf 9cacaafb8f Fix styling issue in notifications drawer
The header of the notification drawer had a margin to the
right side in Google Chrome caused by overflow: scroll on
the #notifications-drawer element.
2020-04-12 11:57:22 +02:00
Jonathan Baird 269382869e fix error in notifications cleanup cron 2020-04-11 17:28:15 -06:00
Júnior Mendonça 8648e32108 Add gitpod config
this commit adds support for Gitpod.io, a free automated
dev environment that makes contributing and generally working on GitHub
projects much easier. It allows anyone to start a ready-to-code dev
environment for any branch, issue and pull request with a single click.
2020-04-11 23:27:59 +00:00
Nico edf52bc438 Public boards overview 2020-04-12 00:56:35 +02:00
Lauri Ojansivu 58ce859368 v3.94 2020-04-12 00:01:07 +03:00
Lauri Ojansivu e23aacedb3 Update translations. 2020-04-11 22:38:24 +03:00
Lauri Ojansivu 7f02990626 Update ChangeLog. 2020-04-11 22:25:25 +03:00
Lauri Ojansivu c86155f1aa Update ChangeLog. 2020-04-10 12:22:47 +03:00
Lauri Ojansivu 3fae5355d4 Add robots.txt disallow all.
Thanks to xet7 !

Related #3001
2020-04-10 12:19:18 +03:00
Lauri Ojansivu 20e88159ae Update translations. 2020-04-10 12:14:58 +03:00
Lauri Ojansivu a81921382a Merge pull request #3006 from NicoP-S/master
Public vote
2020-04-10 12:05:10 +03:00
Nico 8f28a409c7 Public vote 2020-04-10 01:46:36 +02:00
Lauri Ojansivu 7566f05b97 v3.93 2020-04-09 23:00:00 +03:00
Lauri Ojansivu 268d7fcb32 Upgrade Node to 12.16.2, part 2.
Thanks to Node developers and xet7 !
2020-04-09 22:53:04 +03:00
Lauri Ojansivu 70edd44a01 Update ChangeLog. 2020-04-09 22:50:00 +03:00
Lauri Ojansivu 6db717b9b3 Upgrade to Node v12.16.2
Thanks to Node developers and xet7 !
2020-04-09 22:47:11 +03:00
Lauri Ojansivu f389fd95fb Update translations. 2020-04-09 22:37:36 +03:00
Lauri Ojansivu 363bcab98b Update ChangeLog. 2020-04-09 22:30:31 +03:00
Lauri Ojansivu c4a7e53661 Merge pull request #3005 from jtbairdsr/master
fix bug that prevents editing or deleting comments
2020-04-09 22:30:02 +03:00
Lauri Ojansivu c6afe8d007 Merge pull request #3004 from slvrpdr/master
When adding a user to a board that has subtasks, also add user to the subtask board
2020-04-09 22:26:34 +03:00
Lauri Ojansivu 93eccffd44 Merge pull request #3000 from NicoP-S/master
Trello vote import & hide export button if with_api is disabled
2020-04-09 22:21:43 +03:00
Jonathan Baird fe66169415 fix bug that prevents editing or deleting comments 2020-04-09 12:46:24 -06:00
Pedro Sousa 6ced47aa8c When adding a user to a board that has subtasks, also add user to the subtask board 2020-04-09 19:10:50 +01:00
Nico e661d03e8d Add vote import from Trello 2020-04-09 02:00:15 +02:00
Nico f09219cbfd Remove export button if WITH_API is not enabled
#2938
https://github.com/wekan/wekan/issues/2938#issuecomment-589782402
2020-04-09 01:55:01 +02:00
NicoP-S 7c25542976 Merge pull request #5 from wekan/master
Update
2020-04-08 23:22:49 +02:00
Lauri Ojansivu 121686a928 v3.92 2020-04-08 23:51:38 +03:00
Lauri Ojansivu 3563e0145d Update translations. 2020-04-08 23:41:13 +03:00
Lauri Ojansivu c630714245 Update ChangeLog. 2020-04-08 23:23:45 +03:00
Lauri Ojansivu 5ebb47cb0e Add setting default NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE=2
to all Wekan platforms https://github.com/wekan/wekan/pull/2998

Thanks to xet7 !
2020-04-08 23:16:48 +03:00
Lauri Ojansivu 115701fa65 Merge branch 'jtbairdsr-master' 2020-04-08 22:29:15 +03:00
Jonathan Baird a182dde11f add a "remove all read" button to notification menu 2020-04-08 13:14:29 -06:00
Jonathan Baird 1e20e2601f add a scheduled notification cleanup job 2020-04-08 11:54:00 -06:00
Jonathan Baird 4d066b1f30 stop notifying users about their own behavior 2020-04-08 11:54:00 -06:00
Lauri Ojansivu 7856692946 v3.91 2020-04-08 20:37:43 +03:00
Lauri Ojansivu 7e7c8fd001 Update translations. 2020-04-08 20:29:31 +03:00
Lauri Ojansivu feb602ecd4 Update translations. 2020-04-08 19:59:23 +03:00
Lauri Ojansivu 6ed26e373a Update ChangeLog. 2020-04-08 19:54:12 +03:00
Lauri Ojansivu 4fba0fb1a1 Clarify translation. 2020-04-08 19:43:25 +03:00
Lauri Ojansivu 968ae122b0 Fix typos. 2020-04-08 19:38:30 +03:00
Lauri Ojansivu 06c32cb497 Update translations. 2020-04-08 19:37:41 +03:00
Lauri Ojansivu d2a4925cae Merge branch 'NicoP-S-master' 2020-04-08 19:17:00 +03:00
Lauri Ojansivu 9c97c301bd Merge branch 'master' of https://github.com/NicoP-S/wekan into NicoP-S-master 2020-04-08 19:15:05 +03:00
Lauri Ojansivu d4a91d30ff Update ChangeLog. 2020-04-08 19:14:13 +03:00
Lauri Ojansivu 6a56a495ad Update translations. 2020-04-08 18:47:17 +03:00
Lauri Ojansivu 3330aff12c Merge branch 'daniel-eder-feature/filter-assignee' 2020-04-08 18:39:32 +03:00
Lauri Ojansivu 43bdd56a41 Merge branch 'feature/filter-assignee' of https://github.com/daniel-eder/wekan into daniel-eder-feature/filter-assignee 2020-04-08 18:39:09 +03:00
Lauri Ojansivu a602f4b9ec Update ChangeLog. 2020-04-08 18:38:02 +03:00
Lauri Ojansivu 053e47173f Merge pull request #2996 from ckavili/master
Route template added to helm chart
2020-04-08 18:30:51 +03:00
Daniel Eder fe285c62e1 Add filter option for assignee
Works exactly like member
2020-04-08 16:59:59 +03:00
Cansu Kavili a3d44b0774 README updated 2020-04-08 14:38:55 +02:00
Cansu Kavili 0e79bd25ed values file updated 2020-04-08 14:33:29 +02:00
Cansu Kavili 71f7a680b6 Openshift Route def added 2020-04-08 13:59:33 +02:00
Nico 411b8d3f56 Merge branch 'vote' 2020-04-07 20:43:55 +02:00
Nico 2bbc312ad0 Voteing feature 2020-04-07 20:43:35 +02:00
NicoP-S 14de17b667 Merge pull request #4 from wekan/master
Update
2020-04-07 20:20:41 +02:00
Lauri Ojansivu 9083c341c1 Merge pull request #2990 from doggy8088/langzhtwfix
Correct zh-TW language name (the right way)
2020-04-07 13:03:21 +03:00
Will e0930c32a6 Correct zh-TW language name (the right way) 2020-04-07 09:43:23 +00:00
Lauri Ojansivu f438d04c42 v3.90 2020-04-06 16:25:12 +03:00
Lauri Ojansivu d798f6e3ef Update dependencies. 2020-04-06 15:46:59 +03:00
Lauri Ojansivu c96ca4e875 Update translations. 2020-04-06 15:37:09 +03:00
Lauri Ojansivu 8a71fe39c5 Update ChangeLog. 2020-04-06 15:35:19 +03:00
Lauri Ojansivu e4ec5c38b7 Merge branch 'doggy8088-patch-1' 2020-04-06 15:27:53 +03:00
Will 保哥 b849d4c2ba Update layouts.js 2020-04-06 18:16:17 +08:00
Lauri Ojansivu db9c895da8 v3.89 2020-04-05 01:20:09 +03:00
Lauri Ojansivu a938c386cf Update translations. 2020-04-05 01:06:49 +03:00
NicoP-S a376fb2fab Merge pull request #3 from wekan/master
Update
2020-04-04 23:14:32 +02:00
Lauri Ojansivu 06c2ff0904 Update ChangeLog. 2020-04-04 01:43:09 +03:00
Lauri Ojansivu 76e832c3a6 Merge branch 'daniel-eder-feature/subtask-use-parent-swimlane' 2020-04-04 01:36:43 +03:00
Lauri Ojansivu b7fd79aef0 Merge branch 'feature/subtask-use-parent-swimlane' of https://github.com/daniel-eder/wekan into daniel-eder-feature/subtask-use-parent-swimlane 2020-04-04 01:26:49 +03:00
Lauri Ojansivu 28a9ab7131 Update translations. 2020-04-04 01:19:47 +03:00
Lauri Ojansivu 8e0b1cc056 Merge branch 'slvrpdr-master' 2020-04-04 01:04:17 +03:00
Lauri Ojansivu b424b34cab Merge branch 'master' of https://github.com/slvrpdr/wekan into slvrpdr-master 2020-04-04 00:42:14 +03:00
Lauri Ojansivu 45a83da7be Update translations. 2020-04-04 00:37:23 +03:00
Pedro Sousa 6e86292b99 Search also a Card's Custom Fields 2020-04-03 16:23:48 +01:00
NicoP-S e47ff25d45 Merge pull request #2 from wekan/master
Merge Wekan
2020-04-02 20:43:36 +02:00
Daniel Eder 89fe030fa3 subtasks now use swimlane with title matching parent lane title
As discussed in #1953 this is required to handle two-board scenarios correctly.
2020-04-02 07:49:26 +02:00
NicoP-S 7fa9603f9d Merge pull request #1 from wekan/master
update
2020-03-26 21:17:17 +01:00
Daniel Eder c41c1e5293 subtasks now use parent task swimlane by default 2020-03-26 10:57:05 +01:00
143 changed files with 2926 additions and 11608 deletions

No files matched your search

File renamed without changes.
+10
View File
@@ -0,0 +1,10 @@
FROM gitpod/workspace-mongodb
USER gitpod
# Install custom tools, runtime, etc. using apt-get
# For example, the command below would install "bastet" - a command line tetris clone:
#
# RUN sudo apt-get -q update && # sudo apt-get install -yq bastet && # sudo rm -rf /var/lib/apt/lists/*
#
# More information: https://www.gitpod.io/docs/config-docker/
+4
View File
@@ -0,0 +1,4 @@
tasks:
- init: npm install
image:
file: .gitpod.Dockerfile
+6 -6
View File
@@ -11,7 +11,7 @@ allow-deny@1.1.0
arillo:flow-router-helpers@0.5.2
audit-argument-checks@1.0.7
autoupdate@1.6.0
babel-compiler@7.5.2
babel-compiler@7.5.3
babel-runtime@1.5.0
base64@1.0.12
binary-heap@1.0.11
@@ -20,7 +20,7 @@ blaze-tools@1.0.10
boilerplate-generator@1.7.0
browser-policy-common@1.0.11
browser-policy-framing@1.1.0
caching-compiler@1.2.1
caching-compiler@1.2.2
caching-html-compiler@1.1.3
callback-hook@1.3.0
cfs:access-point@0.1.49
@@ -55,9 +55,9 @@ ddp-rate-limiter@1.0.7
ddp-server@2.3.1
deps@1.0.12
diff-sequence@1.1.1
dynamic-import@0.5.1
dynamic-import@0.5.2
easylogic:summernote@0.8.8
ecmascript@0.14.2
ecmascript@0.14.3
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.10.0
ecmascript-runtime-server@0.9.0
@@ -110,7 +110,7 @@ modern-browsers@0.1.5
modules@0.15.0
modules-runtime@0.12.0
momentjs:moment@2.24.0
mongo@1.9.0
mongo@1.9.1
mongo-decimal@0.1.1
mongo-dev-server@1.1.0
mongo-id@1.0.7
@@ -186,7 +186,7 @@ useraccounts:core@1.14.2
useraccounts:flow-routing@1.14.2
useraccounts:unstyled@1.14.2
verron:autosize@3.0.8
webapp@1.9.0
webapp@1.9.1
webapp-hashing@1.0.9
wekan-accounts-cas@0.1.0
wekan-accounts-oidc@1.0.10
@@ -1,20 +0,0 @@
# This file contains information which helps Meteor properly upgrade your
# app when you run 'meteor update'. You should check it into version control
# with your project.
notices-for-0.9.0
notices-for-0.9.1
0.9.4-platform-file
notices-for-facebook-graph-api-2
1.2.0-standard-minifiers-package
1.2.0-meteor-platform-split
1.2.0-cordova-changes
1.2.0-breaking-changes
1.3.0-split-minifiers-package
1.3.5-remove-old-dev-bundle-link
1.4.0-remove-old-dev-bundle-link
1.4.1-add-shell-server-package
1.4.3-split-account-service-packages
1.5-add-dynamic-import-package
1.7-split-underscore-from-meteor-base
1.8.3-split-jquery-from-blaze
-2
View File
@@ -1,2 +0,0 @@
dev_bundle
local
-7
View File
@@ -1,7 +0,0 @@
# This file contains a token that is unique to your project.
# Check it into your repository along with the rest of this directory.
# It can be used for purposes such as:
# - ensuring you don't accidentally deploy one app on top of another
# - providing package authors with aggregated statistics
dvyihgykyzec6y1dpg
Whitespace-only changes.
-100
View File
@@ -1,100 +0,0 @@
# Meteor packages used by this project, one per line.
#
# 'meteor add' and 'meteor remove' will edit this file for you,
# but you can also edit it by hand.
meteor-base@1.4.0
# Build system
ecmascript@0.13.2
standard-minifier-css@1.5.4
standard-minifier-js@2.5.2
mquandalle:jade
# Polyfills
es5-shim@4.8.0
# Collections
aldeed:collection2
cfs:standard-packages
cottz:publish-relations
dburles:collection-helpers
idmontie:migrations
matb33:collection-hooks
matteodem:easy-search
mongo@1.7.0
mquandalle:collection-mutations
# Account system
kenton:accounts-sandstorm
service-configuration@1.0.11
useraccounts:unstyled
useraccounts:flow-routing
wekan-ldap
wekan-accounts-cas
wekan-accounts-oidc
# Utilities
check@1.3.1
jquery@1.11.10
random@1.1.0
reactive-dict@1.3.0
session@1.2.0
tracker@1.2.0
underscore@1.0.10
3stack:presence
alethes:pages
arillo:flow-router-helpers
audit-argument-checks@1.0.7
kadira:blaze-layout
kadira:dochead
mquandalle:autofocus
ongoworks:speakingurl
raix:handlebar-helpers
tap:i18n
http@1.4.2
# UI components
blaze
reactive-var@1.0.11
fortawesome:fontawesome
mousetrap:mousetrap
mquandalle:jquery-textcomplete
mquandalle:jquery-ui-drag-drop-sort
mquandalle:mousetrap-bindglobal
peerlibrary:blaze-components@=0.15.1
templates:tabs
verron:autosize
simple:json-routes
rajit:bootstrap3-datepicker
shell-server@0.4.0
simple:rest-accounts-password
useraccounts:core
email@1.2.3
horka:swipebox
dynamic-import@0.5.1
staringatlights:fast-render
accounts-password@1.5.2
cfs:gridfs
rzymek:fullcalendar
momentjs:moment@2.22.2
browser-policy-framing@1.1.0
mquandalle:moment
msavin:usercache
wekan-scrollbar
mquandalle:perfect-scrollbar
mdg:meteor-apm-agent@3.2.0-rc.0!
# Keep stylus in 1.1.0, because building v2 takes extra 52 minutes.
coagmano:stylus@1.1.0!
lucasantoniassi:accounts-lockout
meteorhacks:subs-manager
meteorhacks:picker
lamhieu:unblock
meteorhacks:aggregate@1.3.0
wekan-markdown
konecty:mongo-counter
percolate:synced-cron
easylogic:summernote
cfs:filesystem
ostrio:cookies
-2
View File
@@ -1,2 +0,0 @@
server
browser
-1
View File
@@ -1 +0,0 @@
METEOR@1.8.3
-198
View File
@@ -1,198 +0,0 @@
3stack:presence@1.1.2
accounts-base@1.4.5
accounts-oauth@1.1.16
accounts-password@1.5.2
aldeed:collection2@2.10.0
aldeed:collection2-core@1.2.0
aldeed:schema-deny@1.1.0
aldeed:schema-index@1.1.1
aldeed:simple-schema@1.5.4
alethes:pages@1.8.6
allow-deny@1.1.0
arillo:flow-router-helpers@0.5.2
audit-argument-checks@1.0.7
autoupdate@1.6.0
babel-compiler@7.4.2
babel-runtime@1.4.0
base64@1.0.12
binary-heap@1.0.11
blaze@2.3.4
blaze-tools@1.0.10
boilerplate-generator@1.6.0
browser-policy-common@1.0.11
browser-policy-framing@1.1.0
caching-compiler@1.2.1
caching-html-compiler@1.1.3
callback-hook@1.2.0
cfs:access-point@0.1.49
cfs:base-package@0.0.30
cfs:collection@0.5.5
cfs:collection-filters@0.2.4
cfs:data-man@0.0.6
cfs:file@0.1.17
cfs:filesystem@0.1.2
cfs:gridfs@0.0.34
cfs:http-methods@0.0.32
cfs:http-publish@0.0.13
cfs:power-queue@0.9.11
cfs:reactive-list@0.0.9
cfs:reactive-property@0.0.4
cfs:standard-packages@0.5.10
cfs:storage-adapter@0.2.4
cfs:tempstore@0.1.6
cfs:upload-http@0.0.20
cfs:worker@0.1.5
check@1.3.1
chuangbo:cookie@1.1.0
coagmano:stylus@1.1.0
coffeescript@1.0.17
cottz:publish-relations@2.0.8
dburles:collection-helpers@1.1.0
ddp@1.4.0
ddp-client@2.3.3
ddp-common@1.4.0
ddp-rate-limiter@1.0.7
ddp-server@2.3.0
deps@1.0.12
diff-sequence@1.1.1
dynamic-import@0.5.1
easylogic:summernote@0.8.8
ecmascript@0.13.2
ecmascript-runtime@0.7.0
ecmascript-runtime-client@0.9.0
ecmascript-runtime-server@0.8.0
ejson@1.1.1
email@1.2.3
es5-shim@4.8.0
fastclick@1.0.13
fetch@0.1.1
fortawesome:fontawesome@4.7.0
geojson-utils@1.0.10
horka:swipebox@1.0.2
hot-code-push@1.0.4
html-tools@1.0.11
htmljs@1.0.11
http@1.4.2
id-map@1.1.0
idmontie:migrations@1.0.3
inter-process-messaging@0.1.0
jquery@1.11.11
kadira:blaze-layout@2.3.0
kadira:dochead@1.5.0
kadira:flow-router@2.12.1
kenton:accounts-sandstorm@0.7.0
konecty:mongo-counter@0.0.5_3
lamhieu:meteorx@2.1.1
lamhieu:unblock@1.0.0
launch-screen@1.1.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.20
lucasantoniassi:accounts-lockout@1.0.0
matb33:collection-hooks@0.9.1
matteodem:easy-search@1.6.4
mdg:meteor-apm-agent@3.2.5
mdg:validation-error@0.5.1
meteor@1.9.3
meteor-base@1.4.0
meteor-platform@1.2.6
meteorhacks:aggregate@1.3.0
meteorhacks:collection-utils@1.2.0
meteorhacks:picker@1.0.3
meteorhacks:subs-manager@1.6.4
meteorspark:util@0.2.0
minifier-css@1.4.3
minifier-js@2.5.1
minifiers@1.1.8-faster-rebuild.0
minimongo@1.4.5
mobile-status-bar@1.0.14
modern-browsers@0.1.4
modules@0.14.0
modules-runtime@0.11.0
momentjs:moment@2.24.0
mongo@1.7.0
mongo-decimal@0.1.1
mongo-dev-server@1.1.0
mongo-id@1.0.7
mongo-livedata@1.0.12
mousetrap:mousetrap@1.4.6_1
mquandalle:autofocus@1.0.0
mquandalle:collection-mutations@0.1.0
mquandalle:jade@0.4.9
mquandalle:jade-compiler@0.4.5
mquandalle:jquery-textcomplete@0.8.0_1
mquandalle:jquery-ui-drag-drop-sort@0.2.0
mquandalle:moment@1.0.1
mquandalle:mousetrap-bindglobal@0.0.1
mquandalle:perfect-scrollbar@0.6.5_2
msavin:usercache@1.8.0
npm-bcrypt@0.9.3
npm-mongo@3.2.0
oauth@1.2.8
oauth2@1.2.1
observe-sequence@1.0.16
ongoworks:speakingurl@1.1.0
ordered-dict@1.1.0
ostrio:cookies@2.5.0
peerlibrary:assert@0.3.0
peerlibrary:base-component@0.16.0
peerlibrary:blaze-components@0.15.1
peerlibrary:computed-field@0.10.0
peerlibrary:reactive-field@0.6.0
percolate:synced-cron@1.3.2
promise@0.11.2
raix:eventemitter@0.1.3
raix:handlebar-helpers@0.2.5
rajit:bootstrap3-datepicker@1.7.1_1
random@1.1.0
rate-limit@1.0.9
reactive-dict@1.3.0
reactive-var@1.0.11
reload@1.3.0
retry@1.1.0
routepolicy@1.1.0
rzymek:fullcalendar@3.8.0
server-render@0.3.1
service-configuration@1.0.11
session@1.2.0
sha@1.0.9
shell-server@0.4.0
simple:authenticate-user-by-token@1.0.1
simple:json-routes@2.1.0
simple:rest-accounts-password@1.1.2
simple:rest-bearer-token-parser@1.0.1
simple:rest-json-error-handler@1.0.1
socket-stream-client@0.2.2
softwarerero:accounts-t9n@1.3.11
spacebars@1.0.15
spacebars-compiler@1.1.3
srp@1.0.12
standard-minifier-css@1.5.4
standard-minifier-js@2.5.2
staringatlights:fast-render@3.2.0
staringatlights:inject-data@2.3.0
tap:i18n@1.8.2
templates:tabs@2.3.0
templating@1.3.2
templating-compiler@1.3.3
templating-runtime@1.3.2
templating-tools@1.1.2
tracker@1.2.0
twbs:bootstrap@3.3.6
ui@1.0.13
underscore@1.0.10
url@1.2.0
useraccounts:core@1.14.2
useraccounts:flow-routing@1.14.2
useraccounts:unstyled@1.14.2
verron:autosize@3.0.8
webapp@1.7.5
webapp-hashing@1.0.9
wekan-accounts-cas@0.1.0
wekan-accounts-oidc@1.0.10
wekan-ldap@0.0.2
wekan-markdown@1.0.7
wekan-oidc@1.0.12
wekan-scrollbar@3.1.3
yasaricli:slugify@0.0.7
zimme:active-route@2.3.2
-914
View File
@@ -1,914 +0,0 @@
(function () {
/* Imports */
var Meteor = Package.meteor.Meteor;
var global = Package.meteor.global;
var meteorEnv = Package.meteor.meteorEnv;
var FS = Package['cfs:base-package'].FS;
var check = Package.check.check;
var Match = Package.check.Match;
var EJSON = Package.ejson.EJSON;
var HTTP = Package['cfs:http-methods'].HTTP;
/* Package-scope variables */
var rootUrlPathPrefix, baseUrl, getHeaders, getHeadersByCollection, _existingMountPoints, mountUrls;
(function(){
///////////////////////////////////////////////////////////////////////
// //
// packages/cfs_access-point/packages/cfs_access-point.js //
// //
///////////////////////////////////////////////////////////////////////
//
(function () {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// packages/cfs:access-point/access-point-common.js //
// //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
rootUrlPathPrefix = __meteor_runtime_config__.ROOT_URL_PATH_PREFIX || ""; // 1
// Adjust the rootUrlPathPrefix if necessary // 2
if (rootUrlPathPrefix.length > 0) { // 3
if (rootUrlPathPrefix.slice(0, 1) !== '/') { // 4
rootUrlPathPrefix = '/' + rootUrlPathPrefix; // 5
} // 6
if (rootUrlPathPrefix.slice(-1) === '/') { // 7
rootUrlPathPrefix = rootUrlPathPrefix.slice(0, -1); // 8
} // 9
} // 10
// 11
// prepend ROOT_URL when isCordova // 12
if (Meteor.isCordova) { // 13
rootUrlPathPrefix = Meteor.absoluteUrl(rootUrlPathPrefix.replace(/^\/+/, '')).replace(/\/+$/, ''); // 14
} // 15
// 16
baseUrl = '/cfs'; // 17
FS.HTTP = FS.HTTP || {}; // 18
// 19
// Note the upload URL so that client uploader packages know what it is // 20
FS.HTTP.uploadUrl = rootUrlPathPrefix + baseUrl + '/files'; // 21
// 22
/** // 23
* @method FS.HTTP.setBaseUrl // 24
* @public // 25
* @param {String} newBaseUrl - Change the base URL for the HTTP GET and DELETE endpoints. // 26
* @returns {undefined} // 27
*/ // 28
FS.HTTP.setBaseUrl = function setBaseUrl(newBaseUrl) { // 29
// 30
// Adjust the baseUrl if necessary // 31
if (newBaseUrl.slice(0, 1) !== '/') { // 32
newBaseUrl = '/' + newBaseUrl; // 33
} // 34
if (newBaseUrl.slice(-1) === '/') { // 35
newBaseUrl = newBaseUrl.slice(0, -1); // 36
} // 37
// 38
// Update the base URL // 39
baseUrl = newBaseUrl; // 40
// 41
// Change the upload URL so that client uploader packages know what it is // 42
FS.HTTP.uploadUrl = rootUrlPathPrefix + baseUrl + '/files'; // 43
// 44
// Remount URLs with the new baseUrl, unmounting the old, on the server only. // 45
// If existingMountPoints is empty, then we haven't run the server startup // 46
// code yet, so this new URL will be used at that point for the initial mount. // 47
if (Meteor.isServer && !FS.Utility.isEmpty(_existingMountPoints)) { // 48
mountUrls(); // 49
} // 50
}; // 51
// 52
/* // 53
* FS.File extensions // 54
*/ // 55
// 56
/** // 57
* @method FS.File.prototype.url Construct the file url // 58
* @public // 59
* @param {Object} [options] // 60
* @param {String} [options.store] Name of the store to get from. If not defined, the first store defined in `options.stores` for the collection on the client is used.
* @param {Boolean} [options.auth=null] Add authentication token to the URL query string? By default, a token for the current logged in user is added on the client. Set this to `false` to omit the token. Set this to a string to provide your own token. Set this to a number to specify an expiration time for the token in seconds.
* @param {Boolean} [options.download=false] Should headers be set to force a download? Typically this means that clicking the link with this URL will download the file to the user's Downloads folder instead of displaying the file in the browser.
* @param {Boolean} [options.brokenIsFine=false] Return the URL even if we know it's currently a broken link because the file hasn't been saved in the requested store yet.
* @param {Boolean} [options.metadata=false] Return the URL for the file metadata access point rather than the file itself.
* @param {String} [options.uploading=null] A URL to return while the file is being uploaded. // 66
* @param {String} [options.storing=null] A URL to return while the file is being stored. // 67
* @param {String} [options.filename=null] Override the filename that should appear at the end of the URL. By default it is the name of the file in the requested store.
* // 69
* Returns the HTTP URL for getting the file or its metadata. // 70
*/ // 71
FS.File.prototype.url = function(options) { // 72
var self = this; // 73
options = options || {}; // 74
options = FS.Utility.extend({ // 75
store: null, // 76
auth: null, // 77
download: false, // 78
metadata: false, // 79
brokenIsFine: false, // 80
uploading: null, // return this URL while uploading // 81
storing: null, // return this URL while storing // 82
filename: null // override the filename that is shown to the user // 83
}, options.hash || options); // check for "hash" prop if called as helper // 84
// 85
// Primarily useful for displaying a temporary image while uploading an image // 86
if (options.uploading && !self.isUploaded()) { // 87
return options.uploading; // 88
} // 89
// 90
if (self.isMounted()) { // 91
// See if we've stored in the requested store yet // 92
var storeName = options.store || self.collection.primaryStore.name; // 93
if (!self.hasStored(storeName)) { // 94
if (options.storing) { // 95
return options.storing; // 96
} else if (!options.brokenIsFine) { // 97
// We want to return null if we know the URL will be a broken // 98
// link because then we can avoid rendering broken links, broken // 99
// images, etc. // 100
return null; // 101
} // 102
} // 103
// 104
// Add filename to end of URL if we can determine one // 105
var filename = options.filename || self.name({store: storeName}); // 106
if (typeof filename === "string" && filename.length) { // 107
filename = '/' + filename; // 108
} else { // 109
filename = ''; // 110
} // 111
// 112
// TODO: Could we somehow figure out if the collection requires login? // 113
var authToken = ''; // 114
if (Meteor.isClient && typeof Accounts !== "undefined" && typeof Accounts._storedLoginToken === "function") { // 115
if (options.auth !== false) { // 116
// Add reactive deps on the user // 117
Meteor.userId(); // 118
// 119
var authObject = { // 120
authToken: Accounts._storedLoginToken() || '' // 121
}; // 122
// 123
// If it's a number, we use that as the expiration time (in seconds) // 124
if (options.auth === +options.auth) { // 125
authObject.expiration = FS.HTTP.now() + options.auth * 1000; // 126
} // 127
// 128
// Set the authToken // 129
var authString = JSON.stringify(authObject); // 130
authToken = FS.Utility.btoa(authString); // 131
} // 132
} else if (typeof options.auth === "string") { // 133
// If the user supplies auth token the user will be responsible for // 134
// updating // 135
authToken = options.auth; // 136
} // 137
// 138
// Construct query string // 139
var params = {}; // 140
if (authToken !== '') { // 141
params.token = authToken; // 142
} // 143
if (options.download) { // 144
params.download = true; // 145
} // 146
if (options.store) { // 147
// We use options.store here instead of storeName because we want to omit the queryString // 148
// whenever possible, allowing users to have "clean" URLs if they want. The server will // 149
// assume the first store defined on the server, which means that we are assuming that // 150
// the first on the client is also the first on the server. If that's not the case, the // 151
// store option should be supplied. // 152
params.store = options.store; // 153
} // 154
var queryString = FS.Utility.encodeParams(params); // 155
if (queryString.length) { // 156
queryString = '?' + queryString; // 157
} // 158
// 159
// Determine which URL to use // 160
var area; // 161
if (options.metadata) { // 162
area = '/record'; // 163
} else { // 164
area = '/files'; // 165
} // 166
// 167
// Construct and return the http method url // 168
return rootUrlPathPrefix + baseUrl + area + '/' + self.collection.name + '/' + self._id + filename + queryString; // 169
} // 170
// 171
}; // 172
// 173
// 174
// 175
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}).call(this);
(function () {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// packages/cfs:access-point/access-point-handlers.js //
// //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
getHeaders = []; // 1
getHeadersByCollection = {}; // 2
// 3
FS.HTTP.Handlers = {}; // 4
// 5
/** // 6
* @method FS.HTTP.Handlers.Del // 7
* @public // 8
* @returns {any} response // 9
* // 10
* HTTP DEL request handler // 11
*/ // 12
FS.HTTP.Handlers.Del = function httpDelHandler(ref) { // 13
var self = this; // 14
var opts = FS.Utility.extend({}, self.query || {}, self.params || {}); // 15
// 16
// If DELETE request, validate with 'remove' allow/deny, delete the file, and return // 17
FS.Utility.validateAction(ref.collection.files._validators['remove'], ref.file, self.userId); // 18
// 19
/* // 20
* From the DELETE spec: // 21
* A successful response SHOULD be 200 (OK) if the response includes an // 22
* entity describing the status, 202 (Accepted) if the action has not // 23
* yet been enacted, or 204 (No Content) if the action has been enacted // 24
* but the response does not include an entity. // 25
*/ // 26
self.setStatusCode(200); // 27
// 28
return { // 29
deleted: !!ref.file.remove() // 30
}; // 31
}; // 32
// 33
/** // 34
* @method FS.HTTP.Handlers.GetList // 35
* @public // 36
* @returns {Object} response // 37
* // 38
* HTTP GET file list request handler // 39
*/ // 40
FS.HTTP.Handlers.GetList = function httpGetListHandler() { // 41
// Not Yet Implemented // 42
// Need to check publications and return file list based on // 43
// what user is allowed to see // 44
}; // 45
// 46
/* // 47
requestRange will parse the range set in request header - if not possible it // 48
will throw fitting errors and autofill range for both partial and full ranges // 49
// 50
throws error or returns the object: // 51
{ // 52
start // 53
end // 54
length // 55
unit // 56
partial // 57
} // 58
*/ // 59
var requestRange = function(req, fileSize) { // 60
if (req) { // 61
if (req.headers) { // 62
var rangeString = req.headers.range; // 63
// 64
// Make sure range is a string // 65
if (rangeString === ''+rangeString) { // 66
// 67
// range will be in the format "bytes=0-32767" // 68
var parts = rangeString.split('='); // 69
var unit = parts[0]; // 70
// 71
// Make sure parts consists of two strings and range is of type "byte" // 72
if (parts.length == 2 && unit == 'bytes') { // 73
// Parse the range // 74
var range = parts[1].split('-'); // 75
var start = Number(range[0]); // 76
var end = Number(range[1]); // 77
// 78
// Fix invalid ranges? // 79
if (range[0] != start) start = 0; // 80
if (range[1] != end || !end) end = fileSize - 1; // 81
// 82
// Make sure range consists of a start and end point of numbers and start is less than end // 83
if (start < end) { // 84
// 85
var partSize = 0 - start + end + 1; // 86
// 87
// Return the parsed range // 88
return { // 89
start: start, // 90
end: end, // 91
length: partSize, // 92
size: fileSize, // 93
unit: unit, // 94
partial: (partSize < fileSize) // 95
}; // 96
// 97
} else { // 98
throw new Meteor.Error(416, "Requested Range Not Satisfiable"); // 99
} // 100
// 101
} else { // 102
// The first part should be bytes // 103
throw new Meteor.Error(416, "Requested Range Unit Not Satisfiable"); // 104
} // 105
// 106
} else { // 107
// No range found // 108
} // 109
// 110
} else { // 111
// throw new Error('No request headers set for _parseRange function'); // 112
} // 113
} else { // 114
throw new Error('No request object passed to _parseRange function'); // 115
} // 116
// 117
return { // 118
start: 0, // 119
end: fileSize - 1, // 120
length: fileSize, // 121
size: fileSize, // 122
unit: 'bytes', // 123
partial: false // 124
}; // 125
}; // 126
// 127
/** // 128
* @method FS.HTTP.Handlers.Get // 129
* @public // 130
* @returns {any} response // 131
* // 132
* HTTP GET request handler // 133
*/ // 134
FS.HTTP.Handlers.Get = function httpGetHandler(ref) { // 135
var self = this; // 136
// Once we have the file, we can test allow/deny validators // 137
// XXX: pass on the "share" query eg. ?share=342hkjh23ggj for shared url access? // 138
FS.Utility.validateAction(ref.collection._validators['download'], ref.file, self.userId /*, self.query.shareId*/); // 139
// 140
var storeName = ref.storeName; // 141
// 142
// If no storeName was specified, use the first defined storeName // 143
if (typeof storeName !== "string") { // 144
// No store handed, we default to primary store // 145
storeName = ref.collection.primaryStore.name; // 146
} // 147
// 148
// Get the storage reference // 149
var storage = ref.collection.storesLookup[storeName]; // 150
// 151
if (!storage) { // 152
throw new Meteor.Error(404, "Not Found", 'There is no store "' + storeName + '"'); // 153
} // 154
// 155
// Get the file // 156
var copyInfo = ref.file.copies[storeName]; // 157
// 158
if (!copyInfo) { // 159
throw new Meteor.Error(404, "Not Found", 'This file was not stored in the ' + storeName + ' store'); // 160
} // 161
// 162
// Set the content type for file // 163
if (typeof copyInfo.type === "string") { // 164
self.setContentType(copyInfo.type); // 165
} else { // 166
self.setContentType('application/octet-stream'); // 167
} // 168
// 169
// Add 'Content-Disposition' header if requested a download/attachment URL // 170
if (typeof ref.download !== "undefined") { // 171
var filename = ref.filename || copyInfo.name; // 172
self.addHeader('Content-Disposition', 'attachment; filename="' + filename + '"'); // 173
} else { // 174
self.addHeader('Content-Disposition', 'inline'); // 175
} // 176
// 177
// Get the contents range from request // 178
var range = requestRange(self.request, copyInfo.size); // 179
// 180
// Some browsers cope better if the content-range header is // 181
// still included even for the full file being returned. // 182
self.addHeader('Content-Range', range.unit + ' ' + range.start + '-' + range.end + '/' + range.size); // 183
// 184
// If a chunk/range was requested instead of the whole file, serve that' // 185
if (range.partial) { // 186
self.setStatusCode(206, 'Partial Content'); // 187
} else { // 188
self.setStatusCode(200, 'OK'); // 189
} // 190
// 191
// Add any other global custom headers and collection-specific custom headers // 192
FS.Utility.each(getHeaders.concat(getHeadersByCollection[ref.collection.name] || []), function(header) { // 193
self.addHeader(header[0], header[1]); // 194
}); // 195
// 196
// Inform clients about length (or chunk length in case of ranges) // 197
self.addHeader('Content-Length', range.length); // 198
// 199
// Last modified header (updatedAt from file info) // 200
self.addHeader('Last-Modified', copyInfo.updatedAt.toUTCString()); // 201
// 202
// Inform clients that we accept ranges for resumable chunked downloads // 203
self.addHeader('Accept-Ranges', range.unit); // 204
// 205
if (FS.debug) console.log('Read file "' + (ref.filename || copyInfo.name) + '" ' + range.unit + ' ' + range.start + '-' + range.end + '/' + range.size);
// 207
var readStream = storage.adapter.createReadStream(ref.file, {start: range.start, end: range.end}); // 208
// 209
readStream.on('error', function(err) { // 210
// Send proper error message on get error // 211
if (err.message && err.statusCode) { // 212
self.Error(new Meteor.Error(err.statusCode, err.message)); // 213
} else { // 214
self.Error(new Meteor.Error(503, 'Service unavailable')); // 215
} // 216
}); // 217
// 218
readStream.pipe(self.createWriteStream()); // 219
}; // 220
const originalHandler = FS.HTTP.Handlers.Get;
FS.HTTP.Handlers.Get = function (ref) {
//console.log(ref.filename);
try {
var userAgent = (this.requestHeaders['user-agent']||'').toLowerCase();
if(userAgent.indexOf('msie') >= 0 || userAgent.indexOf('trident') >= 0 || userAgent.indexOf('chrome') >= 0) {
ref.filename = encodeURIComponent(ref.filename);
} else if(userAgent.indexOf('firefox') >= 0) {
ref.filename = new Buffer(ref.filename).toString('binary');
} else {
/* safari*/
ref.filename = new Buffer(ref.filename).toString('binary');
}
} catch (ex){
ref.filename = 'tempfix';
}
return originalHandler.call(this, ref);
};
// 221
/** // 222
* @method FS.HTTP.Handlers.PutInsert // 223
* @public // 224
* @returns {Object} response object with _id property // 225
* // 226
* HTTP PUT file insert request handler // 227
*/ // 228
FS.HTTP.Handlers.PutInsert = function httpPutInsertHandler(ref) { // 229
var self = this; // 230
var opts = FS.Utility.extend({}, self.query || {}, self.params || {}); // 231
// 232
FS.debug && console.log("HTTP PUT (insert) handler"); // 233
// 234
// Create the nice FS.File // 235
var fileObj = new FS.File(); // 236
// 237
// Set its name // 238
fileObj.name(opts.filename || null); // 239
// 240
// Attach the readstream as the file's data // 241
fileObj.attachData(self.createReadStream(), {type: self.requestHeaders['content-type'] || 'application/octet-stream'});
// 243
// Validate with insert allow/deny // 244
FS.Utility.validateAction(ref.collection.files._validators['insert'], fileObj, self.userId); // 245
// 246
// Insert file into collection, triggering readStream storage // 247
ref.collection.insert(fileObj); // 248
// 249
// Send response // 250
self.setStatusCode(200); // 251
// 252
// Return the new file id // 253
return {_id: fileObj._id}; // 254
}; // 255
// 256
/** // 257
* @method FS.HTTP.Handlers.PutUpdate // 258
* @public // 259
* @returns {Object} response object with _id and chunk properties // 260
* // 261
* HTTP PUT file update chunk request handler // 262
*/ // 263
FS.HTTP.Handlers.PutUpdate = function httpPutUpdateHandler(ref) { // 264
var self = this; // 265
var opts = FS.Utility.extend({}, self.query || {}, self.params || {}); // 266
// 267
var chunk = parseInt(opts.chunk, 10); // 268
if (isNaN(chunk)) chunk = 0; // 269
// 270
FS.debug && console.log("HTTP PUT (update) handler received chunk: ", chunk); // 271
// 272
// Validate with insert allow/deny; also mounts and retrieves the file // 273
FS.Utility.validateAction(ref.collection.files._validators['insert'], ref.file, self.userId); // 274
// 275
self.createReadStream().pipe( FS.TempStore.createWriteStream(ref.file, chunk) ); // 276
// 277
// Send response // 278
self.setStatusCode(200); // 279
// 280
return { _id: ref.file._id, chunk: chunk }; // 281
}; // 282
// 283
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}).call(this);
(function () {
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// //
// packages/cfs:access-point/access-point-server.js //
// //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
var path = Npm.require("path"); // 1
// 2
HTTP.publishFormats({ // 3
fileRecordFormat: function (input) { // 4
// Set the method scope content type to json // 5
this.setContentType('application/json'); // 6
if (FS.Utility.isArray(input)) { // 7
return EJSON.stringify(FS.Utility.map(input, function (obj) { // 8
return FS.Utility.cloneFileRecord(obj); // 9
})); // 10
} else { // 11
return EJSON.stringify(FS.Utility.cloneFileRecord(input)); // 12
} // 13
} // 14
}); // 15
// 16
/** // 17
* @method FS.HTTP.setHeadersForGet // 18
* @public // 19
* @param {Array} headers - List of headers, where each is a two-item array in which item 1 is the header name and item 2 is the header value.
* @param {Array|String} [collections] - Which collections the headers should be added for. Omit this argument to add the header for all collections.
* @returns {undefined} // 22
*/ // 23
FS.HTTP.setHeadersForGet = function setHeadersForGet(headers, collections) { // 24
if (typeof collections === "string") { // 25
collections = [collections]; // 26
} // 27
if (collections) { // 28
FS.Utility.each(collections, function(collectionName) { // 29
getHeadersByCollection[collectionName] = headers || []; // 30
}); // 31
} else { // 32
getHeaders = headers || []; // 33
} // 34
}; // 35
// 36
/** // 37
* @method FS.HTTP.publish // 38
* @public // 39
* @param {FS.Collection} collection // 40
* @param {Function} func - Publish function that returns a cursor. // 41
* @returns {undefined} // 42
* // 43
* Publishes all documents returned by the cursor at a GET URL // 44
* with the format baseUrl/record/collectionName. The publish // 45
* function `this` is similar to normal `Meteor.publish`. // 46
*/ // 47
FS.HTTP.publish = function fsHttpPublish(collection, func) { // 48
var name = baseUrl + '/record/' + collection.name; // 49
// Mount collection listing URL using http-publish package // 50
HTTP.publish({ // 51
name: name, // 52
defaultFormat: 'fileRecordFormat', // 53
collection: collection, // 54
collectionGet: true, // 55
collectionPost: false, // 56
documentGet: true, // 57
documentPut: false, // 58
documentDelete: false // 59
}, func); // 60
// 61
FS.debug && console.log("Registered HTTP method GET URLs:\n\n" + name + '\n' + name + '/:id\n'); // 62
}; // 63
// 64
/** // 65
* @method FS.HTTP.unpublish // 66
* @public // 67
* @param {FS.Collection} collection // 68
* @returns {undefined} // 69
* // 70
* Unpublishes a restpoint created by a call to `FS.HTTP.publish` // 71
*/ // 72
FS.HTTP.unpublish = function fsHttpUnpublish(collection) { // 73
// Mount collection listing URL using http-publish package // 74
HTTP.unpublish(baseUrl + '/record/' + collection.name); // 75
}; // 76
// 77
_existingMountPoints = {}; // 78
// 79
/** // 80
* @method defaultSelectorFunction // 81
* @private // 82
* @returns { collection, file } // 83
* // 84
* This is the default selector function // 85
*/ // 86
var defaultSelectorFunction = function() { // 87
var self = this; // 88
// Selector function // 89
// // 90
// This function will have to return the collection and the // 91
// file. If file not found undefined is returned - if null is returned the // 92
// search was not possible // 93
var opts = FS.Utility.extend({}, self.query || {}, self.params || {}); // 94
// 95
// Get the collection name from the url // 96
var collectionName = opts.collectionName; // 97
// 98
// Get the id from the url // 99
var id = opts.id; // 100
// 101
// Get the collection // 102
var collection = FS._collections[collectionName]; // 103
// 104
// Get the file if possible else return null // 105
var file = (id && collection)? collection.findOne({ _id: id }): null; // 106
// 107
// Return the collection and the file // 108
return { // 109
collection: collection, // 110
file: file, // 111
storeName: opts.store, // 112
download: opts.download, // 113
filename: opts.filename // 114
}; // 115
}; // 116
// 117
/* // 118
* @method FS.HTTP.mount // 119
* @public // 120
* @param {array of string} mountPoints mount points to map rest functinality on // 121
* @param {function} selector_f [selector] function returns `{ collection, file }` for mount points to work with // 122
* // 123
*/ // 124
FS.HTTP.mount = function(mountPoints, selector_f) { // 125
// We take mount points as an array and we get a selector function // 126
var selectorFunction = selector_f || defaultSelectorFunction; // 127
// 128
var accessPoint = { // 129
'stream': true, // 130
'auth': expirationAuth, // 131
'post': function(data) { // 132
// Use the selector for finding the collection and file reference // 133
var ref = selectorFunction.call(this); // 134
// 135
// We dont support post - this would be normal insert eg. of filerecord? // 136
throw new Meteor.Error(501, "Not implemented", "Post is not supported"); // 137
}, // 138
'put': function(data) { // 139
// Use the selector for finding the collection and file reference // 140
var ref = selectorFunction.call(this); // 141
// 142
// Make sure we have a collection reference // 143
if (!ref.collection) // 144
throw new Meteor.Error(404, "Not Found", "No collection found"); // 145
// 146
// Make sure we have a file reference // 147
if (ref.file === null) { // 148
// No id supplied so we will create a new FS.File instance and // 149
// insert the supplied data. // 150
return FS.HTTP.Handlers.PutInsert.apply(this, [ref]); // 151
} else { // 152
if (ref.file) { // 153
return FS.HTTP.Handlers.PutUpdate.apply(this, [ref]); // 154
} else { // 155
throw new Meteor.Error(404, "Not Found", 'No file found'); // 156
} // 157
} // 158
}, // 159
'get': function(data) { // 160
// Use the selector for finding the collection and file reference // 161
var ref = selectorFunction.call(this); // 162
// 163
// Make sure we have a collection reference // 164
if (!ref.collection) // 165
throw new Meteor.Error(404, "Not Found", "No collection found"); // 166
// 167
// Make sure we have a file reference // 168
if (ref.file === null) { // 169
// No id supplied so we will return the published list of files ala // 170
// http.publish in json format // 171
return FS.HTTP.Handlers.GetList.apply(this, [ref]); // 172
} else { // 173
if (ref.file) { // 174
return FS.HTTP.Handlers.Get.apply(this, [ref]); // 175
} else { // 176
throw new Meteor.Error(404, "Not Found", 'No file found'); // 177
} // 178
} // 179
}, // 180
'delete': function(data) { // 181
// Use the selector for finding the collection and file reference // 182
var ref = selectorFunction.call(this); // 183
// 184
// Make sure we have a collection reference // 185
if (!ref.collection) // 186
throw new Meteor.Error(404, "Not Found", "No collection found"); // 187
// 188
// Make sure we have a file reference // 189
if (ref.file) { // 190
return FS.HTTP.Handlers.Del.apply(this, [ref]); // 191
} else { // 192
throw new Meteor.Error(404, "Not Found", 'No file found'); // 193
} // 194
} // 195
}; // 196
// 197
var accessPoints = {}; // 198
// 199
// Add debug message // 200
FS.debug && console.log('Registered HTTP method URLs:'); // 201
// 202
FS.Utility.each(mountPoints, function(mountPoint) { // 203
// Couple mountpoint and accesspoint // 204
accessPoints[mountPoint] = accessPoint; // 205
// Remember our mountpoints // 206
_existingMountPoints[mountPoint] = mountPoint; // 207
// Add debug message // 208
FS.debug && console.log(mountPoint); // 209
}); // 210
// 211
// XXX: HTTP:methods should unmount existing mounts in case of overwriting? // 212
HTTP.methods(accessPoints); // 213
// 214
}; // 215
// 216
/** // 217
* @method FS.HTTP.unmount // 218
* @public // 219
* @param {string | array of string} [mountPoints] Optional, if not specified all mountpoints are unmounted // 220
* // 221
*/ // 222
FS.HTTP.unmount = function(mountPoints) { // 223
// The mountPoints is optional, can be string or array if undefined then // 224
// _existingMountPoints will be used // 225
var unmountList; // 226
// Container for the mount points to unmount // 227
var unmountPoints = {}; // 228
// 229
if (typeof mountPoints === 'undefined') { // 230
// Use existing mount points - unmount all // 231
unmountList = _existingMountPoints; // 232
} else if (mountPoints === ''+mountPoints) { // 233
// Got a string // 234
unmountList = [mountPoints]; // 235
} else if (mountPoints.length) { // 236
// Got an array // 237
unmountList = mountPoints; // 238
} // 239
// 240
// If we have a list to unmount // 241
if (unmountList) { // 242
// Iterate over each item // 243
FS.Utility.each(unmountList, function(mountPoint) { // 244
// Check _existingMountPoints to make sure the mount point exists in our // 245
// context / was created by the FS.HTTP.mount // 246
if (_existingMountPoints[mountPoint]) { // 247
// Mark as unmount // 248
unmountPoints[mountPoint] = false; // 249
// Release // 250
delete _existingMountPoints[mountPoint]; // 251
} // 252
}); // 253
FS.debug && console.log('FS.HTTP.unmount:'); // 254
FS.debug && console.log(unmountPoints); // 255
// Complete unmount // 256
HTTP.methods(unmountPoints); // 257
} // 258
}; // 259
// 260
// ### FS.Collection maps on HTTP pr. default on the following restpoints: // 261
// * // 262
// baseUrl + '/files/:collectionName/:id/:filename', // 263
// baseUrl + '/files/:collectionName/:id', // 264
// baseUrl + '/files/:collectionName' // 265
// // 266
// Change/ replace the existing mount point by: // 267
// ```js // 268
// // unmount all existing // 269
// FS.HTTP.unmount(); // 270
// // Create new mount point // 271
// FS.HTTP.mount([ // 272
// '/cfs/files/:collectionName/:id/:filename', // 273
// '/cfs/files/:collectionName/:id', // 274
// '/cfs/files/:collectionName' // 275
// ]); // 276
// ``` // 277
// // 278
mountUrls = function mountUrls() { // 279
// We unmount first in case we are calling this a second time // 280
FS.HTTP.unmount(); // 281
// 282
FS.HTTP.mount([ // 283
baseUrl + '/files/:collectionName/:id/:filename', // 284
baseUrl + '/files/:collectionName/:id', // 285
baseUrl + '/files/:collectionName' // 286
]); // 287
}; // 288
// 289
// Returns the userId from URL token // 290
var expirationAuth = function expirationAuth() { // 291
var self = this; // 292
// 293
// Read the token from '/hello?token=base64' // 294
var encodedToken = self.query.token; // 295
// 296
FS.debug && console.log("token: "+encodedToken); // 297
// 298
if (!encodedToken || !Meteor.users) return false; // 299
// 300
// Check the userToken before adding it to the db query // 301
// Set the this.userId // 302
var tokenString = FS.Utility.atob(encodedToken); // 303
// 304
var tokenObject; // 305
try { // 306
tokenObject = JSON.parse(tokenString); // 307
} catch(err) { // 308
throw new Meteor.Error(400, 'Bad Request'); // 309
} // 310
// 311
// XXX: Do some check here of the object // 312
var userToken = tokenObject.authToken; // 313
if (userToken !== ''+userToken) { // 314
throw new Meteor.Error(400, 'Bad Request'); // 315
} // 316
// 317
// If we have an expiration token we should check that it's still valid // 318
if (tokenObject.expiration != null) { // 319
// check if its too old // 320
var now = Date.now(); // 321
if (tokenObject.expiration < now) { // 322
FS.debug && console.log('Expired token: ' + tokenObject.expiration + ' is less than ' + now); // 323
throw new Meteor.Error(500, 'Expired token'); // 324
} // 325
} // 326
// 327
// We are not on a secure line - so we have to look up the user... // 328
var user = Meteor.users.findOne({ // 329
$or: [ // 330
{'services.resume.loginTokens.hashedToken': Accounts._hashLoginToken(userToken)}, // 331
{'services.resume.loginTokens.token': userToken} // 332
] // 333
}); // 334
// 335
// Set the userId in the scope // 336
return user && user._id; // 337
}; // 338
// 339
HTTP.methods( // 340
{'/cfs/servertime': { // 341
get: function(data) { // 342
return Date.now().toString(); // 343
} // 344
} // 345
}); // 346
// 347
// Unify client / server api // 348
FS.HTTP.now = function() { // 349
return Date.now(); // 350
}; // 351
// 352
// Start up the basic mount points // 353
Meteor.startup(function () { // 354
mountUrls(); // 355
}); // 356
// 357
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
}).call(this);
///////////////////////////////////////////////////////////////////////
}).call(this);
/* Exports */
if (typeof Package === 'undefined') Package = {};
Package['cfs:access-point'] = {};
})();
-238
View File
@@ -1,238 +0,0 @@
/* global JsonRoutes */
if (Meteor.isServer) {
// todo XXX once we have a real API in place, move that route there
// todo XXX also share the route definition between the client and the server
// so that we could use something like
// `ApiRoutes.path('boards/export', boardId)``
// on the client instead of copy/pasting the route path manually between the
// client and the server.
/**
* @operation export
* @tag Boards
*
* @summary This route is used to export the board.
*
* @description If user is already logged-in, pass loginToken as param
* "authToken": '/api/boards/:boardId/export?authToken=:token'
*
* See https://blog.kayla.com.au/server-side-route-authentication-in-meteor/
* for detailed explanations
*
* @param {string} boardId the ID of the board we are exporting
* @param {string} authToken the loginToken
*/
JsonRoutes.add('get', '/api/boards/:boardId/export', function(req, res) {
const boardId = req.params.boardId;
let user = null;
const loginToken = req.query.authToken;
if (loginToken) {
const hashToken = Accounts._hashLoginToken(loginToken);
user = Meteor.users.findOne({
'services.resume.loginTokens.hashedToken': hashToken,
});
} else if (!Meteor.settings.public.sandstorm) {
Authentication.checkUserId(req.userId);
user = Users.findOne({ _id: req.userId, isAdmin: true });
}
const exporter = new Exporter(boardId);
if (exporter.canExport(user)) {
JsonRoutes.sendResult(res, {
code: 200,
data: exporter.build(),
});
} else {
// we could send an explicit error message, but on the other hand the only
// way to get there is by hacking the UI so let's keep it raw.
JsonRoutes.sendResult(res, 403);
}
});
}
// exporter maybe is broken since Gridfs introduced, add fs and path
export class Exporter {
constructor(boardId) {
this._boardId = boardId;
}
build() {
const fs = Npm.require('fs');
const os = Npm.require('os');
const path = Npm.require('path');
const byBoard = { boardId: this._boardId };
const byBoardNoLinked = {
boardId: this._boardId,
linkedId: { $in: ['', null] },
};
// we do not want to retrieve boardId in related elements
const noBoardId = {
fields: {
boardId: 0,
},
};
const result = {
_format: 'wekan-board-1.0.0',
};
_.extend(
result,
Boards.findOne(this._boardId, {
fields: {
stars: 0,
},
}),
);
result.lists = Lists.find(byBoard, noBoardId).fetch();
result.cards = Cards.find(byBoardNoLinked, noBoardId).fetch();
result.swimlanes = Swimlanes.find(byBoard, noBoardId).fetch();
result.customFields = CustomFields.find(
{ boardIds: { $in: [this.boardId] } },
{ fields: { boardId: 0 } },
).fetch();
result.comments = CardComments.find(byBoard, noBoardId).fetch();
result.activities = Activities.find(byBoard, noBoardId).fetch();
result.rules = Rules.find(byBoard, noBoardId).fetch();
result.checklists = [];
result.checklistItems = [];
result.subtaskItems = [];
result.triggers = [];
result.actions = [];
result.cards.forEach(card => {
result.checklists.push(
...Checklists.find({
cardId: card._id,
}).fetch(),
);
result.checklistItems.push(
...ChecklistItems.find({
cardId: card._id,
}).fetch(),
);
result.subtaskItems.push(
...Cards.find({
parentId: card._id,
}).fetch(),
);
});
result.rules.forEach(rule => {
result.triggers.push(
...Triggers.find(
{
_id: rule.triggerId,
},
noBoardId,
).fetch(),
);
result.actions.push(
...Actions.find(
{
_id: rule.actionId,
},
noBoardId,
).fetch(),
);
});
// [Old] for attachments we only export IDs and absolute url to original doc
// [New] Encode attachment to base64
const getBase64Data = function(doc, callback) {
let buffer = new Buffer(0);
// callback has the form function (err, res) {}
const tmpFile = path.join(
os.tmpdir(),
`tmpexport${process.pid}${Math.random()}`,
);
const tmpWriteable = fs.createWriteStream(tmpFile);
const readStream = doc.createReadStream();
readStream.on('data', function(chunk) {
buffer = Buffer.concat([buffer, chunk]);
});
readStream.on('error', function(err) {
callback(err, null);
});
readStream.on('end', function() {
// done
fs.unlink(tmpFile, () => {
//ignored
});
callback(null, buffer.toString('base64'));
});
readStream.pipe(tmpWriteable);
};
const getBase64DataSync = Meteor.wrapAsync(getBase64Data);
result.attachments = Attachments.find(byBoard)
.fetch()
.map(attachment => {
return {
_id: attachment._id,
cardId: attachment.cardId,
// url: FlowRouter.url(attachment.url()),
file: getBase64DataSync(attachment),
name: attachment.original.name,
type: attachment.original.type,
};
});
// we also have to export some user data - as the other elements only
// include id but we have to be careful:
// 1- only exports users that are linked somehow to that board
// 2- do not export any sensitive information
const users = {};
result.members.forEach(member => {
users[member.userId] = true;
});
result.lists.forEach(list => {
users[list.userId] = true;
});
result.cards.forEach(card => {
users[card.userId] = true;
if (card.members) {
card.members.forEach(memberId => {
users[memberId] = true;
});
}
});
result.comments.forEach(comment => {
users[comment.userId] = true;
});
result.activities.forEach(activity => {
users[activity.userId] = true;
});
result.checklists.forEach(checklist => {
users[checklist.userId] = true;
});
const byUserIds = {
_id: {
$in: Object.getOwnPropertyNames(users),
},
};
// we use whitelist to be sure we do not expose inadvertently
// some secret fields that gets added to User later.
const userFields = {
fields: {
_id: 1,
username: 1,
'profile.fullname': 1,
'profile.initials': 1,
'profile.avatarUrl': 1,
},
};
result.users = Users.find(byUserIds, userFields)
.fetch()
.map(user => {
// user avatar is stored as a relative url, we export absolute
if ((user.profile || {}).avatarUrl) {
user.profile.avatarUrl = FlowRouter.url(user.profile.avatarUrl);
}
return user;
});
return result;
}
canExport(user) {
const board = Boards.findOne(this._boardId);
return board && board.isVisibleBy(user);
}
}
-640
View File
@@ -1,640 +0,0 @@
import ldapjs from 'ldapjs';
import util from 'util';
import Bunyan from 'bunyan';
import { log_debug, log_info, log_warn, log_error } from './logger';
export default class LDAP {
constructor() {
this.ldapjs = ldapjs;
this.connected = false;
this.options = {
host: this.constructor.settings_get('LDAP_HOST'),
port: this.constructor.settings_get('LDAP_PORT'),
Reconnect: this.constructor.settings_get('LDAP_RECONNECT'),
timeout: this.constructor.settings_get('LDAP_TIMEOUT'),
connect_timeout: this.constructor.settings_get('LDAP_CONNECT_TIMEOUT'),
idle_timeout: this.constructor.settings_get('LDAP_IDLE_TIMEOUT'),
encryption: this.constructor.settings_get('LDAP_ENCRYPTION'),
ca_cert: this.constructor.settings_get('LDAP_CA_CERT'),
reject_unauthorized:
this.constructor.settings_get('LDAP_REJECT_UNAUTHORIZED') || false,
Authentication: this.constructor.settings_get('LDAP_AUTHENTIFICATION'),
Authentication_UserDN: this.constructor.settings_get(
'LDAP_AUTHENTIFICATION_USERDN',
),
Authentication_Password: this.constructor.settings_get(
'LDAP_AUTHENTIFICATION_PASSWORD',
),
Authentication_Fallback: this.constructor.settings_get(
'LDAP_LOGIN_FALLBACK',
),
BaseDN: this.constructor.settings_get('LDAP_BASEDN'),
Internal_Log_Level: this.constructor.settings_get('INTERNAL_LOG_LEVEL'),
User_Authentication: this.constructor.settings_get(
'LDAP_USER_AUTHENTICATION',
),
User_Authentication_Field: this.constructor.settings_get(
'LDAP_USER_AUTHENTICATION_FIELD',
),
User_Attributes: this.constructor.settings_get('LDAP_USER_ATTRIBUTES'),
User_Search_Filter: this.constructor.settings_get(
'LDAP_USER_SEARCH_FILTER',
),
User_Search_Scope: this.constructor.settings_get(
'LDAP_USER_SEARCH_SCOPE',
),
User_Search_Field: this.constructor.settings_get(
'LDAP_USER_SEARCH_FIELD',
),
Search_Page_Size: this.constructor.settings_get('LDAP_SEARCH_PAGE_SIZE'),
Search_Size_Limit: this.constructor.settings_get(
'LDAP_SEARCH_SIZE_LIMIT',
),
group_filter_enabled: this.constructor.settings_get(
'LDAP_GROUP_FILTER_ENABLE',
),
group_filter_object_class: this.constructor.settings_get(
'LDAP_GROUP_FILTER_OBJECTCLASS',
),
group_filter_group_id_attribute: this.constructor.settings_get(
'LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE',
),
group_filter_group_member_attribute: this.constructor.settings_get(
'LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE',
),
group_filter_group_member_format: this.constructor.settings_get(
'LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT',
),
group_filter_group_name: this.constructor.settings_get(
'LDAP_GROUP_FILTER_GROUP_NAME',
),
};
}
static settings_get(name, ...args) {
let value = process.env[name];
if (value !== undefined) {
if (value === 'true' || value === 'false') {
value = JSON.parse(value);
} else if (value !== '' && !isNaN(value)) {
value = Number(value);
}
return value;
} else {
log_warn(`Lookup for unset variable: ${name}`);
}
}
connectSync(...args) {
if (!this._connectSync) {
this._connectSync = Meteor.wrapAsync(this.connectAsync, this);
}
return this._connectSync(...args);
}
searchAllSync(...args) {
if (!this._searchAllSync) {
this._searchAllSync = Meteor.wrapAsync(this.searchAllAsync, this);
}
return this._searchAllSync(...args);
}
connectAsync(callback) {
log_info('Init setup');
let replied = false;
const connectionOptions = {
url: `${this.options.host}:${this.options.port}`,
timeout: this.options.timeout,
connectTimeout: this.options.connect_timeout,
idleTimeout: this.options.idle_timeout,
reconnect: this.options.Reconnect,
};
if (this.options.Internal_Log_Level !== 'disabled') {
connectionOptions.log = new Bunyan({
name: 'ldapjs',
component: 'client',
stream: process.stderr,
level: this.options.Internal_Log_Level,
});
}
const tlsOptions = {
rejectUnauthorized: this.options.reject_unauthorized,
};
if (this.options.ca_cert && this.options.ca_cert !== '') {
// Split CA cert into array of strings
const chainLines = this.constructor
.settings_get('LDAP_CA_CERT')
.split('\n');
let cert = [];
const ca = [];
chainLines.forEach(line => {
cert.push(line);
if (line.match(/-END CERTIFICATE-/)) {
ca.push(cert.join('\n'));
cert = [];
}
});
tlsOptions.ca = ca;
}
if (this.options.encryption === 'ssl') {
connectionOptions.url = `ldaps://${connectionOptions.url}`;
connectionOptions.tlsOptions = tlsOptions;
} else {
connectionOptions.url = `ldap://${connectionOptions.url}`;
}
log_info('Connecting', connectionOptions.url);
log_debug(`connectionOptions${util.inspect(connectionOptions)}`);
this.client = ldapjs.createClient(connectionOptions);
this.bindSync = Meteor.wrapAsync(this.client.bind, this.client);
this.client.on('error', error => {
log_error('connection', error);
if (replied === false) {
replied = true;
callback(error, null);
}
});
this.client.on('idle', () => {
log_info('Idle');
this.disconnect();
});
this.client.on('close', () => {
log_info('Closed');
});
if (this.options.encryption === 'tls') {
// Set host parameter for tls.connect which is used by ldapjs starttls. This shouldn't be needed in newer nodejs versions (e.g v5.6.0).
// https://github.com/RocketChat/Rocket.Chat/issues/2035
// https://github.com/mcavage/node-ldapjs/issues/349
tlsOptions.host = this.options.host;
log_info('Starting TLS');
log_debug('tlsOptions', tlsOptions);
this.client.starttls(tlsOptions, null, (error, response) => {
if (error) {
log_error('TLS connection', error);
if (replied === false) {
replied = true;
callback(error, null);
}
return;
}
log_info('TLS connected');
this.connected = true;
if (replied === false) {
replied = true;
callback(null, response);
}
});
} else {
this.client.on('connect', response => {
log_info('LDAP connected');
this.connected = true;
if (replied === false) {
replied = true;
callback(null, response);
}
});
}
setTimeout(() => {
if (replied === false) {
log_error('connection time out', connectionOptions.connectTimeout);
replied = true;
callback(new Error('Timeout'));
}
}, connectionOptions.connectTimeout);
}
getUserFilter(username) {
const filter = [];
if (this.options.User_Search_Filter !== '') {
if (this.options.User_Search_Filter[0] === '(') {
filter.push(`${this.options.User_Search_Filter}`);
} else {
filter.push(`(${this.options.User_Search_Filter})`);
}
}
const usernameFilter = this.options.User_Search_Field.split(',').map(
item => `(${item}=${username})`,
);
if (usernameFilter.length === 0) {
log_error('LDAP_LDAP_User_Search_Field not defined');
} else if (usernameFilter.length === 1) {
filter.push(`${usernameFilter[0]}`);
} else {
filter.push(`(|${usernameFilter.join('')})`);
}
return `(&${filter.join('')})`;
}
bindUserIfNecessary(username, password) {
if (this.domainBinded === true) {
return;
}
if (!this.options.User_Authentication) {
return;
}
if (!this.options.BaseDN) throw new Error('BaseDN is not provided');
const userDn = `${this.options.User_Authentication_Field}=${username},${this.options.BaseDN}`;
this.bindSync(userDn, password);
this.domainBinded = true;
}
bindIfNecessary() {
if (this.domainBinded === true) {
return;
}
if (this.options.Authentication !== true) {
return;
}
log_info('Binding UserDN', this.options.Authentication_UserDN);
this.bindSync(
this.options.Authentication_UserDN,
this.options.Authentication_Password,
);
this.domainBinded = true;
}
searchUsersSync(username, page) {
this.bindIfNecessary();
const searchOptions = {
filter: this.getUserFilter(username),
scope: this.options.User_Search_Scope || 'sub',
sizeLimit: this.options.Search_Size_Limit,
};
if (!!this.options.User_Attributes)
searchOptions.attributes = this.options.User_Attributes.split(',');
if (this.options.Search_Page_Size > 0) {
searchOptions.paged = {
pageSize: this.options.Search_Page_Size,
pagePause: !!page,
};
}
log_info('Searching user', username);
log_debug('searchOptions', searchOptions);
log_debug('BaseDN', this.options.BaseDN);
if (page) {
return this.searchAllPaged(this.options.BaseDN, searchOptions, page);
}
return this.searchAllSync(this.options.BaseDN, searchOptions);
}
getUserByIdSync(id, attribute) {
this.bindIfNecessary();
const Unique_Identifier_Field = this.constructor
.settings_get('LDAP_UNIQUE_IDENTIFIER_FIELD')
.split(',');
let filter;
if (attribute) {
filter = new this.ldapjs.filters.EqualityFilter({
attribute,
value: new Buffer(id, 'hex'),
});
} else {
const filters = [];
Unique_Identifier_Field.forEach(item => {
filters.push(
new this.ldapjs.filters.EqualityFilter({
attribute: item,
value: new Buffer(id, 'hex'),
}),
);
});
filter = new this.ldapjs.filters.OrFilter({ filters });
}
const searchOptions = {
filter,
scope: 'sub',
};
log_info('Searching by id', id);
log_debug('search filter', searchOptions.filter.toString());
log_debug('BaseDN', this.options.BaseDN);
const result = this.searchAllSync(this.options.BaseDN, searchOptions);
if (!Array.isArray(result) || result.length === 0) {
return;
}
if (result.length > 1) {
log_error('Search by id', id, 'returned', result.length, 'records');
}
return result[0];
}
getUserByUsernameSync(username) {
this.bindIfNecessary();
const searchOptions = {
filter: this.getUserFilter(username),
scope: this.options.User_Search_Scope || 'sub',
};
log_info('Searching user', username);
log_debug('searchOptions', searchOptions);
log_debug('BaseDN', this.options.BaseDN);
const result = this.searchAllSync(this.options.BaseDN, searchOptions);
if (!Array.isArray(result) || result.length === 0) {
return;
}
if (result.length > 1) {
log_error(
'Search by username',
username,
'returned',
result.length,
'records',
);
}
return result[0];
}
getUserGroups(username, ldapUser) {
if (!this.options.group_filter_enabled) {
return true;
}
const filter = ['(&'];
if (this.options.group_filter_object_class !== '') {
filter.push(`(objectclass=${this.options.group_filter_object_class})`);
}
if (this.options.group_filter_group_member_attribute !== '') {
const format_value =
ldapUser[this.options.group_filter_group_member_format];
if (format_value) {
filter.push(
`(${this.options.group_filter_group_member_attribute}=${format_value})`,
);
}
}
filter.push(')');
const searchOptions = {
filter: filter.join('').replace(/#{username}/g, username),
scope: 'sub',
};
log_debug('Group list filter LDAP:', searchOptions.filter);
const result = this.searchAllSync(this.options.BaseDN, searchOptions);
if (!Array.isArray(result) || result.length === 0) {
return [];
}
const grp_identifier = this.options.group_filter_group_id_attribute || 'cn';
const groups = [];
result.map(item => {
groups.push(item[grp_identifier]);
});
log_debug(`Groups: ${groups.join(', ')}`);
return groups;
}
isUserInGroup(username, ldapUser) {
if (!this.options.group_filter_enabled) {
return true;
}
const grps = this.getUserGroups(username, ldapUser);
const filter = ['(&'];
if (this.options.group_filter_object_class !== '') {
filter.push(`(objectclass=${this.options.group_filter_object_class})`);
}
if (this.options.group_filter_group_member_attribute !== '') {
const format_value =
ldapUser[this.options.group_filter_group_member_format];
if (format_value) {
filter.push(
`(${this.options.group_filter_group_member_attribute}=${format_value})`,
);
}
}
if (this.options.group_filter_group_id_attribute !== '') {
filter.push(
`(${this.options.group_filter_group_id_attribute}=${this.options.group_filter_group_name})`,
);
}
filter.push(')');
const searchOptions = {
filter: filter.join('').replace(/#{username}/g, username),
scope: 'sub',
};
log_debug('Group filter LDAP:', searchOptions.filter);
const result = this.searchAllSync(this.options.BaseDN, searchOptions);
if (!Array.isArray(result) || result.length === 0) {
return false;
}
return true;
}
extractLdapEntryData(entry) {
const values = {
_raw: entry.raw,
};
Object.keys(values._raw).forEach(key => {
const value = values._raw[key];
if (!['thumbnailPhoto', 'jpegPhoto'].includes(key)) {
if (value instanceof Buffer) {
values[key] = value.toString();
} else {
values[key] = value;
}
}
});
return values;
}
searchAllPaged(BaseDN, options, page) {
this.bindIfNecessary();
const processPage = ({ entries, title, end, next }) => {
log_info(title);
// Force LDAP idle to wait the record processing
this.client._updateIdle(true);
page(null, entries, {
end,
next: () => {
// Reset idle timer
this.client._updateIdle();
next && next();
},
});
};
this.client.search(BaseDN, options, (error, res) => {
if (error) {
log_error(error);
page(error);
return;
}
res.on('error', error => {
log_error(error);
page(error);
return;
});
let entries = [];
const internalPageSize =
options.paged && options.paged.pageSize > 0
? options.paged.pageSize * 2
: 500;
res.on('searchEntry', entry => {
entries.push(this.extractLdapEntryData(entry));
if (entries.length >= internalPageSize) {
processPage({
entries,
title: 'Internal Page',
end: false,
});
entries = [];
}
});
res.on('page', (result, next) => {
if (!next) {
this.client._updateIdle(true);
processPage({
entries,
title: 'Final Page',
end: true,
});
} else if (entries.length) {
log_info('Page');
processPage({
entries,
title: 'Page',
end: false,
next,
});
entries = [];
}
});
res.on('end', () => {
if (entries.length) {
processPage({
entries,
title: 'Final Page',
end: true,
});
entries = [];
}
});
});
}
searchAllAsync(BaseDN, options, callback) {
this.bindIfNecessary();
this.client.search(BaseDN, options, (error, res) => {
if (error) {
log_error(error);
callback(error);
return;
}
res.on('error', error => {
log_error(error);
callback(error);
return;
});
const entries = [];
res.on('searchEntry', entry => {
entries.push(this.extractLdapEntryData(entry));
});
res.on('end', () => {
log_info('Search result count', entries.length);
callback(null, entries);
});
});
}
authSync(dn, password) {
log_info('Authenticating', dn);
try {
if (password === '') {
throw new Error('Password is not provided');
}
this.bindSync(dn, password);
log_info('Authenticated', dn);
return true;
} catch (error) {
log_info('Not authenticated', dn);
log_debug('error', error);
return false;
}
}
disconnect() {
this.connected = false;
this.domainBinded = false;
log_info('Disconecting');
this.client.unbind();
}
}
-163
View File
@@ -1,163 +0,0 @@
Oidc = {};
OAuth.registerService('oidc', 2, null, function(query) {
var debug = process.env.DEBUG || false;
var token = getToken(query);
if (debug) console.log('XXX: register token:', token);
var accessToken = token.access_token || token.id_token;
var expiresAt = +new Date() + 1000 * parseInt(token.expires_in, 10);
var userinfo = getUserInfo(accessToken);
if (debug) console.log('XXX: userinfo:', userinfo);
var serviceData = {};
serviceData.id = userinfo[process.env.OAUTH2_ID_MAP]; // || userinfo["id"];
serviceData.username = userinfo[process.env.OAUTH2_USERNAME_MAP]; // || userinfo["uid"];
serviceData.fullname = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
serviceData.accessToken = accessToken;
serviceData.expiresAt = expiresAt;
serviceData.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
if (accessToken) {
var tokenContent = getTokenContent(accessToken);
var fields = _.pick(
tokenContent,
getConfiguration().idTokenWhitelistFields,
);
_.extend(serviceData, fields);
}
if (token.refresh_token) serviceData.refreshToken = token.refresh_token;
if (debug) console.log('XXX: serviceData:', serviceData);
var profile = {};
profile.name = userinfo[process.env.OAUTH2_FULLNAME_MAP]; // || userinfo["displayName"];
profile.email = userinfo[process.env.OAUTH2_EMAIL_MAP]; // || userinfo["email"];
if (debug) console.log('XXX: profile:', profile);
return {
serviceData: serviceData,
options: { profile: profile },
};
});
var userAgent = 'Meteor';
if (Meteor.release) {
userAgent += '/' + Meteor.release;
}
var getToken = function(query) {
var debug = process.env.DEBUG || false;
var config = getConfiguration();
if (config.tokenEndpoint.includes('https://')) {
var serverTokenEndpoint = config.tokenEndpoint;
} else {
var serverTokenEndpoint = config.serverUrl + config.tokenEndpoint;
}
var requestPermissions = config.requestPermissions;
var response;
try {
response = HTTP.post(serverTokenEndpoint, {
headers: {
Accept: 'application/json',
'User-Agent': userAgent,
},
params: {
code: query.code,
client_id: config.clientId,
client_secret: OAuth.openSecret(config.secret),
redirect_uri: OAuth._redirectUri('oidc', config),
grant_type: 'authorization_code',
scope: requestPermissions,
state: query.state,
},
});
} catch (err) {
throw _.extend(
new Error(
'Failed to get token from OIDC ' +
serverTokenEndpoint +
': ' +
err.message,
),
{ response: err.response },
);
}
if (response.data.error) {
// if the http response was a json object with an error attribute
throw new Error(
'Failed to complete handshake with OIDC ' +
serverTokenEndpoint +
': ' +
response.data.error,
);
} else {
if (debug) console.log('XXX: getToken response: ', response.data);
return response.data;
}
};
var getUserInfo = function(accessToken) {
var debug = process.env.DEBUG || false;
var config = getConfiguration();
// Some userinfo endpoints use a different base URL than the authorization or token endpoints.
// This logic allows the end user to override the setting by providing the full URL to userinfo in their config.
if (config.userinfoEndpoint.includes('https://')) {
var serverUserinfoEndpoint = config.userinfoEndpoint;
} else {
var serverUserinfoEndpoint = config.serverUrl + config.userinfoEndpoint;
}
var response;
try {
response = HTTP.get(serverUserinfoEndpoint, {
headers: {
'User-Agent': userAgent,
Authorization: 'Bearer ' + accessToken,
},
});
} catch (err) {
throw _.extend(
new Error(
'Failed to fetch userinfo from OIDC ' +
serverUserinfoEndpoint +
': ' +
err.message,
),
{ response: err.response },
);
}
if (debug) console.log('XXX: getUserInfo response: ', response.data);
return response.data;
};
var getConfiguration = function() {
var config = ServiceConfiguration.configurations.findOne({ service: 'oidc' });
if (!config) {
throw new ServiceConfiguration.ConfigError('Service oidc not configured.');
}
return config;
};
var getTokenContent = function(token) {
var content = null;
if (token) {
try {
var parts = token.split('.');
var header = JSON.parse(new Buffer(parts[0], 'base64').toString());
content = JSON.parse(new Buffer(parts[1], 'base64').toString());
var signature = new Buffer(parts[2], 'base64');
var signed = parts[0] + '.' + parts[1];
} catch (err) {
this.content = {
exp: 0,
};
}
}
return content;
};
Oidc.retrieveCredential = function(credentialToken, credentialSecret) {
return OAuth.retrieveCredential(credentialToken, credentialSecret);
};
File diff suppressed because it is too large. Load diff
-73
View File
@@ -1,73 +0,0 @@
{
"name": "wekan",
"version": "v3.88.0",
"description": "Open-Source kanban",
"private": true,
"scripts": {
"lint": "eslint --cache --ext .js --ignore-path .eslintignore .",
"lint:eslint:fix": "eslint --ext .js --ignore-path .eslintignore --fix .",
"lint:staged": "lint-staged",
"prettify": "prettier --write '**/*.js' '**/*.jsx'",
"test": "npm run lint"
},
"lint-staged": {
"*.js": [
"meteor npm run prettify",
"meteor npm run lint:eslint:fix",
"git add --force"
],
"*.jsx": [
"meteor npm run prettify",
"meteor npm run lint:eslint:fix",
"git add --force"
],
"*.json": [
"prettier --write",
"git add --force"
]
},
"pre-commit": "lint:staged",
"eslintConfig": {
"extends": "@meteorjs/eslint-config-meteor"
},
"repository": {
"type": "git",
"url": "git+https://github.com/wekan/wekan.git"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/wekan/wekan/issues"
},
"homepage": "https://wekan.github.io",
"devDependencies": {
"eslint": "^6.8.0",
"eslint-config-meteor": "^0.1.1",
"eslint-config-prettier": "^6.10.0",
"eslint-import-resolver-meteor": "^0.4.0",
"eslint-plugin-import": "^2.20.1",
"eslint-plugin-meteor": "^6.0.0",
"eslint-plugin-prettier": "^3.1.2",
"lint-staged": "^10.0.8",
"pre-commit": "^1.2.2",
"prettier": "^1.19.1",
"prettier-eslint": "^9.0.1"
},
"dependencies": {
"@babel/runtime": "^7.8.7",
"ajv": "^6.12.0",
"babel-runtime": "^6.26.0",
"bcrypt": "^4.0.1",
"bson": "^4.0.3",
"bunyan": "^1.8.12",
"es6-promise": "^4.2.8",
"gridfs-stream": "^1.1.1",
"ldapjs": "^1.0.2",
"meteor-node-stubs": "^1.0.0",
"mongodb": "^3.5.5",
"os": "^0.1.1",
"page": "^1.11.5",
"qs": "^6.9.1",
"source-map-support": "^0.5.16",
"xss": "^1.0.6"
}
}
-244
View File
@@ -1,244 +0,0 @@
name: wekan
version: 0
version-script: git describe --tags | cut -c 2-
summary: The open-source kanban
description: |
Wekan is an open-source and collaborative kanban board application.
Whether you’re maintaining a personal todo list, planning your holidays with some friends, or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool to keep your things organized. They give you a visual overview of the current state of your project, and make you productive by allowing you to focus on the few items that matter the most.
Depending on target environment, some configuration settings might need to be adjusted.
For full list of configuration options call:
$ wekan.help
confinement: strict
grade: stable
architectures:
- amd64
plugs:
mongodb-plug:
interface: content
target: $SNAP_DATA/shared
hooks:
configure:
plugs:
- network
- network-bind
slots:
mongodb-slot:
interface: content
write:
- $SNAP_DATA/share
apps:
wekan:
command: wekan-control
daemon: simple
plugs: [network, network-bind]
mongodb:
command: mongodb-control
daemon: simple
plugs: [network, network-bind]
caddy:
command: caddy-control
daemon: simple
plugs: [network, network-bind]
help:
command: wekan-help
database-backup:
command: mongodb-backup
plugs: [network, network-bind]
database-list-backups:
command: ls -al $SNAP_COMMON/db-backups/
database-restore:
command: mongodb-restore
plugs: [network, network-bind]
parts:
mongodb:
source: https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-ubuntu1604-3.2.22.tgz
plugin: dump
stage-packages: [libssl1.0.0]
filesets:
mongo:
- usr
- bin
- lib
stage:
- $mongo
prime:
- $mongo
wekan:
source: .
plugin: nodejs
node-engine: 8.17.0
node-packages:
- node-gyp
- node-pre-gyp
- fibers@2.0.0
build-packages:
- ca-certificates
- apt-utils
- python
# - python3
- g++
- capnproto
- curl
- execstack
- nodejs
- npm
stage-packages:
- libfontconfig1
override-build: |
echo "Cleaning environment first"
rm -rf ~/.meteor ~/.npm /usr/local/lib/node_modules
# Create the OpenAPI specification
rm -rf .build
#mkdir -p .build/python
#cd .build/python
#git clone --depth 1 -b master https://github.com/Kronuz/esprima-python
#cd esprima-python
#python3 setup.py install
#cd ../../..
#mkdir -p ./public/api
#python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml
# we temporary need api2html and mkdirp
#npm install -g api2html@0.3.0
#npm install -g mkdirp
#api2html -c ./public/logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml
#npm uninstall -g mkdirp
#npm uninstall -g api2html
# Node Fibers 100% CPU usage issue:
# https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-381453161
# https://github.com/meteor/meteor/issues/9796#issuecomment-381676326
# https://github.com/sandstorm-io/sandstorm/blob/0f1fec013fe7208ed0fd97eb88b31b77e3c61f42/shell/server/00-startup.js#L99-L129
# Also see beginning of wekan/server/authentication.js
# import Fiber from "fibers";
# Fiber.poolSize = 1e9;
# OLD: Download node version 8.12.0 prerelease build => Official node 8.12.0 has been released
# Description at https://releases.wekan.team/node.txt
##echo "375bd8db50b9c692c0bbba6e96d4114cd29bee3770f901c1ff2249d1038f1348 node" >> node-SHASUMS256.txt.asc
##curl https://releases.wekan.team/node -o node
# Verify Fibers patched node authenticity
##echo "Fibers 100% CPU issue patched node authenticity:"
##grep node node-SHASUMS256.txt.asc | shasum -a 256 -c -
##rm -f node-SHASUMS256.txt.asc
##chmod +x node
##mv node `which node`
# DOES NOT WORK: paxctl fix.
# Removed from build-packages: - paxctl
#echo "Applying paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303"
#paxctl -mC `which node`
#echo "Installing npm"
#curl -L https://www.npmjs.com/install.sh | sh
echo "Installing meteor"
curl https://install.meteor.com/ -o install_meteor.sh
#sed -i "s|RELEASE=.*|RELEASE=\"1.8.1-beta.0\"|g" install_meteor.sh
chmod +x install_meteor.sh
sh install_meteor.sh
rm install_meteor.sh
# REPOS BELOW ARE INCLUDED TO WEKAN REPO
#if [ ! -d "packages" ]; then
# mkdir packages
#fi
#if [ ! -d "packages/kadira-flow-router" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router
# cd ..
#fi
#if [ ! -d "packages/meteor-useraccounts-core" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core
# sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' meteor-useraccounts-core/package.js
# cd ..
#fi
#if [ ! -d "packages/meteor-accounts-cas" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git meteor-accounts-cas
# cd ..
#fi
#if [ ! -d "packages/wekan-ldap" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git
# cd ..
#fi
#if [ ! -d "packages/wekan-scrollbar" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git
# cd ..
#fi
#if [ ! -d "packages/wekan_accounts-oidc" ]; then
# cd packages
# git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git
# mv meteor-accounts-oidc/packages/switch_accounts-oidc wekan-accounts-oidc
# mv meteor-accounts-oidc/packages/switch_oidc wekan-oidc
# rm -rf meteor-accounts-oidc
# cd ..
#fi
#if [ ! -d "packages/markdown" ]; then
# cd packages
# git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git
# cd ..
#fi
rm -rf .build
meteor add standard-minifier-js --allow-superuser
meteor npm install --allow-superuser
meteor npm install --allow-superuser --save babel-runtime
meteor build .build --directory --allow-superuser
cp -f fix-download-unicode/cfs_access-point.txt .build/bundle/programs/server/packages/cfs_access-point.js
#Removed binary version of bcrypt because of security vulnerability that is not fixed yet.
#https://github.com/wekan/wekan/commit/4b2010213907c61b0e0482ab55abb06f6a668eac
#https://github.com/wekan/wekan/commit/7eeabf14be3c63fae2226e561ef8a0c1390c8d3c
#cd .build/bundle/programs/server/npm/node_modules/meteor/npm-bcrypt
#rm -rf node_modules/bcrypt
#meteor npm install --save bcrypt
# Change from npm-bcrypt directory back to .build/bundle/programs/server directory.
#cd ../../../../
# Change to directory .build/bundle/programs/server
cd .build/bundle/programs/server
npm install
npm install --allow-superuser --save babel-runtime
#meteor npm install --save bcrypt
# Change back to Wekan source directory
cd ../../../..
cp -r .build/bundle/* $SNAPCRAFT_PART_INSTALL/
cp .build/bundle/.node_version.txt $SNAPCRAFT_PART_INSTALL/
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/wekan
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/npm/node_modules/tar/lib/.mkdir.js.swp
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
rm -f $SNAPCRAFT_PART_INSTALL/lib/node_modules/node-gyp/node_modules/tar/lib/.mkdir.js.swp
# Meteor 1.8.x additional .swp remove
rm -f $SNAPCRAFT_PART_INSTALL/programs/server/node_modules/node-pre-gyp/node_modules/tar/lib/.mkdir.js.swp
organize:
README: README.wekan
prime:
- -lib/node_modules/node-pre-gyp/node_modules/tar/lib/.unpack.js.swp
helpers:
source: snap-src
plugin: dump
caddy:
plugin: dump
source: https://caddyserver.com/download/linux/amd64?license=personal&telemetry=off
source-type: tar
organize:
caddy: bin/caddy
CHANGES.txt: CADDY_CHANGES.txt
EULA.txt: CADDY_EULA.txt
LICENSES.txt: CADDY_LICENSES.txt
README.txt: CADDY_README.txt
stage:
- -init
-853
View File
@@ -1,853 +0,0 @@
const DateString = Match.Where(function(dateAsString) {
check(dateAsString, String);
return moment(dateAsString, moment.ISO_8601).isValid();
});
export class WekanCreator {
constructor(data) {
// we log current date, to use the same timestamp for all our actions.
// this helps to retrieve all elements performed by the same import.
this._nowDate = new Date();
// The object creation dates, indexed by Wekan id
// (so we only parse actions once!)
this.createdAt = {
board: null,
cards: {},
lists: {},
swimlanes: {},
};
// The object creator Wekan Id, indexed by the object Wekan id
// (so we only parse actions once!)
this.createdBy = {
cards: {}, // only cards have a field for that
};
// Map of labels Wekan ID => Wekan ID
this.labels = {};
// Map of swimlanes Wekan ID => Wekan ID
this.swimlanes = {};
// Map of lists Wekan ID => Wekan ID
this.lists = {};
// Map of cards Wekan ID => Wekan ID
this.cards = {};
// Map of comments Wekan ID => Wekan ID
this.commentIds = {};
// Map of attachments Wekan ID => Wekan ID
this.attachmentIds = {};
// Map of checklists Wekan ID => Wekan ID
this.checklists = {};
// Map of checklistItems Wekan ID => Wekan ID
this.checklistItems = {};
// The comments, indexed by Wekan card id (to map when importing cards)
this.comments = {};
// Map of rules Wekan ID => Wekan ID
this.rules = {};
// the members, indexed by Wekan member id => Wekan user ID
this.members = data.membersMapping ? data.membersMapping : {};
// Map of triggers Wekan ID => Wekan ID
this.triggers = {};
// Map of actions Wekan ID => Wekan ID
this.actions = {};
// maps a wekanCardId to an array of wekanAttachments
this.attachments = {};
}
/**
* If dateString is provided,
* return the Date it represents.
* If not, will return the date when it was first called.
* This is useful for us, as we want all import operations to
* have the exact same date for easier later retrieval.
*
* @param {String} dateString a properly formatted Date
*/
_now(dateString) {
if (dateString) {
return new Date(dateString);
}
if (!this._nowDate) {
this._nowDate = new Date();
}
return this._nowDate;
}
/**
* if wekanUserId is provided and we have a mapping,
* return it.
* Otherwise return current logged user.
* @param wekanUserId
* @private
*/
_user(wekanUserId) {
if (wekanUserId && this.members[wekanUserId]) {
return this.members[wekanUserId];
}
return Meteor.userId();
}
checkActivities(wekanActivities) {
check(wekanActivities, [
Match.ObjectIncluding({
activityType: String,
createdAt: DateString,
}),
]);
// XXX we could perform more thorough checks based on action type
}
checkBoard(wekanBoard) {
check(
wekanBoard,
Match.ObjectIncluding({
archived: Boolean,
title: String,
// XXX refine control by validating 'color' against a list of
// allowed values (is it worth the maintenance?)
color: String,
permission: Match.Where(value => {
return ['private', 'public'].indexOf(value) >= 0;
}),
}),
);
}
checkCards(wekanCards) {
check(wekanCards, [
Match.ObjectIncluding({
archived: Boolean,
dateLastActivity: DateString,
labelIds: [String],
title: String,
sort: Number,
}),
]);
}
checkLabels(wekanLabels) {
check(wekanLabels, [
Match.ObjectIncluding({
// XXX refine control by validating 'color' against a list of allowed
// values (is it worth the maintenance?)
color: String,
}),
]);
}
checkLists(wekanLists) {
check(wekanLists, [
Match.ObjectIncluding({
archived: Boolean,
title: String,
}),
]);
}
checkSwimlanes(wekanSwimlanes) {
check(wekanSwimlanes, [
Match.ObjectIncluding({
archived: Boolean,
title: String,
}),
]);
}
checkChecklists(wekanChecklists) {
check(wekanChecklists, [
Match.ObjectIncluding({
cardId: String,
title: String,
}),
]);
}
checkChecklistItems(wekanChecklistItems) {
check(wekanChecklistItems, [
Match.ObjectIncluding({
cardId: String,
title: String,
}),
]);
}
checkRules(wekanRules) {
check(wekanRules, [
Match.ObjectIncluding({
triggerId: String,
actionId: String,
title: String,
}),
]);
}
checkTriggers(wekanTriggers) {
// XXX More check based on trigger type
check(wekanTriggers, [
Match.ObjectIncluding({
activityType: String,
desc: String,
}),
]);
}
getMembersToMap(data) {
// we will work on the list itself (an ordered array of objects) when a
// mapping is done, we add a 'wekan' field to the object representing the
// imported member
const membersToMap = data.members;
const users = data.users;
// auto-map based on username
membersToMap.forEach(importedMember => {
importedMember.id = importedMember.userId;
delete importedMember.userId;
const user = users.filter(user => {
return user._id === importedMember.id;
})[0];
if (user.profile && user.profile.fullname) {
importedMember.fullName = user.profile.fullname;
}
importedMember.username = user.username;
const wekanUser = Users.findOne({ username: importedMember.username });
if (wekanUser) {
importedMember.wekanId = wekanUser._id;
}
});
return membersToMap;
}
checkActions(wekanActions) {
// XXX More check based on action type
check(wekanActions, [
Match.ObjectIncluding({
actionType: String,
desc: String,
}),
]);
}
// You must call parseActions before calling this one.
createBoardAndLabels(boardToImport) {
const boardToCreate = {
archived: boardToImport.archived,
color: boardToImport.color,
// very old boards won't have a creation activity so no creation date
createdAt: this._now(boardToImport.createdAt),
labels: [],
members: [
{
userId: Meteor.userId(),
wekanId: Meteor.userId(),
isActive: true,
isAdmin: true,
isNoComments: false,
isCommentOnly: false,
swimlaneId: false,
},
],
// Standalone Export has modifiedAt missing, adding modifiedAt to fix it
modifiedAt: this._now(boardToImport.modifiedAt),
permission: boardToImport.permission,
slug: getSlug(boardToImport.title) || 'board',
stars: 0,
title: boardToImport.title,
};
// now add other members
if (boardToImport.members) {
boardToImport.members.forEach(wekanMember => {
// do we already have it in our list?
if (
!boardToCreate.members.some(
member => member.wekanId === wekanMember.wekanId,
)
)
boardToCreate.members.push({
...wekanMember,
userId: wekanMember.wekanId,
});
});
}
boardToImport.labels.forEach(label => {
const labelToCreate = {
_id: Random.id(6),
color: label.color,
name: label.name,
};
// We need to remember them by Wekan ID, as this is the only ref we have
// when importing cards.
this.labels[label._id] = labelToCreate._id;
boardToCreate.labels.push(labelToCreate);
});
const boardId = Boards.direct.insert(boardToCreate);
Boards.direct.update(boardId, {
$set: {
modifiedAt: this._now(),
},
});
// log activity
Activities.direct.insert({
activityType: 'importBoard',
boardId,
createdAt: this._now(),
source: {
id: boardToImport.id,
system: 'Wekan',
},
// We attribute the import to current user,
// not the author from the original object.
userId: this._user(),
});
return boardId;
}
/**
* Create the Wekan cards corresponding to the supplied Wekan cards,
* as well as all linked data: activities, comments, and attachments
* @param wekanCards
* @param boardId
* @returns {Array}
*/
createCards(wekanCards, boardId) {
const result = [];
wekanCards.forEach(card => {
const cardToCreate = {
archived: card.archived,
boardId,
// very old boards won't have a creation activity so no creation date
createdAt: this._now(this.createdAt.cards[card._id]),
dateLastActivity: this._now(),
description: card.description,
listId: this.lists[card.listId],
swimlaneId: this.swimlanes[card.swimlaneId],
sort: card.sort,
title: card.title,
// we attribute the card to its creator if available
userId: this._user(this.createdBy.cards[card._id]),
isOvertime: card.isOvertime || false,
startAt: card.startAt ? this._now(card.startAt) : null,
dueAt: card.dueAt ? this._now(card.dueAt) : null,
spentTime: card.spentTime || null,
};
// add labels
if (card.labelIds) {
cardToCreate.labelIds = card.labelIds.map(wekanId => {
return this.labels[wekanId];
});
}
// add members {
if (card.members) {
const wekanMembers = [];
// we can't just map, as some members may not have been mapped
card.members.forEach(sourceMemberId => {
if (this.members[sourceMemberId]) {
const wekanId = this.members[sourceMemberId];
// we may map multiple Wekan members to the same wekan user
// in which case we risk adding the same user multiple times
if (!wekanMembers.find(wId => wId === wekanId)) {
wekanMembers.push(wekanId);
}
}
return true;
});
if (wekanMembers.length > 0) {
cardToCreate.members = wekanMembers;
}
}
// set color
if (card.color) {
cardToCreate.color = card.color;
}
// insert card
const cardId = Cards.direct.insert(cardToCreate);
// keep track of Wekan id => Wekan id
this.cards[card._id] = cardId;
// // log activity
// Activities.direct.insert({
// activityType: 'importCard',
// boardId,
// cardId,
// createdAt: this._now(),
// listId: cardToCreate.listId,
// source: {
// id: card._id,
// system: 'Wekan',
// },
// // we attribute the import to current user,
// // not the author of the original card
// userId: this._user(),
// });
// add comments
const comments = this.comments[card._id];
if (comments) {
comments.forEach(comment => {
const commentToCreate = {
boardId,
cardId,
createdAt: this._now(comment.createdAt),
text: comment.text,
// we attribute the comment to the original author, default to current user
userId: this._user(comment.userId),
};
// dateLastActivity will be set from activity insert, no need to
// update it ourselves
const commentId = CardComments.direct.insert(commentToCreate);
this.commentIds[comment._id] = commentId;
// Activities.direct.insert({
// activityType: 'addComment',
// boardId: commentToCreate.boardId,
// cardId: commentToCreate.cardId,
// commentId,
// createdAt: this._now(commentToCreate.createdAt),
// // we attribute the addComment (not the import)
// // to the original author - it is needed by some UI elements.
// userId: commentToCreate.userId,
// });
});
}
const attachments = this.attachments[card._id];
const wekanCoverId = card.coverId;
if (attachments) {
attachments.forEach(att => {
const file = new FS.File();
// Simulating file.attachData on the client generates multiple errors
// - HEAD returns null, which causes exception down the line
// - the template then tries to display the url to the attachment which causes other errors
// so we make it server only, and let UI catch up once it is done, forget about latency comp.
const self = this;
if (Meteor.isServer) {
if (att.url) {
file.attachData(att.url, function(error) {
file.boardId = boardId;
file.cardId = cardId;
file.userId = self._user(att.userId);
// The field source will only be used to prevent adding
// attachments' related activities automatically
file.source = 'import';
if (error) {
throw error;
} else {
const wekanAtt = Attachments.insert(file, () => {
// we do nothing
});
self.attachmentIds[att._id] = wekanAtt._id;
//
if (wekanCoverId === att._id) {
Cards.direct.update(cardId, {
$set: {
coverId: wekanAtt._id,
},
});
}
}
});
} else if (att.file) {
file.attachData(
new Buffer(att.file, 'base64'),
{
type: att.type,
},
error => {
file.name(att.name);
file.boardId = boardId;
file.cardId = cardId;
file.userId = self._user(att.userId);
// The field source will only be used to prevent adding
// attachments' related activities automatically
file.source = 'import';
if (error) {
throw error;
} else {
const wekanAtt = Attachments.insert(file, () => {
// we do nothing
});
this.attachmentIds[att._id] = wekanAtt._id;
//
if (wekanCoverId === att._id) {
Cards.direct.update(cardId, {
$set: {
coverId: wekanAtt._id,
},
});
}
}
},
);
}
}
// todo XXX set cover - if need be
});
}
result.push(cardId);
});
return result;
}
// Create labels if they do not exist and load this.labels.
createLabels(wekanLabels, board) {
wekanLabels.forEach(label => {
const color = label.color;
const name = label.name;
const existingLabel = board.getLabel(name, color);
if (existingLabel) {
this.labels[label.id] = existingLabel._id;
} else {
const idLabelCreated = board.pushLabel(name, color);
this.labels[label.id] = idLabelCreated;
}
});
}
createLists(wekanLists, boardId) {
wekanLists.forEach((list, listIndex) => {
const listToCreate = {
archived: list.archived,
boardId,
// We are being defensing here by providing a default date (now) if the
// creation date wasn't found on the action log. This happen on old
// Wekan boards (eg from 2013) that didn't log the 'createList' action
// we require.
createdAt: this._now(this.createdAt.lists[list.id]),
title: list.title,
sort: list.sort ? list.sort : listIndex,
};
const listId = Lists.direct.insert(listToCreate);
Lists.direct.update(listId, {
$set: {
updatedAt: this._now(),
},
});
this.lists[list._id] = listId;
// // log activity
// Activities.direct.insert({
// activityType: 'importList',
// boardId,
// createdAt: this._now(),
// listId,
// source: {
// id: list._id,
// system: 'Wekan',
// },
// // We attribute the import to current user,
// // not the creator of the original object
// userId: this._user(),
// });
});
}
createSwimlanes(wekanSwimlanes, boardId) {
wekanSwimlanes.forEach((swimlane, swimlaneIndex) => {
const swimlaneToCreate = {
archived: swimlane.archived,
boardId,
// We are being defensing here by providing a default date (now) if the
// creation date wasn't found on the action log. This happen on old
// Wekan boards (eg from 2013) that didn't log the 'createList' action
// we require.
createdAt: this._now(this.createdAt.swimlanes[swimlane._id]),
title: swimlane.title,
sort: swimlane.sort ? swimlane.sort : swimlaneIndex,
};
// set color
if (swimlane.color) {
swimlaneToCreate.color = swimlane.color;
}
const swimlaneId = Swimlanes.direct.insert(swimlaneToCreate);
Swimlanes.direct.update(swimlaneId, {
$set: {
updatedAt: this._now(),
},
});
this.swimlanes[swimlane._id] = swimlaneId;
});
}
createChecklists(wekanChecklists) {
const result = [];
wekanChecklists.forEach((checklist, checklistIndex) => {
// Create the checklist
const checklistToCreate = {
cardId: this.cards[checklist.cardId],
title: checklist.title,
createdAt: checklist.createdAt,
sort: checklist.sort ? checklist.sort : checklistIndex,
};
const checklistId = Checklists.direct.insert(checklistToCreate);
this.checklists[checklist._id] = checklistId;
result.push(checklistId);
});
return result;
}
createTriggers(wekanTriggers, boardId) {
wekanTriggers.forEach(trigger => {
if (trigger.hasOwnProperty('labelId')) {
trigger.labelId = this.labels[trigger.labelId];
}
if (trigger.hasOwnProperty('memberId')) {
trigger.memberId = this.members[trigger.memberId];
}
trigger.boardId = boardId;
const oldId = trigger._id;
delete trigger._id;
this.triggers[oldId] = Triggers.direct.insert(trigger);
});
}
createActions(wekanActions, boardId) {
wekanActions.forEach(action => {
if (action.hasOwnProperty('labelId')) {
action.labelId = this.labels[action.labelId];
}
if (action.hasOwnProperty('memberId')) {
action.memberId = this.members[action.memberId];
}
action.boardId = boardId;
const oldId = action._id;
delete action._id;
this.actions[oldId] = Actions.direct.insert(action);
});
}
createRules(wekanRules, boardId) {
wekanRules.forEach(rule => {
// Create the rule
rule.boardId = boardId;
rule.triggerId = this.triggers[rule.triggerId];
rule.actionId = this.actions[rule.actionId];
delete rule._id;
Rules.direct.insert(rule);
});
}
createChecklistItems(wekanChecklistItems) {
wekanChecklistItems.forEach((checklistitem, checklistitemIndex) => {
// Create the checklistItem
const checklistItemTocreate = {
title: checklistitem.title,
checklistId: this.checklists[checklistitem.checklistId],
cardId: this.cards[checklistitem.cardId],
sort: checklistitem.sort ? checklistitem.sort : checklistitemIndex,
isFinished: checklistitem.isFinished,
};
const checklistItemId = ChecklistItems.direct.insert(
checklistItemTocreate,
);
this.checklistItems[checklistitem._id] = checklistItemId;
});
}
parseActivities(wekanBoard) {
wekanBoard.activities.forEach(activity => {
switch (activity.activityType) {
case 'addAttachment': {
// We have to be cautious, because the attachment could have been removed later.
// In that case Wekan still reports its addition, but removes its 'url' field.
// So we test for that
const wekanAttachment = wekanBoard.attachments.filter(attachment => {
return attachment._id === activity.attachmentId;
})[0];
if (typeof wekanAttachment !== 'undefined' && wekanAttachment) {
if (wekanAttachment.url || wekanAttachment.file) {
// we cannot actually create the Wekan attachment, because we don't yet
// have the cards to attach it to, so we store it in the instance variable.
const wekanCardId = activity.cardId;
if (!this.attachments[wekanCardId]) {
this.attachments[wekanCardId] = [];
}
this.attachments[wekanCardId].push(wekanAttachment);
}
}
break;
}
case 'addComment': {
const wekanComment = wekanBoard.comments.filter(comment => {
return comment._id === activity.commentId;
})[0];
const id = activity.cardId;
if (!this.comments[id]) {
this.comments[id] = [];
}
this.comments[id].push(wekanComment);
break;
}
case 'createBoard': {
this.createdAt.board = activity.createdAt;
break;
}
case 'createCard': {
const cardId = activity.cardId;
this.createdAt.cards[cardId] = activity.createdAt;
this.createdBy.cards[cardId] = activity.userId;
break;
}
case 'createList': {
const listId = activity.listId;
this.createdAt.lists[listId] = activity.createdAt;
break;
}
case 'createSwimlane': {
const swimlaneId = activity.swimlaneId;
this.createdAt.swimlanes[swimlaneId] = activity.createdAt;
break;
}
}
});
}
importActivities(activities, boardId) {
activities.forEach(activity => {
switch (activity.activityType) {
// Board related activities
// TODO: addBoardMember, removeBoardMember
case 'createBoard': {
Activities.direct.insert({
userId: this._user(activity.userId),
type: 'board',
activityTypeId: boardId,
activityType: activity.activityType,
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
// List related activities
// TODO: removeList, archivedList
case 'createList': {
Activities.direct.insert({
userId: this._user(activity.userId),
type: 'list',
activityType: activity.activityType,
listId: this.lists[activity.listId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
// Card related activities
// TODO: archivedCard, restoredCard, joinMember, unjoinMember
case 'createCard': {
Activities.direct.insert({
userId: this._user(activity.userId),
activityType: activity.activityType,
listId: this.lists[activity.listId],
cardId: this.cards[activity.cardId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
case 'moveCard': {
Activities.direct.insert({
userId: this._user(activity.userId),
oldListId: this.lists[activity.oldListId],
activityType: activity.activityType,
listId: this.lists[activity.listId],
cardId: this.cards[activity.cardId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
// Comment related activities
case 'addComment': {
Activities.direct.insert({
userId: this._user(activity.userId),
activityType: activity.activityType,
cardId: this.cards[activity.cardId],
commentId: this.commentIds[activity.commentId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
// Attachment related activities
case 'addAttachment': {
Activities.direct.insert({
userId: this._user(activity.userId),
type: 'card',
activityType: activity.activityType,
attachmentId: this.attachmentIds[activity.attachmentId],
cardId: this.cards[activity.cardId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
// Checklist related activities
case 'addChecklist': {
Activities.direct.insert({
userId: this._user(activity.userId),
activityType: activity.activityType,
cardId: this.cards[activity.cardId],
checklistId: this.checklists[activity.checklistId],
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
case 'addChecklistItem': {
Activities.direct.insert({
userId: this._user(activity.userId),
activityType: activity.activityType,
cardId: this.cards[activity.cardId],
checklistId: this.checklists[activity.checklistId],
checklistItemId: activity.checklistItemId.replace(
activity.checklistId,
this.checklists[activity.checklistId],
),
boardId,
createdAt: this._now(activity.createdAt),
});
break;
}
}
});
}
//check(board) {
check() {
//try {
// check(data, {
// membersMapping: Match.Optional(Object),
// });
// this.checkActivities(board.activities);
// this.checkBoard(board);
// this.checkLabels(board.labels);
// this.checkLists(board.lists);
// this.checkSwimlanes(board.swimlanes);
// this.checkCards(board.cards);
//this.checkChecklists(board.checklists);
// this.checkRules(board.rules);
// this.checkActions(board.actions);
//this.checkTriggers(board.triggers);
//this.checkChecklistItems(board.checklistItems);
//} catch (e) {
// throw new Meteor.Error('error-json-schema');
// }
}
create(board, currentBoardId) {
// TODO : Make isSandstorm variable global
const isSandstorm =
Meteor.settings &&
Meteor.settings.public &&
Meteor.settings.public.sandstorm;
if (isSandstorm && currentBoardId) {
const currentBoard = Boards.findOne(currentBoardId);
currentBoard.archive();
}
this.parseActivities(board);
const boardId = this.createBoardAndLabels(board);
this.createLists(board.lists, boardId);
this.createSwimlanes(board.swimlanes, boardId);
this.createCards(board.cards, boardId);
this.createChecklists(board.checklists);
this.createChecklistItems(board.checklistItems);
this.importActivities(board.activities, boardId);
this.createTriggers(board.triggers, boardId);
this.createActions(board.actions, boardId);
this.createRules(board.rules, boardId);
// XXX add members
return boardId;
}
}
+1 -1
View File
@@ -3,7 +3,7 @@ sudo: required
env:
TRAVIS_DOCKER_COMPOSE_VERSION: 1.24.0
TRAVIS_NODE_VERSION: 12.15.0
TRAVIS_NODE_VERSION: 12.16.2
TRAVIS_NPM_VERSION: latest
before_install:
+172 -2
View File
@@ -1,3 +1,173 @@
# v3.97 2020-04-19 Wekan release
This release adds the following new features:
- [Sortable boards](https://github.com/wekan/wekan/pull/3027).
Thanks to boeserwolf.
- [Added dockerfiles for multi-arch builds and manifest](https://github.com/wekan/wekan/pull/3023).
[In Progress](https://github.com/wekan/wekan/issues/2999).
Thanks to brokencode64.
- [Make linked card clickable](https://github.com/wekan/wekan/pull/3025).
Thanks to boeserwolf.
and fixes the following bugs:
- [Fix using checklists on mobile and iPad](https://github.com/wekan/wekan/pull/3019).
Thanks to devinsm.
- [Improve card layout on mobile devices](https://github.com/wekan/wekan/pull/3024).
Thanks to marc1006.
- [Make OCP OAuth work with Openshift 4.x](https://github.com/wekan/wekan/pull/3020).
Thanks to ckavili.
- [Remove old warning from Sandstorm import board data loss, because bug has been already
fixed](https://github.com/wekan/wekan/commit/960fe5163b6a2f7c3dca03b5e31d69611b49f079).
Thanks to aputsiaq and xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.96 2020-04-15 Wekan release
This release adds the following Sandstorm updates:
- This is the first Sandstorm Wekan release that uses newest Meteor 1.10.1 and Node 12.x.
Now all Wekan platforms use newest Meteor and Node 12.x LTS.
Thanks to kentonv and xet7.
- [Fix capnp workaround to work with newest Meteor and
Node 12.x](https://github.com/wekan/wekan/commit/b2d546579c4957352c29b36c0c8a4a08b944dbb4).
Thanks to kentonv.
- [Update Sandstorm release script for newest Meteor and
Node 12.x](https://github.com/wekan/wekan/commit/c5f782976b971fa3f2323e80a013bbf6a49c0596).
Thanks to xet7.
- [Remove Meteor 1.8.x files because Sandstorm Wekan now uses newest
Meteor](https://github.com/wekan/wekan/commit/1a836969e10215bad47ac56a9b0d9de801b66fd2).
Thanks to xet7.
and adds the following new features:
- [Hide password auth with environment variable PASSWORD_LOGIN_ENABLED=false](https://github.com/wekan/wekan/pull/3014).
Snap example: `sudo snap set wekan password-login-enabled='false'` .
Thanks to salleman33.
and fixes the following bugs:
- [Fix Board admins can not clone or archive their boards at All Boards
page](https://github.com/wekan/wekan/pull/3013).
Thanks to salleman33.
- [Fix `<p>` margin in card labels](https://github.com/wekan/wekan/pull/3015).
Thanks to boeserwolf.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.95 2020-04-12 Wekan release
This release adds the following new features:
- [Add gitpod config](https://github.com/wekan/wekan/pull/3009).
This adds support for Gitpod.io, a free automated
dev environment that makes contributing and generally working on GitHub
projects much easier. It allows anyone to start a ready-to-code dev
environment for any branch, issue and pull request with a single click.
Thanks to juniormendonca.
- [Public boards overview](https://github.com/wekan/wekan/pull/3008).
Thanks to NicoP-S.
and fixes the following bugs:
- [Fix styling issue in notifications drawer](https://github.com/wekan/wekan/pull/3012).
Thanks to boeserwolf.
- [Fix error in notifications cleanup cron](https://github.com/wekan/wekan/pull/3010).
Thanks to jtbairdsr.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.94 2020-04-12 Wekan release
This release adds the following new features:
- [Public vote](https://github.com/wekan/wekan/pull/3006).
Thanks to NicoP-S.
- [Add robots.txt disallow all](https://github.com/wekan/wekan/commit/3fae5355d40055757bf4a5f0c503581195609720).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.93 2020-04-10 Wekan release
This release adds the following new features:
- [Trello vote import & hide export button if with_api is
disabled](https://github.com/wekan/wekan/pull/3000).
Thanks to NicoP-S.
- [When adding a user to a board that has subtasks, also add user to the subtask
board](https://github.com/wekan/wekan/pull/3004).
Thanks to slvrpdr.
and adds the following updates:
- Upgrade to Node v12.16.2 [Part1](https://github.com/wekan/wekan/commit/6db717b9b384fe1491063e507b80e67791a07e3a)
and [Part2](https://github.com/wekan/wekan/commit/268d7fcb32186a902a84e7f6d80c50b1f3790bad).
Thanks to Node developers and xet7.
and fixes the following bugs:
- [Fix bug that prevents editing or deleting
comments](https://github.com/wekan/wekan/pull/3005).
Thanks to jtbairdsr.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.92 2020-04-09 Wekan release
This release adds the following new features:
- [Scheduler to clean up read notifications. Also added a button to manually remove all
read notifications, and a fix to prevent users form getting notifications for their own
actions](https://github.com/wekan/wekan/pull/2998).
Thanks to jtbairdsr.
- [Add setting](https://github.com/wekan/wekan/commit/5ebb47cb0ec7272894a37d99579ede872251f55c)
default [NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE=2](https://github.com/wekan/wekan/pull/2998)
to all Wekan platforms.
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.91 2020-04-08 Wekan release
This release adds the following new features:
- [OpenShift: Route template added to helm chart for Openshift v4x
cluster](https://github.com/wekan/wekan/pull/2996).
Thanks to ckavili.
- [Filter by Assignee](https://github.com/wekan/wekan/pull/2997).
Thanks to daniel-eder.
- [Vote on Card](https://github.com/wekan/wekan/pull/2994).
Thanks to NicoP-S and xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.90 2020-04-06 Wekan release
This release makes the following updates:
- [Update dependencies](https://github.com/wekan/wekan/commit/d798f6e3ef09595ce4f1d1fbc053eec70fc91fb9).
and updates the following translations:
- [Update layouts.js for zh-TW language name](https://github.com/wekan/wekan/pull/2988).
Thanks to doggy8088.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.89 2020-04-05 Wekan release
This release adds the following new features:
- [Create subtasks in parenttask swimlane](https://github.com/wekan/wekan/issues/1953).
Thanks to TOSCom-DanielEder.
- [When searching cards in a board, also search from Custom Fields](https://github.com/wekan/wekan/pull/2985).
Thanks to slvrpdr.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.88 2020-04-02 Wekan release
This release adds the following new features:
@@ -14,7 +184,7 @@ and fixes the following bugs:
- [Fix start-wekan.sh MongoDB port to 27017](https://github.com/wekan/wekan/commit/c60a092fc0ed9fe15c417bcb443b1e3e3aaedf7e).
Thanks to Keelan and xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.87 2020-04-01 Wekan release
@@ -54,7 +224,7 @@ This release fixes the following bugs:
@member mention not close card, and disabling clicking of
@member mention](https://github.com/wekan/wekan/commit/b9099a8b7ea6f63c79bdcbb871cb993b2cb7e325).
Thanks to xet7 !
Thanks to above GitHub users for their contributions and translators for their translations.
# v3.85 2020-03-23 Wekan release
+4 -2
View File
@@ -6,7 +6,7 @@ LABEL maintainer="wekan"
# ENV BUILD_DEPS="paxctl"
ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-essential git ca-certificates python3" \
DEBUG=false \
NODE_VERSION=v12.16.1 \
NODE_VERSION=v12.16.2 \
METEOR_RELEASE=1.10-rc.2 \
USE_EDGE=false \
METEOR_EDGE=1.5-beta.17 \
@@ -26,6 +26,7 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
ATTACHMENTS_STORE_PATH="" \
MAX_IMAGE_PIXEL="" \
IMAGE_COMPRESS_RATIO="" \
NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE="" \
BIGEVENTS_PATTERN=NONE \
NOTIFY_DUE_DAYS_BEFORE_AND_AFTER="" \
NOTIFY_DUE_AT_HOUR_OF_DAY="" \
@@ -112,7 +113,8 @@ ENV BUILD_DEPS="apt-utils libarchive-tools gnupg gosu wget curl bzip2 g++ build-
CORS_EXPOSE_HEADERS="" \
DEFAULT_AUTHENTICATION_METHOD="" \
SCROLLINERTIA="0" \
SCROLLAMOUNT="auto"
SCROLLAMOUNT="auto" \
PASSWORD_LOGIN_ENABLED=true
# Copy the app to the image
COPY ${SRC_PATH} /home/wekan/app
+77
View File
@@ -0,0 +1,77 @@
FROM amd64/alpine:3.7 AS builder
# Set the environment variables for builder
ENV QEMU_VERSION=v4.2.0-6 \
QEMU_ARCHITECTURE=aarch64 \
NODE_ARCHITECTURE=linux-arm64 \
NODE_VERSION=v12.16.1 \
WEKAN_VERSION=3.96 \
WEKAN_ARCHITECTURE=arm64
# Install dependencies
RUN apk update && apk add ca-certificates outils-sha1 && \
\
# Download qemu static for our architecture
wget https://github.com/multiarch/qemu-user-static/releases/download/${QEMU_VERSION}/qemu-${QEMU_ARCHITECTURE}-static.tar.gz -O - | tar -xz && \
\
# Download wekan and shasum
wget https://releases.wekan.team/raspi3/wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip && \
wget https://releases.wekan.team/raspi3/SHA256SUMS.txt && \
# Verify wekan
grep wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip SHA256SUMS.txt | sha256sum -c - && \
\
# Unzip wekan
unzip wekan-${WEKAN_VERSION}-${WEKAN_ARCHITECTURE}.zip && \
\
# Download node and shasums
wget https://nodejs.org/dist/${NODE_VERSION}/node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz && \
wget https://nodejs.org/dist/${NODE_VERSION}/SHASUMS256.txt.asc && \
\
# Verify nodejs authenticity
grep node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz SHASUMS256.txt.asc | sha256sum -c - && \
\
# Extract node and remove tar.gz
tar xvzf node-${NODE_VERSION}-${NODE_ARCHITECTURE}.tar.gz
# Build wekan dockerfile
FROM arm64v8/ubuntu:19.10
LABEL maintainer="wekan"
# Set the environment variables (defaults where required)
ENV QEMU_ARCHITECTURE=aarch64 \
NODE_ARCHITECTURE=linux-arm64 \
NODE_VERSION=v12.16.1 \
NODE_ENV=production \
NPM_VERSION=latest \
WITH_API=true \
PORT=8080 \
ROOT_URL=http://localhost \
MONGO_URL=mongodb://127.0.0.1:27017/wekan
# Copy qemu-static to image
COPY --from=builder qemu-${QEMU_ARCHITECTURE}-static /usr/bin
# Copy the app to the image
COPY --from=builder bundle /home/wekan/bundle
# Copy
COPY --from=builder node-${NODE_VERSION}-${NODE_ARCHITECTURE} /opt/nodejs
RUN \
set -o xtrace && \
# Add non-root user wekan
useradd --user-group --system --home-dir /home/wekan wekan && \
\
# Install Node
ln -s /opt/nodejs/bin/node /usr/bin/node && \
ln -s /opt/nodejs/bin/npm /usr/bin/npm && \
mkdir -p /opt/nodejs/lib/node_modules/fibers/.node-gyp /root/.node-gyp/8.16.1 /home/wekan/.config && \
chown wekan --recursive /home/wekan/.config && \
\
# Install Node dependencies
npm install -g npm@${NPM_VERSION}
EXPOSE $PORT
USER wekan
CMD ["node", "/home/wekan/bundle/main.js"]
+2
View File
@@ -1,3 +1,5 @@
[![Gitpod Ready-to-Code](https://img.shields.io/badge/Gitpod-Ready--to--Code-blue?logo=gitpod)](https://gitpod.io/#https://github.com/wekan/wekan)
# Wekan - Open Source kanban
[![Contributors](https://img.shields.io/github/contributors/wekan/wekan.svg "Contributors")](https://github.com/wekan/wekan/graphs/contributors)
+1 -1
View File
@@ -1,5 +1,5 @@
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
appVersion: "v3.88.0"
appVersion: "v3.97.0"
files:
userUploads:
- README.md
+2 -2
View File
@@ -180,7 +180,7 @@ BlazeComponent.extendComponent({
{
// XXX We should use Popup.afterConfirmation here
'click .js-delete-comment'() {
const commentId = this.currentData().commentId;
const commentId = this.currentData().activity.commentId;
CardComments.remove(commentId);
},
'submit .js-edit-comment'(evt) {
@@ -188,7 +188,7 @@ BlazeComponent.extendComponent({
const commentText = this.currentComponent()
.getValue()
.trim();
const commentId = Template.parentData().commentId;
const commentId = Template.parentData().activity.commentId;
if (commentText) {
CardComments.update(commentId, {
$set: {
+1 -1
View File
@@ -7,7 +7,7 @@ BlazeComponent.extendComponent({
return Boards.find(
{ archived: true },
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ }
},
);
},
-16
View File
@@ -33,22 +33,6 @@ Template.boardMenuPopup.events({
'click .js-card-settings': Popup.open('boardCardSettings'),
});
Template.boardMenuPopup.helpers({
exportUrl() {
const params = {
boardId: Session.get('currentBoard'),
};
const queryParams = {
authToken: Accounts._storedLoginToken(),
};
return FlowRouter.path('/api/boards/:boardId/export', params, queryParams);
},
exportFilename() {
const boardId = Session.get('currentBoard');
return `wekan-export-board-${boardId}.json`;
},
});
Template.boardChangeTitlePopup.events({
submit(event, templateInstance) {
const newTitle = templateInstance
+4 -4
View File
@@ -1,10 +1,10 @@
template(name="boardList")
.wrapper
ul.board-list.clearfix
ul.board-list.clearfix.js-boards
li.js-add-board
a.board-list-item.label {{_ 'add-board'}}
each boards
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass)
li(class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board
if isInvited
.board-list-item
span.details
@@ -39,7 +39,7 @@ template(name="boardList")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
else if currentUser.isBoardAdmin
else if isAdministrable
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
@@ -55,7 +55,7 @@ template(name="boardList")
title="{{_ 'archive-board'}}")
template(name="boardListHeaderBar")
h1 {{_ 'my-boards'}}
h1 {{_ title }}
.board-header-btns.right
a.board-header-btn.js-open-archived-board
i.fa.fa-archive
+70 -8
View File
@@ -1,4 +1,5 @@
const subManager = new SubsManager();
const { calculateIndex, enableClickOnTouch } = Utils;
Template.boardListHeaderBar.events({
'click .js-open-archived-board'() {
@@ -7,6 +8,9 @@ Template.boardListHeaderBar.events({
});
Template.boardListHeaderBar.helpers({
title() {
return FlowRouter.getRouteName() == 'home' ? 'my-boards' : 'public';
},
templatesBoardId() {
return Meteor.user() && Meteor.user().getTemplatesBoardId();
},
@@ -20,20 +24,78 @@ BlazeComponent.extendComponent({
Meteor.subscribe('setting');
},
boards() {
return Boards.find(
{
archived: false,
'members.userId': Meteor.userId(),
type: 'board',
onRendered() {
const self = this;
function userIsAllowedToMove() {
return Meteor.user();
}
const itemsSelector = '.js-board:not(.placeholder)';
const $boards = this.$('.js-boards');
$boards.sortable({
connectWith: '.js-boards',
tolerance: 'pointer',
appendTo: '.board-list',
helper: 'clone',
distance: 7,
items: itemsSelector,
placeholder: 'board-wrapper placeholder',
start(evt, ui) {
ui.helper.css('z-index', 1000);
ui.placeholder.height(ui.helper.height());
EscapeActions.executeUpTo('popup-close');
},
{ sort: ['title'] },
);
stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following card -- if any.
const prevBoardDom = ui.item.prev('.js-board').get(0);
const nextBoardBom = ui.item.next('.js-board').get(0);
const sortIndex = calculateIndex(prevBoardDom, nextBoardBom, 1);
const boardDomElement = ui.item.get(0);
const board = Blaze.getData(boardDomElement);
// Normally the jquery-ui sortable library moves the dragged DOM element
// to its new position, which disrupts Blaze reactive updates mechanism
// (especially when we move the last card of a list, or when multiple
// users move some cards at the same time). To prevent these UX glitches
// we ask sortable to gracefully cancel the move, and to put back the
// DOM in its initial state. The card move is then handled reactively by
// Blaze with the below query.
$boards.sortable('cancel');
board.move(sortIndex.base);
},
});
// ugly touch event hotfix
enableClickOnTouch(itemsSelector);
// Disable drag-dropping if the current user is not a board member or is comment only
this.autorun(() => {
$boards.sortable('option', 'disabled', !userIsAllowedToMove());
});
},
boards() {
let query = {
archived: false,
type: 'board',
};
if (FlowRouter.getRouteName() == 'home')
query['members.userId'] = Meteor.userId();
else query.permission = 'public';
return Boards.find(query, { sort: { sort: 1 /* boards default sorting */ } });
},
isStarred() {
const user = Meteor.user();
return user && user.hasStarred(this.currentData()._id);
},
isAdministrable() {
const user = Meteor.user();
return user && user.isBoardAdmin(this.currentData()._id);
},
hasOvertimeCards() {
subManager.subscribe('board', this.currentData()._id, false);
+14 -1
View File
@@ -11,6 +11,19 @@ $spaceBetweenTiles = 16px
box-sizing: border-box
position: relative
&.placeholder:after
content: '';
display: block;
background: darken(white, 20%)
border-radius: 3px;
height: 106px;
margin: 8px;
&.ui-sortable-helper
cursor: grabbing
transform: rotate(4deg)
display: block !important
&.starred
.fa-star,
.fa-star-o
@@ -183,7 +196,7 @@ $spaceBetweenTiles = 16px
overflow: scroll
li
width: 50%
width: 50%
.board-list-item
overflow: hidden
+61 -1
View File
@@ -32,7 +32,7 @@ template(name="cardDetails")
// else
{{_ 'top-level-card'}}
if isLinkedCard
h3.linked-card-location
a.linked-card-location.js-go-to-linked-card
+viewer
| {{getBoardTitle}} > {{getTitle}}
@@ -199,6 +199,24 @@ template(name="cardDetails")
+viewer
= getAssignedBy
if getVoteQuestion
hr
.vote-title
h3
i.fa.fa-thumbs-up
card-details-item-title {{_ 'vote-question'}}
.vote-result
if votePublic
a.card-label.card-label-green.js-show-positive-votes {{ voteCountPositive }}
a.card-label.card-label-red.js-show-negative-votes {{ voteCountNegative }}
else
.card-label.card-label-green {{ voteCountPositive }}
.card-label.card-label-red {{ voteCountNegative }}
+viewer
= getVoteQuestion
button.card-details-green.js-vote.js-vote-positive(class="{{#if voteState}}voted{{/if}}") {{_ 'vote-for-it'}}
button.card-details-red.js-vote.js-vote-negative(class="{{#if $eq voteState false}}voted{{/if}}") {{_ 'vote-against'}}
//- XXX We should use "editable" to avoid repetiting ourselves
if canModifyCard
unless currentUser.isWorker
@@ -315,6 +333,16 @@ template(name="cardDetailsActionsPopup")
//li: a.js-members {{_ 'card-edit-members'}}
//li: a.js-labels {{_ 'card-edit-labels'}}
//li: a.js-attachments {{_ 'card-edit-attachments'}}
if getVoteQuestion
li
a.js-cancel-voting
i.fa.fa-thumbs-up
| {{_ 'card-cancel-voting'}}
else
li
a.js-start-voting
i.fa.fa-thumbs-up
| {{_ 'card-start-voting'}}
li
a.js-custom-fields
i.fa.fa-list-alt
@@ -538,3 +566,35 @@ template(name="cardDeletePopup")
unless archived
p {{_ "card-delete-suggest-archive"}}
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
template(name="cardStartVotingPopup")
form.edit-vote-question
.fields
label(for="vote") {{_ 'vote-question'}}
input.js-vote-field#vote(type="text" name="vote" value="{{card.getVoteQuestion}}" autofocus)
label(for="vote-public") {{_ 'vote-public'}}
a.js-toggle-vote-public
.materialCheckBox#vote-public(name="vote-public")
button.primary.confirm.js-submit {{_ 'save'}}
//- button.js-remove-color.negate.wide.right {{_ 'delete'}}
template(name="positiveVoteMembersPopup")
ul.pop-over-list.js-card-member-list
each m in voteMemberPositive
li.item
a.name
+userAvatar(userId=m._id)
span.full-name
= m.profile.fullname
| (<span class="username">{{ m.username }}</span>)
template(name="negativeVoteMembersPopup")
ul.pop-over-list.js-card-member-list
each m in voteMemberNegative
li.item
a.name
+userAvatar(userId=m._id)
span.full-name
= m.profile.fullname
| (<span class="username">{{ m.username }}</span>)
+86 -6
View File
@@ -38,6 +38,38 @@ BlazeComponent.extendComponent({
Meteor.subscribe('unsaved-edits');
},
voteState() {
const card = this.currentData();
const userId = Meteor.userId();
let state;
if (card.vote) {
if (card.vote.positive) {
state = _.contains(card.vote.positive, userId);
if (state === true) return true;
}
if (card.vote.negative) {
state = _.contains(card.vote.negative, userId);
if (state === true) return false;
}
}
return null;
},
votePublic() {
const card = this.currentData();
if (card.vote)
return card.vote.public
return null
},
voteCountPositive() {
const card = this.currentData();
if (card.vote && card.vote.positive) return card.vote.positive.length;
return null;
},
voteCountNegative() {
const card = this.currentData();
if (card.vote && card.vote.negative) return card.vote.negative.length;
return null;
},
isWatching() {
const card = this.currentData();
return card.findWatcher(Meteor.userId());
@@ -347,6 +379,9 @@ BlazeComponent.extendComponent({
this.data().setRequestedBy('');
}
},
'click .js-go-to-linked-card'() {
Utils.goCardId(this.data().linkedId)
},
'click .js-member': Popup.open('cardMember'),
'click .js-add-members': Popup.open('cardMembers'),
'click .js-assignee': Popup.open('cardAssignee'),
@@ -356,6 +391,8 @@ BlazeComponent.extendComponent({
'click .js-start-date': Popup.open('editCardStartDate'),
'click .js-due-date': Popup.open('editCardDueDate'),
'click .js-end-date': Popup.open('editCardEndDate'),
'click .js-show-positive-votes':Popup.open('positiveVoteMembers'),
'click .js-show-negative-votes': Popup.open('negativeVoteMembers'),
'mouseenter .js-card-details'() {
const parentComponent = this.parentComponent().parentComponent();
//on mobile view parent is Board, not BoardBody.
@@ -379,6 +416,18 @@ BlazeComponent.extendComponent({
'click #toggleButton'() {
Meteor.call('toggleSystemMessages');
},
'click .js-vote'(e) {
const forIt = $(e.target).hasClass('js-vote-positive');
let newState = null;
if (
this.voteState() == null ||
(this.voteState() == false && forIt) ||
(this.voteState() == true && !forIt)
) {
newState = forIt;
}
this.data().setVote(Meteor.userId(), newState);
},
},
];
},
@@ -560,6 +609,7 @@ Template.cardDetailsActionsPopup.events({
'click .js-assignees': Popup.open('cardAssignees'),
'click .js-labels': Popup.open('cardLabels'),
'click .js-attachments': Popup.open('cardAttachments'),
'click .js-start-voting': Popup.open('cardStartVoting'),
'click .js-custom-fields': Popup.open('cardCustomFields'),
'click .js-received-date': Popup.open('editCardReceivedDate'),
'click .js-start-date': Popup.open('editCardStartDate'),
@@ -570,6 +620,11 @@ Template.cardDetailsActionsPopup.events({
'click .js-copy-card': Popup.open('copyCard'),
'click .js-copy-checklist-cards': Popup.open('copyChecklistToManyCards'),
'click .js-set-card-color': Popup.open('setCardColor'),
'click .js-cancel-voting'(event) {
event.preventDefault();
this.unsetVote();
Popup.close();
},
'click .js-move-card-to-top'(event) {
event.preventDefault();
const minOrder = _.min(
@@ -603,7 +658,7 @@ Template.cardDetailsActionsPopup.events({
},
});
Template.editCardTitleForm.onRendered(function() {
Template.editCardTitleForm.onRendered(function () {
autosize(this.$('.js-edit-card-title'));
});
@@ -617,7 +672,7 @@ Template.editCardTitleForm.events({
},
});
Template.editCardRequesterForm.onRendered(function() {
Template.editCardRequesterForm.onRendered(function () {
autosize(this.$('.js-edit-card-requester'));
});
@@ -630,7 +685,7 @@ Template.editCardRequesterForm.events({
},
});
Template.editCardAssignerForm.onRendered(function() {
Template.editCardAssignerForm.onRendered(function () {
autosize(this.$('.js-edit-card-assigner'));
});
@@ -672,7 +727,7 @@ BlazeComponent.extendComponent({
_id: { $ne: Meteor.user().getTemplatesBoardId() },
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
return boards;
@@ -770,7 +825,7 @@ Template.copyChecklistToManyCardsPopup.events({
// copy subtasks
cursor = Cards.find({ parentId: oldId });
cursor.forEach(function() {
cursor.forEach(function () {
'use strict';
const subtask = arguments[0];
subtask.parentId = _id;
@@ -848,7 +903,7 @@ BlazeComponent.extendComponent({
},
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
return boards;
@@ -945,6 +1000,31 @@ BlazeComponent.extendComponent({
},
}).register('cardMorePopup');
BlazeComponent.extendComponent({
onCreated() {
this.currentCard = this.currentData();
this.voteQuestion = new ReactiveVar(this.currentCard.voteQuestion);
},
events() {
return [
{
'submit .edit-vote-question'(evt) {
evt.preventDefault();
const voteQuestion = evt.target.vote.value;
const publicVote = $('#vote-public').hasClass('is-checked');
this.currentCard.setVoteQuestion(voteQuestion, publicVote);
Popup.close();
},
'click a.js-toggle-vote-public'(event) {
event.preventDefault();
$('#vote-public').toggleClass('is-checked');
},
},
];
},
}).register('cardStartVotingPopup');
// Close the card details pane by pressing escape
EscapeActions.register(
'detailsPane',
+14 -3
View File
@@ -94,17 +94,18 @@ avatar-radius = 50%
animation: flexGrowIn 0.1s
box-shadow: 0 0 7px 0 darken(white, 30%)
transition: flex-basis 0.1s
box-sizing: border-box
.mCustomScrollBox
padding-left: 0
.ps-scrollbar-y-rail
pointer-event: all
position: absolute;
position: absolute
.card-details-canvas
width: 470px
padding-left: 20px;
padding-left: 20px
.card-details-header
margin: 0 -20px 5px
@@ -241,7 +242,7 @@ input[type="submit"].attachment-add-link-submit
.card-details-canvas
width: 100%
padding-left: 0px;
padding-left: 0px
.card-details-header
.close-card-details
@@ -330,3 +331,13 @@ card-details-color(background, color...)
.card-details-indigo
card-details-color(#4b0082, #ffffff) //White text for better visibility
.voted
opacity: .7
.vote-title
display: flex
justify-content: space-between
.vote-result
display: flex
.js-show-positive-votes
cursor: pointer
+2 -1
View File
@@ -88,7 +88,8 @@ template(name="checklistItems")
template(name='checklistItemDetail')
.js-checklist-item.checklist-item
if canModifyCard
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
.check-box-container
.check-box.materialCheckBox(class="{{#if item.isFinished }}is-checked{{/if}}")
.item-title.js-open-inlined-form.is-editable(class="{{#if item.isFinished }}is-checked{{/if}}")
+viewer
= item.title
+1 -1
View File
@@ -250,7 +250,7 @@ BlazeComponent.extendComponent({
events() {
return [
{
'click .js-checklist-item .check-box': this.toggleItem,
'click .js-checklist-item .check-box-container': this.toggleItem,
},
];
},
+4 -1
View File
@@ -113,6 +113,9 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
&:hover
background-color: darken(white, 8%)
.check-box-container
padding-right: 1px;
.check-box
margin: 0.1em 0 0 0;
&.is-checked
@@ -121,7 +124,7 @@ textarea.js-add-checklist-item, textarea.js-edit-checklist-item
.item-title
flex: 1
padding-left: 10px;
margin-left: 10px;
&.is-checked
color: #8c8c8c
font-style: italic
+2
View File
@@ -158,6 +158,8 @@
.edit-labels-pop-over
margin-bottom: 8px
.card-label .viewer p
margin: 0
.edit-labels-pop-over .shortcut
display: inline-block
+4
View File
@@ -100,6 +100,10 @@ template(name="minicard")
if getDescription
.badge.badge-state-image-only(title=getDescription)
span.badge-icon.fa.fa-align-left
if getVoteQuestion
.badge.badge-state-image-only(title=getVoteQuestion)
span.badge-icon.fa.fa-thumbs-up
span.badge-icon.fa.fa-thumbs-down
if attachments.count
.badge
span.badge-icon.fa.fa-paperclip
+16 -1
View File
@@ -20,7 +20,22 @@ BlazeComponent.extendComponent({
const crtBoard = Boards.findOne(card.boardId);
const targetBoard = crtBoard.getDefaultSubtasksBoard();
const listId = targetBoard.getDefaultSubtasksListId();
const swimlaneId = targetBoard.getDefaultSwimline()._id;
//Get the full swimlane data for the parent task.
const parentSwimlane = Swimlanes.findOne({
boardId: crtBoard._id,
_id: card.swimlaneId,
});
//find the swimlane of the same name in the target board.
const targetSwimlane = Swimlanes.findOne({
boardId: targetBoard._id,
title: parentSwimlane.title,
});
//If no swimlane with a matching title exists in the target board, fall back to the default swimlane.
const swimlaneId =
targetSwimlane === undefined
? targetBoard.getDefaultSwimline()._id
: targetSwimlane._id;
if (title) {
const _id = Cards.insert({
-3
View File
@@ -15,9 +15,6 @@ template(name="importTextarea")
p: label(for='import-textarea') {{_ instruction}} {{_ 'import-board-instruction-about-errors'}}
textarea.js-import-json(placeholder="{{_ 'import-json-placeholder'}}" autofocus)
| {{jsonText}}
if isSandstorm
h1.warning {{_ 'import-sandstorm-backup-warning'}}
p.warning {{_ 'import-sandstorm-warning'}}
input.primary.wide(type="submit" value="{{_ 'import'}}")
template(name="importMapMembers")
+2 -2
View File
@@ -411,7 +411,7 @@ BlazeComponent.extendComponent({
type: 'board',
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
return boards;
@@ -597,7 +597,7 @@ BlazeComponent.extendComponent({
type: 'board',
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
return boards;
+5
View File
@@ -24,6 +24,11 @@ template(name="header")
a(href="{{pathFor 'home'}}")
span.fa.fa-home
| {{_ 'all-boards'}}
li.separator -
li
a(href="{{pathFor 'public'}}")
span.fa.fa-globe
| {{_ 'public'}}
each currentUser.starredBoards
li.separator -
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
+1 -1
View File
@@ -127,7 +127,7 @@
&.current
color: darken(white, 5%)
&:first-child .fa-home
&:first-child .fa-home,&:nth-child(3) .fa-globe
margin-right: 5px
a.js-create-board
+7
View File
@@ -31,6 +31,11 @@ Template.userFormsLayout.onCreated(function() {
return this.stop();
},
});
Meteor.call('isPasswordLoginDisabled', (_, result) => {
if (result) {
$('.at-pwd-form').hide();
}
});
});
Template.userFormsLayout.onRendered(() => {
@@ -73,6 +78,8 @@ Template.userFormsLayout.helpers({
name = 'Igbo';
} else if (lang.name === 'oc') {
name = 'Occitan';
} else if (lang.name === '繁体中文(台湾)') {
name = '繁體中文(台灣)';
}
return { tag, name };
}).sort(function(a, b) {
@@ -14,3 +14,7 @@ template(name='notificationsDrawer')
+notification(activityData=activity index=dbIndex read=read)
if($gt unreadNotifications 0)
a.all-read {{_ 'mark-all-as-read'}}
if ($and ($.Session.get 'showReadNotifications') ($gt readNotifications 0))
a.remove-read
i.fa.fa-trash
| {{_ 'remove-all-read'}}
@@ -16,6 +16,13 @@ Template.notificationsDrawer.helpers({
transformedProfile() {
return Users.findOne(Meteor.userId());
},
readNotifications() {
const readNotifications = _.filter(
Meteor.user().profile.notifications,
v => !!v.read,
);
return readNotifications.length;
},
});
Template.notificationsDrawer.events({
@@ -35,4 +42,12 @@ Template.notificationsDrawer.events({
'click .toggle-read'() {
Session.set('showReadNotifications', !Session.get('showReadNotifications'));
},
'click .remove-read'() {
const user = Meteor.user();
for (const notification of user.profile.notifications) {
if (notification.read) {
user.removeNotification(notification.activity);
}
}
},
});
@@ -10,8 +10,7 @@ section#notifications-drawer
border-radius: 2px
max-height: calc(100vh - 28px - 36px)
color: black
padding-top 36px;
overflow: scroll
padding-top 36px
a:hover
color: belize !important
@@ -45,13 +44,26 @@ section#notifications-drawer
line-height: 24px
opacity 1
.all-read
.all-read,
.remove-read
color belize
background-color: #fafafa
margin 8px 16px 12px
display inline-block
.remove-read
float right
&:hover
color #eb4646 !important
i.fa
color inherit
ul.notifications
display: block
padding: 0px 16px
margin: 0
height: calc(100vh - 102px)
overflow-y: scroll
@@ -11,7 +11,7 @@ BlazeComponent.extendComponent({
},
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
return boards;
+1 -1
View File
@@ -48,7 +48,7 @@ BlazeComponent.extendComponent({
'members.isAdmin': true,
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
},
+11 -9
View File
@@ -298,10 +298,11 @@ template(name="boardMenuPopup")
if currentUser.isBoardAdmin
hr
ul.pop-over-list
li
a(href="{{exportUrl}}", download="{{exportFilename}}")
i.fa.fa-share-alt
| {{_ 'export-board'}}
if withApi
li
a(href="{{exportUrl}}", download="{{exportFilename}}")
i.fa.fa-share-alt
| {{_ 'export-board'}}
li
a.js-outgoing-webhooks
i.fa.fa-globe
@@ -326,11 +327,12 @@ template(name="boardMenuPopup")
if isSandstorm
hr
ul.pop-over-list
li
a(href="{{exportUrl}}", download="{{exportFilename}}")
i.fa.fa-share-alt
i.fa.fa-sign-out
| {{_ 'export-board'}}
if withApi
li
a(href="{{exportUrl}}", download="{{exportFilename}}")
i.fa.fa-share-alt
i.fa.fa-sign-out
| {{_ 'export-board'}}
li
a.js-import-board
i.fa.fa-share-alt
+16 -5
View File
@@ -196,14 +196,14 @@ Template.boardMenuPopup.events({
},
'click .js-change-board-color': Popup.open('boardChangeColor'),
'click .js-change-language': Popup.open('changeLanguage'),
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() {
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function () {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
currentBoard.archive();
// XXX We should have some kind of notification on top of the page to
// confirm that the board was successfully archived.
FlowRouter.go('home');
}),
'click .js-delete-board': Popup.afterConfirm('deleteBoard', function() {
'click .js-delete-board': Popup.afterConfirm('deleteBoard', function () {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
Popup.close();
Boards.remove(currentBoard._id);
@@ -215,7 +215,18 @@ Template.boardMenuPopup.events({
'click .js-card-settings': Popup.open('boardCardSettings'),
});
Template.boardMenuPopup.onCreated(function () {
this.apiEnabled = new ReactiveVar(false);
Meteor.call('_isApiEnabled', (e, result) => {
this.apiEnabled.set(result)
})
})
Template.boardMenuPopup.helpers({
withApi() {
return Template.instance().apiEnabled.get()
},
exportUrl() {
const params = {
boardId: Session.get('currentBoard'),
@@ -237,7 +248,7 @@ Template.memberPopup.events({
Popup.close();
},
'click .js-change-role': Popup.open('changePermissions'),
'click .js-remove-member': Popup.afterConfirm('removeMember', function() {
'click .js-remove-member': Popup.afterConfirm('removeMember', function () {
const boardId = Session.get('currentBoard');
const memberId = this.userId;
Cards.find({ boardId, members: memberId }).forEach(card => {
@@ -499,7 +510,7 @@ BlazeComponent.extendComponent({
'members.userId': Meteor.userId(),
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
},
@@ -677,7 +688,7 @@ BlazeComponent.extendComponent({
'members.userId': Meteor.userId(),
},
{
sort: ['title'],
sort: { sort: 1 /* boards default sorting */ },
},
);
},
@@ -45,6 +45,24 @@ template(name="filterSidebar")
if Filter.members.isSelected _id
i.fa.fa-check
hr
ul.sidebar-list
li(class="{{#if Filter.assignees.isSelected undefined}}active{{/if}}")
a.name.js-toggle-assignee-filter
span.sidebar-list-item-description
| {{_ 'filter-no-assignee'}}
if Filter.assignees.isSelected undefined
i.fa.fa-check
each currentBoard.activeMembers
with getUser userId
li(class="{{#if Filter.assignees.isSelected _id}}active{{/if}}")
a.name.js-toggle-assignee-filter
+userAvatar(userId=this._id)
span.sidebar-list-item-description
= profile.fullname
| (<span class="username">{{ username }}</span>)
if Filter.assignees.isSelected _id
i.fa.fa-check
hr
ul.sidebar-list
li(class="{{#if Filter.customFields.isSelected undefined}}active{{/if}}")
a.name.js-toggle-custom-fields-filter
@@ -18,6 +18,11 @@ BlazeComponent.extendComponent({
Filter.members.toggle(this.currentData()._id);
Filter.resetExceptions();
},
'click .js-toggle-assignee-filter'(evt) {
evt.preventDefault();
Filter.assignees.toggle(this.currentData()._id);
Filter.resetExceptions();
},
'click .js-toggle-archive-filter'(evt) {
evt.preventDefault();
Filter.archive.toggle(this.currentData()._id);
+2
View File
@@ -166,6 +166,8 @@ Template.changeLanguagePopup.helpers({
name = 'Igbo';
} else if (lang.name === 'oc') {
name = 'Occitan';
} else if (lang.name === '繁体中文(台湾)') {
name = '繁體中文(台灣)';
}
return { tag, name };
}).sort(function(a, b) {
+9 -1
View File
@@ -459,13 +459,21 @@ Filter = {
// before changing the schema.
labelIds: new SetFilter(),
members: new SetFilter(),
assignees: new SetFilter(),
archive: new SetFilter(),
hideEmpty: new SetFilter(),
customFields: new SetFilter('_id'),
advanced: new AdvancedFilter(),
lists: new AdvancedFilter(), // we need the ability to filter list by name as well
_fields: ['labelIds', 'members', 'archive', 'hideEmpty', 'customFields'],
_fields: [
'labelIds',
'members',
'assignees',
'archive',
'hideEmpty',
'customFields',
],
// We don't filter cards that have been added after the last filter change. To
// implement this we keep the id of these cards in this `_exceptions` fields
+21
View File
@@ -26,6 +26,27 @@ FlowRouter.route('/', {
},
});
FlowRouter.route('/public', {
name: 'public',
triggersEnter: [AccountsTemplates.ensureSignedIn],
action() {
Session.set('currentBoard', null);
Session.set('currentList', null);
Session.set('currentCard', null);
Filter.reset();
EscapeActions.executeAll();
Utils.manageCustomUI();
Utils.manageMatomo();
BlazeLayout.render('defaultLayout', {
headerBar: 'boardListHeaderBar',
content: 'boardList',
});
},
});
FlowRouter.route('/b/:id/:slug', {
name: 'board',
action(params) {
+8
View File
@@ -254,6 +254,11 @@ services:
#-MAX_IMAGE_PIXEL=1024
#-IMAGE_COMPRESS_RATIO=80
#---------------------------------------------------------------
# ==== NOTIFICATION TRAY AFTER READ DAYS BEFORE REMOVE =====
# Number of days after a notification is read before we remove it.
# Default: 2
#- NOTIFICATION_TRAY_AFTER_READ_DAYS_BEFORE_REMOVE=2
#---------------------------------------------------------------
# ==== BIGEVENTS DUE ETC NOTIFICATIONS =====
# https://github.com/wekan/wekan/pull/2541
# Introduced a system env var BIGEVENTS_PATTERN default as "NONE",
@@ -593,6 +598,9 @@ services:
# example : LOGOUT_ON_MINUTES=55
#- LOGOUT_ON_MINUTES=
#-------------------------------------------------------------------
# Hide password login form
# - PASSWORD_LOGIN_ENABLED=true
#-------------------------------------------------------------------
depends_on:
- wekandb
+7
View File
@@ -56,3 +56,10 @@ mongodb-replicaset:
This section controls the scale of the MongoDB redundant Replica Set.
**replicas:** This is the number of MongoDB instances to include in the set. You can set this to 1 for a single server - this will still allow you to scale-up later with a helm upgrade.
### Install OCP route
If you use this chart to deploy Wekan on an OCP cluster, you can create route instead of ingress with following command:
``` bash
$ helm template --set route.enabled=true,ingress.enabled=false values.yaml . | oc apply -f-
```
+6
View File
@@ -37,6 +37,12 @@ spec:
value: {{ .Values.root_url | default "https://wekan.local" | quote }}
- name: MONGO_URL
value: "{{ template "mongodb-replicaset.url" . }}"
{{- range $key := .Values.env }}
{{- if .value }}
- name: {{ .name }}
value: {{ .value | quote }}
{{- end }}
{{- end }}
livenessProbe:
httpGet:
path: /
+23
View File
@@ -0,0 +1,23 @@
{{- if .Values.route.enabled -}}
{{- $fullName := include "wekan.fullname" . -}}
apiVersion: route.openshift.io/v1
kind: Route
metadata:
annotations:
haproxy.router.openshift.io/timeout: 4m
openshift.io/host.generated: "true"
labels:
app: {{ template "wekan.name" . }}
service: {{ template "wekan.name" . }}
name: {{ template "wekan.name" . }}
spec:
port:
targetPort: http
tls:
termination: edge
to:
kind: Service
name: {{ template "wekan.name" . }}
weight: 100
wildcardPolicy: None
{{- end }}
+4
View File
@@ -2,6 +2,10 @@
apiVersion: v1
kind: ServiceAccount
metadata:
{{- if .Values.serviceAccounts.annotations }}
annotations:
{{ .Values.serviceAccounts.annotations | indent 4}}
{{- end }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
+8 -2
View File
@@ -8,6 +8,7 @@
serviceAccounts:
create: true
name: ""
annotations: ""
## Wekan image configuration
##
@@ -29,7 +30,9 @@ credentials:
## Specify additional environmental variables for the Deployment
##
env: {}
env:
- name: ""
value: ""
service:
type: NodePort
@@ -59,7 +62,10 @@ ingress:
# hosts:
# - wekan-example.local
resources:
route:
enabled: false
resources:
requests:
memory: 128Mi
cpu: 300m
+37 -28
View File
@@ -74,12 +74,12 @@
"activity-checklist-completed-card": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted-card": "uncompleted the checklist %s",
"activity-editComment": "edited comment %s",
"activity-deleteComment": "deleted comment %s",
"activity-deleteComment": "تعليق محذوف %s",
"add-attachment": "إضافة مرفق",
"add-board": "إضافة لوحة",
"add-card": "إضافة بطاقة",
"add-swimlane": "Add Swimlane",
"add-subtask": "Add Subtask",
"add-subtask": "إضافة مهمة فرعية",
"add-checklist": "إضافة قائمة تدقيق",
"add-checklist-item": "إضافة عنصر إلى قائمة التحقق",
"add-cover": "إضافة غلاف",
@@ -111,8 +111,8 @@
"restore-board": "استعادة اللوحة",
"no-archived-boards": "لا توجد لوحات في الأرشيف.",
"archives": "أرشيف",
"template": "Template",
"templates": "Templates",
"template": "نموذج",
"templates": "نماذج",
"assign-member": "تعيين عضو",
"attached": "أُرفق)",
"attachment": "مرفق",
@@ -152,6 +152,8 @@
"card-spent": "امضى وقتا",
"card-edit-attachments": "تعديل المرفقات",
"card-edit-custom-fields": "تعديل الحقل المعدل",
"card-start-voting": "ابدأ التصويت",
"card-cancel-voting": "حذف التصويت وجميع الأصوات",
"card-edit-labels": "تعديل العلامات",
"card-edit-members": "تعديل الأعضاء",
"card-labels-title": "تعديل علامات البطاقة.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "إرفاق من",
"cardCustomField-datePopup-title": "تغير التاريخ",
"cardCustomFieldsPopup-title": "تعديل الحقل المعدل",
"cardStartVotingPopup-title": "ابدأ تصويت",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "مع",
"vote-against": "ضد",
"cardDeletePopup-title": "حذف البطاقة ?",
"cardDetailsActionsPopup-title": "إجراءات على البطاقة",
"cardLabelsPopup-title": "علامات",
@@ -183,7 +192,7 @@
"changePasswordPopup-title": "تغيير كلمة المرور",
"changePermissionsPopup-title": "تعديل الصلاحيات",
"changeSettingsPopup-title": "تغيير الاعدادات",
"subtasks": "Subtasks",
"subtasks": "المهمات الفرعية",
"checklists": "قوائم التّدقيق",
"click-to-star": "اضغط لإضافة اللوحة للمفضلة.",
"click-to-unstar": "اضغط لحذف اللوحة من المفضلة.",
@@ -194,9 +203,9 @@
"color-black": "black",
"color-blue": "blue",
"color-crimson": "crimson",
"color-darkgreen": "darkgreen",
"color-gold": "gold",
"color-gray": "gray",
"color-darkgreen": "اخضر غامق",
"color-gold": "ذهبي",
"color-gray": "رمادي",
"color-green": "green",
"color-indigo": "indigo",
"color-lime": "lime",
@@ -211,17 +220,17 @@
"color-purple": "purple",
"color-red": "red",
"color-saddlebrown": "saddlebrown",
"color-silver": "silver",
"color-silver": "فضي",
"color-sky": "sky",
"color-slateblue": "slateblue",
"color-white": "white",
"color-white": "أبيض",
"color-yellow": "yellow",
"unset-color": "Unset",
"comment": "تعليق",
"comment-placeholder": "أكتب تعليق",
"comment-only": "التعليق فقط",
"comment-only-desc": "يمكن التعليق على بطاقات فقط.",
"no-comments": "No comments",
"no-comments": "لا يوجد تعليقات",
"no-comments-desc": "Can not see comments and activities.",
"worker": "Worker",
"worker-desc": "Can only move cards, assign itself to card and comment.",
@@ -239,8 +248,8 @@
"createBoardPopup-title": "إنشاء لوحة",
"chooseBoardSourcePopup-title": "استيراد لوحة",
"createLabelPopup-title": "إنشاء علامة",
"createCustomField": "Create Field",
"createCustomFieldPopup-title": "Create Field",
"createCustomField": "انشاء حقل",
"createCustomFieldPopup-title": "انشاء حقل",
"current": "الحالي",
"custom-field-delete-pop": "There is no undo. This will remove this custom field from all cards and destroy its history.",
"custom-field-checkbox": "Checkbox",
@@ -250,8 +259,8 @@
"custom-field-dropdown-options": "List Options",
"custom-field-dropdown-options-placeholder": "Press enter to add more options",
"custom-field-dropdown-unknown": "(unknown)",
"custom-field-number": "Number",
"custom-field-text": "Text",
"custom-field-number": "رقم",
"custom-field-text": "نص",
"custom-fields": "Custom Fields",
"date": "تاريخ",
"decline": "Decline",
@@ -319,6 +328,7 @@
"filter-clear": "مسح التصفية",
"filter-no-label": "لا يوجد ملصق",
"filter-no-member": "ليس هناك أي عضو",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -333,13 +343,11 @@
"headerBarCreateBoardPopup-title": "إنشاء لوحة",
"home": "الرئيسية",
"import": "Import",
"link": "Link",
"link": "رابط",
"import-board": "استيراد لوحة",
"import-board-c": "استيراد لوحة",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "من تريلو",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
@@ -440,7 +448,7 @@
"save": "حفظ",
"search": "بحث",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "اختيار اللون",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -466,15 +474,15 @@
"this-board": "هذه اللوحة",
"this-card": "هذه البطاقة",
"spent-time-hours": "Spent time (hours)",
"overtime-hours": "Overtime (hours)",
"overtime": "Overtime",
"overtime-hours": "وقت اضافي (ساعات)",
"overtime": "وقت اضافي",
"has-overtime-cards": "Has overtime cards",
"has-spenttime-cards": "Has spent time cards",
"time": "الوقت",
"title": "عنوان",
"tracking": "تتبع",
"tracking-info": "You will be notified of any changes to those cards you are involved as creator or member.",
"type": "Type",
"type": "النوع",
"unassign-member": "إلغاء تعيين العضو",
"unsaved-description": "لديك وصف غير محفوظ",
"unwatch": "غير مُشاهد",
@@ -548,7 +556,7 @@
"OS_Totalmem": "الذاكرة الكلية لنظام التشغيل",
"OS_Type": "نوع نظام التشغيل",
"OS_Uptime": "مدة تشغيل نظام التشغيل",
"days": "days",
"days": "أيام",
"hours": "الساعات",
"minutes": "الدقائق",
"seconds": "الثواني",
@@ -562,17 +570,17 @@
"accounts-allowUserNameChange": "Allow Username Change",
"createdAt": "Created at",
"verified": "Verified",
"active": "Active",
"active": "نشط",
"card-received": "Received",
"card-received-on": "Received on",
"card-end": "End",
"card-end-on": "Ends on",
"editCardReceivedDatePopup-title": "Change received date",
"editCardEndDatePopup-title": "Change end date",
"setCardColorPopup-title": "Set color",
"setCardActionsColorPopup-title": "Choose a color",
"setSwimlaneColorPopup-title": "Choose a color",
"setListColorPopup-title": "Choose a color",
"setCardColorPopup-title": "حدد اللون",
"setCardActionsColorPopup-title": "اختر لوناً",
"setSwimlaneColorPopup-title": "اختر لوناً",
"setListColorPopup-title": "اختر لوناً",
"assigned-by": "Assigned By",
"requested-by": "Requested By",
"board-delete-notice": "Deleting is permanent. You will lose all lists, cards and actions associated with this board.",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Изработено време",
"card-edit-attachments": "Промени прикачените файлове",
"card-edit-custom-fields": "Промени собствените полета",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Промени етикетите",
"card-edit-members": "Промени членовете",
"card-labels-title": "Промени етикетите за картата.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Прикачи от",
"cardCustomField-datePopup-title": "Промени датата",
"cardCustomFieldsPopup-title": "Промени собствените полета",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Желаете да изтриете картата?",
"cardDetailsActionsPopup-title": "Опции",
"cardLabelsPopup-title": "Етикети",
@@ -319,6 +328,7 @@
"filter-clear": "Премахване на филтрите",
"filter-no-label": "без етикет",
"filter-no-member": "без член",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Няма Собствени полета",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Импортирай Табло",
"import-board-title-trello": "Импорт на табло от Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Импортирането ще изтрие всичката налична информация в таблото и ще я замени с нова.",
"from-trello": "От Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Запази",
"search": "Търсене",
"rules": "Правила",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Избери цвят",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Diverkañ ar gartenn ?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Temps Dedicat",
"card-edit-attachments": "Edita arxius adjunts",
"card-edit-custom-fields": "Editar camps personalitzats",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edita etiquetes",
"card-edit-members": "Edita membres",
"card-labels-title": "Canvia les etiquetes de la fitxa",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Adjunta des de",
"cardCustomField-datePopup-title": "Canviar data",
"cardCustomFieldsPopup-title": "Editar camps personalitzats",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Esborrar fitxa?",
"cardDetailsActionsPopup-title": "Accions de fitxes",
"cardLabelsPopup-title": "Etiquetes",
@@ -319,6 +328,7 @@
"filter-clear": "Elimina filtre",
"filter-no-label": "Sense etiqueta",
"filter-no-member": "Sense membres",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Importa tauler",
"import-board-title-trello": "Importa tauler des de Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Estau segur que voleu esborrar aquesta checklist?",
"from-trello": "Des de Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "En el teu tauler Trello, ves a 'Menú', 'Més'.' Imprimir i Exportar', 'Exportar JSON', i copia el text resultant.",
@@ -440,7 +448,7 @@
"save": "Desa",
"search": "Cerca",
"rules": "Regles",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text que cercar?",
"select-color": "Selecciona color",
"set-wip-limit-value": "Limita el màxim nombre de tasques en aquesta llista",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Strávený čas",
"card-edit-attachments": "Upravit přílohy",
"card-edit-custom-fields": "Upravit vlastní pole",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Upravit štítky",
"card-edit-members": "Upravit členy",
"card-labels-title": "Změnit štítky karty.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Přiložit formulář",
"cardCustomField-datePopup-title": "Změnit datum",
"cardCustomFieldsPopup-title": "Upravit vlastní pole",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Smazat kartu?",
"cardDetailsActionsPopup-title": "Akce karty",
"cardLabelsPopup-title": "Štítky",
@@ -319,6 +328,7 @@
"filter-clear": "Vyčistit filtr",
"filter-no-label": "Žádný štítek",
"filter-no-member": "Žádný člen",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Žádné vlastní pole",
"filter-show-archive": "Zobrazit archivované listy",
"filter-hide-empty": "Skrýt prázdné listy",
@@ -338,8 +348,6 @@
"import-board-c": "Importovat tablo",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Importovat tablo z předchozího exportu",
"import-sandstorm-backup-warning": "Nemažte data, která importujete z původního exportovaného tabla nebo Trello předtím, nežli zkontrolujete, jestli lze tuto část zavřít a znovu otevřít nebo jestli se Vám nezobrazuje chyba tabla, což znamená ztrátu dat.",
"import-sandstorm-warning": "Importované tablo spaže všechny existující data v tablu a nahradí je importovaným tablem.",
"from-trello": "Z Trella",
"from-wekan": "Z předchozího exportu",
"import-board-instruction-trello": "Na svém Trello tablu, otevři 'Menu', pak 'More', 'Print and Export', 'Export JSON', a zkopíruj výsledný text",
@@ -440,7 +448,7 @@
"save": "Uložit",
"search": "Hledat",
"rules": "Pravidla",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Hledaný text",
"select-color": "Vybrat barvu",
"set-wip-limit-value": "Nastaví limit pro maximální počet úkolů ve sloupci.",
@@ -764,6 +772,7 @@
"view-all": "Zobrazit vše",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Označit vše jako přečtené",
"remove-all-read": "Remove all read",
"allow-rename": "Povolit přejmenování",
"allowRenamePopup-title": "Povolit přejmenování"
}
+749 -740
View File
File diff suppressed because it is too large. Load diff
+18 -9
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "hat %s in Checkliste %s von %s abgewählt",
"activity-checklist-added": "hat eine Checkliste zu %s hinzugefügt",
"activity-checklist-removed": "entfernte eine Checkliste von %s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "Abgeschlossene Checkliste",
"activity-checklist-uncompleted": "unvervollständigte die Checkliste %s von %s",
"activity-checklist-item-added": "hat ein Checklistenelement zu '%s' in %s hinzugefügt",
"activity-checklist-item-removed": "hat ein Checklistenelement von '%s' in %s entfernt",
@@ -152,6 +152,8 @@
"card-spent": "Aufgewendete Zeit",
"card-edit-attachments": "Anhänge ändern",
"card-edit-custom-fields": "Benutzerdefinierte Felder editieren",
"card-start-voting": "Abstimmung starten",
"card-cancel-voting": "Abstimmung mit allen Stimmen löschen ",
"card-edit-labels": "Labels ändern",
"card-edit-members": "Mitglieder ändern",
"card-labels-title": "Labels für diese Karte ändern.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Anhängen von",
"cardCustomField-datePopup-title": "Datum ändern",
"cardCustomFieldsPopup-title": "Benutzerdefinierte Felder editieren",
"cardStartVotingPopup-title": "Abstimmung starten",
"positiveVoteMembersPopup-title": "Befürworter",
"negativeVoteMembersPopup-title": "Gegner",
"vote-question": "Abstimmen über",
"vote-public": "Öffentliche Abstimmung",
"vote-for-it": "Dafür",
"vote-against": "Dagegen",
"cardDeletePopup-title": "Karte löschen?",
"cardDetailsActionsPopup-title": "Kartenaktionen",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Filter entfernen",
"filter-no-label": "Kein Label",
"filter-no-member": "Kein Mitglied",
"filter-no-assignee": "Nicht zugewiesen",
"filter-no-custom-fields": "Keine benutzerdefinierten Felder",
"filter-show-archive": "Archivierte Listen anzeigen",
"filter-hide-empty": "Leere Listen verstecken",
@@ -338,8 +348,6 @@
"import-board-c": "Board importieren",
"import-board-title-trello": "Board von Trello importieren",
"import-board-title-wekan": "Board aus vorherigem Export importieren",
"import-sandstorm-backup-warning": "Löschen Sie keine Daten, die Sie aus einem ursprünglich exportierten oder Trelloboard importieren, bevor Sie geprüft haben, ob alles funktioniert. Andernfalls kann es zu Datenverlust kommen, falls es zu einem \"Board nicht gefunden\"-Fehler kommt.",
"import-sandstorm-warning": "Das importierte Board wird alle bereits existierenden Daten löschen und mit den importierten Daten überschreiben.",
"from-trello": "Von Trello",
"from-wekan": "Aus vorherigem Export",
"import-board-instruction-trello": "Gehen Sie in ihrem Trello-Board auf 'Menü', dann 'Mehr', 'Drucken und Exportieren', 'JSON-Export' und kopieren Sie den dort angezeigten Text",
@@ -440,7 +448,7 @@
"save": "Speichern",
"search": "Suchen",
"rules": "Regeln",
"search-cards": "Suche nach Karten-/Listentiteln und Beschreibungen auf diesem Board",
"search-cards": "Suche nach Karten-/Listentiteln, Beschreibungen und personalisierten Feldern auf diesem Brett ",
"search-example": "Suchbegriff",
"select-color": "Farbe auswählen",
"set-wip-limit-value": "Setzen Sie ein Limit für die maximale Anzahl von Aufgaben in dieser Liste",
@@ -761,9 +769,10 @@
"editUserPopup-title": "Benutzer ändern",
"newUserPopup-title": "Neuer Benutzer",
"notifications": "Benachrichtigungen",
"view-all": "View All",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Mark all as read",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
"view-all": "Alle anzeigen",
"filter-by-unread": "Nur ungelesene",
"mark-all-as-read": "Alle als gelesen markieren",
"remove-all-read": "Alle gelesenen entfernen",
"allow-rename": "Umbenennen erlauben",
"allowRenamePopup-title": "Umbenennen erlauben"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Διαγραφή Κάρτας;",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Ετικέτες",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "Κανένα μέλος",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Εισαγωγή πίνακα",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "Από το Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Αποθήκευση",
"search": "Αναζήτηση",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Επιλέξτε Χρώμα",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Colour",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -767,6 +775,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Redakti etikedojn",
"card-edit-members": "Redakti membrojn",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Etikedoj",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "Nenia etikedo",
"filter-no-member": "Nenia membro",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Savi",
"search": "Serĉi",
"rules": "Reguloj",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+16 -7
View File
@@ -1,8 +1,8 @@
{
"accept": "Aceptar",
"act-activity-notify": "Notificación de Actividad",
"act-addAttachment": "added attachment __attachment__ to 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-addAttachment": "agregado archivo adjunto __attachment__ a tarjeta __card__ en la lista __list__ en el swimlane __swimlane__ en el tablero __board__",
"act-deleteAttachment": "eliminado archivo adjunto __attachment__ de la tarjeta __card__ en la lista __list__ en el swimlane __swimlane__ en el tablero __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-addedLabel": "Added label __label__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
@@ -73,8 +73,8 @@
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted-card": "uncompleted the checklist %s",
"activity-editComment": "edited comment %s",
"activity-deleteComment": "deleted comment %s",
"activity-editComment": "comentario %s editado",
"activity-deleteComment": "comentario %s eliminado",
"add-attachment": "Agregar Adjunto",
"add-board": "Agregar Tablero",
"add-card": "Agregar Tarjeta",
@@ -152,6 +152,8 @@
"card-spent": "Tiempo Empleado",
"card-edit-attachments": "Editar adjuntos",
"card-edit-custom-fields": "Editar campos personalizados",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Editar etiquetas",
"card-edit-members": "Editar miembros",
"card-labels-title": "Cambiar las etiquetas de la tarjeta.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Adjuntar De",
"cardCustomField-datePopup-title": "Cambiar fecha",
"cardCustomFieldsPopup-title": "Editar campos personalizados",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "¿Borrar Tarjeta?",
"cardDetailsActionsPopup-title": "Acciones de la Tarjeta",
"cardLabelsPopup-title": "Etiquetas",
@@ -319,6 +328,7 @@
"filter-clear": "Sacar filtro",
"filter-no-label": "Sin etiqueta",
"filter-no-member": "No es miembro",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Importar tablero",
"import-board-title-trello": "Importar tablero de Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "El tablero importado va a borrar todos los datos existentes en el tablero y reemplazarlos con los del tablero en cuestión.",
"from-trello": "De Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "En tu tablero de Trello, ve a 'Menú', luego a 'Más', 'Imprimir y Exportar', 'Exportar JSON', y copia el texto resultante.",
@@ -440,7 +448,7 @@
"save": "Grabar",
"search": "Buscar",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "¿Texto a buscar?",
"select-color": "Seleccionar Color",
"set-wip-limit-value": "Fijar un límite para el número máximo de tareas en esta lista",
@@ -764,6 +772,7 @@
"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"
}
+13 -4
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "desmarcado %s en lista %s de %s",
"activity-checklist-added": "ha añadido una lista de verificación a %s",
"activity-checklist-removed": "eliminada una lista de verificación desde %s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "lista de verificación completada %s de %s",
"activity-checklist-uncompleted": "no completado la lista %s de %s",
"activity-checklist-item-added": "ha añadido el elemento de la lista de verificación a '%s' en %s",
"activity-checklist-item-removed": "eliminado un elemento de la lista de verificación desde '%s' en %s",
@@ -152,6 +152,8 @@
"card-spent": "Tiempo consumido",
"card-edit-attachments": "Editar los adjuntos",
"card-edit-custom-fields": "Editar los campos personalizados",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Editar las etiquetas",
"card-edit-members": "Editar los miembros",
"card-labels-title": "Cambia las etiquetas de la tarjeta",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Adjuntar desde",
"cardCustomField-datePopup-title": "Cambiar la fecha",
"cardCustomFieldsPopup-title": "Editar los campos personalizados",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "contrarios",
"cardDeletePopup-title": "¿Eliminar la tarjeta?",
"cardDetailsActionsPopup-title": "Acciones de la tarjeta",
"cardLabelsPopup-title": "Etiquetas",
@@ -319,6 +328,7 @@
"filter-clear": "Limpiar el filtro",
"filter-no-label": "Sin etiqueta",
"filter-no-member": "Sin miembro",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Sin campos personalizados",
"filter-show-archive": "Mostrar las listas archivadas",
"filter-hide-empty": "Ocultar las listas vacías",
@@ -338,8 +348,6 @@
"import-board-c": "Importar un tablero",
"import-board-title-trello": "Importar un tablero desde Trello",
"import-board-title-wekan": "Importar tablero desde una exportación previa",
"import-sandstorm-backup-warning": "No elimine los datos que está importando del tablero o Trello original antes de verificar que la semilla pueda cerrarse y abrirse nuevamente, o que ocurra un error de \"Tablero no encontrado\", de lo contrario perderá sus datos.",
"import-sandstorm-warning": "El tablero importado eliminará todos los datos existentes en este tablero y los reemplazará con los datos del tablero importado.",
"from-trello": "Desde Trello",
"from-wekan": "Desde exportación previa",
"import-board-instruction-trello": "En tu tablero de Trello, ve a 'Menú', luego 'Más' > 'Imprimir y exportar' > 'Exportar JSON', y copia el texto resultante.",
@@ -440,7 +448,7 @@
"save": "Añadir",
"search": "Buscar",
"rules": "Reglas",
"search-cards": "Buscar entre los títulos y las descripciones de las tarjetas en este tablero.",
"search-cards": "Buscar entre los títulos, las descripciones de las tarjetas/listas y los campos personalizados en este tablero. ",
"search-example": "¿Texto a buscar?",
"select-color": "Seleccionar el color",
"set-wip-limit-value": "Cambiar el límite para el número máximo de tareas en esta lista.",
@@ -764,6 +772,7 @@
"view-all": "Ver todo",
"filter-by-unread": "Filtrar por no leído",
"mark-all-as-read": "Marcar todo como leido",
"remove-all-read": "Remove all read",
"allow-rename": "Permitir renombrar",
"allowRenamePopup-title": "Permitir renombrar"
}
+13 -4
View File
@@ -1,6 +1,6 @@
{
"accept": "Onartu",
"act-activity-notify": "Activity Notification",
"act-activity-notify": "Jardueraren jakinarazpena",
"act-addAttachment": "added attachment __attachment__ to 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__",
@@ -152,6 +152,8 @@
"card-spent": "Erabilitako denbora",
"card-edit-attachments": "Editatu eranskinak",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Editatu etiketak",
"card-edit-members": "Editatu kideak",
"card-labels-title": "Aldatu txartelaren etiketak",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Erantsi hemendik",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Ezabatu txartela?",
"cardDetailsActionsPopup-title": "Txartel-ekintzak",
"cardLabelsPopup-title": "Etiketak",
@@ -319,6 +328,7 @@
"filter-clear": "Garbitu iragazkia",
"filter-no-label": "Etiketarik ez",
"filter-no-member": "Kiderik ez",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Inportatu arbela",
"import-board-title-trello": "Inportatu arbela Trellotik",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Inportatutako arbelak oraingo arbeleko informazio guztia ezabatuko du eta inportatutako arbeleko informazioarekin ordeztu.",
"from-trello": "Trellotik",
"from-wekan": "From previous export",
"import-board-instruction-trello": "Zure Trello arbelean, aukeratu 'Menu\", 'More', 'Print and Export', 'Export JSON', eta kopiatu jasotako testua hemen.",
@@ -440,7 +448,7 @@
"save": "Gorde",
"search": "Bilatu",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Aukeratu kolorea",
"set-wip-limit-value": "Zerrenda honetako atazen muga maximoa ezarri",
@@ -764,6 +772,7 @@
"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"
}
+20 -11
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "چک نشده %s در چک لیست %s از %s",
"activity-checklist-added": "سیاهه به %s اضافه شد",
"activity-checklist-removed": "از چک لیست حذف گردید",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "چک‌لیست انجام شده %s از %s",
"activity-checklist-uncompleted": "تمام نشده ها در چک لیست %s از %s",
"activity-checklist-item-added": "added checklist item to '%s' in %s",
"activity-checklist-item-removed": "حذف شده از چک لیست '%s' در %s",
@@ -152,6 +152,8 @@
"card-spent": "زمان صرف شده",
"card-edit-attachments": "ویرایش ضمائم",
"card-edit-custom-fields": "ویرایش فیلدهای شخصی",
"card-start-voting": "شروع رای گیری",
"card-cancel-voting": "حذف رای گیری و همه آرا",
"card-edit-labels": "ویرایش برچسب",
"card-edit-members": "ویرایش اعضا",
"card-labels-title": "تغییر برچسب کارت",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "ضمیمه از",
"cardCustomField-datePopup-title": "تغییر تاریخ",
"cardCustomFieldsPopup-title": "ویرایش فیلدهای شخصی",
"cardStartVotingPopup-title": "شروع به رای",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "سوال رای گیری",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "آیا می خواهید کارت را حذف کنید؟",
"cardDetailsActionsPopup-title": "اعمال کارت",
"cardLabelsPopup-title": "برچسب ها",
@@ -319,6 +328,7 @@
"filter-clear": "حذف صافی ـ فیلتر ـ",
"filter-no-label": "بدون برچسب",
"filter-no-member": "بدون عضو",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "هیچ فیلدشخصی ای وجود ندارد",
"filter-show-archive": "نمایش لیست‌های آرشیو شده",
"filter-hide-empty": "مخفی کردن لیست‌های خالی",
@@ -338,8 +348,6 @@
"import-board-c": "وارد کردن برد",
"import-board-title-trello": "وارد کردن برد از Trello",
"import-board-title-wekan": "بارگذاری برد ها از آخرین خروجی",
"import-sandstorm-backup-warning": "قبل از بررسی این داده ها را از صفحه اصلی صادر شده یا Trello وارد نمیکنید این دانه دوباره باز می شود و یا دوباره باز می شود، یا برد را پیدا نمی کنید، این بدان معنی است که از دست دادن اطلاعات.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "از Trello",
"from-wekan": "از آخرین خروجی",
"import-board-instruction-trello": "در Trello-ی خود به 'Menu'، 'More'، 'Print'، 'Export to JSON رفته و متن نهایی را دراینجا وارد نمایید.",
@@ -440,7 +448,7 @@
"save": "ذخیره",
"search": "جستجو",
"rules": "قوانین",
"search-cards": "جتستجو از عنوان لیست/کارت ها و توضیحات در این برد",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "متن مورد جستجو؟",
"select-color": "انتخاب رنگ",
"set-wip-limit-value": "تعیین بیشینه تعداد وظایف در این فهرست",
@@ -757,13 +765,14 @@
"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",
"new": "جدید",
"editUserPopup-title": "ویرایش کاربر",
"newUserPopup-title": "کاربر جدید",
"notifications": "اعلان‌ها",
"view-all": "مشاهده همه",
"filter-by-unread": "فیلتر با خوانده نشده",
"mark-all-as-read": "علامت همه به خوانده شده",
"remove-all-read": "حذف همه خوانده شده",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Käytetty aika",
"card-edit-attachments": "Muokkaa liitetiedostoja",
"card-edit-custom-fields": "Muokkaa mukautettuja kenttiä",
"card-start-voting": "Aloita äänestys",
"card-cancel-voting": "Poista äänestys ja kaikki äänet",
"card-edit-labels": "Muokkaa nimilappuja",
"card-edit-members": "Muokkaa jäseniä",
"card-labels-title": "Muokkaa kortin nimilappuja.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Liitä mistä",
"cardCustomField-datePopup-title": "Muokkaa päivää",
"cardCustomFieldsPopup-title": "Muokkaa mukautettuja kenttiä",
"cardStartVotingPopup-title": "Äänestä",
"positiveVoteMembersPopup-title": "Kannattajat",
"negativeVoteMembersPopup-title": "Vastustajat",
"vote-question": "Äänestys kysymys",
"vote-public": "Julkinen äänestys",
"vote-for-it": "puolesta",
"vote-against": "vastaan",
"cardDeletePopup-title": "Poista kortti?",
"cardDetailsActionsPopup-title": "Korttitoimet",
"cardLabelsPopup-title": "Nimilaput",
@@ -319,6 +328,7 @@
"filter-clear": "Poista suodatin",
"filter-no-label": "Ei nimilappua",
"filter-no-member": "Ei jäseniä",
"filter-no-assignee": "Ei käsittelijää",
"filter-no-custom-fields": "Ei mukautettuja kenttiä",
"filter-show-archive": "Näytä arkistoidut listat",
"filter-hide-empty": "Näytä tyhjät listat",
@@ -338,8 +348,6 @@
"import-board-c": "Tuo taulu",
"import-board-title-trello": "Tuo taulu Trellosta",
"import-board-title-wekan": "Tuo taulu edellisestä viennistä",
"import-sandstorm-backup-warning": "Älä poista tietoja joita toit alkuperäisestä viennistä tai Trellosta ennen kuin tarkistat onnistuuko sulkea ja avata tämä jyvä uudelleen, vai näkyykö Board not found -virhe, joka tarkoittaa tietojen häviämistä.",
"import-sandstorm-warning": "Tuotu taulu poistaa kaikki olemassa olevan taulun tiedot ja korvaa ne tuodulla taululla.",
"from-trello": "Trellosta",
"from-wekan": "Edellisestä viennistä",
"import-board-instruction-trello": "Mene Trello-taulullasi 'Menu', sitten 'More', 'Print and Export', 'Export JSON', ja kopioi tuloksena saamasi teksti",
@@ -440,7 +448,7 @@
"save": "Tallenna",
"search": "Etsi",
"rules": "Säännöt",
"search-cards": "Etsi kortin/listan otsikoista ja kuvauksista tällä taululla",
"search-cards": "Etsi kortin/listan otsikoista, kuvauksista ja mukautetuista kentistä tällä taululla ",
"search-example": "Etsittävä teksti?",
"select-color": "Valitse väri",
"set-wip-limit-value": "Aseta tämän listan tehtävien enimmäismäärä",
@@ -764,6 +772,7 @@
"view-all": "Näytä kaikki",
"filter-by-unread": "Suodata lukemattomat",
"mark-all-as-read": "Merkkaa kaikki luetuksi",
"remove-all-read": "Poista kaikki luetut",
"allow-rename": "Salli uudelleennimeäminen",
"allowRenamePopup-title": "Salli uudelleennimeäminen"
}
+15 -6
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "a décoché %s dans la checklist %s de %s",
"activity-checklist-added": "a ajouté une checklist à %s",
"activity-checklist-removed": "a supprimé une checklist de %s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "a complété la checklist %s de %s",
"activity-checklist-uncompleted": "a rendu incomplète la checklist %s de %s",
"activity-checklist-item-added": "a ajouté un élément à la checklist '%s' dans %s",
"activity-checklist-item-removed": "a supprimé une checklist de '%s' dans %s",
@@ -152,6 +152,8 @@
"card-spent": "Temps passé",
"card-edit-attachments": "Modifier les pièces jointes",
"card-edit-custom-fields": "Éditer les champs personnalisés",
"card-start-voting": "Commencer le vote",
"card-cancel-voting": "Supprimer le vote",
"card-edit-labels": "Gérer les étiquettes",
"card-edit-members": "Gérer les participants",
"card-labels-title": "Modifier les étiquettes de la carte.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Ajouter depuis",
"cardCustomField-datePopup-title": "Modifier la date",
"cardCustomFieldsPopup-title": "Éditer les champs personnalisés",
"cardStartVotingPopup-title": "Commencer un vote",
"positiveVoteMembersPopup-title": "Pour",
"negativeVoteMembersPopup-title": "Contre",
"vote-question": "Question du vote",
"vote-public": "Vote public",
"vote-for-it": "pour",
"vote-against": "contre",
"cardDeletePopup-title": "Supprimer la carte ?",
"cardDetailsActionsPopup-title": "Actions sur la carte",
"cardLabelsPopup-title": "Étiquettes",
@@ -319,6 +328,7 @@
"filter-clear": "Supprimer les filtres",
"filter-no-label": "Aucune étiquette",
"filter-no-member": "Aucun participant",
"filter-no-assignee": "Pas de personne assignée",
"filter-no-custom-fields": "Pas de champs personnalisés",
"filter-show-archive": "Montrer les listes archivées",
"filter-hide-empty": "Cacher les listes vides",
@@ -338,8 +348,6 @@
"import-board-c": "Importer un tableau",
"import-board-title-trello": "Importer un tableau depuis Trello",
"import-board-title-wekan": "Importer un tableau depuis un export précédent",
"import-sandstorm-backup-warning": "Ne supprimez pas les données que vous importez d'un tableau exporté d'origine ou de Trello avant de vérifier que la graine peut se fermer et s'ouvrir à nouveau ou qu'une erreur \"Tableau introuvable\" survient, sinon vous perdrez vos données.",
"import-sandstorm-warning": "Le tableau importé supprimera toutes les données du tableau et les remplacera avec celles du tableau importé.",
"from-trello": "Depuis Trello",
"from-wekan": "Depuis un export précédent",
"import-board-instruction-trello": "Dans votre tableau Trello, allez sur 'Menu', puis sur 'Plus', 'Imprimer et exporter', 'Exporter en JSON' et copiez le texte du résultat",
@@ -440,7 +448,7 @@
"save": "Enregistrer",
"search": "Chercher",
"rules": "Règles",
"search-cards": "Chercher selon les titres de carte/liste et descriptions de ce tableau",
"search-cards": "Rechercher parmi les titres, descriptions et champs personnalisés des cartes/listes de ce tableau",
"search-example": "Texte à rechercher ?",
"select-color": "Sélectionner une couleur",
"set-wip-limit-value": "Définit une limite maximale au nombre de cartes de cette liste",
@@ -753,8 +761,8 @@
"accounts-allowUserDelete": "Autoriser les utilisateurs à supprimer leur compte",
"hide-minicard-label-text": "Cacher le label de la minicarte",
"show-desktop-drag-handles": "Voir les poignées de déplacement du bureau",
"assignee": "Cessionnaire",
"cardAssigneesPopup-title": "Cessionnaire",
"assignee": "Personne assignée",
"cardAssigneesPopup-title": "Personne assignée",
"addmore-detail": "Ajouter une description plus détaillée",
"show-on-card": "Afficher sur la carte",
"new": "Nouveau",
@@ -764,6 +772,7 @@
"view-all": "Voir tout",
"filter-by-unread": "Filtrer par non lu",
"mark-all-as-read": "Marquer comme lus",
"remove-all-read": "Supprimer les lus",
"allow-rename": "Autoriser le renommage",
"allowRenamePopup-title": "Autoriser le renommage"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Editar anexos",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Editar etiquetas",
"card-edit-members": "Editar membros",
"card-labels-title": "Cambiar as etiquetas da tarxeta.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Etiquetas",
@@ -319,6 +328,7 @@
"filter-clear": "Limpar filtro",
"filter-no-label": "Non hai etiquetas",
"filter-no-member": "Non hai membros",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Importar taboleiro",
"import-board-title-trello": "Importar taboleiro de Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "De Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+19 -10
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "בוטל הסימון של %s ברשימת המשימות %s מתוך %s",
"activity-checklist-added": "נוספה רשימת משימות אל %s",
"activity-checklist-removed": "הוסרה רשימת משימות מ־%s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "הושלמה רשימת משימות %s מתוך %s",
"activity-checklist-uncompleted": "רשימת המשימות %s מתוך %s סומנה כבלתי מושלמת",
"activity-checklist-item-added": "נוסף פריט רשימת משימות אל ‚%s‘ תחת %s",
"activity-checklist-item-removed": "הוסר פריט מרשימת המשימות ‚%s’ תחת %s",
@@ -152,6 +152,8 @@
"card-spent": "זמן שהושקע",
"card-edit-attachments": "עריכת קבצים מצורפים",
"card-edit-custom-fields": "עריכת שדות בהתאמה אישית",
"card-start-voting": "ניתן להצביע",
"card-cancel-voting": "מחיקת אפשרות ההצבעה ואת כל הקולות",
"card-edit-labels": "עריכת תוויות",
"card-edit-members": "עריכת חברים",
"card-labels-title": "שינוי תוויות לכרטיס.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "לצרף מ־",
"cardCustomField-datePopup-title": "החלפת תאריך",
"cardCustomFieldsPopup-title": "עריכת שדות בהתאמה אישית",
"cardStartVotingPopup-title": "התחלת הצבעה",
"positiveVoteMembersPopup-title": "תומכים",
"negativeVoteMembersPopup-title": "יריבים",
"vote-question": "שאלת הסקר",
"vote-public": "הצבעה ציבורית",
"vote-for-it": "בעד",
"vote-against": "נגד",
"cardDeletePopup-title": "למחוק כרטיס?",
"cardDetailsActionsPopup-title": "פעולות על הכרטיס",
"cardLabelsPopup-title": "תוויות",
@@ -319,6 +328,7 @@
"filter-clear": "ניקוי המסנן",
"filter-no-label": "אין תווית",
"filter-no-member": "אין חבר כזה",
"filter-no-assignee": "אין אחראי",
"filter-no-custom-fields": "אין שדות מותאמים אישית",
"filter-show-archive": "הצגת רשימות שהועברו לארכיון",
"filter-hide-empty": "הסתרת רשימות ריקות",
@@ -338,8 +348,6 @@
"import-board-c": "יבוא לוח",
"import-board-title-trello": "ייבוא לוח מטרלו",
"import-board-title-wekan": "ייבוא לוח מייצוא קודם",
"import-sandstorm-backup-warning": "עדיף לא למחוק נתונים שייובאו מייצוא מקורי או מ־Trello בטרם בדיקה האם הגרעין הזה נסגר ונפתח שוב או אם מתקבלת שגיאה על כך שהלוח לא נמצא, משמעות הדבר היא אבדן מידע.",
"import-sandstorm-warning": "הלוח שייובא ימחק את כל הנתונים הקיימים בלוח ויחליף אותם בלוח שייובא.",
"from-trello": "מ־Trello",
"from-wekan": "מייצוא קודם",
"import-board-instruction-trello": "בלוח הטרלו שלך, עליך ללחוץ על ‚תפריט‘, ואז על ‚עוד‘, ‚הדפסה וייצוא‘, ‚יצוא JSON‘ ולהעתיק את הטקסט שנוצר.",
@@ -440,7 +448,7 @@
"save": "שמירה",
"search": "חיפוש",
"rules": "כללים",
"search-cards": "חיפוש בין כותרות של כרטיסים/רשימות ותיאורים בלוח זה",
"search-cards": "חיפוש מבין כותרות של כרטיסים/רשימות, תיאורים ושדות בהתאמה אישית בלוח זה",
"search-example": "טקסט לחיפוש ?",
"select-color": "בחירת צבע",
"set-wip-limit-value": "הגדרת מגבלה למספר המרבי של משימות ברשימה זו",
@@ -760,10 +768,11 @@
"new": "חדש",
"editUserPopup-title": "עריכת משתמש",
"newUserPopup-title": "משתמש חדש",
"notifications": "Notifications",
"view-all": "View All",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Mark all as read",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
"notifications": "הודעות",
"view-all": "להציג הכול",
"filter-by-unread": "סימון לפי כאלו שלא נקראו",
"mark-all-as-read": "לסמן הכול כאילו שנקראו",
"remove-all-read": "הסרת כל אלו שנקראו",
"allow-rename": "לאפשר שינוי שם",
"allowRenamePopup-title": "לאפשר שינוי שם"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "समय बिताया",
"card-edit-attachments": "संपादित संलग्नक",
"card-edit-custom-fields": "संपादित प्रचलन क्षेत्र",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "संपादित नामपत्र",
"card-edit-members": "संपादित सदस्य",
"card-labels-title": "कार्ड के लिए नामपत्र परिवर्तित करें ।",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "से अनुलग्न करें",
"cardCustomField-datePopup-title": "तारीख बदलें",
"cardCustomFieldsPopup-title": "संपादित करें प्रचलन क्षेत्र",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "मिटाएँ कार्ड?",
"cardDetailsActionsPopup-title": "कार्ड क्रियाएँ",
"cardLabelsPopup-title": "नामपत्र",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No सदस्य",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No प्रचलन क्षेत्र",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import बोर्ड",
"import-board-title-trello": "Import बोर्ड से Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "सूचित कर बोर्ड will मिटाएँ संपूर्ण existing data on बोर्ड और replace it साथ में सूचित कर बोर्ड.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello बोर्ड, go तक 'Menu', then 'More', 'Print और Export', 'Export JSON', और copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text तक search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set एक limit for the maximum number of tasks अंदर में यह list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Eltöltött idő",
"card-edit-attachments": "Mellékletek szerkesztése",
"card-edit-custom-fields": "Egyéni mezők szerkesztése",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Címkék szerkesztése",
"card-edit-members": "Tagok szerkesztése",
"card-labels-title": "A kártya címkéinek megváltoztatása.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Innen csatolva",
"cardCustomField-datePopup-title": "Dátum megváltoztatása",
"cardCustomFieldsPopup-title": "Egyéni mezők szerkesztése",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Törli a kártyát?",
"cardDetailsActionsPopup-title": "Kártyaműveletek",
"cardLabelsPopup-title": "Címkék",
@@ -319,6 +328,7 @@
"filter-clear": "Szűrő törlése",
"filter-no-label": "Nincs címke",
"filter-no-member": "Nincs tag",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Nincsenek egyéni mezők",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Tábla importálása",
"import-board-title-trello": "Tábla importálása a Trello oldalról",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Az importált tábla törölni fogja a táblán lévő összes meglévő adatot, és kicseréli az importált táblával.",
"from-trello": "A Trello oldalról",
"from-wekan": "From previous export",
"import-board-instruction-trello": "A Trello tábláján menjen a „Menü”, majd a „Több”, „Nyomtatás és exportálás”, „JSON exportálása” menüpontokra, és másolja ki az eredményül kapott szöveget.",
@@ -440,7 +448,7 @@
"save": "Mentés",
"search": "Keresés",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "keresőkifejezés",
"select-color": "Szín kiválasztása",
"set-wip-limit-value": "Korlát beállítása a listán lévő feladatok legnagyobb számához",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Sunting lampiran",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Sunting label",
"card-edit-members": "Sunting anggota",
"card-labels-title": "Ubah label kartu",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Lampirkan dari",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Hapus kartu",
"cardDetailsActionsPopup-title": "Aksi Kartu",
"cardLabelsPopup-title": "Daftar Label",
@@ -319,6 +328,7 @@
"filter-clear": "Bersihkan penyaringan",
"filter-no-label": "Tidak ada label",
"filter-no-member": "Tidak ada anggota",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Impor panel dari Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "Di panel Trello anda, ke 'Menu', terus 'More', 'Print and Export','Export JSON', dan salin hasilnya",
@@ -440,7 +448,7 @@
"save": "Simpan",
"search": "Cari",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Aha",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+27 -18
View File
@@ -1,5 +1,5 @@
{
"accept": "Accetta",
"accept": "Accept",
"act-activity-notify": "Notifica attività",
"act-addAttachment": "aggiunto allegato __attachment__ alla scheda __card__ della lista __list__ della corsia __swimlane__  nella bacheca __board__",
"act-deleteAttachment": "eliminato allegato __attachment__ dalla scheda __card__ della lista __list__ della corsia __swimlane__  nella bacheca __board__",
@@ -64,7 +64,7 @@
"activity-unchecked-item": "disattivato %s nella checklist %s di %s",
"activity-checklist-added": "aggiunta checklist a %s",
"activity-checklist-removed": "È stata rimossa una checklist da%s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "%s di %s checklists completate",
"activity-checklist-uncompleted": "La checklist non è stata completata",
"activity-checklist-item-added": "Aggiunto l'elemento checklist a '%s' in %s",
"activity-checklist-item-removed": "è stato rimosso un elemento della checklist da '%s' in %s",
@@ -152,6 +152,8 @@
"card-spent": "Tempo trascorso",
"card-edit-attachments": "Modifica allegati",
"card-edit-custom-fields": "Modifica campo personalizzato",
"card-start-voting": "Inizia a votare",
"card-cancel-voting": "Cancella votazione e tutti i voti",
"card-edit-labels": "Modifica etichette",
"card-edit-members": "Modifica membri",
"card-labels-title": "Cambia le etichette per questa scheda.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Allega da",
"cardCustomField-datePopup-title": "Cambia data",
"cardCustomFieldsPopup-title": "Modifica campo personalizzato",
"cardStartVotingPopup-title": "Inizia una votazione",
"positiveVoteMembersPopup-title": "Favorevoli",
"negativeVoteMembersPopup-title": "Contrari",
"vote-question": "Domanda di votazione",
"vote-public": "Voto pubblico",
"vote-for-it": "a favore",
"vote-against": "contro",
"cardDeletePopup-title": "Elimina scheda?",
"cardDetailsActionsPopup-title": "Azioni scheda",
"cardLabelsPopup-title": "Etichette",
@@ -319,6 +328,7 @@
"filter-clear": "Pulisci filtri",
"filter-no-label": "Nessuna etichetta",
"filter-no-member": "Nessun membro",
"filter-no-assignee": "Nessun assegnatario",
"filter-no-custom-fields": "Nessun campo personalizzato",
"filter-show-archive": "Mostra le liste archiviate",
"filter-hide-empty": "Nascondi liste vuote",
@@ -338,8 +348,6 @@
"import-board-c": "Importa bacheca",
"import-board-title-trello": "Importa una bacheca da Trello",
"import-board-title-wekan": "Importa bacheca dall'esportazione precedente",
"import-sandstorm-backup-warning": "Non cancellare i dati che importi dalla bacheca esportata in origine o da Trello prima che il controllo finisca e si riapra ancora, altrimenti otterrai un messaggio di errore Bacheca non trovata, che significa che i dati sono perduti.",
"import-sandstorm-warning": "La bacheca importata cancellerà tutti i dati esistenti su questa bacheca e li rimpiazzerà con quelli della bacheca importata.",
"from-trello": "Da Trello",
"from-wekan": "Dall'esportazione precedente",
"import-board-instruction-trello": "Nella tua bacheca Trello vai a 'Menu', poi 'Altro', 'Stampa ed esporta', 'Esporta JSON', e copia il testo che compare.",
@@ -440,7 +448,7 @@
"save": "Salva",
"search": "Cerca",
"rules": "Regole",
"search-cards": "Ricerca per titolo e descrizione scheda/lista su questa bacheca",
"search-cards": "Ricerca per titolo, descrizione scheda/lista e campi personalizzati su questa bacheca",
"search-example": "Testo da ricercare?",
"select-color": "Seleziona Colore",
"set-wip-limit-value": "Seleziona un limite per il massimo numero di attività in questa lista",
@@ -733,21 +741,21 @@
"loading": "Loading, please wait.",
"previous_as": "l'ultima volta è stata",
"act-a-dueAt": "Scadenza modificata in __timeValue__\nData precedente: __timeOldValue__",
"act-a-endAt": "modified ending time to __timeValue__ from (__timeOldValue__)",
"act-a-startAt": "modified starting time to __timeValue__ from (__timeOldValue__)",
"act-a-receivedAt": "modified received time to __timeValue__ from (__timeOldValue__)",
"a-dueAt": "modified due time to be",
"a-endAt": "modified ending time to be",
"a-startAt": "modified starting time to be",
"a-receivedAt": "modified received time to be",
"act-a-endAt": "orario finale modificato in __timeValue__ (precedentemente: __timeOldValue__)",
"act-a-startAt": "orario iniziale modificato in __timeValue__ (precedentemente: __timeOldValue__)",
"act-a-receivedAt": "orario di ricezione modificato in __timeValue__ (precedentemente: __timeOldValue__)",
"a-dueAt": "scadenza modificata in",
"a-endAt": "orario finale modificato in",
"a-startAt": "orario iniziale modificato in",
"a-receivedAt": "orario di ricezione modificato in",
"almostdue": "la data di scadenza attuale %s si sta avvicinando",
"pastdue": "la data di scadenza attuale %s è scaduta",
"duenow": "la data di scadenza attuale %s è oggi",
"act-newDue": "__list__/__card__ has 1st due reminder [__board__]",
"act-withDue": "__list__/__card__ due reminders [__board__]",
"act-almostdue": "was reminding the current due (__timeValue__) of __card__ is approaching",
"act-pastdue": "was reminding the current due (__timeValue__) of __card__ is past",
"act-duenow": "was reminding the current due (__timeValue__) of __card__ is now",
"act-newDue": "__list__/__card__ ha un 1° sollecito [__board__]",
"act-withDue": "sollecito relativo a __list__/__card__ [__board__]",
"act-almostdue": "sollecito inviato: la scadenza (__timeValue__) di __card__ è vicina",
"act-pastdue": "sollecito inviato: la scadenza (__timeValue__) di __card__ è già passata",
"act-duenow": "sollecito inviato: la scadenza (__timeValue__) di __card__ è adesso",
"act-atUserComment": "Sei stato menzionato in [__board__] __list__/__card__",
"delete-user-confirm-popup": "Sei sicuro di voler cancellare questo profilo? Non sarà possibile ripristinarlo.",
"accounts-allowUserDelete": "Permetti agli utenti di cancellare il loro profilo",
@@ -762,8 +770,9 @@
"newUserPopup-title": "Nuovo utente",
"notifications": "Notifiche",
"view-all": "Mostra Tutto",
"filter-by-unread": "Filtra per non Letto",
"filter-by-unread": "Filtra per non letto",
"mark-all-as-read": "Segna come letto",
"remove-all-read": "Rimuovi tutti i già letti",
"allow-rename": "Consenti Rinomina",
"allowRenamePopup-title": "Consenti Rinomina"
}
+18 -9
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "チェックが外されました %s チェックリスト %s / %s",
"activity-checklist-added": "%s にチェックリストを追加しました",
"activity-checklist-removed": "チェックリストを %s から削除しました",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "チェックリスト%s / %s が完了しました",
"activity-checklist-uncompleted": "チェックリスト %s / %s が未完了になりました",
"activity-checklist-item-added": "チェックリスト項目を '%s' / %s に追加しました",
"activity-checklist-item-removed": "'%s' の チェックリスト %s の項目を削除しました",
@@ -152,6 +152,8 @@
"card-spent": "作業時間",
"card-edit-attachments": "添付ファイルの編集",
"card-edit-custom-fields": "カスタムフィールドの編集",
"card-start-voting": "投票を開始",
"card-cancel-voting": "投票と全ての結果を削除",
"card-edit-labels": "ラベルの編集",
"card-edit-members": "メンバーの編集",
"card-labels-title": "カードのラベルを変更する",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "添付元",
"cardCustomField-datePopup-title": "日時変更",
"cardCustomFieldsPopup-title": "カスタムフィールドの編集",
"cardStartVotingPopup-title": "投票を開始",
"positiveVoteMembersPopup-title": "支持者",
"negativeVoteMembersPopup-title": "反対者",
"vote-question": "投票の質問事項",
"vote-public": "投票を公開",
"vote-for-it": "賛成",
"vote-against": "反対",
"cardDeletePopup-title": "カードを削除しますか?",
"cardDetailsActionsPopup-title": "カード操作",
"cardLabelsPopup-title": "ラベル",
@@ -319,6 +328,7 @@
"filter-clear": "フィルターの解除",
"filter-no-label": "ラベルなし",
"filter-no-member": "メンバーなし",
"filter-no-assignee": "担当者なし",
"filter-no-custom-fields": "カスタムフィールドなし",
"filter-show-archive": "アーカイブされたリストを表示",
"filter-hide-empty": "空のリストを隠す",
@@ -338,8 +348,6 @@
"import-board-c": "ボードをインポート",
"import-board-title-trello": "Trelloからボードをインポート",
"import-board-title-wekan": "以前のエクスポートからボードをインポート",
"import-sandstorm-backup-warning": "この操作が完了して再度開くことができるのを確認するまでインポート元のボードまたはTrelloのデータを削除しないでください。「ボードが見つかりません」が表示された場合、データが失われたことを意味します。",
"import-sandstorm-warning": "ボードのインポートは、既存ボードのすべてのデータを置き換えます。",
"from-trello": "Trelloから",
"from-wekan": "以前のエクスポートから",
"import-board-instruction-trello": "Trelloボードの、 'Menu' → 'More' → 'Print and Export' → 'Export JSON'を選択し、テキストをコピーしてください。",
@@ -440,7 +448,7 @@
"save": "保存",
"search": "検索",
"rules": "ルール",
"search-cards": "ボードのカード/リストのタイトルと詳細から検索",
"search-cards": "このボード上のカード/リストタイトル、詳細、カスタムフィールドから検索",
"search-example": "検索文字",
"select-color": "色を選択",
"set-wip-limit-value": "このリスト中のタスクの最大数を設定",
@@ -761,9 +769,10 @@
"editUserPopup-title": "ユーザーを編集",
"newUserPopup-title": "新規ユーザー",
"notifications": "通知",
"view-all": "View All",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Mark all as read",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
"view-all": "全てを表示",
"filter-by-unread": "未読でフィルタ",
"mark-all-as-read": "全て既読にする",
"remove-all-read": "全ての既読を削除",
"allow-rename": "リネームを許可する",
"allowRenamePopup-title": "リネームを許可する"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "დახარჯული დრო",
"card-edit-attachments": "მიბმული ფაილის შესწორება",
"card-edit-custom-fields": "მომხმარებლის ველის შესწორება",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "ნიშნის შესწორება",
"card-edit-members": "მომხმარებლების შესწორება",
"card-labels-title": "ნიშნის შეცვლა ბარათისთვის.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "მიბმა შემდეგი წყაროდან: ",
"cardCustomField-datePopup-title": "დროის ცვლილება",
"cardCustomFieldsPopup-title": "მომხმარებლის ველის შესწორება",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "წავშალოთ ბარათი? ",
"cardDetailsActionsPopup-title": "ბარათის მოქმედებები",
"cardLabelsPopup-title": "ნიშნები",
@@ -319,6 +328,7 @@
"filter-clear": "ფილტრის გასუფთავება",
"filter-no-label": "ნიშანი არ გვაქვს",
"filter-no-member": "არ არის წევრები ",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "არა მომხმარებლის ველი",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "დაფის იმპორტი",
"import-board-title-trello": "დაფის იმპორტი Trello-დან",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "იმპორტირებული დაფა წაშლის ყველა არსებულ მონაცემს დაფაზე და შეანაცვლებს მას იმპორტირებული დაფა. ",
"from-trello": "Trello-დან",
"from-wekan": "From previous export",
"import-board-instruction-trello": "თქვენს Trello დაფაზე, შედით \"მენიუ\"-ში, შემდეგ დააკლიკეთ \"მეტი\", \"ამოპრინტერება და ექსპორტი\", \"JSON-ის ექსპორტი\" და დააკოპირეთ შედეგი. ",
@@ -440,7 +448,7 @@
"save": "დამახსოვრება",
"search": "ძებნა",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "საძიებო ტექსტი",
"select-color": "ფერის მონიშვნა",
"set-wip-limit-value": "დააყენეთ შეზღუდვა დავალებების მაქსიმალურ რაოდენობაზე ",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "첨부 파일 수정",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "라벨 수정",
"card-edit-members": "멤버 수정",
"card-labels-title": "카드의 라벨 변경.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "첨부 파일",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "카드를 삭제합니까?",
"cardDetailsActionsPopup-title": "카드 액션",
"cardLabelsPopup-title": "라벨",
@@ -319,6 +328,7 @@
"filter-clear": "필터 초기화",
"filter-no-label": "라벨 없음",
"filter-no-member": "멤버 없음",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "보드 가져오기",
"import-board-title-trello": "Trello에서 보드 가져오기",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "Trello 게시판에서 'Menu' -> 'More' -> 'Print and Export', 'Export JSON' 선택하여 텍스트 결과값 복사",
@@ -440,7 +448,7 @@
"save": "저장",
"search": "검색",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "색 선택",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Изработено време",
"card-edit-attachments": "Промени прикачените датотеки",
"card-edit-custom-fields": "Промени собствените полета",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Промени етикетите",
"card-edit-members": "Промени членовете",
"card-labels-title": "Промени етикетите за картата.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Прикачи от",
"cardCustomField-datePopup-title": "Промени датата",
"cardCustomFieldsPopup-title": "Промени собствените полета",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Желаете да изтриете картата?",
"cardDetailsActionsPopup-title": "Опции",
"cardLabelsPopup-title": "Етикети",
@@ -319,6 +328,7 @@
"filter-clear": "Премахване на филтрите",
"filter-no-label": "без етикет",
"filter-no-member": "без член",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Няма Собствени полета",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Импортирай Табло",
"import-board-title-trello": "Импорт на табло от Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Импортирането ще изтрие всичката налична информация в таблото и ще я замени с нова.",
"from-trello": "От Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Запази",
"search": "Търсене",
"rules": "Правила",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Избери цвят",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Edit attachments",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Edit labels",
"card-edit-members": "Edit members",
"card-labels-title": "Change the labels for the card.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Attach From",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Delete Card?",
"cardDetailsActionsPopup-title": "Card Actions",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Spent Time",
"card-edit-attachments": "Rediger vedlegg",
"card-edit-custom-fields": "Edit custom fields",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Rediger etiketter",
"card-edit-members": "Endre medlemmer",
"card-labels-title": "Endre etiketter for kortet.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Legg ved fra",
"cardCustomField-datePopup-title": "Change date",
"cardCustomFieldsPopup-title": "Edit custom fields",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Slett kort?",
"cardDetailsActionsPopup-title": "Kort-handlinger",
"cardLabelsPopup-title": "Etiketter",
@@ -319,6 +328,7 @@
"filter-clear": "Clear filter",
"filter-no-label": "No label",
"filter-no-member": "No member",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "No Custom Fields",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Import board",
"import-board-title-trello": "Import board from Trello",
"import-board-title-wekan": "Import board from previous export",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Imported board will delete all existing data on board and replace it with imported board.",
"from-trello": "From Trello",
"from-wekan": "From previous export",
"import-board-instruction-trello": "In your Trello board, go to 'Menu', then 'More', 'Print and Export', 'Export JSON', and copy the resulting text.",
@@ -440,7 +448,7 @@
"save": "Save",
"search": "Search",
"rules": "Rules",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Select Color",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+19 -10
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "%s uitgevinkt in checklist %s van %s",
"activity-checklist-added": "checklist toegevoegd aan %s",
"activity-checklist-removed": "checklist verwijderd van %s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "checklist %s afgewerkt van %s",
"activity-checklist-uncompleted": "checklist %s onafgewerkt van %s",
"activity-checklist-item-added": "checklist item toegevoegd aan '%s' in '%s'",
"activity-checklist-item-removed": "checklist item verwijderd van '%s' in %s",
@@ -152,6 +152,8 @@
"card-spent": "Gespendeerde tijd",
"card-edit-attachments": "Wijzig bijlagen",
"card-edit-custom-fields": "Wijzig maatwerkvelden",
"card-start-voting": "Start stemming",
"card-cancel-voting": "Verwijder stemming en verwijder stemmen",
"card-edit-labels": "Wijzig labels",
"card-edit-members": "Wijzig leden",
"card-labels-title": "Wijzig de labels van de kaart.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Voeg bestand toe vanuit",
"cardCustomField-datePopup-title": "Wijzigingsdatum",
"cardCustomFieldsPopup-title": "Wijzig maatwerkvelden",
"cardStartVotingPopup-title": "Start een stemming",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Stemvraag",
"vote-public": "Public vote",
"vote-for-it": "Voor",
"vote-against": "tegen",
"cardDeletePopup-title": "Kaart verwijderen?",
"cardDetailsActionsPopup-title": "Kaart actie ondernemen",
"cardLabelsPopup-title": "Labels",
@@ -319,6 +328,7 @@
"filter-clear": "Wis filter",
"filter-no-label": "Geen label",
"filter-no-member": "Geen lid",
"filter-no-assignee": "Niemand toegewezen",
"filter-no-custom-fields": "Geen maatwerkvelden",
"filter-show-archive": "Toon gearchiveerde lijsten",
"filter-hide-empty": "Verberg lege lijsten",
@@ -338,8 +348,6 @@
"import-board-c": "Importeer bord",
"import-board-title-trello": "Importeer bord vanuit Trello",
"import-board-title-wekan": "Importeer bord vanuit eerdere export",
"import-sandstorm-backup-warning": "Verwijder nog niet de data van je geëxporteerde Trello-bord totdat je vastgesteld hebt dat het Wekan-bord werkt. Doe dit door het nieuwe bord te sluiten en opnieuw te openen. Als er dan een foutmelding krijgt of het nieuwe bord opent niet dan kun je nog terugvallen op het originele bord. ",
"import-sandstorm-warning": "Het geïmporteerde bord verwijdert alle huidige data op dit bord, om het daarna te vervangen.",
"from-trello": "Vanuit Trello",
"from-wekan": "Vanuit eerdere export",
"import-board-instruction-trello": "Op jouw Trello bord, ga naar 'Menu', dan naar 'Meer', 'Print en Exporteer', 'Exporteer JSON', en kopieer de tekst.",
@@ -440,7 +448,7 @@
"save": "Opslaan",
"search": "Zoek",
"rules": "Regels",
"search-cards": "Zoek op kaarten/lijsten en omschrijvingen op dit bord",
"search-cards": "Zoek in kaart/lijst, titels, beschrijvingen en maatwerkvelden op dit bord",
"search-example": "Tekst om naar te zoeken?",
"select-color": "Selecteer kleur",
"set-wip-limit-value": "Zet een limiet voor het maximaal aantal taken in deze lijst",
@@ -760,10 +768,11 @@
"new": "Nieuw",
"editUserPopup-title": "Wijzig gebruiker",
"newUserPopup-title": "Nieuwe gebruiker",
"notifications": "Notifications",
"view-all": "View All",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Mark all as read",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
"notifications": "Meldingen",
"view-all": "Bekijk alles",
"filter-by-unread": "Filter op Ongelezen",
"mark-all-as-read": "Markeer alles als gelezen",
"remove-all-read": "verwijder alle gelezen",
"allow-rename": "Sta Hernoemen toe",
"allowRenamePopup-title": "Sta Hernoemen toe"
}
+12 -3
View File
@@ -152,6 +152,8 @@
"card-spent": "Temps passat",
"card-edit-attachments": "Cambiar las pèças jonchas",
"card-edit-custom-fields": "Cambiar los camps personalizats",
"card-start-voting": "Start voting",
"card-cancel-voting": "Delete voting and all votes",
"card-edit-labels": "Cambiar los labèls",
"card-edit-members": "Cambiar los participants",
"card-labels-title": "Cambiar l'etiqueta de la carta.",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Apondut dempuèi",
"cardCustomField-datePopup-title": "Cambiar la data",
"cardCustomFieldsPopup-title": "Cambiar los camps personalizats",
"cardStartVotingPopup-title": "Start a vote",
"positiveVoteMembersPopup-title": "Proponents",
"negativeVoteMembersPopup-title": "Opponents",
"vote-question": "Voting question",
"vote-public": "Public vote",
"vote-for-it": "for it",
"vote-against": "against",
"cardDeletePopup-title": "Suprimir la carta?",
"cardDetailsActionsPopup-title": "Accions sus la carta",
"cardLabelsPopup-title": "Etiquetas",
@@ -319,6 +328,7 @@
"filter-clear": "Escafar lo filtre",
"filter-no-label": "Pas cap d'etiqueta",
"filter-no-member": "Pas cap de participant",
"filter-no-assignee": "No assignee",
"filter-no-custom-fields": "Pas de camp personalizat",
"filter-show-archive": "Show archived lists",
"filter-hide-empty": "Hide empty lists",
@@ -338,8 +348,6 @@
"import-board-c": "Importar un tablèu",
"import-board-title-trello": "Importar un tablèu dempuèi Trello",
"import-board-title-wekan": "Importar un tablèu dempuèi un export passat",
"import-sandstorm-backup-warning": "Do not delete data you import from original exported board or Trello before checking does this grain close and open again, or do you get Board not found error, that means data loss.",
"import-sandstorm-warning": "Importar lo tablèu va quitar totes las donadas del tablèu e lo va remplaçar amb las donadas del tablèu importat.",
"from-trello": "Dempuèi Trello",
"from-wekan": "Dempuèi un export passat",
"import-board-instruction-trello": "Dins vòstre tablèu Trello, vos cal anar dins \"Menut\", puèi \"Mai\", \"Export\", \"Export JSON\", e copiar lo tèxte balhat.",
@@ -440,7 +448,7 @@
"save": "Salvar",
"search": "Cèrca",
"rules": "Règlas",
"search-cards": "Search from card/list titles and descriptions on this board",
"search-cards": "Search from card/list titles, descriptions and custom fields on this board",
"search-example": "Text to search for?",
"select-color": "Color causida",
"set-wip-limit-value": "Set a limit for the maximum number of tasks in this list",
@@ -764,6 +772,7 @@
"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"
}
+19 -10
View File
@@ -64,7 +64,7 @@
"activity-unchecked-item": "odznaczono %s w liście zadań %s z %s",
"activity-checklist-added": "dodał(a) listę zadań do %s",
"activity-checklist-removed": "usunął listę zadań z %s",
"activity-checklist-completed": "completed checklist %s of %s",
"activity-checklist-completed": "ukończono listę zadań %s z %s",
"activity-checklist-uncompleted": "nieukończono listy zadań %s z %s",
"activity-checklist-item-added": "dodał(a) zadanie '%s' do %s",
"activity-checklist-item-removed": "usunął element z listy zadań '%s' w %s",
@@ -152,6 +152,8 @@
"card-spent": "Spędzony czas",
"card-edit-attachments": "Edytuj załączniki",
"card-edit-custom-fields": "Edytuj niestandardowe pola",
"card-start-voting": "Rozpocznij głosowanie",
"card-cancel-voting": "Usuń głosowanie i wszystkie głosy",
"card-edit-labels": "Edytuj etykiety",
"card-edit-members": "Edytuj członków",
"card-labels-title": "Zmień etykiety karty",
@@ -161,6 +163,13 @@
"cardAttachmentsPopup-title": "Dodaj załącznik z",
"cardCustomField-datePopup-title": "Zmień datę",
"cardCustomFieldsPopup-title": "Edytuj niestandardowe pola",
"cardStartVotingPopup-title": "Zacznij głosowanie",
"positiveVoteMembersPopup-title": "Zwolennicy",
"negativeVoteMembersPopup-title": "Przeciwnicy",
"vote-question": "Pytanie do głosowania",
"vote-public": "Głosowanie publiczne",
"vote-for-it": "za",
"vote-against": "przeciwko",
"cardDeletePopup-title": "Usunąć kartę?",
"cardDetailsActionsPopup-title": "Czynności kart",
"cardLabelsPopup-title": "Etykiety",
@@ -319,6 +328,7 @@
"filter-clear": "Usuń filter",
"filter-no-label": "Brak etykiety",
"filter-no-member": "Brak członków",
"filter-no-assignee": "Nieprzypisane ",
"filter-no-custom-fields": "Brak niestandardowych pól",
"filter-show-archive": "Pokaż zarchiwizowane listy",
"filter-hide-empty": "Ukryj puste listy",
@@ -338,8 +348,6 @@
"import-board-c": "Import tablicy",
"import-board-title-trello": "Importuj tablicę z Trello",
"import-board-title-wekan": "Importuj tablicę z poprzedniego eksportu",
"import-sandstorm-backup-warning": "Nie usuwaj danych, które importujesz ze źródłowej tablicy lub Trello zanim upewnisz się, że wszystko zostało prawidłowo przeniesione przy czym brane jest pod uwagę ponowne uruchomienie strony, ponieważ w przypadku błędu braku tablicy stracisz dane.",
"import-sandstorm-warning": "Zaimportowana tablica usunie wszystkie istniejące dane na aktualnej tablicy oraz zastąpi ją danymi z tej importowanej.",
"from-trello": "Z Trello",
"from-wekan": "Z poprzedniego eksportu",
"import-board-instruction-trello": "W twojej tablicy na Trello przejdź do 'Menu', następnie 'Więcej', 'Drukuj i eksportuj', 'Eksportuj jako JSON' i skopiuj wynik",
@@ -440,7 +448,7 @@
"save": "Zapisz",
"search": "Wyszukaj",
"rules": "Reguły",
"search-cards": "Szukaj w tytułach kart/list oraz opisach na tej tablicy",
"search-cards": "Szukaj w tytułach kart/list oraz opisach i niestandardowych polach na tej tablicy",
"search-example": "Czego mam szukać?",
"select-color": "Wybierz kolor",
"set-wip-limit-value": "Ustaw maksymalny limit zadań na tej liście",
@@ -760,10 +768,11 @@
"new": "Nowy",
"editUserPopup-title": "Edytuj użytkownika",
"newUserPopup-title": "Nowy użytkownik",
"notifications": "Notifications",
"view-all": "View All",
"filter-by-unread": "Filter by Unread",
"mark-all-as-read": "Mark all as read",
"allow-rename": "Allow Rename",
"allowRenamePopup-title": "Allow Rename"
"notifications": "Powiadomienia",
"view-all": "Wyświetl wszystko",
"filter-by-unread": "Filtruj nieprzeczytane",
"mark-all-as-read": "Zaznacz wszystkie jako przeczytane",
"remove-all-read": "Usuń wszystkie przeczytane",
"allow-rename": "Zezwól na zmianę nazwy",
"allowRenamePopup-title": "Zezwól na zmianę nazwy"
}
Loaded 100 of 143 files, more files were not shown because too many files have changed in this diff. Show more