Compare commits

...
601 Commits
Author SHA1 Message Date
Lauri Ojansivu 7c89336ea9 v2.91 2019-06-27 00:52:20 +03:00
Lauri Ojansivu bca1a2f95b Update changelog. 2019-06-26 23:14:16 +03:00
Lauri Ojansivu 6a2f120d00 Fix Attachment Outgoing Webhook missing list and swimlane name.
Thanks to xet7 !

Related #1969,
Closes #2170
2019-06-26 23:06:50 +03:00
Lauri Ojansivu e8ccfb6743 Update translations. 2019-06-26 22:14:51 +03:00
Lauri Ojansivu 8f5e2c4af3 v2.90 2019-06-21 21:28:30 +03:00
Lauri Ojansivu e5c0d0ea18 Revert v2.89 setting every Sandstorm Wekan user as admin.
Thanks to xet7.

Related #2405
2019-06-21 21:23:42 +03:00
Lauri Ojansivu 47e64c269c v2.89 2019-06-21 20:58:30 +03:00
Lauri Ojansivu cd69b03ac1 Update translations. 2019-06-21 20:55:36 +03:00
Lauri Ojansivu 5afaa5bce6 Update changelog. 2019-06-21 20:53:58 +03:00
Lauri Ojansivu 60d62a6ae3 - Sandstorm Wekan: Set everyone as Admin. Please test does this help with
[Problem with the user management: can't add users or give wekan admin rights](https://github.com/wekan/wekan/issues/2405).

Thanks to xet7 !

Related #2405
2019-06-21 20:46:05 +03:00
Lauri Ojansivu 4f46adc389 - If board does not exist, redirect to All Boards page, at all Wekan platforms.
So now at Sandstorm when loading Wekan grain, if first Sandstorm board is found,
  it is opened. If first Sandstorm board is not found (it's deleted or archived),
  then redirect automatically to All Boards page.

Closes #3132
2019-06-21 20:09:18 +03:00
Lauri Ojansivu d2dfcf36d9 v2.88 2019-06-21 18:11:19 +03:00
Lauri Ojansivu 353768b4b5 Update translations. 2019-06-21 18:07:45 +03:00
Lauri Ojansivu 4f3e83b363 v2.87 2019-06-21 12:50:13 +03:00
Lauri Ojansivu 263ec64453 Update changelog. 2019-06-21 12:46:19 +03:00
Lauri Ojansivu 140dc6db25 Update translations. 2019-06-21 12:22:29 +03:00
Lauri Ojansivu 47a7097044 Merge pull request #2508 from road42/bug/card_move_to_top_bottom_fix
Inferface: Can move cardToTop/Bottom. Fixes #2289
2019-06-21 11:54:01 +03:00
Lauri Ojansivu b8e774107a Merge pull request #2507 from road42/bug/english_language_fix_card_trigger
English language update. Fixes #2456
2019-06-21 11:53:44 +03:00
Lauri Ojansivu 3d3c78260b Merge pull request #2506 from road42/feature/rule_card_action_setdate
Adds rule feature: cardAction - SetDate #2504
2019-06-21 11:53:20 +03:00
Christoph Jahn e8f4c4d8b8 Inferface: Can move cardToTop/Bottom. Fixes #2289 2019-06-21 10:11:40 +02:00
Christoph Jahn 2156b28445 English language fixed #2456 2019-06-21 09:11:42 +02:00
Christoph Jahn a9fc74a9b4 Adds rule feature: cardAction - SetDate #2504 2019-06-21 07:24:21 +02:00
Lauri Ojansivu 02de9164f0 v2.86 2019-06-19 22:56:46 +03:00
Lauri Ojansivu 140a2d7915 Update changelog. 2019-06-19 22:50:49 +03:00
Lauri Ojansivu 17c4c96c29 - [Fix Wekan unable to Select Text from Description edit box](https://github.com/wekan/wekan/issues/2451)
by removing feature of card description submit on click outside. This is because when selecting text
  and dragging up did trigger submit of description, so description was closed and selecting text failed.
  This did affect all Chromium-based browsers: Chrome, Chromium, Chromium Edge.

Thanks to xet7 !

Closes #2451
2019-06-19 22:39:29 +03:00
Lauri Ojansivu 56e5585730 v2.85 2019-06-19 11:41:59 +03:00
Lauri Ojansivu 51a0dd8861 [Fixed bug: rule doesn't move card to top/bottom](https://github.com/wekan/wekan/pull/2502).
Thanks to road42 !

Closes #2501
2019-06-19 11:36:13 +03:00
Lauri Ojansivu 8bfd94474a Merge pull request #2502 from road42/bug/rule_action_card_move_fix
Fixed bug (rule doesn't move card to top/bottom) #2501
2019-06-19 11:33:34 +03:00
Christoph Jahn 6789e8564a Fixed bug #2501
card.move needs boardId as first parameter
2019-06-19 06:57:58 +02:00
Lauri Ojansivu b48c6a5b9c v2.84 2019-06-18 23:43:49 +03:00
Lauri Ojansivu b39b9f5463 Update changelog. 2019-06-18 21:28:32 +03:00
Lauri Ojansivu e72f186a36 Merge branch 'road42-devel' into devel 2019-06-18 21:25:33 +03:00
Christoph Jahn c3d495e7c6 Show buttons for isBoardAdmin 2019-06-17 21:05:21 +02:00
Lauri Ojansivu 98c6ea467a v2.83 2019-06-17 21:55:16 +03:00
Lauri Ojansivu 6e73abde50 Update changelog. 2019-06-17 21:51:59 +03:00
Lauri Ojansivu 7ff6f24a90 Fix Bug: Unable to click board submenu on mobile.
Thanks to xet7 !

Closes #2261
2019-06-17 21:47:02 +03:00
Lauri Ojansivu 8368461b57 v2.82 2019-06-14 16:30:34 +03:00
Lauri Ojansivu 7dc8a2d659 [Fix OIDC Docker login. Empty string results to empty array at wekan/server/authentication.js](https://github.com/wekan/wekan/commit/bddbaa7bc2f3cfe8553a2265e168231ab51876f3).
Thanks to xet7 !

Closes #2206
2019-06-14 16:27:40 +03:00
Lauri Ojansivu bddbaa7bc2 - Fix OIDC Docker login. Empty string results to empty array at wekan/server/authentication.js
Thanks to xet7 !

Closes #2206
2019-06-14 16:23:18 +03:00
Lauri Ojansivu f9abfe5244 v2.81 2019-06-13 19:29:41 +03:00
Lauri Ojansivu 97d57b05ad Update changelog. 2019-06-13 19:28:08 +03:00
Lauri Ojansivu 4334fbbb9d - Change OAuth2 whitelist default to empty string at snap, so it would be used as array on wekan/server/authentication.js.
Thanks to xet7 !
2019-06-13 19:24:50 +03:00
Lauri Ojansivu 595c657b57 Add missing text. 2019-06-13 19:00:18 +03:00
Lauri Ojansivu ed04769947 v2.80 2019-06-13 18:21:51 +03:00
Lauri Ojansivu 44dbd462b1 Default whitelist array, not string.
Thanks to xet7 !
2019-06-13 18:18:03 +03:00
Lauri Ojansivu 291797b238 v2.79 2019-06-13 18:14:43 +03:00
Lauri Ojansivu 1178a48e68 Add back [OAuth2 idTokenWhitelistFields default empty array](https://github.com/wekan/wekan/commit/8b31c0768c34fc4557b54cec936a0b4288a8e722#commitcomment-33921882).
Thanks to moserben16 !
2019-06-13 11:03:45 +03:00
Lauri Ojansivu 34b7bfd19c Update translations. 2019-06-12 19:07:31 +03:00
Lauri Ojansivu 02c418f4bb Update changelog. 2019-06-12 19:05:29 +03:00
Lauri Ojansivu ae3b061d4c Merge pull request #2488 from DominikPf/fix-dockerfile-oauth2-typo
fix oauth2 typos in dockerfile & compose
2019-06-12 18:44:50 +03:00
Dominik Pfeifer eb49bb5e10 fix oauth2 typos in dockerfile & compose 2019-06-12 13:41:10 +02:00
Lauri Ojansivu 79745d1892 v2.78 2019-06-12 06:34:46 +03:00
Lauri Ojansivu 8b31c0768c Try to fix OIDC login.
Thanks to xet7 !
2019-06-12 06:29:57 +03:00
Lauri Ojansivu 25e294fd92 v2.77 2019-06-11 20:27:17 +03:00
Lauri Ojansivu 017d2deeee Fix Snap build.
Thanks to xet7 !
2019-06-11 20:20:29 +03:00
Lauri Ojansivu e1e20275a6 v2.76 2019-06-11 17:03:01 +03:00
Lauri Ojansivu 3c4f8f6796 Support scopes in OAuth2, so Authentication via OAuth2 with Google is now possible.
Thanks to moserben16 !

Closes #2454
2019-06-11 16:56:45 +03:00
Lauri Ojansivu 406a9492fd Merge branch 'moserben16-patch-1' into devel 2019-06-11 16:51:36 +03:00
Lauri Ojansivu c859cd2278 Merge branch 'patch-1' of https://github.com/moserben16/wekan into moserben16-patch-1 2019-06-11 16:36:14 +03:00
Lauri Ojansivu cd70d9d09e Update changelog. 2019-06-11 16:34:36 +03:00
Lauri Ojansivu 86e7e1c600 More CORS headers settings related to https://github.com/wekan/wekan/pull/2429
Thanks to xet7 !
2019-06-11 16:32:42 +03:00
Lauri Ojansivu e540148d09 Update changelog. 2019-06-11 16:10:34 +03:00
Lauri Ojansivu 30b108ab36 Merge pull request #2442 from Jason-Cooke/patch-1
docs: fix typo
2019-06-11 16:07:58 +03:00
Lauri Ojansivu ec535aaa9c Update changelog. 2019-06-11 16:02:53 +03:00
Lauri Ojansivu bb108b2144 Merge branch 'road42-devel' into edge 2019-06-11 16:00:44 +03:00
Lauri Ojansivu f3c76ac60b Update ChangeLog. 2019-06-11 15:56:41 +03:00
Lauri Ojansivu 23ccb3b991 Show attachment name in Outgoing Webhook when attachment is removed from card.
Thanks to xet7 !

Related #2285
2019-06-11 13:11:35 +03:00
Lauri Ojansivu 992ecfefa2 Show attachment name in Outgoing Webhook when attachment is added to card.
Thanks to xet7 !

Related #2285
2019-06-11 10:53:50 +03:00
benji fd390d2560 Update oidc_server.js
with this fix, Authentication via OAuth2 with Google is possible.
1.) token endpoint and userinfo-endpoint in Google are different, so you have to check that,
2.) request the scopes of the environment variable "process.env.OAUTH2_REQUEST_PERMISSIONS"
with this small little fix the login with google in oauth2-protocol gets possible :-)
I would be very happy about a master-merge

thank you in advance
2019-06-11 09:23:12 +02:00
Lauri Ojansivu 3f1ac6b5db Update translations. 2019-06-10 18:57:07 +03:00
Lauri Ojansivu d8f112278b Additional CORS headers settings, added earlier. In progress. 2019-06-10 18:29:33 +03:00
Christoph Jahn 0704cfb8b6 isAdmin and isBoardAdmin should add rules 2019-06-08 22:04:09 +02:00
Jason Cooke 5e806c3879 docs: fix typo 2019-06-01 09:57:45 +12:00
Christoph Jahn 27b0fd35b4 Allow BoardAdmin to create board rules. #2431 2019-05-28 17:41:39 +02:00
Lauri Ojansivu 5c1818fc9a Update changelog. 2019-05-24 22:38:23 +03:00
Lauri Ojansivu a7fb9662e3 Merge branch 'risacher-master' into edge 2019-05-24 22:35:35 +03:00
Daniel Risacher cb00cfc1b7 Add support for more CORS headers 2019-05-24 12:39:54 -04:00
Lauri Ojansivu d7bc8d100d Update changelog. 2019-05-23 11:47:50 +03:00
Lauri Ojansivu d067b3976c Merge pull request #2427 from DominikPf/OAuth2-fix
Fix Scope parsing Issue for OAuth2 Login with simple String
2019-05-23 11:43:10 +03:00
DominikPf 892ee60527 Fix Scope parsing Issue for OAuth2 Login 2019-05-23 10:28:08 +02:00
Lauri Ojansivu d83cb75f95 v2.75 2019-05-22 21:47:49 +03:00
Lauri Ojansivu 697aaa895d Update translations. 2019-05-22 21:44:23 +03:00
Lauri Ojansivu 8add28d328 Update changelog. 2019-05-22 21:42:59 +03:00
Lauri Ojansivu 634df8f6f2 - Fix: OAuth2 Requested Scopes are wrong / cannot be configured.
Thanks to DominikPf and xet7 !

Closes #2412
2019-05-22 21:37:01 +03:00
Lauri Ojansivu d194cc7a5a - [CAS allowed LDAP groups](https://github.com/wekan/meteor-accounts-cas/pull/4).
Thanks to ppoulard !

Please test.

Related #2356
2019-05-22 20:15:24 +03:00
Lauri Ojansivu 0834f6ed1e v2.74 2019-05-14 21:33:12 +03:00
Lauri Ojansivu 9d5e288bca Update changelog. 2019-05-14 21:29:46 +03:00
Lauri Ojansivu 0fe40ad9ec - Add missing [wekan-ldap#40](https://github.com/wekan/wekan-ldap/pull/40) code about LDAP_SYNC_ADMIN_STATUS.
Thanks to JulianJacobi, n-st, chirrut2 and xet7 !

Closes #2351
2019-05-14 21:24:11 +03:00
Lauri Ojansivu 0765278195 v2.73 2019-05-14 16:48:18 +03:00
Lauri Ojansivu f782b9c298 Update translations (fi). 2019-05-14 16:42:05 +03:00
Lauri Ojansivu e611685e50 Fix lint errors. 2019-05-14 16:37:41 +03:00
Lauri Ojansivu 3edef95c4e - [Few fixes for Dockerfile](https://github.com/wekan/wekan/pulls/2407).
Thanks to bentiss !
2019-05-14 16:31:13 +03:00
Lauri Ojansivu 9b902e1ca0 Merge pull request #2407 from bentiss/dockerfile-fixes
Few fixes for Dockerfile
2019-05-14 16:28:51 +03:00
Lauri Ojansivu fc835815d8 - [Card count placement and export API functionality back](https://github.com/wekan/wekan/pulls/2406).
Thanks to bentiss.

Closes #2403,
closes #2328
2019-05-14 16:27:15 +03:00
Lauri Ojansivu da083c2e20 Merge pull request #2406 from bentiss/fixes
card count placement and export API functionality back
2019-05-14 16:25:05 +03:00
Lauri Ojansivu 6ee17ab080 - Fixed [#2338](https://github.com/wekan/wekan/issues/2338) -> [Slow opening of big boards with too many archived items](https://github.com/wekan/wekan/pull/2402).
If some Wekan users see errors with this, please empty your browser cache.
  Thanks to nerminator.

Closes #2338
2019-05-14 16:23:52 +03:00
Benjamin Tissoires 1e34585548 Dockerfile: no need to change the permissions once again
we carefully used gosu where needed, so there is no need to re-run a
check on the permissions.
2019-05-14 10:33:41 +02:00
Benjamin Tissoires 76cd5a2844 Dockerfile: use gosu for creating the openapi files 2019-05-14 10:33:41 +02:00
Benjamin Tissoires ffd1b93abf Dockerfile: bump api2html to version 0.3.3 2019-05-14 10:33:41 +02:00
Benjamin Tissoires 1eea102f26 openAPI: also handle export statement in the scripts
The files are actually modules, not plain scripts, and thus we are allowed
to use `export`. Without `parseModule`, the script would silently fail
when parsing `export.js` and the export function will not be present.
2019-05-14 10:10:21 +02:00
Benjamin Tissoires 94c1367684 Restore export API
Commit 477d71e0b9 was based on an older version of export.js, which
means it reverted a few changes that were made previously.

Fixes #2328
2019-05-14 09:37:56 +02:00
Benjamin Tissoires 9bf19f81a4 Fix card count position
When introducing markdown in the title (b795115042), the card
count got pushed outside of the List Header.

Add its own style (by manually merge small and quiet), and restore its
original placement.

Fixes #2403
2019-05-14 09:37:34 +02:00
Lauri Ojansivu 21de0ec396 Merge pull request #2402 from nerminator/feature/performance_archive
Fixed #2338 -> Slow opening of big boards with too many archived items
2019-05-13 12:56:12 +03:00
wekan ab4fec0f3c Fixed #2338 -> Slow opening of big boards with too many archived items 2019-05-13 11:01:50 +02:00
Lauri Ojansivu b983479476 v2.72 2019-05-13 10:49:41 +03:00
Lauri Ojansivu f6e5e514ef Merge pull request #2401 from guyzyl/devel
Added BIDI support to "Add Card" #884
2019-05-13 10:42:42 +03:00
Guy Zylberberg ddd828083e Added BIDI support to "Add Card" #884 2019-05-13 00:37:40 +03:00
Lauri Ojansivu e079b4df17 v2.71 2019-05-12 20:49:27 +03:00
Lauri Ojansivu 4e5ff17e18 Update translations. 2019-05-12 20:43:23 +03:00
Lauri Ojansivu 86e1a9cd5d Update changelog. 2019-05-12 20:40:32 +03:00
Lauri Ojansivu 8a0efffdf8 Merge pull request #2400 from atilaromero/devel
Add partentId support on card web API
2019-05-12 20:27:50 +03:00
Lauri Ojansivu c21f710a70 Fix typo. 2019-05-12 19:15:49 +03:00
Atila Romero f3382abe3b Add partentId support on card web API 2019-05-12 10:26:08 -03:00
Lauri Ojansivu d6c86f3cba v2.70 2019-05-11 23:50:47 +03:00
Lauri Ojansivu 3a6516f0cb Update changelog. 2019-05-11 23:47:11 +03:00
Lauri Ojansivu b795115042 - [View markdown on List names, Custom Fields (Text and Dropdown), Label names,
All Boards view Board names and Board descriptions](https://github.com/wekan/wekan/issues/2334).

Thanks to shaygover and xet7 !

Related #2334
2019-05-11 23:40:18 +03:00
Lauri Ojansivu 52fe845d24 v2.69 2019-05-11 00:07:37 +03:00
Lauri Ojansivu b2b6bb2d39 Update changelog. 2019-05-11 00:05:34 +03:00
Lauri Ojansivu db40ca25ac - Fix translation name in Wekan menu: oc to Occitan.
Thanks to xet7 !
2019-05-11 00:02:40 +03:00
Lauri Ojansivu 3eef42eee0 v2.68 2019-05-10 23:18:12 +03:00
Lauri Ojansivu 38d0ad74a9 Update changelog. 2019-05-10 23:13:20 +03:00
Lauri Ojansivu 3bbc805ee4 Option to login to the LDAP server with the user's own username and password, instead of an administrator key. Default: false (use administrator key).
With new setting: LDAP_USER_AUTHENTICATION=true
Added to Snap, Docker and Source.

Thanks to xet7 !

Related https://github.com/wekan/wekan/pull/2399
2019-05-10 23:04:51 +03:00
Lauri Ojansivu c37a454bd5 Merge branch 'thiagofernando-devel' into devel 2019-05-10 22:23:15 +03:00
Lauri Ojansivu 6f98be5608 Merge branch 'devel' of https://github.com/thiagofernando/wekan into thiagofernando-devel 2019-05-10 22:21:50 +03:00
Lauri Ojansivu ab4dab2ade v2.67 2019-05-10 21:01:34 +03:00
Lauri Ojansivu 88ffddfeba Update changelog. 2019-05-10 20:58:35 +03:00
Thiago Fernando 36f148a7cb Update loginHandler.js
additional option to login in ldap server with user account
2019-05-10 14:58:19 -03:00
Thiago Fernando fd1af07e43 Update ldap.js 2019-05-10 14:56:07 -03:00
Lauri Ojansivu fca87b53f0 Update changelog. 2019-05-10 20:55:35 +03:00
Thiago Fernando ce0473480b Merge pull request #1 from wekan/devel
ldap changes
2019-05-10 14:54:25 -03:00
Lauri Ojansivu 828f6ea321 - Add Feature: Move board to Archive button at each board at All Boards page.
Thanks to xet7 !

Related #2389
2019-05-10 20:50:53 +03:00
Lauri Ojansivu 7ff4067e88 v2.66 2019-05-09 16:32:34 +03:00
Lauri Ojansivu 491d27638a Delete user feature. 2019-05-09 16:24:13 +03:00
Lauri Ojansivu e1b016cf3d Prevent data loss.
Thanks to xet7 !
2019-05-09 16:17:53 +03:00
Lauri Ojansivu c850669777 Merge pull request #2384 from Akuket/origin/edge
Delete user feature
2019-05-09 16:06:17 +03:00
Lauri Ojansivu 04c7372a4e Update changelog. 2019-05-09 16:02:54 +03:00
Lauri Ojansivu 64ee60a008 Fix missing profile checks.
Thanks to justinr1234 !
2019-05-09 14:32:38 +03:00
Lauri Ojansivu 434ed895ed Merge pull request #2395 from guyzyl/devel
Fixed RTL issue #884
2019-05-09 14:24:35 +03:00
Guy Zylberberg 1bdc1017d6 Fixed RTL issue #884 2019-05-08 21:30:38 +03:00
Lauri Ojansivu 6218d8c7ed Update translations. 2019-05-08 18:20:49 +03:00
Lauri Ojansivu c250554177 Update translations. Add Chinese (Hong Kong). 2019-05-06 20:57:01 +03:00
Lauri Ojansivu de772a8c3b Update changelog. 2019-04-29 01:18:17 +03:00
Lauri Ojansivu 23f1cf5f49 Update translations. 2019-04-29 01:17:52 +03:00
Lauri Ojansivu 723fa11a74 Merge pull request #2385 from faust64/patch-1
fix(oidc): can not log in
2019-04-26 23:08:45 +03:00
Lauri Ojansivu 94b602e167 Update translations. 2019-04-26 23:07:38 +03:00
Samuel b17359ec6f fix(oidc): can not log in
Trying to configure wekan authenticating against LemonLDAP-NG, I used to read about errors like the following:

```
XXX: getUserInfo response:  { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
{"line":"431","file":"oauth.js","message":"Error in OAuth Server: id is not defined","time":{"$date":1556286530412},"level":"warn"}
Exception while invoking method 'login' { stack: 'ReferenceError: id is not defined\n    at Object.handleOauthRequest (packages/wekan-oidc.js:39:68)\n    at OAuth._requestHandlers.(anonymous function) (packages/oauth2.js:27:31)\n    at middleware (packages/oauth.js:203:5)\n    at packages/oauth.js:176:5',
source: 'method' }
```

Looking at the sources, that error message seems to be right: we have several references to `id`, `uid`, `displayName` or `email`, which are not defined. Probably a typo, assuming we meant these to be strings.

Applying that patch, I confirm I can finally log in:

```
XXX: getUserInfo response:  { sub: 'demoone' }
XXX: userinfo: { sub: 'demoone' }
XXX: serviceData: { id: undefined,
  username: undefined,
  fullname: undefined,
  accessToken: 'e57dc4e9e81cc98c279db3ed08b1c72f',
  expiresAt: 1556298699213,
  email: undefined }
XXX: profile: { name: undefined, email: undefined }
```

All the credit goes to @pcurie .
2019-04-26 18:21:42 +02:00
guillaume cdef8a33e4 Delete user feature 2019-04-26 17:53:48 +02:00
Lauri Ojansivu 11a91bfc78 Update translations. 2019-04-24 16:12:29 +03:00
Lauri Ojansivu aeb3dd0220 v2.65 2019-04-24 14:40:04 +03:00
Lauri Ojansivu 9647a33209 Update translations. 2019-04-24 14:01:38 +03:00
Lauri Ojansivu 2d966863e3 Merge branch 'Akuket-edge' into edge 2019-04-24 13:51:00 +03:00
Lauri Ojansivu a66632f767 Update translations. 2019-04-24 13:41:29 +03:00
Lauri Ojansivu 1c2ee631f4 Update changelog. 2019-04-24 13:37:19 +03:00
guillaume 259ff3436f fix lints 2019-04-24 12:35:00 +02:00
Lauri Ojansivu a750ecaafd - Remove from card menu, because they also exist at card:
members, labels, attachments, dates received/start/due/end.

Thanks to sfahrenholz, jrsupplee and xet7 !

Closes #2242,
related https://community.vanila.io/?t=517527b6-3d84-4e9d-b2ec-6f560a9cfdf7
2019-04-24 13:32:36 +03:00
guillaume 8b3601248d Loading authentication page 2019-04-24 12:28:11 +02:00
Lauri Ojansivu 6420020309 v2.64 2019-04-23 19:49:07 +03:00
Lauri Ojansivu 65d86a42d7 Update translations (es). 2019-04-23 19:45:54 +03:00
Lauri Ojansivu 4eaffdc6a4 [Board Archive: Delete Card/List/Swimlane](https://github.com/wekan/wekan/pull/2376).
Thanks to Akuket !

Closes #1625
2019-04-23 19:43:02 +03:00
Lauri Ojansivu 454e8a3962 Update translations. 2019-04-23 19:38:23 +03:00
Lauri Ojansivu 11e8a9d5c4 Merge branch 'Akuket-feature/removeArchived' into edge 2019-04-23 19:30:23 +03:00
guillaume 8137f2692f remove feature 2019-04-23 18:00:09 +02:00
Lauri Ojansivu 6933424fca Remove python2 from Dockerfile, to make Docker image smaller.
Thanks to xet7 !
2019-04-23 15:10:47 +03:00
Lauri Ojansivu ff8a10c231 v2.63 2019-04-23 14:41:33 +03:00
Lauri Ojansivu 6a94500170 Remove caddy plugins http.filter, http.ipfilter and http.realip from caddy
because they are currently broken, preventing download of caddy
during Wekan Snap build.

Thanks to xet7 !
2019-04-23 14:35:41 +03:00
Lauri Ojansivu 41eb47bc15 v2.62 2019-04-23 14:08:13 +03:00
Lauri Ojansivu 211f772447 Merge pull request #2374 from hupptechnologies/center-card-list-view
Issue : Mobile UI Center cards in list view #2371
2019-04-23 14:02:04 +03:00
Lauri Ojansivu 6d6e3fd127 Update translations. 2019-04-23 14:00:12 +03:00
hupptechnologies 14ef0ab6d1 Issue : Mobile UI Center cards in list view #2371
Resolved #2371
2019-04-23 15:09:09 +05:30
Lauri Ojansivu 8434069539 v2.61 2019-04-20 17:11:14 +03:00
Lauri Ojansivu c7621f251f Fix release build script. package repos are included to Wekan now. 2019-04-20 17:04:59 +03:00
Lauri Ojansivu a5122cc076 Update translations. 2019-04-20 16:47:54 +03:00
Lauri Ojansivu 5993d6862b Change enter => search 2019-04-20 16:46:26 +03:00
Lauri Ojansivu 348b612f98 Fix rebuild script. 2019-04-20 16:34:16 +03:00
Lauri Ojansivu f714b59c88 Uncomment not needed lines. 2019-04-20 16:31:10 +03:00
Lauri Ojansivu b627499acd Merge branch 'Akuket-edge' into edge 2019-04-20 16:29:08 +03:00
Lauri Ojansivu 43beccc2eb Update translations. 2019-04-20 16:28:03 +03:00
Lauri Ojansivu b8275b3404 Merge branch 'edge' of https://github.com/Akuket/wekan into Akuket-edge 2019-04-20 16:22:20 +03:00
Lauri Ojansivu 6e4da08164 LDAP issues now at main Wekan repo. 2019-04-20 16:21:21 +03:00
Lauri Ojansivu f2ac52bcdf Update changelog. 2019-04-20 16:20:00 +03:00
Lauri Ojansivu 46e976513b Move https://github.com/wekan/wekan-postgresql to
wekan/torodb-postgresql at https://github.com/wekan/wekan

Thanks to xet7 !
2019-04-20 16:05:54 +03:00
Lauri Ojansivu 816ccf6509 Update package names. 2019-04-20 15:24:09 +03:00
Lauri Ojansivu 73e265d8fd Include to Wekan packages directory contents, so that meteor command would build all directly.
This also simplifies build scripts.

Thanks to xet7 !
2019-04-20 15:18:33 +03:00
Lauri Ojansivu 6117097a93 - Upgrade to Node 8.16.0
- Change git repo urls from git:// to https://

Thanks to xet7 !
2019-04-20 14:52:37 +03:00
Lauri Ojansivu fee732dba1 Fix repo urls. 2019-04-20 14:47:33 +03:00
Lauri Ojansivu 1138e8062f Fix repo url. 2019-04-20 14:46:11 +03:00
Lauri Ojansivu 123cf0d7b8 Fix typos in directory names. 2019-04-20 14:03:35 +03:00
Lauri Ojansivu bd14ee3b1f Ubuntu base image to ubuntu:disco
Thanks to Ubuntu and xet7 !
2019-04-20 13:44:14 +03:00
guillaume e63eee0c68 fix lints 2019-04-19 16:39:14 +02:00
guillaume 070feb4b66 Number of users 2019-04-19 16:17:17 +02:00
guillaume 308417852c Search user in admin panel 2019-04-19 14:57:52 +02:00
Lauri Ojansivu 9c3a976250 - Remove [extra](https://github.com/wekan/wekan/pull/2332) [quotes](https://github.com/wekan/wekan/pull/2333) from docker-compose.yml.
Thanks to hibare !
2019-04-18 13:42:00 +03:00
Lauri Ojansivu 688973bae5 [Fix Full width of lists and space before first list](https://github.com/wekan/wekan/pull/2343).
Thanks to hupptehcnologies !

Closes #2336
2019-04-18 13:38:37 +03:00
Lauri Ojansivu d93b0be0d4 Add missing packages back. 2019-04-18 13:36:14 +03:00
Lauri Ojansivu 773abbae13 Merge pull request #2343 from hupptechnologies/improve-mobile-ui
Issue: Full width of lists and space before first list #2336
2019-04-18 13:35:20 +03:00
Lauri Ojansivu 0f3579fd7b Merge branch 'devel' into improve-mobile-ui 2019-04-18 13:34:40 +03:00
Lauri Ojansivu db7b7158fa Merge branch 'master' into devel 2019-04-18 13:30:49 +03:00
Lauri Ojansivu b5a61f2dd8 Merge pull request #2333 from hibare/devel
Removed quotes
2019-04-18 13:30:23 +03:00
Lauri Ojansivu 8347f15de2 Merge pull request #2332 from hibare/master
Removed quotes
2019-04-18 13:30:05 +03:00
Lauri Ojansivu 26309fad10 Update translations. 2019-04-18 13:26:46 +03:00
Lauri Ojansivu ba4d8b0b35 Update to newest GitHub flawored markdown.
Thanks to shaygover and xet7 !

Related #2334
2019-04-18 13:23:48 +03:00
hupp-mac-4 dc11e0c79c Issue: Full width of lists and space before first list #2336
Resolved #2336
2019-04-18 15:41:23 +05:30
Lauri Ojansivu a13d931cfd Change to correct issue number as noticed typo at #2295 2019-04-18 13:10:49 +03:00
Lauri Ojansivu fea2ad3d7d Test newest markdown. 2019-04-18 10:57:59 +03:00
Shubham Hibare b8c10def8e Removed quotes 2019-04-12 00:44:54 +05:30
Shubham Hibare 80afc28719 Removed quotes 2019-04-12 00:43:59 +05:30
Lauri Ojansivu 561cd77e68 Replace header login example variable names.
Related #2019
2019-04-08 12:01:26 +03:00
Lauri Ojansivu d8554ec67e Combine to same line. 2019-04-08 10:58:49 +03:00
Lauri Ojansivu a43237d4f9 v2.60 2019-04-08 10:31:48 +03:00
Lauri Ojansivu 6af7d782d4 Update translations. 2019-04-08 10:29:29 +03:00
Lauri Ojansivu 6d2b778ac5 [Fix: Description of Board is out of visible after Feature "Duplicate Board"](https://github.com/wekan/wekan/issues/2324).
Thanks to sfahrenholz and xet7 !

Closes #2324
2019-04-08 09:07:58 +03:00
Lauri Ojansivu eada773048 [Fix: Description of Board is out of visible after Feature "Duplicate Board"](https://github.com/wekan/wekan/issues/2324).
Thanks to sfahrenholz and xet7 !

Closes #2324
2019-04-08 09:03:55 +03:00
Lauri Ojansivu 9bff4e061e Update translations. 2019-04-07 18:27:17 +03:00
Lauri Ojansivu 753ce8e119 v2.59 2019-04-06 14:15:40 +03:00
Lauri Ojansivu 4be6719db4 - [Add variables for activity notifications, Fixes #2285](https://github.com/wekan/wekan/pull/2320).
Thanks to rinnaz !

Closes #2285
2019-04-06 14:07:55 +03:00
Lauri Ojansivu a6e1dc4269 Merge pull request #2320 from rinnaz/fix/issue-2285
Add variables for activity notifications Fixes #2285
2019-04-06 14:04:09 +03:00
Lauri Ojansivu ad241b9f84 v2.58 2019-04-06 13:54:32 +03:00
Lauri Ojansivu 53e76288cb [Add Duplicate Board tooltip, and remove adding text "Copy" to duplicated board](https://github.com/wekan/wekan/commit/0f15b6d1982c383f76e8411cb501ff27e8febd42).
Thanks to xet7 !
2019-04-06 13:52:05 +03:00
Lauri Ojansivu 0f15b6d198 - Add Duplicate Board tooltip, and remove adding text "Copy" to duplicated board.
Thanks to xet7 !
2019-04-06 13:47:15 +03:00
windblow 143e93f483 Add variables for activity notifications Fixes #2285 2019-04-06 12:45:31 +03:00
Lauri Ojansivu 93a5bb2baa Add the following new features:
- [Duplicate Board](https://github.com/wekan/wekan/issues/2257). Related #2225.
  Thanks to Angtrim. Closes #2257.

and fix the following bugs:

- [Fix Swimlane Rules don't work](https://github.com/wekan/wekan/issues/2225).
  Thanks to Angtrim.
2019-04-06 09:19:33 +03:00
Lauri Ojansivu ebfc8e5a1b Fix lint errors.
Thanks to xet7 !
2019-04-06 09:00:13 +03:00
Lauri Ojansivu 972b9b6e91 Remove extra files.
Thanks to xet7 !
2019-04-06 08:50:56 +03:00
Lauri Ojansivu 56cccc6781 Merge remote-tracking branch 'Angtrim/feature-duplicate' into edge 2019-04-06 08:46:40 +03:00
Lauri Ojansivu b680bb5372 - [Remove not needed ARGS from Dockerfile to reduce amount of Docker layers](https://github.com/wekan/wekan/issues/2301).
Thanks to folhabranca !

Closes #2301
2019-04-06 08:14:37 +03:00
Lauri Ojansivu 217b3ae488 Remove not needed ARGS from Dockerfile to reduce amount of Docker layers.
Thanks to folhabranca !

Closes #2301
2019-04-06 08:11:08 +03:00
Lauri Ojansivu 959392f815 [Center reduce left margin in card view on mobile browser](https://github.com/wekan/wekan/pull/2314).
Thanks to hupptechnologies !
2019-04-06 07:57:30 +03:00
Lauri Ojansivu d1e13e48fe Restore original meteor packages and versions.
Thanks to xet7 !
2019-04-06 07:47:08 +03:00
Lauri Ojansivu 1c04502963 Merge branch 'devel' of github.com:wekan/wekan into devel 2019-04-06 07:45:16 +03:00
Lauri Ojansivu 34da23783e Merge pull request #2314 from hupptechnologies/card-view-on-mobile-browser
Issue: Center reduce left margin in card view on mobile browser #2188
2019-04-06 07:45:03 +03:00
Lauri Ojansivu 2b603cfbb5 Merge branch 'edge' into devel 2019-04-06 07:44:03 +03:00
Lauri Ojansivu a1fe22c08c [Add proper variables for unjoin card](https://github.com/wekan/wekan/pull/2313).
Thanks to chotaire.
2019-04-06 07:43:14 +03:00
Lauri Ojansivu bc04ae24a7 Merge pull request #2313 from chotaire/edge
Add proper variables for unjoin card
2019-04-05 22:10:05 +03:00
Angelo Gallarello 48216e1653 Minor fixes 2019-04-05 10:38:39 +02:00
hupptechnologies 8aca82a593 Issue: Center (or reduce left margin) in card view on mobile browser #2188
Resolved #2188
2019-04-05 13:27:41 +05:30
chotaire 68d8cbe68a Merge pull request #1 from chotaire/chotaire-patch-1
Add proper variables for unjoin card
2019-04-05 03:03:57 +02:00
chotaire 4bc3acb14d Add proper variables for unjoin card 2019-04-05 02:59:35 +02:00
Lauri Ojansivu a974ec9dee Update translations. 2019-04-04 20:22:25 +03:00
Lauri Ojansivu e91c43466d Merge pull request #2303 from fossabot/devel
Add license scan report and status
2019-04-02 16:36:29 +03:00
fossabot dfc4ab6dd8 Add license scan report and status
Signed-off-by: fossabot <badges@fossa.io>
2019-04-02 06:32:34 -07:00
Lauri Ojansivu 9f5ffde2dd v2.57 2019-04-02 15:26:40 +03:00
Lauri Ojansivu 678bef2360 Update changelog. 2019-04-02 15:19:21 +03:00
Lauri Ojansivu 3b12cdc179 Merge branch 'bentiss-spinners-no-IntersectionObserver' into devel 2019-04-02 15:15:34 +03:00
Benjamin Tissoires 261754f18b list: do not use IntersectionObserver to reduce CPU usage
Switch back to a custom spinner detection, as the IntersectionObserver
is eating a lot of CPU resources on idle.

This should also take care of #2250 properly: the previous `onDestroyed()`
was removing the resize and scroll callbacks, but they were not unique
enough, and they were shared across swimlanes. So if a list had 2 swimlanes
with spinners, when one was removed, the other was not triggering its
callbacks anymore.

Related: #2294
2019-04-01 23:54:35 +02:00
Lauri Ojansivu 980db9cb0c Merge branch 'edge' of github.com:wekan/wekan into edge 2019-03-30 19:07:05 +02:00
Lauri Ojansivu a80cd455de - [Add back zoom fixes of #2250](https://github.com/wekan/wekan/issues/2250).
Thanks to xet7 !
2019-03-30 19:06:09 +02:00
Lauri Ojansivu 289e3d6286 More deps. 2019-03-30 14:34:32 +02:00
Lauri Ojansivu 4b181620d8 Added nodejs to install dependencies.
Thanks to xet7 !
2019-03-30 14:30:04 +02:00
Lauri Ojansivu 088ec7fd94 [Add proper variables for join card](https://github.com/wekan/wekan/commit/289f1fe1340c85eb2af19825f4972e9057a86b7a),
fixes [Incorrect variable replacement on email notifications](https://github.com/wekan/wekan/issues/2295).

Thanks to justinr1234 !

Closes #2295
2019-03-29 14:39:35 +02:00
Lauri Ojansivu 289f1fe134 Merge pull request #2291 from justinr1234/patch-3
Add proper variables for join card Fixes #2285
2019-03-29 14:35:06 +02:00
Lauri Ojansivu 6b9ac52af6 Update translations. 2019-03-29 14:34:24 +02:00
Lauri Ojansivu 0e422eb70d [Revert spinner etc fixes of Wekan v2.56, because of some new bugs](https://github.com/wekan/wekan/issues/2250).
Thanks to gerroon !

Related #2250
2019-03-29 14:31:26 +02:00
Lauri Ojansivu df32545b07 Revert spinner etc fixes of Wekan v2.56, because of some new bugs.
Thanks to gerroon !

Related #2250
2019-03-29 14:27:37 +02:00
justinr1234 bab340a849 Add proper variables for join card Fixes #2285 2019-03-28 19:38:02 -05:00
Lauri Ojansivu 494d44f8bb v2.56 2019-03-27 17:51:54 +02:00
Lauri Ojansivu ad1a81e8a0 Update translations. 2019-03-27 17:46:09 +02:00
Lauri Ojansivu b0d507c2dd [Fixes the following bugs](https://github.com/wekan/wekan/pull/2287):
- [#2250 -> the spinner could be shown on startup and never goes away](https://github.com/wekan/wekan/issues/2250).
- The code will now only load extra cards that will be in the current viewport.
- When 2 users were interacting on the same board, there was a situation where the spinner could show up on the other user, without being able to load the extra cards.
- The code is now much simpler, thanks to the IntersectionObserver, and all of this for fewer lines of code :)

Thanks to bentiss with Apache I-CLA !

Closes #2250
2019-03-27 17:38:54 +02:00
Lauri Ojansivu 619e5e944b Merge branch 'bentiss-fix-infinite-scroll' into edge 2019-03-27 17:33:53 +02:00
Benjamin Tissoires e2d0faa539 list: disconnect infinite-scroll observer to prevent memory leak 2019-03-26 16:28:25 +01:00
Benjamin Tissoires cbb6c82113 list: move the spinner into its own blaze component
This way, when a list is at the maximum number of cards shown and adding
a new card would make the spinner appear, the list would load the next
N items.

This can happen if user A and B are both looking at the same board,
B adds a new cards, and A will see the spinner and will not be able to
remove it.
2019-03-26 16:27:52 +01:00
Benjamin Tissoires 00376b43f8 list: make sure the spinner of infinite scrolling doesn't show on load
When loading a board on a high resolution screen, there is a chance there
is not enough cards displayed and the spinner is still there, spinning
forever.

Add an idle callback that checks if the spinner is still there, and while
it is there, extend the number of cards to show.

Fixes #2250
2019-03-26 16:26:59 +01:00
Benjamin Tissoires fb163a2493 list: simplify infinite scrolling
Use IntersectionObserver instead of custom made one.
This adds the benefit of not loading any extra cards if the list is
not shown on screen
2019-03-26 16:25:49 +01:00
Lauri Ojansivu 14c493fc63 v2.55 2019-03-25 19:11:35 +02:00
Lauri Ojansivu 625682a4da - Use older api2html@0.3.0 to fix broken snap and docker build,
because newer api2html caused
  [breaking change](https://github.com/tobilg/api2html/commit/a9a41bca18db3f9ec61395d7262eff071a995783)
  at api2html/bin/api2html.js:23 has error about "php: "PHP".

Thanks to bentiss with Apache I-CLA !

Closes #2286
2019-03-25 18:57:35 +02:00
Lauri Ojansivu eec8f45de5 v2.54 2019-03-25 17:11:29 +02:00
Lauri Ojansivu 0855e3e32f Update translations. 2019-03-25 17:04:29 +02:00
Lauri Ojansivu fab3ce46b8 - Fix typos.
- Fix Outgoing Webhook message about created new swimlane.

Related #1969
2019-03-25 17:02:36 +02:00
Lauri Ojansivu 08c8ebc100 - Fix typos.
- Fix Outgoing Webhook message about created new swimlane.

Related #1969
2019-03-25 16:59:12 +02:00
Lauri Ojansivu 0039fe09be Removed commented out text. 2019-03-24 17:44:03 +02:00
Lauri Ojansivu 97beed6fd1 v2.53 2019-03-23 21:34:43 +02:00
Lauri Ojansivu 994314cfa3 Fix filenames and urls. 2019-03-23 21:30:41 +02:00
Lauri Ojansivu db6dbe34c3 Fix docker-compose.yml 2019-03-23 21:13:03 +02:00
Lauri Ojansivu fa7ef361e2 Update translations. 2019-03-23 13:17:36 +02:00
Lauri Ojansivu 296349a83b v2.52 2019-03-22 13:08:36 +02:00
Lauri Ojansivu 563458e0b5 Update translations. 2019-03-22 12:03:25 +02:00
Lauri Ojansivu 169301fa18 Update translations. 2019-03-22 09:25:18 +02:00
Lauri Ojansivu 0363e6f122 Remove extra title quotes, so that Custom Product Name comes visible.
Thanks to xet7 !
2019-03-22 01:35:53 +02:00
Lauri Ojansivu c259324185 Fix cloning repos. 2019-03-21 23:58:58 +02:00
Lauri Ojansivu 57767d9906 Update translations. 2019-03-21 23:48:36 +02:00
Lauri Ojansivu 1a26f9fb82 Update translations. 2019-03-21 22:35:13 +02:00
Lauri Ojansivu 19ab7db239 Add vanila community link. 2019-03-21 22:34:41 +02:00
Lauri Ojansivu ded430c155 - [Add LDAP config example, remove extra text](https://github.com/wekan/wekan/commit/506acda70b5e78737c52455e5eee9c8758243196).
Thanks to xet7 !
2019-03-21 22:24:35 +02:00
Lauri Ojansivu 506acda70b - Add LDAP config example, remove extra text.
Thanks to xet7 !
2019-03-21 22:22:46 +02:00
Lauri Ojansivu d173844f98 OAUTH2_LOGIN_STYLE popup or redirect, part 2 and 3. 2019-03-21 21:41:18 +02:00
Lauri Ojansivu 7919ae3628 - OAUTH2_LOGIN_STYLE popup or redirect, part 2.
Thanks to xet7 !
2019-03-21 21:37:38 +02:00
Lauri Ojansivu 188d42dcd6 [Add option to redirect OIDC OAuth2 login](https://github.com/wekan/wekan-ldap/commit/82a894ac20ba9e7c6fdf053cff1721cab709bf8a).
Thanks to xet7 !
2019-03-21 20:59:45 +02:00
Lauri Ojansivu 7735394373 - [Fix IFTTT email sending](https://github.com/wekan/wekan/pull/2279).
Thanks to justinr1234.

Related #1972
2019-03-21 20:38:06 +02:00
Lauri Ojansivu 30bf8a1724 Merge pull request #2279 from justinr1234/patch-2
Fix IFTTT email sending
2019-03-21 20:35:38 +02:00
Lauri Ojansivu 0310560938 More whitelabeling. 2019-03-21 20:32:07 +02:00
Lauri Ojansivu 2969161afb - More whitelabeling.
Thanks to xet7 !
2019-03-21 20:27:21 +02:00
Lauri Ojansivu a6213d4a6f Update translations. 2019-03-21 20:21:21 +02:00
justinr1234 12268bd065 Fix IFTTT email sending 2019-03-21 10:22:57 -05:00
Lauri Ojansivu 35a66c3550 Fix typo. 2019-03-21 02:41:21 +02:00
Lauri Ojansivu 402a974a70 v2.51 2019-03-21 01:22:09 +02:00
Lauri Ojansivu 079cd95e0e Merge pull request #2269 from andresmanelli/fix_2268
Fix #2268
2019-03-21 01:13:33 +02:00
Lauri Ojansivu e9f5aaa397 v2.50 2019-03-21 01:11:48 +02:00
Lauri Ojansivu ca0236fdfd [Fix](https://github.com/wekan/wekan/pull/2269) [Unable to change card title in Template](https://github.com/wekan/wekan/issues/2268)
and [Fix Unable to create a new board from a template](https://github.com/wekan/wekan/issues/2267).

Thanks to andresmanelli !

Closes 2268,
closes #2267
2019-03-21 00:56:18 +02:00
Lauri Ojansivu da3edb35cc v2.49 2019-03-21 00:39:35 +02:00
Andrés Manelli ef6054b859 Fix #2268 2019-03-20 23:32:52 +01:00
Lauri Ojansivu 1046976c08 [Fix Cards disappear when rearranged on template board](https://github.com/wekan/wekan/issues/2266).
Thanks to andresmanelli !

Closes #2266
2019-03-21 00:23:35 +02:00
Lauri Ojansivu f8cbbfc2cd Merge pull request #2270 from andresmanelli/fix_2266
Fix #2266
2019-03-21 00:21:19 +02:00
Lauri Ojansivu f083fc0d7b Update changelog. 2019-03-21 00:13:31 +02:00
Lauri Ojansivu 72cb820f1f Merge branch 'andresmanelli-fix_subtasks' into edge 2019-03-21 00:12:06 +02:00
Lauri Ojansivu d5d33247fb Merge branch 'fix_subtasks' of https://github.com/andresmanelli/wekan into andresmanelli-fix_subtasks 2019-03-20 23:50:43 +02:00
Lauri Ojansivu 9f95a10591 Update translations. 2019-03-20 21:45:56 +02:00
Lauri Ojansivu 5ca083105c Update changelog. 2019-03-20 21:36:19 +02:00
Lauri Ojansivu 6bc8d8dd56 git push origin edgeMerge branch 'andresmanelli-edge' into edge 2019-03-20 21:24:45 +02:00
Lauri Ojansivu dce89bcfa8 Merge branch 'edge' of https://github.com/andresmanelli/wekan into andresmanelli-edge 2019-03-20 19:30:44 +02:00
Lauri Ojansivu e5370ce859 Merge branch 'devel' of github.com:wekan/wekan into devel 2019-03-20 19:29:32 +02:00
Lauri Ojansivu 6f35d73fe8 Update changelog. 2019-03-20 19:28:56 +02:00
Lauri Ojansivu af2fb5f399 Merge pull request #2272 from justinr1234/patch-1
Don't swallow email errors
2019-03-20 19:26:00 +02:00
Lauri Ojansivu e976565550 Update changelog. 2019-03-20 19:25:28 +02:00
justinr1234 7a6b4adcc1 Disable eslint for console error 2019-03-18 23:50:15 -05:00
justinr1234 ec30665bc4 Don't swallow email errors
Fixes #2246
2019-03-18 23:06:18 -05:00
Andrés Manelli 9651d62b96 Fix #2266 2019-03-18 22:55:56 +01:00
Andrés Manelli a6e3c8984d Fix dissapearing subtasks 2019-03-17 16:37:06 +01:00
Andrés Manelli 777d9ac353 Lint fix 2019-03-16 23:15:30 +01:00
Andrés Manelli d01fccd949 - Fix card copy & move between boards with customFields
- Fix card copy & move between boards with labels with same name
- Fix activities for labels when copying and moving card
- Fix activities for customFields when copying and moving card
2019-03-16 22:49:45 +01:00
Andrés Manelli 4cd0d1c397 Migrate customFields 2019-03-16 22:49:45 +01:00
Lauri Ojansivu bf3ec060f7 Merge pull request #2263 from inoio/devel
make emails for invitations lowercase, compatible with AccountsTemplates
2019-03-16 16:24:02 +02:00
Ole Langbehn 40a3267615 make emails for invitations all lowercase for compatibility with AccountsTemplates
Email addresses for invitations are stored case sensitive in mongo,
together with the invitation codes. When someone tries to sign up due to
an invitation, in the sign up form, due to AccountsTemplates defaults,
the email address is lowercased on blur of the textbox. When they then
try to sign in, they get an error about the invitation code not existing.
This makes it impossible to successfully invite people using
non-lowercased email addresses.

This patch lowercases the emails on the client side when inviting them.

Other possibilities would be to lowercase them on the server side before
storing them to mongodb, making a case insensitive search on mongodb, or
making the email input field in the sign up form not lowercase the email
string.

This patch was chosen in favor of the other possibilities because of its
simplicity.
2019-03-16 14:32:39 +01:00
Lauri Ojansivu ff19d6744e v2.48 2019-03-15 11:08:07 +02:00
Lauri Ojansivu c26af16688 Update translations. 2019-03-15 11:03:52 +02:00
Lauri Ojansivu 216b3cfe01 Fix LDAP login.
Thanks to xet7 !

Closes wekan/wekan-ldap#43,
closes wekan/wekan-snap#85
2019-03-15 10:59:54 +02:00
Lauri Ojansivu fd70556c82 v2.47 2019-03-14 00:39:24 +02:00
Lauri Ojansivu 0fee20cc12 Update changelog. 2019-03-14 00:27:46 +02:00
Lauri Ojansivu 32f6de1eec Try to fix [LDAP Login: "Login forbidden", ReferenceError: req is not defined](https://github.com/wekan/wekan-ldap/issues/44).
Please test.

Thanks to xet7 !

Closes wekan/wekan-ldap#44
2019-03-14 00:25:40 +02:00
Lauri Ojansivu 8671f08a0e Remove ordering of cards by stars/color/description, so that cards would not reorder all the time.
Thanks to xet7 !

Closes #2241
2019-03-14 00:16:39 +02:00
Lauri Ojansivu 299484f7b2 v2.46 2019-03-13 15:55:52 +02:00
Lauri Ojansivu d16086fcdb Update changelog. 2019-03-13 15:40:20 +02:00
Lauri Ojansivu 1968b7da31 Revert hiding of Subtask boards, because of feedback from Wekan users,
that need Subtask boards to be visible.

Thanks to xet7 !
2019-03-13 15:35:34 +02:00
Lauri Ojansivu 95a40a45e5 Update translations. 2019-03-13 00:30:07 +02:00
Lauri Ojansivu 0ad7f080b7 Merge branch 'devel' of github.com:wekan/wekan into devel 2019-03-12 23:01:31 +02:00
Lauri Ojansivu aca3048036 Update changelog. 2019-03-12 23:01:18 +02:00
Lauri Ojansivu 1158cd42cc Merge pull request #2253 from justinr1234/devel
Fix watchers undefined #2252
2019-03-12 22:57:38 +02:00
Justin Reynolds 0e2b7458d7 Fix watchers undefined #2252 2019-03-12 12:04:59 -05:00
Lauri Ojansivu cf7d740004 v2.45 2019-03-11 23:39:05 +02:00
Lauri Ojansivu dc4c4d9ade Merge pull request #2248 from andresmanelli/circular_migration
Rename migration to re run
2019-03-11 23:32:46 +02:00
Andrés Manelli a347ae3676 Rename migration to re run 2019-03-11 22:30:16 +01:00
Lauri Ojansivu 7da2a8a15e v2.44 2019-03-11 20:23:27 +02:00
Lauri Ojansivu 0002559d6e Update translations. 2019-03-11 20:20:45 +02:00
Lauri Ojansivu afda0ed4da Try to get ordering of All Boards working so that it does
not keep reordering.

Thanks to bentiss, with Apache I-CLA.

Related #2241
2019-03-11 19:56:17 +02:00
Lauri Ojansivu 473f389bbe [Changed brute force protection package from eluck:accounts-lockout to lucasantoniassi:accounts-lockout that is maintained and works.
Added Snap/Docker/Source settings](https://github.com/wekan/wekan/commit/b7c000b78b9af253fb115bbfa5ef0d4c0681abbb).

Thanks to xet7.
2019-03-11 19:53:13 +02:00
Lauri Ojansivu b7c000b78b Changed brute force protection package from eluck:accounts-lockout to
lucasantoniassi:accounts-lockout that is maintained and works.
Added Snap/Docker/Source settings.

Thanks to xet7 !

Closes #1572,
closes #1821
2019-03-11 19:47:23 +02:00
Lauri Ojansivu 4ac8247db0 [Fix imports](https://github.com/wekan/wekan/pull/2245).
Thanks to bentiss with Apache I-CLA.
2019-03-11 19:40:03 +02:00
Lauri Ojansivu 0471d1ac97 Merge branch 'edge' of github.com:wekan/wekan into edge 2019-03-11 19:37:52 +02:00
Lauri Ojansivu c0221dafde Update changelog. 2019-03-11 19:37:40 +02:00
Lauri Ojansivu 8f337f17e4 - Order All Boards by starred, color, board name and board description. Part 2.
Thanks to xet7 !
2019-03-11 19:32:58 +02:00
Lauri Ojansivu de5a63f7b2 Merge pull request #2245 from bentiss/fix-imports
Fix imports
2019-03-11 19:28:03 +02:00
Lauri Ojansivu 52a744b443 Update changelog. 2019-03-11 19:16:53 +02:00
Lauri Ojansivu 4be5fa598e Merge pull request #2244 from bentiss/edge
customFields: fix leftover from lint
2019-03-11 19:04:13 +02:00
Benjamin Tissoires d03a7e7a98 wekan-import: also import each swimlane color 2019-03-11 11:47:01 +01:00
Benjamin Tissoires ebc4d6fdbd wekan-import: also import each card color 2019-03-11 11:42:22 +01:00
Benjamin Tissoires 35ffd02814 Fix import error 500
while running an import from a previously exported board, we encounter
the following error:

Exception while invoking method 'importBoard' Error: Did not check() all arguments during call to 'importBoard'
    at ArgumentChecker.throwUnlessAllArgumentsHaveBeenChecked (packages/check.js:483:13)
    at Object._failIfArgumentsAreNotAllChecked (packages/check.js:131:16)
    at maybeAuditArgumentChecks (packages/ddp-server/livedata_server.js:1765:18)
    at DDP._CurrentMethodInvocation.withValue (packages/ddp-server/livedata_server.js:719:19)
    at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1186:15)
    at DDPServer._CurrentWriteFence.withValue (packages/ddp-server/livedata_server.js:717:46)
    at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1186:15)
    at Promise (packages/ddp-server/livedata_server.js:715:46)
    at new Promise (<anonymous>)
    at Session.method (packages/ddp-server/livedata_server.js:689:23)
    at packages/mdg_meteor-apm-agent.js:2617:38
    at Meteor.EnvironmentVariable.EVp.withValue (packages/meteor.js:1186:15)
    at Session.sessionProto.protocol_handlers.method (packages/mdg_meteor-apm-agent.js:2616:44)
    at packages/ddp-server/livedata_server.js:559:43

Commit 4cf9813449 removed the checks as the original board might
not have all the required fields, but we actually still need to run
a general check on all parameters
2019-03-11 11:42:05 +01:00
Benjamin Tissoires 4c72479d12 customFields: fix leftover from lint
Looks like I forgot to use the camelCase notation here, and this leads
to an exception while updating a custom field.
2019-03-11 10:12:19 +01:00
Lauri Ojansivu 907c761f71 Update translations. 2019-03-10 21:35:55 +02:00
Lauri Ojansivu 97206aa8f6 Update changelog. 2019-03-10 21:31:40 +02:00
Andrés Manelli 2ec1664408 Fix removed checklistItem activity => dangling activities created 2019-03-08 21:13:41 +01:00
Andrés Manelli 97822f35fd Avoid set self as parent card, for real 2019-03-08 20:41:32 +01:00
Lauri Ojansivu c5e72d1a2b Merge branch 'edge' of github.com:wekan/wekan into edge 2019-03-08 20:51:57 +02:00
Lauri Ojansivu 117c9e069e Update changelog. 2019-03-08 20:51:43 +02:00
Lauri Ojansivu 951a9f81d6 Merge pull request #2239 from bentiss/customFields-activities
Activities: register customFields changes in the activities
2019-03-08 20:48:49 +02:00
Lauri Ojansivu 6f30c33f11 Add language: Occitan. 2019-03-08 20:47:05 +02:00
Lauri Ojansivu 8050117adf Add language: Occintan.
Thanks to translators !
2019-03-08 20:45:39 +02:00
Lauri Ojansivu 98031aacce v2.43 2019-03-08 19:12:11 +02:00
Lauri Ojansivu 2781ce6fa0 Update translations. 2019-03-08 19:02:31 +02:00
Lauri Ojansivu 08db39d76a Fix lint errors.
Thanks to xet7 !

Related #2019
2019-03-08 19:00:56 +02:00
Lauri Ojansivu da267e1488 [HTTP header automatic login](https://github.com/wekan/wekan/commit/ff825d6123ecfd033ccb08ce97c11cefee676104)
for [3rd party authentication server method](https://github.com/wekan/wekan/issues/2019) like siteminder, and any webserver that
handles authentication and based on it adds HTTP headers to be used for login. Please test.

Thanks to xet7 !

Related #2019
2019-03-08 18:55:36 +02:00
Lauri Ojansivu ff825d6123 [HTTP header automatic login. Not tested yet.](https://github.com/wekan/wekan/issues/2019).
Thanks to xet7 !

Related #2019
2019-03-08 18:40:43 +02:00
Benjamin Tissoires 6d6bb8fc57 Activities: register customFields changed in the activities
This stores the updates to the custom fields in the activities side bar.

Only manual updates to the custom fields are currently registered.
2019-03-08 11:32:59 +01:00
Lauri Ojansivu 7836ab83d0 - Order All Boards by Starred, Color and Title and Description.
Thanks to xet7 !

Closes #1990,
Related #252
2019-03-08 10:44:20 +02:00
Lauri Ojansivu 8568728152 - [Hide Subtask boards from All Boards](https://github.com/wekan/wekan/issues/1990).
- Order All Boards by Starred, Color and Title.

Thanks to xet7 !

Closes #1990,
Related #641
2019-03-08 09:41:36 +02:00
Lauri Ojansivu 8783983945 Update changelog. 2019-03-07 17:20:25 +02:00
Lauri Ojansivu 4055f451fd Reverts the following change of v2.42, because it did not fix anything:
- [Tried to fix snap mongodb-control not starting database](https://github.com/wekan/wekan/commit/2c5628b5fbcc25427021d0b22e74577a71149c21).

Thanks to xet7.
2019-03-07 17:17:21 +02:00
Lauri Ojansivu 31777ce804 Update changelog. 2019-03-07 11:27:06 +02:00
Lauri Ojansivu 97a9e92969 Merge remote-tracking branch 'andresmanelli/edge' into edge 2019-03-07 02:03:34 +02:00
Lauri Ojansivu c5ca414e8f v2.42 2019-03-07 01:52:53 +02:00
Lauri Ojansivu 2c5628b5fb Fix mongodb-control.
Thanks to xet7 and qurqar[m].
2019-03-07 01:48:42 +02:00
Andrés Manelli a338e937e5 Add migration to fix circular references 2019-03-07 00:13:21 +01:00
Lauri Ojansivu 1089572d66 v2.41 2019-03-07 00:04:50 +02:00
Lauri Ojansivu ddb2460187 [Fix: Card was selected as parent card (circular reference) and now board can be not opened anymore](https://github.com/wekan/wekan/issues/2202)
with [Avoid setting same card as parentCard. Avoid listing templates board in copy/move/more menus](https://github.com/wekan/wekan/commit/745f39ed20169f56b99c0339f2043f8c4ed43873).

Thanks to andresmanelli.

Closes #2202
2019-03-06 23:48:36 +02:00
Andrés Manelli 745f39ed20 Avoid setting same card as parentCard.
Avoid listing templates board in copy/move/more menus
2019-03-06 20:57:19 +01:00
Lauri Ojansivu 18cccd514f Fix typos. 2019-03-06 20:56:58 +02:00
Lauri Ojansivu 9c0eba4f00 v2.40 2019-03-06 18:21:26 +02:00
Lauri Ojansivu f19625d835 Fix manifest and icon urls, part 2.
Thanks to xet7 !
2019-03-06 18:18:34 +02:00
Lauri Ojansivu c4754d9f85 v2.39 2019-03-06 17:31:15 +02:00
Lauri Ojansivu acdc5dc1f4 Update translations. 2019-03-06 17:23:33 +02:00
Lauri Ojansivu 4927609af0 Update changelog. 2019-03-06 17:20:47 +02:00
Lauri Ojansivu e845fe3e71 Fix manifest and icon paths.
Thanks to xet7 !

Closes #2168,
closes #1692
2019-03-06 17:15:36 +02:00
Lauri Ojansivu d807efd4f8 Update translations. 2019-03-06 03:14:13 +02:00
Lauri Ojansivu 5f76695298 Update release scripts. 2019-03-06 03:12:27 +02:00
Lauri Ojansivu aadb1f3109 v2.38 2019-03-06 03:07:50 +02:00
Lauri Ojansivu cb986912c4 [Added support for LDAP admin status sync](https://github.com/wekan/wekan-ldap/pull/40).
Examples: LDAP_SYNC_ADMIN_STATUS=true, LDAP_SYNC_ADMIN_GROUP=group1,group2 (https://github.com/wekan/wekan/commit/7e451d9033eb6162cd37de3e5ffabdc22e272948).
Thanks to JulianJacobi and xet7.
2019-03-06 02:55:13 +02:00
Lauri Ojansivu 7e451d9033 [Add support for admin status sync](https://github.com/wekan/wekan-ldap/pull/40).
Examples: LDAP_SYNC_ADMIN_STATUS=true, LDAP_SYNC_ADMIN_GROUP=group1,group2

Thanks to JulianJacobi and xet7 !
2019-03-06 02:47:27 +02:00
Lauri Ojansivu a024b6d692 Update changelog. 2019-03-06 02:00:31 +02:00
Lauri Ojansivu a45ccf1db7 [Remove phantomjs binary from Docker/Snap/Stackerfile to reduce size](https://github.com/wekan/wekan/issues/2229).
Thanks to soohwa !

Closes #2229
2019-03-06 01:56:32 +02:00
Lauri Ojansivu 30bf430a91 - [Use ubuntu:cosmic base in Dockerfile](https://github.com/wekan/wekan/commit/df00776e6ca47080435eca9a31a16fd24c0770ed). Thanks to xet7. 2019-03-06 01:44:47 +02:00
Lauri Ojansivu df00776e6c Use ubuntu:cosmic base in Dockerfile.
Thanks to xet7 !
2019-03-06 01:42:30 +02:00
Lauri Ojansivu 1dc0d0c12e Update changelog. 2019-03-06 01:34:58 +02:00
Lauri Ojansivu 002fd411ea [Fix: LDAP Authentication with Recursive Group Filtering Does Not Work on Snap](https://github.com/wekan/wekan/issues/2228).
Thanks to apages2 !

Closes #2228,
closes wekan/wekan-ldap#23
2019-03-06 01:27:40 +02:00
Lauri Ojansivu 6311cf0c5a Update translations. 2019-03-06 01:23:40 +02:00
Lauri Ojansivu d71543beb6 - [Fix card deletion from archive](https://github.com/wekan/wekan/commit/77754cf32f28498e550a46325d90eb41f08f8552).
- [Fix card move with wrong swimlaneId](https://github.com/wekan/wekan/commit/1bef3a3f8ff4eac43bf97cc8b86d85e618b0e2ef).
  NOTE: This does not yet fix card move with Custom Field, it will be fixed later.

Thanks to andresmanelli !

Closes wekan/wekan-snap#83,
closes #2224,
closes #2230,
related #2233
2019-03-06 01:05:15 +02:00
Lauri Ojansivu 5a9837f676 Merge remote-tracking branch 'andresmanelli/edge' into edge 2019-03-06 00:58:49 +02:00
Andrés Manelli 77754cf32f Fix card deletion from archive 2019-03-05 22:48:29 +01:00
Lauri Ojansivu 43a74fb99b Merge remote-tracking branch 'andresmanelli/edge' into edge 2019-03-05 23:38:47 +02:00
Andrés Manelli 1bef3a3f8f Fix card move with wrong swimlaneId 2019-03-05 22:35:45 +01:00
Lauri Ojansivu b6b6be34f6 Update translations. 2019-03-04 21:29:04 +02:00
Lauri Ojansivu f1cde3e873 - [Added a Helm Chart to the project](https://github.com/wekan/wekan/pull/2227).
Thanks to TechnoTaff !
2019-03-04 21:27:35 +02:00
Lauri Ojansivu dcd6ae2e01 Merge pull request #2227 from TechnoTaff/devel
Added a Helm Chart to the project
2019-03-04 21:21:51 +02:00
Stephen Randall 8984172ff6 Readme updates 2019-03-04 16:44:12 +00:00
Stephen Randall 87a5e7f030 Merge branch 'devel' of https://github.com/TechnoTaff/wekan into devel 2019-03-04 16:29:29 +00:00
Stephen Randall 115d07da5a Added some notes 2019-03-04 16:28:44 +00:00
Steve Randall e67ed023cd Create .gitkeep 2019-03-04 16:26:34 +00:00
Steve Randall 1f1d753791 Delete requirements.lock 2019-03-04 16:13:34 +00:00
Steve Randall 34fcce60af Delete mongodb-replicaset-3.6.4.tgz 2019-03-04 16:13:11 +00:00
Stephen Randall e7a90d9a7c Added helm chart v1 2019-03-04 15:55:20 +00:00
Lauri Ojansivu 9d6d5e1a14 v2.37 2019-03-04 12:08:55 +02:00
Lauri Ojansivu 763cf81c97 [Fix Adding Labels to cards is not possible anymore](https://github.com/wekan/wekan/issues/2223).
Thanks to xet7 !

Closes #2223
2019-03-04 12:04:12 +02:00
Lauri Ojansivu 0b64a46bdc Update translations. 2019-03-04 08:55:42 +02:00
Lauri Ojansivu d417bf058d v2.36 2019-03-03 22:39:09 +02:00
Lauri Ojansivu 46088bfbb5 Update translations. 2019-03-03 22:33:17 +02:00
Lauri Ojansivu a6ea622f78 Update changelog. 2019-03-03 22:32:00 +02:00
Lauri Ojansivu 847ed8570b [Combine hamburger menus at right](https://github.com/wekan/wekan/issues/2219).
Thanks to xet7 !

Related #2219
2019-03-03 22:27:05 +02:00
Lauri Ojansivu 3a9ab817a9 Update translations. 2019-03-03 20:43:12 +02:00
Lauri Ojansivu 2a5c2ed192 [Forked salleman-oidc](https://github.com/wekan/wekan/commit/8867bec8e65f1ef6be0c731918e8eefcacb7acb0)
to https://github.com/wekan/meteor-accounts-oidc where salleman also has write access,
xet7 can make changes directly and GitHub issues are enabled.

Thanks to xet7 !
2019-03-03 20:40:37 +02:00
Lauri Ojansivu 8867bec8e6 Forked salleman-oidc to https://github.com/wekan/meteor-accounts-oidc
where salleman also has write access, xet7 can make changes directly
and GitHub issues are enabled.

Thanks to xet7 !
2019-03-03 20:36:44 +02:00
Lauri Ojansivu 262da85399 Update translations. 2019-03-03 18:10:52 +02:00
Lauri Ojansivu 51a70f2164 Fix translation. 2019-03-03 18:07:14 +02:00
Lauri Ojansivu 0854a658d8 Fix typos in translation. 2019-03-03 17:55:34 +02:00
Lauri Ojansivu d99056ced5 Fix translation. 2019-03-03 17:41:11 +02:00
Lauri Ojansivu 4a5473b4e7 Update translation. 2019-03-03 17:38:23 +02:00
Lauri Ojansivu d3f368efd7 Fix typos in translation. 2019-03-03 17:30:57 +02:00
Lauri Ojansivu ca052566de Fix translation. 2019-03-03 17:19:01 +02:00
Lauri Ojansivu c101e262d6 Fix translation. 2019-03-03 16:52:55 +02:00
Lauri Ojansivu 1f942301ad Fix translation. 2019-03-03 16:45:33 +02:00
Lauri Ojansivu b6db1e12b7 - [Add more Webhook translations](https://github.com/wekan/wekan/issues/1969).
In progress.

Thanks to xet7 !
2019-03-03 16:40:35 +02:00
Lauri Ojansivu 3bfc6ea8d7 [Add more Webhook translations](https://github.com/wekan/wekan/issues/1969).
In progress.

Thanks to xet7 !

Related #1969
2019-03-03 16:33:43 +02:00
Lauri Ojansivu ec30dd4788 Update changelog. 2019-03-03 10:45:50 +02:00
Lauri Ojansivu 990ebbdbcb Update translations. 2019-03-03 10:36:58 +02:00
Lauri Ojansivu 99a856be97 Change board menu:
- Board menu (hamburger icon) to Board Settings (Cog icon)
- Sidebar arrows icons to hamburger icon

Thanks to xet7 !

Related #2219
2019-03-03 10:31:30 +02:00
Lauri Ojansivu 260d0641df Rename Board Menu to Board Settings.
Thanks to xet7 !
2019-03-03 10:26:18 +02:00
Lauri Ojansivu 16963859e1 Update translations. 2019-03-02 17:32:06 +02:00
Lauri Ojansivu 010a201d0c Update readme. 2019-03-02 17:27:34 +02:00
Lauri Ojansivu 95014e6348 Update readme. 2019-03-02 17:26:00 +02:00
Lauri Ojansivu 724912ec48 Update readme. 2019-03-02 17:24:26 +02:00
Lauri Ojansivu 46d8a11c51 Remove outdated team page. 2019-03-02 17:15:18 +02:00
Lauri Ojansivu 065cd05c96 Update readme. 2019-03-02 17:13:50 +02:00
Lauri Ojansivu a4564bed3a v2.35 2019-03-01 15:42:23 +02:00
Lauri Ojansivu 4ef3e587cb [Add Filter fix back](https://github.com/wekan/wekan/issues/2213),
because there was no bug in filter fix.
2019-03-01 14:48:25 +02:00
Lauri Ojansivu d6259836e0 - [Add Filter fix back](https://github.com/wekan/wekan/issues/2213),
because there was no bug in filter fix.

Thanks to xet7 !

Closes #2213,
related #2209
2019-03-01 14:41:09 +02:00
Lauri Ojansivu ef246cfef3 v2.34 2019-03-01 07:10:50 +02:00
Lauri Ojansivu 90dd0ddb94 Revert [Filter fix](https://github.com/wekan/wekan/issues/2213) because of
[mongodb data tampered](https://github.com/wekan/wekan-snap/issues/83).

Thanks to xet7 !
2019-03-01 07:05:49 +02:00
Lauri Ojansivu bd2c54398b v2.33 2019-02-28 23:31:39 +02:00
Lauri Ojansivu e65776f9f0 [Upgrade Node.js to v8.15.1](https://github.com/wekan/wekan/commit/5cafdd9878ab4b6123024ec33279ccdae75f554f).
Thanks to Node.js developers and xet7 !
2019-02-28 23:29:13 +02:00
Lauri Ojansivu 5cafdd9878 Upgrade node to v8.15.1
Thanks to xet7 !
2019-02-28 23:25:03 +02:00
Lauri Ojansivu 49882a05d1 v2.32 2019-02-28 23:01:56 +02:00
Lauri Ojansivu 8e36a2bc83 [Fix filtering in swimlane view](https://github.com/wekan/wekan/commit/49229e1723de14cdc66dc6480624bba426d35e36)
that was [broken since v2.29](https://github.com/wekan/wekan/issues/2213).

Thanks to andresmanelli !

Closes #2213,
Related #2209
2019-02-28 22:57:40 +02:00
Lauri Ojansivu 24e47195e5 - [Fix](https://github.com/wekan/wekan/commit/49229e1723de14cdc66dc6480624bba426d35e36)
[Filtering in swimlane view is broken since v2.29](https://github.com/wekan/wekan/issues/2213).

Thanks to andresmanelli !

Related #2209
2019-02-28 22:45:37 +02:00
Lauri Ojansivu 4b37958140 Merge branch 'devel' into edge 2019-02-28 22:39:02 +02:00
Lauri Ojansivu 3edff32bde [Performance improvements](https://github.com/wekan/wekan/pull/2214), thanks to justinr1234:
- New indexes for queries that were missing an index;
- Bulk querying documents to reduce the number of mongo queries when loading a board;
- Ensure oplog is being used to query the database by providing a `sort` key when `limit` is used querying the `boards` collection.
2019-02-28 22:37:28 +02:00
Lauri Ojansivu 78c5e0f7ef Merge branch 'justinr1234-wekan-perf-improvements' into devel 2019-02-28 22:32:33 +02:00
Andrés Manelli 49229e1723 Fix filter in swimlanes view 2019-02-28 20:46:50 +01:00
Lauri Ojansivu 14e2bfd1bf Merge branch 'wekan-perf-improvements' of https://github.com/justinr1234/wekan into justinr1234-wekan-perf-improvements 2019-02-28 21:19:50 +02:00
Justin Reynolds 3c49e2d0ed Performance Enhancements 2019-02-28 11:44:29 -06:00
Lauri Ojansivu d5bc66c9a4 v2.31 2019-02-28 12:41:07 +02:00
Lauri Ojansivu 4f6977668b Update translations. 2019-02-28 12:37:36 +02:00
Lauri Ojansivu 17826c28e5 - [Fix copy card](https://github.com/wekan/wekan/issues/2210).
Thanks to andresmanelli !

Closes #2210,
Related #2209
2019-02-28 12:34:48 +02:00
Lauri Ojansivu a3d71dd694 Merge remote-tracking branch 'andresmanelli/edge' into edge 2019-02-28 12:29:14 +02:00
Andrés Manelli a5c39342ba Fix card copy 2019-02-28 08:10:33 +01:00
Lauri Ojansivu ad75c541cf v2.30 2019-02-28 00:52:36 +02:00
Lauri Ojansivu cd46cbeb8f Add new [Template features](https://github.com/wekan/wekan/issues/2209):
- [Fix popup title. Add element title modification](https://github.com/wekan/wekan/commit/888e1ad5d3e32be53283aa32198057f669f3d706);
- [Copy template attachments](https://github.com/wekan/wekan/commit/abb71083215462d91b084c4de13af0b130638e4d);
- [Standarize copy functions. Match labels by name](https://github.com/wekan/wekan/commit/da21a2a410c9b905de89d66236748e0c8f5357ea).

Thanks to andresmanelli !

Related #2209
2019-02-28 00:44:13 +02:00
Andrés Manelli 888e1ad5d3 Fix popup title
Add element title modification
2019-02-27 21:50:08 +01:00
Andrés Manelli abb7108321 Copy template attachments 2019-02-27 21:50:08 +01:00
Andrés Manelli da21a2a410 Standarize copy functions. Match labels by name 2019-02-27 21:50:08 +01:00
Lauri Ojansivu 904b5bf0f5 v2.29 2019-02-27 21:01:32 +02:00
Lauri Ojansivu d21aa97219 Update translations. 2019-02-27 20:39:56 +02:00
Andrés Manelli 6ee75fbdba Fix templates board not found 2019-02-27 19:34:53 +01:00
Lauri Ojansivu c3b2a0c955 Merge branch 'devel' into edge 2019-02-27 17:29:21 +02:00
Lauri Ojansivu 0ac42c145e Fix typo. 2019-02-27 17:28:44 +02:00
Lauri Ojansivu 4a77bc930f Merge branch 'devel' into edge 2019-02-27 16:26:48 +02:00
Lauri Ojansivu 29c3080eb6 v2.28 2019-02-27 16:21:31 +02:00
Lauri Ojansivu 57516177a0 Update ChangeLog. 2019-02-27 16:17:21 +02:00
Lauri Ojansivu 34d8235551 Add the following new Sandstorm features and fixes:
- All Boards page [so it's possible to go back from subtask board](https://github.com/wekan/wekan/issues/2082)
- Board favorites
- New Sandstorm board first user is Admin and [has IFTTT Rules](https://github.com/wekan/wekan/issues/2125)
  and Standalone Wekan Admin Panel. Probably some Admin Panel features do not work yet. Please keep backup of your grains before testig Admin Panel.
- Linked Cards and Linked Boards.
- Some not needed options like Logout etc have been hidden from top bar right menu.
- [Import board now works. "Board not found" is not problem anymore](https://github.com/wekan/wekan/issues/1430), because you can go to All Boards page to change to imported board.

and removes the following features:

- Remove Welcome Board from Standalone Wekan, [to fix Welcome board not translated](https://github.com/wekan/wekan/issues/1601).
  Sandstorm Wekan does not have Welcome Board.

Thanks to xet7 !

Closes #2125,
closes #2082,
closes #1430,
closes #1601,
related #2205,
related #2070,
related #1695,
related #1192.
2019-02-27 16:14:14 +02:00
Lauri Ojansivu 8d51245161 Merge branch 'devel' into edge 2019-02-27 06:20:30 +02:00
Lauri Ojansivu 55ad98ecc4 v2.27 2019-02-27 06:18:51 +02:00
Lauri Ojansivu ed04181bb9 Update translations. 2019-02-27 06:16:37 +02:00
Lauri Ojansivu 868fba55cd Update changelog. 2019-02-27 06:14:15 +02:00
Lauri Ojansivu 05351c0ac1 - Fix OIDC error "a.join is not a function" b reverting
configurable OAUTH2_ID_TOKEN_WHITELIST_FIELDS and
  OAUTH2_REQUEST_PERMISSIONS from Wekan v2.22-2.26.

Thanks to xet7 !

Closes #2206,
Related #1874,
Related #1722
2019-02-27 06:02:00 +02:00
Lauri Ojansivu a707129146 Removed console.log. 2019-02-26 16:51:24 +02:00
Lauri Ojansivu 2f3138207c Update translations. 2019-02-26 00:28:01 +02:00
Andrés Manelli dc7286a0ef Fix list view issues. Allow creation of boards from templates 2019-02-25 22:48:32 +01:00
Lauri Ojansivu 5e66119bf0 v2.26 2019-02-25 20:03:36 +02:00
Lauri Ojansivu b751fd11e4 - [Fix OAuth2 requestPermissions](https://github.com/wekan/wekan/commit/5e238bfbfea16940ae29647ae347bbdc0d78efb0).
This maybe makes [Auth0 login possible](https://github.com/wekan/wekan/issues/1722) with OIDC.
  Thanks to GitHub user xet7.
2019-02-25 19:51:17 +02:00
Lauri Ojansivu 5e238bfbfe - Fix OAuth2 requestPermissions.
Thanks to xet7 !

Closes #1722
2019-02-25 19:45:41 +02:00
Lauri Ojansivu 7e20a3cac6 - Add setting [EMAIL_NOTIFICATION_TIMEOUT](https://github.com/wekan/wekan/issues/2203).
Defaut 30000 ms (30s). Thanks to GitHub users ngru and xet7.
2019-02-25 18:13:43 +02:00
Lauri Ojansivu 7c1d6e4d2e - Add setting EMAIL_NOTIFICATION_TIMEOUT. Defaut 30000 ms (30s).
Thanks to xet7 !

Closes #2203
2019-02-25 18:10:36 +02:00
Lauri Ojansivu 13c2157e36 Update translations. 2019-02-25 06:14:43 +02:00
Andrés Manelli 7033315cd3 Add migrations 2019-02-24 12:55:34 +01:00
Andrés Manelli 775476f97c Fix miniscreen render 2019-02-24 11:54:52 +01:00
Andrés Manelli eb62c9ce6a Fix lint errors 2019-02-24 00:13:35 +01:00
Andrés Manelli 60be4df76e Allow swimlane creation from template
Mix lists with same name to avoid duplicates
2019-02-24 00:05:00 +01:00
Andrés Manelli f888cfd565 Allow list creation from template 2019-02-24 00:05:00 +01:00
Andrés Manelli 044126188d Allow card creation from template 2019-02-24 00:05:00 +01:00
Andrés Manelli 0fec711545 Prepare to create card from template 2019-02-24 00:05:00 +01:00
Andrés Manelli 7a6afb8aea Add template search in Add Card menu
Archive all cards in list when list is archived
Remove default board in link popup
Only list non-template boards in card link and search
2019-02-24 00:05:00 +01:00
Andrés Manelli 1e72177991 Avoid links on a template-board
Allow creation of template boards with a linked card
Avoid changing the name of the template-container swimlanes
2019-02-24 00:05:00 +01:00
Andrés Manelli cdf070189e Remove links from templates board for the moment
Insert the correct template type in templates board
Allow independant lists in templates board
Add some helpers
2019-02-24 00:05:00 +01:00
Andrés Manelli 64bf455b29 Save template swimlanes in profile. Fix swimlane view for templates board. Avoid deleting template containers 2019-02-24 00:05:00 +01:00
Andrés Manelli 0a53ee87b9 Add first draft of data model and user interface. No actions. 2019-02-24 00:05:00 +01:00
Lauri Ojansivu ef85b71ee4 v2.25 2019-02-23 19:54:37 +02:00
Lauri Ojansivu ac0133e8fa - Revert file permission changes from v2.24 LDAP changes that
caused snap version to not build.

Thanks to xet7 !
2019-02-23 19:51:33 +02:00
Lauri Ojansivu 25ba6df007 v2.24 2019-02-23 19:23:36 +02:00
Lauri Ojansivu 6d750897a8 - [Add LDAP email] matching support](https://github.com/wekan/wekan-ldap/pull/39) and
[related env variables](https://github.com/wekan/wekan/pull/2198).
  Thanks to GitHub user stevenpwaters.
2019-02-23 19:18:43 +02:00
Lauri Ojansivu a7747c537b Merge pull request #2198 from stevenpwaters/devel
Add LDAP email environment variables
2019-02-23 19:07:16 +02:00
Lauri Ojansivu 65b6a21938 - Add missing text .env to wekan/server/authentication.js.
Thanks to Vanila Chat user .gitignore.
2019-02-23 19:04:02 +02:00
Lauri Ojansivu 4e6e78ccd2 - Add missing text .env
Thanks to Vanila Chat user .gitignore !
2019-02-23 19:00:29 +02:00
Lauri Ojansivu fd5d6546b2 Update translations. 2019-02-23 18:52:44 +02:00
Steven Waters 402d484182 Added LDAP email environment variables
Support for LDAP matching existing accounts with e-mail address.
2019-02-21 09:02:47 +00:00
Lauri Ojansivu 4bf0914f1e v2.23 2019-02-17 18:13:54 +02:00
Lauri Ojansivu 96519296e1 Update translations (sv). 2019-02-15 18:47:21 +02:00
Lauri Ojansivu 03d06685b0 - [Fix authentication dropdown](https://github.com/wekan/wekan/pull/2191).
Thanks to Akuket.
2019-02-15 18:45:41 +02:00
Lauri Ojansivu 7d57c56b17 Merge pull request #2191 from Akuket/feature-improve-authentication
Fix authentication dropdown
2019-02-15 18:41:38 +02:00
guillaume 4ce766853c Fix authentication dropdown 2019-02-15 17:06:05 +01:00
Lauri Ojansivu dc7bbd848c v2.22 2019-02-13 03:14:18 +02:00
Lauri Ojansivu 81744e6523 - Add [configurable](https://github.com/wekan/wekan/issues/1874#issuecomment-462759627)
settings [OAUTH2_ID_TOKEN_WHITELIST_FIELDS and
  OAUTH2_REQUEST_PERMISSIONS](https://github.com/wekan/wekan/commit/b66f471e530d41a3f12e4bfc29548313e9a73c35).
  Thanks to xet7.
2019-02-13 03:07:31 +02:00
Lauri Ojansivu b66f471e53 - Add configurable settings OAUTH2_ID_TOKEN_WHITELIST_FIELDS
and OAUTH2_REQUEST_PERMISSIONS.

Thanks to xet7.

Related #1874
2019-02-13 03:01:10 +02:00
Lauri Ojansivu 202b8a92af - Add Kadira integration. Thanks to GavinLilly.
Closes #2152
2019-02-13 02:24:21 +02:00
Lauri Ojansivu 1e98f6b781 Merge branch 'edge' into devel 2019-02-13 02:15:19 +02:00
Lauri Ojansivu f53e8fbd21 Merge pull request #2187 from GavinLilly/kadira-integration
Kadira integration
2019-02-13 02:13:46 +02:00
Gavin Lilly 8e95871534 Adding wekan-ldap back in to build in the Dockerfile 2019-02-13 00:01:47 +00:00
Gavin Lilly 595a2d2baa Cleaning up docker-compose for merge 2019-02-13 00:00:34 +00:00
Gavin Lilly 227772bc33 Added back wekan-ldap after it's fixed in a separate change 2019-02-12 23:56:40 +00:00
Lauri Ojansivu 2ca98e477d - Fix2: Remove overlap of side bar button with card/list menu button on mobile browser
Thanks to xet7 !

Closes #2183
2019-02-13 01:04:30 +02:00
Angelo Gallarello 477d71e0b9 Fixes 2019-02-12 23:40:12 +01:00
Lauri Ojansivu 677bfc3f6b - Fix: Remove overlap of side bar button with card/list menu button on mobile browser
Thanks to xet7 !

Closes #2183
2019-02-13 00:01:38 +02:00
Lauri Ojansivu c7721b048d - Fix indenting textline. 2019-02-12 23:46:25 +02:00
Lauri Ojansivu 1417f091fe Update translations. 2019-02-12 23:38:24 +02:00
Lauri Ojansivu d22964bcfd v2.21 2019-02-12 03:24:32 +02:00
Lauri Ojansivu 59314ab17d - Add OIDC claim mapping parameters to docker-compose.yml/Snap/Source.
Thanks to xet7 !
2019-02-12 03:09:30 +02:00
Gavin Lilly 5c083d99e2 Moved to meteor-apm-agent and removed Wekan LDAP to test if working 2019-02-11 23:16:37 +00:00
Gavin Lilly d3abb0756e Pulled Wekan-LDAP locally for debug 2019-02-11 20:12:53 +00:00
Lauri Ojansivu 4de9848e34 Merge pull request #2182 from danpatdav/oidc
Add parameters for OIDC claim mapping
2019-02-11 20:30:01 +02:00
Daniel Davis bdbbb12f96 Added parameters for OIDC claim mapping
These mapping parameters take advantage of new code in salleman-oidc 1.0.12 to override the default claim names provided by the userinfo endpoint.
2019-02-11 10:48:20 -06:00
Gavin Lilly c1ea3f49ca Merge branch 'devel' of github.com:wekan/wekan into devel 2019-02-11 16:43:57 +00:00
Gavin Lilly 905c45f225 Replaced Kadira by meteor-apm-agent 2019-02-11 16:43:52 +00:00
Daniel Davis 352e5c6cb0 Bump salleman-oidc to 1.0.12 2019-02-11 10:41:24 -06:00
Lauri Ojansivu 2d291c8f5e v2.20 2019-02-11 16:45:11 +02:00
Lauri Ojansivu 86630fa1e0 Update changelog. 2019-02-11 16:38:23 +02:00
Lauri Ojansivu 8e02170dd1 - Add option DEBUG=true for docker-compose.yml/Snap/Source.
Thanks to xet7 !
2019-02-11 16:32:24 +02:00
Lauri Ojansivu 9edf95ec93 Merge pull request #2181 from danpatdav/debug-oidc
Added debug flag and bumped salleman package version
2019-02-11 16:11:15 +02:00
Lauri Ojansivu 2add875a38 Update translations. 2019-02-11 16:09:39 +02:00
Daniel Davis b20309f7aa Syntax 2019-02-11 07:46:24 -06:00
Gavin Lilly 8996df5c09 Added Kadira using meteor add method 2019-02-09 23:37:01 +00:00
Gavin Lilly 7b5f02b4c8 Added Kadira packages and env settings in Docker Compose 2019-02-09 23:22:22 +00:00
Lauri Ojansivu fc0287a829 Update translations. 2019-02-09 21:22:36 +02:00
Lauri Ojansivu ed8bca5394 Update translations (es). 2019-02-09 00:04:51 +02:00
Lauri Ojansivu 9458f4011d v2.19 2019-02-09 00:02:49 +02:00
Lauri Ojansivu f1bd36a3b8 - Remove oplog. Need to think how to do it properly.
Thanks to xet7 !
2019-02-08 23:58:13 +02:00
Lauri Ojansivu f060e02fc0 v2.18 2019-02-08 20:56:45 +02:00
Lauri Ojansivu 0fa2e5d3a0 Add commit link to changelog. 2019-02-08 20:52:28 +02:00
Lauri Ojansivu 6d0055ecb5 Add issue link to changelog. 2019-02-08 20:49:39 +02:00
Lauri Ojansivu 2d3ce9c290 Add commit link to changelog. 2019-02-08 20:48:05 +02:00
Lauri Ojansivu 796b276d02 Update changelog. 2019-02-08 20:37:30 +02:00
Lauri Ojansivu ed98b5c807 Update changelog. 2019-02-08 20:09:42 +02:00
Lauri Ojansivu f1da7dcb0c Merge pull request #2174 from bentiss/fix-sw-reordering
Fix swimlanes sorting
2019-02-08 19:49:50 +02:00
Lauri Ojansivu 35a539eee2 Update translations. 2019-02-08 19:48:12 +02:00
Lauri Ojansivu 79ffb7d502 - Add oplog to snap mongodb.
Thanks to xet7 !
2019-02-08 19:43:21 +02:00
Benjamin Tissoires a2e6f621a2 Fix swimlanes sorting
Since 7cc185ac "Properly fix horizontal rendering on Chrome and Firefox"

The rendering of the new design of the swimlanes was correct, but this
commit broke the reordering capability. Having the swimlane header at
the same level than the lists of cards makes the whole sortable
pattern fail.

2 solutions:
- revert to only have 1 div per swimlane. But this introduces the firefox
  bug mentioned in 7cc185ac, so not ideal
- force the sortable pattern to do what we want.

To force the sortable pattern, we need:
- add in the helper a clone of the list of cards (to not just move the
  header)
- make sure the placeholder never get placed between the header and the
  list of cards in a swimlane
- fix the finding of the next and previous list of cards.

For all of this to be successful, we need to resize the swimlanes to a
known value. This can lead to some visual jumps with scrolling when you
drag or drop the swimlanea. I tried to remedy that by computing the new
scroll value. Still not ideal however, as there are still some jumps when
dropping.

Fixes #2159
2019-02-08 17:37:20 +01:00
Lauri Ojansivu 96e97143f2 Update translations. 2019-02-08 13:06:35 +02:00
Lauri Ojansivu 4126a1a808 Translate also Admin Panel/Layout/Display Authentication Method and Default Authentication Method. Thanks to Akuket and xet7 ! 2019-02-08 12:46:07 +02:00
Lauri Ojansivu 3ce902123f Lint also async. Thanks to Akuket ! 2019-02-08 12:44:48 +02:00
Lauri Ojansivu 7125357a44 Merge remote-tracking branch 'upstream/feature-improve-authentication' into feature-improve-authentication 2019-02-08 12:33:39 +02:00
guillaume ec453b89b8 Fix lints 2019-02-07 11:38:04 +01:00
Daniel Davis 303404acc6 Bumped salleman packages to 1.0.11
1.0.11 includes new debugging code
2019-02-06 10:18:05 -06:00
Daniel Davis f11d42e72d Add a debug argument
Implementing this for OIDC debugging, but I think it will be broadly useful for runtime debugging.
2019-02-06 10:12:32 -06:00
Lauri Ojansivu 329c8d64a8 v2.17 2019-02-04 21:47:50 +02:00
Lauri Ojansivu 698ce8f0e6 Update translations (sv). 2019-02-04 21:07:36 +02:00
Lauri Ojansivu b06e11ba09 Merge pull request #2164 from gil0109/edge
Fix trailing spaces for OIDC fix
2019-02-04 20:23:41 +02:00
Karim Gillani d689a7408b Fix trailing spaces 2019-02-04 09:36:21 -08:00
Lauri Ojansivu c899218fb9 Merge pull request #2162 from gil0109/edge
OIDC BoardView Fix
2019-02-04 19:30:24 +02:00
Karim Gillani c42f2a05d2 OIDC BoardView Fix 2019-02-04 08:24:10 -08:00
Lauri Ojansivu 70ed552e1a Update translations. 2019-02-03 15:45:00 +02:00
Lauri Ojansivu 9a07649b8a v2.16 2019-02-03 05:18:50 +02:00
Lauri Ojansivu 9a6ac544dd - Fix Sandstorm open card on public board, part 2.
Thanks to ChronikEwok !
2019-02-03 05:12:50 +02:00
Lauri Ojansivu 06a1e26655 Add missing text. 2019-02-03 03:06:54 +02:00
Lauri Ojansivu 626e7c2c61 v2.15 2019-02-03 02:31:51 +02:00
Lauri Ojansivu a7aeb491ba Update changelog. 2019-02-03 02:25:14 +02:00
Lauri Ojansivu 7ba8f72d7b - [Fix: Not displaying card content of public board: Snap, Docker and Sandstorm Shared Wekan Board
Link](https://github.com/wekan/wekan/issues/1623) with
  [code from ChronikEwok](https://github.com/ChronikEwok/wekan/commit/cad9b20451bb6149bfb527a99b5001873b06c3de).

Thanks to ChronikEwok !

Closes #1623
2019-02-03 02:18:35 +02:00
Lauri Ojansivu d0f74d7a99 Add missing text. 2019-02-02 21:55:50 +02:00
Lauri Ojansivu 7f33fa5368 v2.14 2019-02-02 21:00:16 +02:00
Lauri Ojansivu 0ab97266f6 - [Fix Sandstorm export board from web](https://github.com/wekan/wekan/issues/2157).
- [Fix Error when logging in to Wekan REST API when using Sandstorm Wekan](https://github.com/wekan/wekan/issues/1279).
  Sandstorm API works this way: Make API key, and from that key copy API URL and API KEY to below. It saves Wekan board to file.
  `curl http://Bearer:APIKEY@api-12345.local.sandstorm.io:6080/api/boards/sandstorm/export?authToken=#APIKEY > wekanboard.json`
  If later API key does not work, you need to remove it and make a new one.

Thanks to xet7 !
2019-02-02 20:57:47 +02:00
Lauri Ojansivu 32f896f19d - [Fix Sandstorm export board from web](https://github.com/wekan/wekan/issues/2157).
- [Fix Error when logging in to Wekan REST API when using Sandstorm Wekan](https://github.com/wekan/wekan/issues/1279).
  Sandstorm API works this way: Make API key, and from that key copy API URL and API KEY to below. It saves Wekan board to file.
  `curl http://Bearer:APIKEY@api-12345.local.sandstorm.io:6080/api/boards/sandstorm/export?authToken=#APIKEY > wekanboard.json`
  If later API key does not work, you need to remove it and make a new one.

Closes #2157,
closes #1279
2019-02-02 20:52:09 +02:00
Lauri Ojansivu de9965213a - Fix lint errors.
Thanks to xet7 !
2019-02-01 21:26:04 +02:00
guillaume c2118f4830 Improve authentication 2019-02-01 19:00:44 +01:00
Lauri Ojansivu 6f0e0748e1 v2.13 2019-02-01 17:15:15 +02:00
Lauri Ojansivu 8e5fc13ba4 Update changelog with latest changes from bentiss. 2019-02-01 17:09:05 +02:00
Lauri Ojansivu 7a35099fb9 - When writing to minicard, press Shift-Enter on minicard to go to next line below,
to continue writing on same minicard 2nd line.

Thanks to bentiss!
2019-02-01 17:03:59 +02:00
Lauri Ojansivu d08bee6817 Merge branch 'bentiss-infinite-scrolling' into edge 2019-02-01 16:54:41 +02:00
Lauri Ojansivu 4fc96904d6 Merge branch 'infinite-scrolling' of https://github.com/bentiss/wekan into bentiss-infinite-scrolling 2019-02-01 16:05:46 +02:00
Benjamin Tissoires 66bc1f28dd Use infinite-scrolling on lists
This allows to reduce the loading time of a big board.

Note that there is an infinite scroll implementation in the mixins,
but this doesn't fit well as the cards in the list can have arbitrary
height.

The idea to rely on the visibility of a spinner is based on
http://www.meteorpedia.com/read/Infinite_Scrolling
2019-02-01 14:58:02 +01:00
Benjamin Tissoires 30d082e709 Use infinite-scrolling on lists
This allows to reduce the loading time of a big board.

Note that there is an infinite scroll implementation in the mixins,
but this doesn't fit well as the cards in the list can have arbitrary
height.

The idea to rely on the visibility of a spinner is based on
http://www.meteorpedia.com/read/Infinite_Scrolling
2019-02-01 13:53:45 +01:00
555 changed files with 49819 additions and 4554 deletions

No files matched your search

+1 -1
View File
@@ -6,7 +6,7 @@
"browser": true
},
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 2017,
"sourceType": "module",
"ecmaFeatures": {
"experimentalObjectRestSpread": true
-1
View File
@@ -1,7 +1,6 @@
## Issue
Add these issues to elsewhere:
- LDAP: https://github.com/wekan/wekan-ldap/issues
- Snap: https://github.com/wekan/wekan-snap/issues
Other Wekan issues can be added here.
+13 -1
View File
@@ -8,7 +8,6 @@ npm-debug.log
.vscode/
.idea/
.build/*
packages/
package-lock.json
**/parts/
**/stage
@@ -17,3 +16,16 @@ package-lock.json
snap/.snapcraft/
.idea
.DS_Store
.DS_Store?
.build*
*.browserify.js.cached
*.browserify.js.map
.build*
versions.json
.versions
.npm
.build*
._*
.Trashes
Thumbs.db
ehthumbs.db
+7 -5
View File
@@ -31,7 +31,9 @@ kenton:accounts-sandstorm
service-configuration@1.0.11
useraccounts:unstyled
useraccounts:flow-routing
salleman:accounts-oidc
wekan-ldap
wekan-accounts-cas
wekan-accounts-oidc
# Utilities
check@1.2.5
@@ -64,7 +66,6 @@ mquandalle:jquery-textcomplete
mquandalle:jquery-ui-drag-drop-sort
mquandalle:mousetrap-bindglobal
peerlibrary:blaze-components@=0.15.1
perak:markdown
templates:tabs
verron:autosize
simple:json-routes
@@ -80,13 +81,14 @@ staringatlights:fast-render
mixmax:smart-disconnect
accounts-password@1.5.0
cfs:gridfs
eluck:accounts-lockout
rzymek:fullcalendar
momentjs:moment@2.22.2
browser-policy-framing
mquandalle:moment
msavin:usercache
wekan:wekan-ldap
wekan:accounts-cas
wekan-scrollbar
mquandalle:perfect-scrollbar
mdg:meteor-apm-agent
meteorhacks:unblock
lucasantoniassi:accounts-lockout
wekan-markdown
+8 -6
View File
@@ -60,7 +60,6 @@ ecmascript-runtime@0.5.0
ecmascript-runtime-client@0.5.0
ecmascript-runtime-server@0.5.0
ejson@1.1.0
eluck:accounts-lockout@0.9.0
email@1.2.3
es5-shim@4.6.15
fastclick@1.0.13
@@ -82,8 +81,10 @@ launch-screen@1.1.1
livedata@1.0.18
localstorage@1.2.0
logging@1.1.19
lucasantoniassi:accounts-lockout@1.0.0
matb33:collection-hooks@0.8.4
matteodem:easy-search@1.6.4
mdg:meteor-apm-agent@3.1.2
mdg:validation-error@0.5.1
meteor@1.8.2
meteor-base@1.2.0
@@ -93,6 +94,7 @@ meteorhacks:collection-utils@1.2.0
meteorhacks:meteorx@1.4.1
meteorhacks:picker@1.0.3
meteorhacks:subs-manager@1.6.4
meteorhacks:unblock@1.1.0
meteorspark:util@0.2.0
minifier-css@1.2.16
minifier-js@2.2.2
@@ -130,7 +132,6 @@ peerlibrary:base-component@0.16.0
peerlibrary:blaze-components@0.15.1
peerlibrary:computed-field@0.7.0
peerlibrary:reactive-field@0.3.0
perak:markdown@1.0.5
promise@0.10.0
raix:eventemitter@0.1.3
raix:handlebar-helpers@0.2.5
@@ -143,8 +144,6 @@ reload@1.1.11
retry@1.0.9
routepolicy@1.0.12
rzymek:fullcalendar@3.8.0
salleman:accounts-oidc@1.0.10
salleman:oidc@1.0.10
service-configuration@1.0.11
session@1.1.7
sha@1.0.9
@@ -179,8 +178,11 @@ useraccounts:unstyled@1.14.2
verron:autosize@3.0.8
webapp@1.4.0
webapp-hashing@1.0.9
wekan-accounts-oidc@1.0.10
wekan-markdown@1.0.7
wekan-oidc@1.0.12
wekan-scrollbar@3.1.3
wekan:accounts-cas@0.1.0
wekan:wekan-ldap@0.0.2
wekan-accounts-cas@0.1.0
wekan-ldap@0.0.2
yasaricli:slugify@0.0.7
zimme:active-route@2.3.2
+1 -1
View File
@@ -39,7 +39,7 @@ host = https://www.transifex.com
# tap:i18n requires us to use `-` separator in the language identifiers whereas
# Transifex uses a `_` separator, without an option to customize it on one side
# or the other, so we need to do a Manual mapping.
lang_map = bg_BG:bg, en_GB:en-GB, es_AR:es-AR, el_GR:el, fi_FI:fi, hu_HU:hu, id_ID:id, mn_MN:mn, no:nb, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, zh_CN:zh-CN, zh_TW:zh-TW
lang_map = bg_BG:bg, en_GB:en-GB, es_AR:es-AR, el_GR:el, fi_FI:fi, hu_HU:hu, id_ID:id, mn_MN:mn, no:nb, lv_LV:lv, pt_BR:pt-BR, ro_RO:ro, zh_CN:zh-CN, zh_TW:zh-TW, zh_HK:zh-HK
[wekan.application]
file_filter = i18n/<lang>.i18n.json
+1002 -14
View File
File diff suppressed because it is too large. Load diff
+52 -87
View File
@@ -1,82 +1,12 @@
FROM debian:buster-slim
FROM ubuntu:disco
LABEL maintainer="wekan"
# Declare Arguments
ARG NODE_VERSION
ARG METEOR_RELEASE
ARG METEOR_EDGE
ARG USE_EDGE
ARG NPM_VERSION
ARG FIBERS_VERSION
ARG ARCHITECTURE
ARG SRC_PATH
ARG WITH_API
ARG MATOMO_ADDRESS
ARG MATOMO_SITE_ID
ARG MATOMO_DO_NOT_TRACK
ARG MATOMO_WITH_USERNAME
ARG BROWSER_POLICY_ENABLED
ARG TRUSTED_URL
ARG WEBHOOKS_ATTRIBUTES
ARG OAUTH2_ENABLED
ARG OAUTH2_CLIENT_ID
ARG OAUTH2_SECRET
ARG OAUTH2_SERVER_URL
ARG OAUTH2_AUTH_ENDPOINT
ARG OAUTH2_USERINFO_ENDPOINT
ARG OAUTH2_TOKEN_ENDPOINT
ARG LDAP_ENABLE
ARG LDAP_PORT
ARG LDAP_HOST
ARG LDAP_BASEDN
ARG LDAP_LOGIN_FALLBACK
ARG LDAP_RECONNECT
ARG LDAP_TIMEOUT
ARG LDAP_IDLE_TIMEOUT
ARG LDAP_CONNECT_TIMEOUT
ARG LDAP_AUTHENTIFICATION
ARG LDAP_AUTHENTIFICATION_USERDN
ARG LDAP_AUTHENTIFICATION_PASSWORD
ARG LDAP_LOG_ENABLED
ARG LDAP_BACKGROUND_SYNC
ARG LDAP_BACKGROUND_SYNC_INTERVAL
ARG LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED
ARG LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS
ARG LDAP_ENCRYPTION
ARG LDAP_CA_CERT
ARG LDAP_REJECT_UNAUTHORIZED
ARG LDAP_USER_SEARCH_FILTER
ARG LDAP_USER_SEARCH_SCOPE
ARG LDAP_USER_SEARCH_FIELD
ARG LDAP_SEARCH_PAGE_SIZE
ARG LDAP_SEARCH_SIZE_LIMIT
ARG LDAP_GROUP_FILTER_ENABLE
ARG LDAP_GROUP_FILTER_OBJECTCLASS
ARG LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE
ARG LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE
ARG LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT
ARG LDAP_GROUP_FILTER_GROUP_NAME
ARG LDAP_UNIQUE_IDENTIFIER_FIELD
ARG LDAP_UTF8_NAMES_SLUGIFY
ARG LDAP_USERNAME_FIELD
ARG LDAP_FULLNAME_FIELD
ARG LDAP_MERGE_EXISTING_USERS
ARG LDAP_SYNC_USER_DATA
ARG LDAP_SYNC_USER_DATA_FIELDMAP
ARG LDAP_SYNC_GROUP_ROLES
ARG LDAP_DEFAULT_DOMAIN
ARG LOGOUT_WITH_TIMER
ARG LOGOUT_IN
ARG LOGOUT_ON_HOURS
ARG LOGOUT_ON_MINUTES
ARG CORS
ARG DEFAULT_AUTHENTICATION_METHOD
# Set the environment variables (defaults where required)
# DOES NOT WORK: paxctl fix for alpine linux: https://github.com/wekan/wekan/issues/1303
# ENV BUILD_DEPS="paxctl"
ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential python python3 python3-distutils git ca-certificates gcc-7" \
NODE_VERSION=v8.15.0 \
ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential python3 python3-pip git ca-certificates gcc-8" \
DEBUG=false \
NODE_VERSION=v8.16.0 \
METEOR_RELEASE=1.6.0.1 \
USE_EDGE=false \
METEOR_EDGE=1.5-beta.17 \
@@ -85,6 +15,13 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth
ARCHITECTURE=linux-x64 \
SRC_PATH=./ \
WITH_API=true \
ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE=3 \
ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD=60 \
ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW=15 \
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE=3 \
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60 \
ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15 \
EMAIL_NOTIFICATION_TIMEOUT=30000 \
MATOMO_ADDRESS="" \
MATOMO_SITE_ID="" \
MATOMO_DO_NOT_TRACK=true \
@@ -93,12 +30,19 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth
TRUSTED_URL="" \
WEBHOOKS_ATTRIBUTES="" \
OAUTH2_ENABLED=false \
OAUTH2_LOGIN_STYLE=redirect \
OAUTH2_CLIENT_ID="" \
OAUTH2_SECRET="" \
OAUTH2_SERVER_URL="" \
OAUTH2_AUTH_ENDPOINT="" \
OAUTH2_USERINFO_ENDPOINT="" \
OAUTH2_TOKEN_ENDPOINT="" \
OAUTH2_ID_MAP="" \
OAUTH2_USERNAME_MAP="" \
OAUTH2_FULLNAME_MAP="" \
OAUTH2_ID_TOKEN_WHITELIST_FIELDS="" \
OAUTH2_REQUEST_PERMISSIONS='openid profile email' \
OAUTH2_EMAIL_MAP="" \
LDAP_ENABLE=false \
LDAP_PORT=389 \
LDAP_HOST="" \
@@ -119,6 +63,7 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth
LDAP_ENCRYPTION=false \
LDAP_CA_CERT="" \
LDAP_REJECT_UNAUTHORIZED=false \
LDAP_USER_AUTHENTICATION=false \
LDAP_USER_SEARCH_FILTER="" \
LDAP_USER_SEARCH_SCOPE="" \
LDAP_USER_SEARCH_FIELD="" \
@@ -135,15 +80,27 @@ ENV BUILD_DEPS="apt-utils bsdtar gnupg gosu wget curl bzip2 build-essential pyth
LDAP_USERNAME_FIELD="" \
LDAP_FULLNAME_FIELD="" \
LDAP_MERGE_EXISTING_USERS=false \
LDAP_EMAIL_FIELD="" \
LDAP_EMAIL_MATCH_ENABLE=false \
LDAP_EMAIL_MATCH_REQUIRE=false \
LDAP_EMAIL_MATCH_VERIFIED=false \
LDAP_SYNC_USER_DATA=false \
LDAP_SYNC_USER_DATA_FIELDMAP="" \
LDAP_SYNC_GROUP_ROLES="" \
LDAP_DEFAULT_DOMAIN="" \
LDAP_SYNC_ADMIN_STATUS="" \
LDAP_SYNC_ADMIN_GROUPS="" \
HEADER_LOGIN_ID="" \
HEADER_LOGIN_FIRSTNAME="" \
HEADER_LOGIN_LASTNAME="" \
HEADER_LOGIN_EMAIL="" \
LOGOUT_WITH_TIMER=false \
LOGOUT_IN="" \
LOGOUT_ON_HOURS="" \
LOGOUT_ON_MINUTES="" \
CORS="" \
CORS_ALLOW_HEADERS="" \
CORS_EXPOSE_HEADERS="" \
DEFAULT_AUTHENTICATION_METHOD=""
# Copy the app to the image
@@ -156,6 +113,7 @@ RUN \
\
# OS dependencies
apt-get update -y && apt-get install -y --no-install-recommends ${BUILD_DEPS} && \
pip3 install -U pip setuptools wheel && \
\
# Meteor installer doesn't work with the default tar binary, so using bsdtar while installing.
# https://github.com/coreos/bugs/issues/1095#issuecomment-350574389
@@ -239,36 +197,43 @@ RUN \
fi; \
\
# Get additional packages
mkdir -p /home/wekan/app/packages && \
chown wekan:wekan --recursive /home/wekan && \
cd /home/wekan/app/packages && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/flow-router.git kadira-flow-router && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/meteor-useraccounts/core.git meteor-useraccounts-core && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/meteor-accounts-cas.git && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/wekan-ldap.git && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/wekan/wekan-scrollbar.git && \
#mkdir -p /home/wekan/app/packages && \
#chown wekan:wekan --recursive /home/wekan && \
# REPOS BELOW ARE INCLUDED TO WEKAN REPO
#cd /home/wekan/app/packages && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/meteor-useraccounts/core.git meteor-useraccounts-core && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-cas.git && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/wekan-ldap.git && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/wekan-scrollbar.git && \
#gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/meteor-accounts-oidc.git && \
#gosu wekan:wekan git clone --depth 1 -b master --recurse-submodules https://github.com/wekan/markdown.git && \
#gosu wekan:wekan mv meteor-accounts-oidc/packages/switch_accounts-oidc wekan-accounts-oidc && \
#gosu wekan:wekan mv meteor-accounts-oidc/packages/switch_oidc wekan-oidc && \
#gosu wekan:wekan rm -rf meteor-accounts-oidc && \
sed -i 's/api\.versionsFrom/\/\/api.versionsFrom/' /home/wekan/app/packages/meteor-useraccounts-core/package.js && \
cd /home/wekan/.meteor && \
gosu wekan:wekan /home/wekan/.meteor/meteor -- help; \
\
# extract the OpenAPI specification
npm install -g api2html && \
npm install -g api2html@0.3.3 && \
mkdir -p /home/wekan/python && \
chown wekan:wekan --recursive /home/wekan/python && \
cd /home/wekan/python && \
gosu wekan:wekan git clone --depth 1 -b master git://github.com/Kronuz/esprima-python && \
gosu wekan:wekan git clone --depth 1 -b master https://github.com/Kronuz/esprima-python && \
cd /home/wekan/python/esprima-python && \
python3 setup.py install --record files.txt && \
cd /home/wekan/app &&\
mkdir -p ./public/api && \
python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml && \
/opt/nodejs/bin/api2html -c ./public/wekan-logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml; \
gosu wekan:wekan mkdir -p ./public/api && \
gosu wekan:wekan python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml && \
gosu wekan:wekan /opt/nodejs/bin/api2html -c ./public/logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml; \
# Build app
cd /home/wekan/app && \
gosu wekan:wekan /home/wekan/.meteor/meteor add standard-minifier-js && \
gosu wekan:wekan /home/wekan/.meteor/meteor npm install && \
gosu wekan:wekan /home/wekan/.meteor/meteor build --directory /home/wekan/app_build && \
cp /home/wekan/app/fix-download-unicode/cfs_access-point.txt /home/wekan/app_build/bundle/programs/server/packages/cfs_access-point.js && \
rm /home/wekan/app_build/bundle/programs/server/npm/node_modules/meteor/rajit_bootstrap3-datepicker/lib/bootstrap-datepicker/node_modules/phantomjs-prebuilt/lib/phantom/bin/phantomjs && \
chown wekan:wekan /home/wekan/app_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
+44 -19
View File
@@ -9,6 +9,7 @@
[![Code Climate](https://codeclimate.com/github/wekan/wekan/badges/gpa.svg "Code Climate")](https://codeclimate.com/github/wekan/wekan)
[![Project Dependencies](https://david-dm.org/wekan/wekan.svg "Project Dependencies")](https://david-dm.org/wekan/wekan)
[![Code analysis at Open Hub](https://img.shields.io/badge/code%20analysis-at%20Open%20Hub-brightgreen.svg "Code analysis at Open Hub")](https://www.openhub.net/p/wekan)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwekan%2Fwekan.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwekan%2Fwekan?ref=badge_shield)
## [Translate Wekan at Transifex](https://transifex.com/wekan/wekan)
@@ -22,9 +23,8 @@ It's better than at chat where details get lost when chat scrolls up.
## Chat
[![Wekan Vanila Chat][vanila_badge]][vanila_chat] - Most Wekan community and developers are here at #wekan chat channel.
Use webbrowser to register, and after that you can also alternatively use mobile app Rocket.Chat by Rocket.Chat with
address https://chat.vanila.io and same username and password.
[![Wekan Chat][vanila_badge]][wekan_chat] - Most Wekan community and developers are here. Works on webbrowser
and PWA app that can be added as icon on Android and bookmark on iOS, used like native app.
[Wekan IRC FAQ](https://github.com/wekan/wekan/wiki/IRC-FAQ)
@@ -39,33 +39,55 @@ address https://chat.vanila.io and same username and password.
Wekan is an completely [Open Source][open_source] and [Free software][free_software]
collaborative kanban board application with MIT license.
Whether you’re maintaining a personal todo list, planning your holidays with some friends, or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool to keep your things organized. They give you a visual overview of the current state of your project, and make you productive by allowing you to focus on the few items that matter the most.
Whether you’re maintaining a personal todo list, planning your holidays with some friends,
or working in a team on your next revolutionary idea, Kanban boards are an unbeatable tool
to keep your things organized. They give you a visual overview of the current state of your project,
and make you productive by allowing you to focus on the few items that matter the most.
Since Wekan is a free software, you don’t have to trust us with your data and can
install Wekan on your own computer or server. In fact we encourage you to do
that by providing one-click installation on various platforms.
- [Features][features]: Wekan has real-time user interface. Not all features are implemented, yet.
- [Platforms][platforms]: Wekan supports many platforms and plan is to add more. This will be the first place to look if you want to **install** it, test out and learn more in depth.
- Wekan is used in [most countries of the world](https://snapcraft.io/wekan).
- Wekan largest user has 13k users using Wekan in their company.
- Wekan has been [translated](https://transifex.com/wekan/wekan) to about 50 languages.
- [Features][features]: Wekan has real-time user interface.
- [Platforms][platforms]: Wekan supports many platforms.
Wekan is critical part of new platforms Wekan is currently being integrated to.
- [Integrations][integrations]: Current possible integrations and future plans.
- [Team](https://github.com/wekan/wekan/wiki/Team): The people who spends their time and make Wekan into what it is right now.
## Requirements
- 64bit: Linux [Snap](https://github.com/wekan/wekan-snap/wiki/Install) or [Sandstorm](https://sandstorm.io) /
[Mac](https://github.com/wekan/wekan/wiki/Mac) / [Windows](https://github.com/wekan/wekan/wiki/Install-Wekan-from-source-on-Windows).
[More Platforms](https://github.com/wekan/wekan/wiki/Platforms). [ARM progress](https://github.com/wekan/wekan/issues/1053#issuecomment-410919264).
- 1 GB RAM minimum free for Wekan. Production server should have minimum total 4 GB RAM.
For thousands of users, for example with [Docker](https://github.com/wekan/wekan/blob/devel/docker-compose.yml): 3 frontend servers,
each having 2 CPU and 2 wekan-app containers. One backend wekan-db server with many CPUs.
- Enough disk space and alerts about low disk space. If you run out disk space, MongoDB database gets corrupted.
- SECURITY: Updating to newest Wekan version very often. Please check you do not have automatic updates of Sandstorm or Snap turned off.
Old versions have security issues because of old versions Node.js etc. Only newest Wekan is supported.
Wekan on Sandstorm is not usually affected by any Standalone Wekan (Snap/Docker/Source) security issues.
- [Reporting all new bugs immediately](https://github.com/wekan/wekan/issues).
New features and fixes are added to Wekan [many times a day](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md).
- [Backups](https://github.com/wekan/wekan/wiki/Backup) of Wekan database once a day miminum.
Bugs, updates, users deleting list or card, harddrive full, harddrive crash etc can eat your data. There is no undo yet.
Some bug can cause Wekan board to not load at all, requiring manual fixing of database content.
## Roadmap
[Roadmap](https://github.com/wekan/wekan/wiki/Roadmap)
[Roadmap Milestones](https://github.com/wekan/wekan/milestones)
Upcoming Wekan App Development Platform will make possible many use cases. If you don't find your feature or integration in
GitHub issues and [Features][features] or [Integrations][integrations] page at wiki, please add them.
[Developer Documentation][dev_docs]
We are very welcoming to new developers and teams to submit new pull requests to devel branch to make this Wekan App Development Platform possible faster. Please see [Developer Documentation][dev_docs] to get started.
- There is many companies and individuals contributing code to Wekan, to add features and bugfixes
[many times a day](https://github.com/wekan/wekan/blob/devel/CHANGELOG.md).
- [Please add Add new Feature Requests and Bug Reports immediately](https://github.com/wekan/wekan/issues).
- [Commercial Support](https://wekan.team).
- [Bounties](https://wekan.team/bounties/index.html).
We also welcome sponsors for features and bugfixes. By working directly with Wekan you get the benefit of active maintenance and new features added by growing Wekan developer community.
Actual work happens at [Wekan GitHub issues][wekan_issues].
See [Development links on Wekan wiki](https://github.com/wekan/wekan/wiki#Development) bottom of the page for more info.
If you want to know what is going on exactly this moment, you can check out the [project page](https://github.com/wekan/wekan/projects/2).
We also welcome sponsors for features and bugfixes.
By working directly with Wekan you get the benefit of active maintenance and new features added by growing Wekan developer community.
## Demo
@@ -111,4 +133,7 @@ with [Meteor](https://www.meteor.com).
[open_source]: https://en.wikipedia.org/wiki/Open-source_software
[free_software]: https://en.wikipedia.org/wiki/Free_software
[vanila_badge]: https://vanila.io/img/join-chat-button2.png
[vanila_chat]: https://chat.vanila.io/channel/wekan
[wekan_chat]: https://community.vanila.io/wekan
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fwekan%2Fwekan.svg?type=large)](https://app.fossa.io/projects/git%2Bgithub.com%2Fwekan%2Fwekan?ref=badge_large)
+1 -1
View File
@@ -1,5 +1,5 @@
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
appVersion: "v2.12.0"
appVersion: "v2.91.0"
files:
userUploads:
- README.md
+14 -1
View File
@@ -99,6 +99,9 @@ template(name="boardActivities")
else
| {{{_ 'activity-added' memberLink cardLink}}}.
if($eq activityType 'moveCardBoard')
| {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
if($eq activityType 'moveCard')
| {{{_ 'activity-moved' cardLink oldList.title list.title}}}.
@@ -114,6 +117,12 @@ template(name="boardActivities")
if($eq activityType 'removedLabel')
| {{{_ 'activity-removed-label' lastLabel cardLink}}}.
if($eq activityType 'setCustomField')
| {{{_ 'activity-set-customfield' lastCustomField lastCustomFieldValue cardLink}}}.
if($eq activityType 'unsetCustomField')
| {{{_ 'activity-unset-customfield' lastCustomField cardLink}}}.
if($eq activityType 'unjoinMember')
if($eq user._id member._id)
| {{{_ 'activity-unjoined' cardLink}}}.
@@ -129,7 +138,7 @@ template(name="cardActivities")
p.activity-desc
+memberName(user=user)
if($eq activityType 'createCard')
| {{_ 'activity-added' cardLabel list.title}}.
| {{_ 'activity-added' cardLabel listName}}.
if($eq activityType 'importCard')
| {{{_ 'activity-imported' cardLabel list.title sourceLink}}}.
if($eq activityType 'joinMember')
@@ -170,6 +179,10 @@ template(name="cardActivities")
| {{_ 'activity-sent' cardLabel boardLabel}}.
if($eq activityType 'moveCard')
| {{_ 'activity-moved' cardLabel oldList.title list.title}}.
if($eq activityType 'moveCardBoard')
| {{{_ 'activity-moved' cardLink oldBoardName boardName}}}.
if($eq activityType 'addAttachment')
| {{{_ 'activity-attached' attachmentLink cardLabel}}}.
if attachment.isImage
@@ -74,6 +74,8 @@ BlazeComponent.extendComponent({
lastLabel(){
const lastLabelId = this.currentData().labelId;
if (!lastLabelId)
return null;
const lastLabel = Boards.findOne(Session.get('currentBoard')).getLabelById(lastLabelId);
if(lastLabel.name === undefined || lastLabel.name === ''){
return lastLabel.color;
@@ -82,6 +84,28 @@ BlazeComponent.extendComponent({
}
},
lastCustomField(){
const lastCustomField = CustomFields.findOne(this.currentData().customFieldId);
if (!lastCustomField)
return null;
return lastCustomField.name;
},
lastCustomFieldValue(){
const lastCustomField = CustomFields.findOne(this.currentData().customFieldId);
if (!lastCustomField)
return null;
const value = this.currentData().value;
if (lastCustomField.settings.dropdownItems && lastCustomField.settings.dropdownItems.length > 0) {
const dropDownValue = _.find(lastCustomField.settings.dropdownItems, (item) => {
return item._id === value;
});
if (dropDownValue)
return dropDownValue.name;
}
return value;
},
listLabel() {
return this.currentData().list().title;
},
@@ -117,6 +141,8 @@ BlazeComponent.extendComponent({
customField() {
const customField = this.currentData().customField();
if (!customField)
return null;
return customField.name;
},
-6
View File
@@ -1,9 +1,3 @@
Template.boardListHeaderBar.events({
'click .js-open-archived-board'() {
Modal.open('archivedBoards');
},
});
BlazeComponent.extendComponent({
onCreated() {
this.subscribe('archivedBoards');
+11 -5
View File
@@ -7,7 +7,8 @@ template(name="board")
+boardBody
else
//- XXX We need a better error message in case the board has been archived
+message(label="board-not-found")
//+message(label="board-not-found")
{{goHome}}
else
+spinner
@@ -20,13 +21,18 @@ template(name="boardBody")
class="{{#if draggingActive.get}}is-dragging-active{{/if}}")
if showOverlay.get
.board-overlay
if isViewSwimlanes
if currentBoard.isTemplatesBoard
each currentBoard.swimlanes
+swimlane(this)
if isViewLists
+listsGroup
if isViewCalendar
else if isViewSwimlanes
each currentBoard.swimlanes
+swimlane(this)
else if isViewLists
+listsGroup(currentBoard)
else if isViewCalendar
+calendarView
else
+listsGroup(currentBoard)
template(name="calendarView")
if isViewCalendar
+81 -9
View File
@@ -1,5 +1,6 @@
const subManager = new SubsManager();
const { calculateIndex, enableClickOnTouch } = Utils;
const swimlaneWhileSortingHeight = 150;
BlazeComponent.extendComponent({
onCreated() {
@@ -13,7 +14,7 @@ BlazeComponent.extendComponent({
const currentBoardId = Session.get('currentBoard');
if (!currentBoardId)
return;
const handle = subManager.subscribe('board', currentBoardId);
const handle = subManager.subscribe('board', currentBoardId, false);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
this.isBoardReady.set(handle.ready());
@@ -26,6 +27,10 @@ BlazeComponent.extendComponent({
return Utils.isMiniScreen() && Session.get('currentCard');
},
goHome() {
FlowRouter.go('home');
},
}).register('board');
BlazeComponent.extendComponent({
@@ -74,21 +79,64 @@ BlazeComponent.extendComponent({
$swimlanesDom.sortable({
tolerance: 'pointer',
appendTo: '.board-canvas',
helper: 'clone',
helper(evt, item) {
const helper = $(`<div class="swimlane"
style="flex-direction: column;
height: ${swimlaneWhileSortingHeight}px;
width: $(boardComponent.width)px;
overflow: hidden;"/>`);
helper.append(item.clone());
// Also grab the list of lists of cards
const list = item.next();
helper.append(list.clone());
return helper;
},
handle: '.js-swimlane-header',
items: '.js-swimlane:not(.placeholder)',
items: '.swimlane:not(.placeholder)',
placeholder: 'swimlane placeholder',
distance: 7,
start(evt, ui) {
const listDom = ui.placeholder.next('.js-swimlane');
const parentOffset = ui.item.parent().offset();
ui.placeholder.height(ui.helper.height());
EscapeActions.executeUpTo('popup-close');
listDom.addClass('moving-swimlane');
boardComponent.setIsDragging(true);
ui.placeholder.insertAfter(ui.placeholder.next());
boardComponent.origPlaceholderIndex = ui.placeholder.index();
// resize all swimlanes + headers to be a total of 150 px per row
// this could be achieved by setIsDragging(true) but we want immediate
// result
ui.item.siblings('.js-swimlane').css('height', `${swimlaneWhileSortingHeight - 26}px`);
// set the new scroll height after the resize and insertion of
// the placeholder. We want the element under the cursor to stay
// at the same place on the screen
ui.item.parent().get(0).scrollTop = ui.placeholder.get(0).offsetTop + parentOffset.top - evt.pageY;
},
beforeStop(evt, ui) {
const parentOffset = ui.item.parent().offset();
const siblings = ui.item.siblings('.js-swimlane');
siblings.css('height', '');
// compute the new scroll height after the resize and removal of
// the placeholder
const scrollTop = ui.placeholder.get(0).offsetTop + parentOffset.top - evt.pageY;
// then reset the original view of the swimlane
siblings.removeClass('moving-swimlane');
// and apply the computed scrollheight
ui.item.parent().get(0).scrollTop = scrollTop;
},
stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following card -- if any.
const prevSwimlaneDom = ui.item.prev('.js-swimlane').get(0);
const nextSwimlaneDom = ui.item.next('.js-swimlane').get(0);
const prevSwimlaneDom = ui.item.prevAll('.js-swimlane').get(0);
const nextSwimlaneDom = ui.item.nextAll('.js-swimlane').get(0);
const sortIndex = calculateIndex(prevSwimlaneDom, nextSwimlaneDom, 1);
$swimlanesDom.sortable('cancel');
@@ -103,6 +151,30 @@ BlazeComponent.extendComponent({
boardComponent.setIsDragging(false);
},
sort(evt, ui) {
// get the mouse position in the sortable
const parentOffset = ui.item.parent().offset();
const cursorY = evt.pageY - parentOffset.top + ui.item.parent().scrollTop();
// compute the intended index of the placeholder (we need to skip the
// slots between the headers and the list of cards)
const newplaceholderIndex = Math.floor(cursorY / swimlaneWhileSortingHeight);
let destPlaceholderIndex = (newplaceholderIndex + 1) * 2;
// if we are scrolling far away from the bottom of the list
if (destPlaceholderIndex >= ui.item.parent().get(0).childElementCount) {
destPlaceholderIndex = ui.item.parent().get(0).childElementCount - 1;
}
// update the placeholder position in the DOM tree
if (destPlaceholderIndex !== ui.placeholder.index()) {
if (destPlaceholderIndex < boardComponent.origPlaceholderIndex) {
ui.placeholder.insertBefore(ui.placeholder.siblings().slice(destPlaceholderIndex - 2, destPlaceholderIndex - 1));
} else {
ui.placeholder.insertAfter(ui.placeholder.siblings().slice(destPlaceholderIndex - 1, destPlaceholderIndex));
}
}
},
});
// ugly touch event hotfix
@@ -123,19 +195,19 @@ BlazeComponent.extendComponent({
isViewSwimlanes() {
const currentUser = Meteor.user();
if (!currentUser) return false;
return (currentUser.profile.boardView === 'board-view-swimlanes');
return ((currentUser.profile || {}).boardView === 'board-view-swimlanes');
},
isViewLists() {
const currentUser = Meteor.user();
if (!currentUser) return true;
return (currentUser.profile.boardView === 'board-view-lists');
return ((currentUser.profile || {}).boardView === 'board-view-lists');
},
isViewCalendar() {
const currentUser = Meteor.user();
if (!currentUser) return false;
return (currentUser.profile.boardView === 'board-view-cal');
return ((currentUser.profile || {}).boardView === 'board-view-cal');
},
openNewListForm() {
@@ -267,6 +339,6 @@ BlazeComponent.extendComponent({
isViewCalendar() {
const currentUser = Meteor.user();
if (!currentUser) return false;
return (currentUser.profile.boardView === 'board-view-cal');
return ((currentUser.profile || {}).boardView === 'board-view-cal');
},
}).register('calendarView');
+1 -1
View File
@@ -50,6 +50,6 @@ position()
display: flex
flex-direction: column
margin: 0
padding: 0 40px 0px 0
padding: 0 0px 0px 0
overflow-x: hidden
overflow-y: auto
+71 -186
View File
@@ -7,71 +7,69 @@ template(name="boardHeaderBar")
.board-header-btns.left
unless isMiniScreen
unless isSandstorm
if currentBoard
if currentUser
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span
= currentBoard.stars
if currentBoard
if currentUser
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span
= currentBoard.stars
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
.board-header-btns.right
if currentBoard
if isMiniScreen
unless isSandstorm
if currentUser
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span
= currentBoard.stars
if currentUser
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'click-to-unstar'}}{{else}}{{_ 'click-to-star'}}{{/if}} {{_ 'starred-boards-description'}}")
i.fa(class="fa-star{{#unless isStarred}}-o{{/unless}}")
if showStarCounter
span
= currentBoard.stars
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}")
i.fa(class="{{#if currentBoard.isPublic}}fa-globe{{else}}fa-lock{{/if}}")
span {{_ currentBoard.permission}}
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
a.board-header-btn.js-watch-board(
title="{{_ watchLevel }}")
if $eq watchLevel "watching"
i.fa.fa-eye
if $eq watchLevel "tracking"
i.fa.fa-bell
if $eq watchLevel "muted"
i.fa.fa-bell-slash
span {{_ watchLevel}}
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
else
a.board-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
if isSandstorm
if currentUser
@@ -87,19 +85,25 @@ template(name="boardHeaderBar")
if Filter.isActive
a.board-header-btn-close.js-filter-reset(title="{{_ 'filter-clear'}}")
i.fa.fa-times-thin
if currentUser.isAdmin
a.board-header-btn.js-open-rules-view(title="{{_ 'rules'}}")
i.fa.fa-magic
span {{_ 'rules'}}
else if currentUser.isBoardAdmin
a.board-header-btn.js-open-rules-view(title="{{_ 'rules'}}")
i.fa.fa-magic
span {{_ 'rules'}}
a.board-header-btn.js-open-search-view(title="{{_ 'search'}}")
i.fa.fa-search
span {{_ 'search'}}
a.board-header-btn.js-toggle-board-view(
title="{{_ 'board-view'}}")
i.fa.fa-th-large
span {{_ currentUser.profile.boardView}}
unless currentBoard.isTemplatesBoard
a.board-header-btn.js-toggle-board-view(
title="{{_ 'board-view'}}")
i.fa.fa-th-large
span {{#if currentUser.profile.boardView}}{{_ currentUser.profile.boardView}}{{else}}{{_ 'board-view-lists'}}{{/if}}
if canModifyBoard
a.board-header-btn.js-multiselection-activate(
@@ -112,40 +116,8 @@ template(name="boardHeaderBar")
i.fa.fa-times-thin
.separator
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}")
i.board-header-btn-icon.fa.fa-navicon
template(name="boardMenuPopup")
ul.pop-over-list
li: a.js-custom-fields {{_ 'custom-fields'}}
li: a.js-open-archives {{_ 'archived-items'}}
if currentUser.isBoardAdmin
li: a.js-change-board-color {{_ 'board-change-color'}}
//-
XXX Language should be handled by sandstorm, but for now display a
language selection link in the board menu. This link is normally present
in the header bar that is not displayed on sandstorm.
if isSandstorm
li: a.js-change-language {{_ 'language'}}
unless isSandstorm
if currentUser.isBoardAdmin
hr
ul.pop-over-list
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
li: a.js-archive-board {{_ 'archive-board'}}
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
hr
ul.pop-over-list
li: a.js-subtask-settings {{_ 'subtask-settings'}}
if isSandstorm
hr
ul.pop-over-list
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
li: a.js-import-board {{_ 'import-board-c'}}
hr
ul.pop-over-list
li: a.js-subtask-settings {{_ 'subtask-settings'}}
a.board-header-btn.js-toggle-sidebar
i.fa.fa-navicon
template(name="boardVisibilityList")
ul.pop-over-list
@@ -196,64 +168,6 @@ template(name="boardChangeWatchPopup")
i.fa.fa-check
span.sub-name {{_ 'muted-info'}}
template(name="boardChangeColorPopup")
.board-backgrounds-list.clearfix
each backgroundColors
.board-background-select.js-select-background
span.background-box(class="board-color-{{this}}")
if isSelected
i.fa.fa-check
template(name="boardSubtaskSettingsPopup")
form.board-subtask-settings
h3 {{_ 'show-parent-in-minicard'}}
a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
span {{_ 'prefix-with-full-path'}}
a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
span {{_ 'prefix-with-parent'}}
a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
span {{_ 'subtext-with-full-path'}}
a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
span {{_ 'subtext-with-parent'}}
a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
span {{_ 'no-parent'}}
div
hr
div.check-div
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
span {{_ 'show-subtasks-field'}}
label
| {{_ 'deposit-subtasks-board'}}
select.js-field-deposit-board(disabled="{{#unless allowsSubtasks}}disabled{{/unless}}")
each boards
if isBoardSelected
option(value=_id selected="selected") {{title}}
else
option(value=_id) {{title}}
if isNullBoardSelected
option(value='null' selected="selected") {{_ 'custom-field-dropdown-none'}}
else
option(value='null') {{_ 'custom-field-dropdown-none'}}
div
hr
label
| {{_ 'deposit-subtasks-list'}}
select.js-field-deposit-list(disabled="{{#unless hasLists}}disabled{{/unless}}")
each lists
if isListSelected
option(value=_id selected="selected") {{title}}
else
option(value=_id) {{title}}
template(name="createBoard")
form
label
@@ -275,50 +189,21 @@ template(name="createBoard")
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import-board'}}
template(name="chooseBoardSource")
ul.pop-over-list
li
a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
li
a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
template(name="boardChangeTitlePopup")
form
label
| {{_ 'title'}}
input.js-board-name(type="text" value=title autofocus)
input.js-board-name(type="text" value=title autofocus dir="auto")
label
| {{_ 'description'}}
textarea.js-board-desc= description
textarea.js-board-desc(dir="auto")= description
input.primary.wide(type="submit" value="{{_ 'rename'}}")
template(name="boardCreateRulePopup")
p {{_ 'close-board-pop'}}
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
template(name="archiveBoardPopup")
p {{_ 'close-board-pop'}}
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
template(name="outgoingWebhooksPopup")
each integrations
form.integration-form
if title
h4 {{title}}
else
h4 {{_ 'no-name'}}
label
| URL
input.js-outgoing-webhooks-url(type="text" name="url" value=url)
input(type="hidden" value=_id name="id")
input.primary.wide(type="submit" value="{{_ 'save'}}")
form.integration-form
h4
| {{_ 'new-outgoing-webhook'}}
label
| URL
input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
input.primary.wide(type="submit" value="{{_ 'save'}}")
+9 -174
View File
@@ -89,14 +89,19 @@ BlazeComponent.extendComponent({
},
'click .js-toggle-board-view'() {
const currentUser = Meteor.user();
if (currentUser.profile.boardView === 'board-view-swimlanes') {
if ((currentUser.profile || {}).boardView === 'board-view-swimlanes') {
currentUser.setBoardView('board-view-cal');
} else if (currentUser.profile.boardView === 'board-view-lists') {
} else if ((currentUser.profile || {}).boardView === 'board-view-lists') {
currentUser.setBoardView('board-view-swimlanes');
} else if (currentUser.profile.boardView === 'board-view-cal') {
} else if ((currentUser.profile || {}).boardView === 'board-view-cal') {
currentUser.setBoardView('board-view-lists');
} else {
currentUser.setBoardView('board-view-swimlanes');
}
},
'click .js-toggle-sidebar'() {
Sidebar.toggle();
},
'click .js-open-filter-view'() {
Sidebar.setView('filter');
},
@@ -135,124 +140,6 @@ Template.boardHeaderBar.helpers({
},
});
BlazeComponent.extendComponent({
backgroundColors() {
return Boards.simpleSchema()._schema.color.allowedValues;
},
isSelected() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
return currentBoard.color === this.currentData().toString();
},
events() {
return [{
'click .js-select-background'(evt) {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const newColor = this.currentData().toString();
currentBoard.setColor(newColor);
evt.preventDefault();
},
}];
},
}).register('boardChangeColorPopup');
BlazeComponent.extendComponent({
onCreated() {
this.currentBoard = Boards.findOne(Session.get('currentBoard'));
},
allowsSubtasks() {
return this.currentBoard.allowsSubtasks;
},
isBoardSelected() {
return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
},
isNullBoardSelected() {
return (this.currentBoard.subtasksDefaultBoardId === null) || (this.currentBoard.subtasksDefaultBoardId === undefined);
},
boards() {
return Boards.find({
archived: false,
'members.userId': Meteor.userId(),
}, {
sort: ['title'],
});
},
lists() {
return Lists.find({
boardId: this.currentBoard._id,
archived: false,
}, {
sort: ['title'],
});
},
hasLists() {
return this.lists().count() > 0;
},
isListSelected() {
return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
},
presentParentTask() {
let result = this.currentBoard.presentParentTask;
if ((result === null) || (result === undefined)) {
result = 'no-parent';
}
return result;
},
events() {
return [{
'click .js-field-has-subtasks'(evt) {
evt.preventDefault();
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
$('.js-field-has-subtasks .materialCheckBox').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
$('.js-field-has-subtasks').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
$('.js-field-deposit-board').prop('disabled', !this.currentBoard.allowsSubtasks);
},
'change .js-field-deposit-board'(evt) {
let value = evt.target.value;
if (value === 'null') {
value = null;
}
this.currentBoard.setSubtasksDefaultBoardId(value);
evt.preventDefault();
},
'change .js-field-deposit-list'(evt) {
this.currentBoard.setSubtasksDefaultListId(evt.target.value);
evt.preventDefault();
},
'click .js-field-show-parent-in-minicard'(evt) {
const value = evt.target.id || $(evt.target).parent()[0].id || $(evt.target).parent()[0].parent()[0].id;
const options = [
'prefix-with-full-path',
'prefix-with-parent',
'subtext-with-full-path',
'subtext-with-parent',
'no-parent'];
options.forEach(function(element) {
if (element !== value) {
$(`#${element} .materialCheckBox`).toggleClass('is-checked', false);
$(`#${element}`).toggleClass('is-checked', false);
}
});
$(`#${value} .materialCheckBox`).toggleClass('is-checked', true);
$(`#${value}`).toggleClass('is-checked', true);
this.currentBoard.setPresentParentTask(value);
evt.preventDefault();
},
}];
},
}).register('boardSubtaskSettingsPopup');
const CreateBoard = BlazeComponent.extendComponent({
template() {
return 'createBoard';
@@ -304,16 +191,11 @@ const CreateBoard = BlazeComponent.extendComponent({
'click .js-import': Popup.open('boardImportBoard'),
submit: this.onSubmit,
'click .js-import-board': Popup.open('chooseBoardSource'),
'click .js-board-template': Popup.open('searchElement'),
}];
},
}).register('createBoardPopup');
BlazeComponent.extendComponent({
template() {
return 'chooseBoardSource';
},
}).register('chooseBoardSourcePopup');
(class HeaderBarCreateBoard extends CreateBoard {
onSubmit(evt) {
super.onSubmit(evt);
@@ -363,50 +245,3 @@ BlazeComponent.extendComponent({
}];
},
}).register('boardChangeWatchPopup');
BlazeComponent.extendComponent({
integrations() {
const boardId = Session.get('currentBoard');
return Integrations.find({ boardId: `${boardId}` }).fetch();
},
integration(id) {
const boardId = Session.get('currentBoard');
return Integrations.findOne({ _id: id, boardId: `${boardId}` });
},
events() {
return [{
'submit'(evt) {
evt.preventDefault();
const url = evt.target.url.value;
const boardId = Session.get('currentBoard');
let id = null;
let integration = null;
if (evt.target.id) {
id = evt.target.id.value;
integration = this.integration(id);
if (url) {
Integrations.update(integration._id, {
$set: {
url: `${url}`,
},
});
} else {
Integrations.remove(integration._id);
}
} else if (url) {
Integrations.insert({
userId: Meteor.userId(),
enabled: true,
type: 'outgoing-webhooks',
url: `${url}`,
boardId: `${boardId}`,
activities: ['all'],
});
}
Popup.close();
},
}];
},
}).register('outgoingWebhooksPopup');
+15 -4
View File
@@ -18,17 +18,25 @@ template(name="boardList")
else
a.js-open-board.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
span.details
span.board-list-item-name= title
span.board-list-item-name
+viewer
= title
i.fa.js-star-board(
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
title="{{_ 'star-board-title'}}")
p.board-list-item-desc
+viewer
= description
if hasSpentTimeCards
i.fa.js-has-spenttime-cards(
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
p.board-list-item-desc= description
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
template(name="boardListHeaderBar")
h1 {{_ 'my-boards'}}
@@ -36,3 +44,6 @@ template(name="boardListHeaderBar")
a.board-header-btn.js-open-archived-board
i.fa.fa-archive
span {{_ 'archives'}}
a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
i.fa.fa-clone
span {{_ 'templates'}}
+39 -6
View File
@@ -1,5 +1,20 @@
const subManager = new SubsManager();
Template.boardListHeaderBar.events({
'click .js-open-archived-board'() {
Modal.open('archivedBoards');
},
});
Template.boardListHeaderBar.helpers({
templatesBoardId() {
return Meteor.user().getTemplatesBoardId();
},
templatesBoardSlug() {
return Meteor.user().getTemplatesBoardSlug();
},
});
BlazeComponent.extendComponent({
onCreated() {
Meteor.subscribe('setting');
@@ -9,23 +24,21 @@ BlazeComponent.extendComponent({
return Boards.find({
archived: false,
'members.userId': Meteor.userId(),
}, {
sort: ['title'],
});
type: 'board',
}, { sort: ['title'] });
},
isStarred() {
const user = Meteor.user();
return user && user.hasStarred(this.currentData()._id);
},
hasOvertimeCards() {
subManager.subscribe('board', this.currentData()._id);
subManager.subscribe('board', this.currentData()._id, false);
return this.currentData().hasOvertimeCards();
},
hasSpentTimeCards() {
subManager.subscribe('board', this.currentData()._id);
subManager.subscribe('board', this.currentData()._id, false);
return this.currentData().hasSpentTimeCards();
},
@@ -42,6 +55,26 @@ BlazeComponent.extendComponent({
Meteor.user().toggleBoardStar(boardId);
evt.preventDefault();
},
'click .js-clone-board'(evt) {
Meteor.call('cloneBoard',
this.currentData()._id,
Session.get('fromBoard'),
(err, res) => {
if (err) {
this.setError(err.error);
} else {
Session.set('fromBoard', null);
Utils.goBoardId(res);
}
}
);
evt.preventDefault();
},
'click .js-archive-board'(evt) {
const boardId = this.currentData()._id;
Meteor.call('archiveBoard', boardId);
evt.preventDefault();
},
'click .js-accept-invite'() {
const boardId = this.currentData()._id;
Meteor.user().removeInvite(boardId);
+28
View File
@@ -94,13 +94,41 @@ $spaceBetweenTiles = 16px
.is-star-active
color: white
.fa-clone
position: absolute;
bottom: 0
font-size: 14px
height: 18px
line-height: 18px
opacity: 0
right: 0
padding: 9px 9px
transition-duration: .15s
transition-property: color, font-size, background
.fa-archive
position: absolute;
bottom: 0
font-size: 14px
height: 18px
line-height: 18px
opacity: 0
left: 0
padding: 9px 9px
transition-duration: .15s
transition-property: color, font-size, background
li:hover a
&:hover
.fa-star,
.fa-clone,
.fa-archive,
.fa-star-o
color: white
.fa-star,
.fa-clone,
.fa-archive,
.fa-star-o
color: white
opacity: .75
+8
View File
@@ -0,0 +1,8 @@
template(name="miniboard")
.minicard(
class="minicard-{{colorClass}}")
.minicard-title
.handle
.fa.fa-arrows
+viewer
= title
+2
View File
@@ -62,6 +62,8 @@ Template.cardAttachmentsPopup.events({
file.cardId = card.linkedId;
} else {
file.boardId = card.boardId;
file.swimlaneId = card.swimlaneId;
file.listId = card.listId;
file.cardId = card._id;
}
file.userId = Meteor.userId();
@@ -4,9 +4,10 @@ template(name="cardCustomFieldsPopup")
li.item(class="")
a.name.js-select-field(href="#")
span.full-name
+viewer
= name
if hasCustomField
i.fa.fa-check
i.fa.fa-check
hr
a.quiet-button.full.js-settings
i.fa.fa-cog
@@ -61,9 +62,13 @@ template(name="cardCustomField-dropdown")
select.inline
each items
if($eq data.value this._id)
option(value=_id selected="selected") {{name}}
option(value=_id selected="selected")
+viewer
= name
else
option(value=_id) {{name}}
option(value=_id)
+viewer
= name
.edit-controls.clearfix
button.primary(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
@@ -73,4 +78,4 @@ template(name="cardCustomField-dropdown")
+viewer
= selectedItem
else
| {{_ 'edit'}}
| {{_ 'edit'}}
+27 -28
View File
@@ -19,16 +19,14 @@ template(name="cardDetails")
a.js-parent-card(href=linkForCard) {{title}}
// else
{{_ 'top-level-card'}}
unless isSandstorm
if isLinkedCard
h3.linked-card-location
+viewer
| {{getBoardTitle}} > {{getTitle}}
if isLinkedCard
h3.linked-card-location
+viewer
| {{getBoardTitle}} > {{getTitle}}
if getArchived
if isLinkedBoard
unless isSandstorm
p.warning {{_ 'board-archived'}}
p.warning {{_ 'board-archived'}}
else
p.warning {{_ 'card-archived'}}
@@ -79,7 +77,9 @@ template(name="cardDetails")
h3.card-details-item-title {{_ 'labels'}}
a(class="{{#if canModifyCard}}js-add-labels{{else}}is-disabled{{/if}}" title="{{_ 'card-labels-title'}}")
each labels
span.card-label(class="card-label-{{color}}" title=name)= name
span.card-label(class="card-label-{{color}}" title=name)
+viewer
= name
if canModifyCard
a.card-label.add-label.js-add-labels(title="{{_ 'card-labels-title'}}")
i.fa.fa-plus
@@ -88,7 +88,8 @@ template(name="cardDetails")
each customFieldsWD
.card-details-item.card-details-item-customfield
h3.card-details-item-title
= definition.name
+viewer
= definition.name
+cardCustomField
.card-details-items
@@ -192,29 +193,27 @@ template(name="cardDetails")
unless currentUser.isNoComments
if isLoaded.get
if isLinkedCard
unless isSandstorm
+activities(card=this mode="linkedcard")
+activities(card=this mode="linkedcard")
else if isLinkedBoard
unless isSandstorm
+activities(card=this mode="linkedboard")
+activities(card=this mode="linkedboard")
else
+activities(card=this mode="card")
template(name="editCardTitleForm")
textarea.js-edit-card-title(rows='1' autofocus)
textarea.js-edit-card-title(rows='1' autofocus dir="auto")
= getTitle
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-title-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
template(name="editCardRequesterForm")
input.js-edit-card-requester(type='text' autofocus value=getRequestedBy)
input.js-edit-card-requester(type='text' autofocus value=getRequestedBy dir="auto")
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-requester-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
template(name="editCardAssignerForm")
input.js-edit-card-assigner(type='text' autofocus value=getAssignedBy)
input.js-edit-card-assigner(type='text' autofocus value=getAssignedBy dir="auto")
.edit-controls.clearfix
button.primary.confirm.js-submit-edit-card-assigner-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
@@ -225,14 +224,14 @@ template(name="cardDetailsActionsPopup")
if canModifyCard
hr
ul.pop-over-list
li: a.js-members {{_ 'card-edit-members'}}
li: a.js-labels {{_ 'card-edit-labels'}}
li: a.js-attachments {{_ 'card-edit-attachments'}}
//li: a.js-members {{_ 'card-edit-members'}}
//li: a.js-labels {{_ 'card-edit-labels'}}
//li: a.js-attachments {{_ 'card-edit-attachments'}}
li: a.js-custom-fields {{_ 'card-edit-custom-fields'}}
li: a.js-received-date {{_ 'editCardReceivedDatePopup-title'}}
li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
li: a.js-end-date {{_ 'editCardEndDatePopup-title'}}
//li: a.js-received-date {{_ 'editCardReceivedDatePopup-title'}}
//li: a.js-start-date {{_ 'editCardStartDatePopup-title'}}
//li: a.js-due-date {{_ 'editCardDueDatePopup-title'}}
//li: a.js-end-date {{_ 'editCardEndDatePopup-title'}}
li: a.js-spent-time {{_ 'editCardSpentTimePopup-title'}}
li: a.js-set-card-color {{_ 'setCardColorPopup-title'}}
hr
@@ -310,27 +309,27 @@ template(name="cardMorePopup")
h2 {{_ 'change-card-parent'}}
label {{_ 'source-board'}}:
select.js-field-parent-board
if isTopLevel
option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
else
option(value="none") {{_ 'custom-field-dropdown-none'}}
each boards
if isParentBoard
option(value="{{_id}}" selected) {{title}}
else
option(value="{{_id}}") {{title}}
if isTopLevel
option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
else
option(value="none") {{_ 'custom-field-dropdown-none'}}
label {{_ 'parent-card'}}:
select.js-field-parent-card
if isTopLevel
option(value="none" selected) {{_ 'custom-field-dropdown-none'}}
else
option(value="none") {{_ 'custom-field-dropdown-none'}}
each cards
if isParentCard
option(value="{{_id}}" selected) {{title}}
else
option(value="{{_id}}") {{title}}
option(value="none") {{_ 'custom-field-dropdown-none'}}
br
| {{_ 'added'}}
span.date(title=card.createdAt) {{ moment createdAt 'LLL' }}
+41 -86
View File
@@ -345,12 +345,12 @@ Template.cardDetailsActionsPopup.events({
'click .js-move-card-to-top' (evt) {
evt.preventDefault();
const minOrder = _.min(this.list().cards(this.swimlaneId).map((c) => c.sort));
this.move(this.swimlaneId, this.listId, minOrder - 1);
this.move(this.boardId, this.swimlaneId, this.listId, minOrder - 1);
},
'click .js-move-card-to-bottom' (evt) {
evt.preventDefault();
const maxOrder = _.max(this.list().cards(this.swimlaneId).map((c) => c.sort));
this.move(this.swimlaneId, this.listId, maxOrder + 1);
this.move(this.boardId, this.swimlaneId, this.listId, maxOrder + 1);
},
'click .js-archive' (evt) {
evt.preventDefault();
@@ -412,17 +412,19 @@ Template.moveCardPopup.events({
// XXX We should *not* get the currentCard from the global state, but
// instead from a “component” state.
const card = Cards.findOne(Session.get('currentCard'));
const bSelect = $('.js-select-boards')[0];
const boardId = bSelect.options[bSelect.selectedIndex].value;
const lSelect = $('.js-select-lists')[0];
const newListId = lSelect.options[lSelect.selectedIndex].value;
const listId = lSelect.options[lSelect.selectedIndex].value;
const slSelect = $('.js-select-swimlanes')[0];
card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
card.move(card.swimlaneId, newListId, 0);
const swimlaneId = slSelect.options[slSelect.selectedIndex].value;
card.move(boardId, swimlaneId, listId, 0);
Popup.close();
},
});
BlazeComponent.extendComponent({
onCreated() {
subManager.subscribe('board', Session.get('currentBoard'));
subManager.subscribe('board', Session.get('currentBoard'), false);
this.selectedBoardId = new ReactiveVar(Session.get('currentBoard'));
},
@@ -430,6 +432,7 @@ BlazeComponent.extendComponent({
const boards = Boards.find({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Meteor.user().getTemplatesBoardId()},
}, {
sort: ['title'],
});
@@ -450,38 +453,21 @@ BlazeComponent.extendComponent({
return [{
'change .js-select-boards'(evt) {
this.selectedBoardId.set($(evt.currentTarget).val());
subManager.subscribe('board', this.selectedBoardId.get());
subManager.subscribe('board', this.selectedBoardId.get(), false);
},
}];
},
}).register('boardsAndLists');
function cloneCheckList(_id, checklist) {
'use strict';
const checklistId = checklist._id;
checklist.cardId = _id;
checklist._id = null;
const newChecklistId = Checklists.insert(checklist);
ChecklistItems.find({checklistId}).forEach(function(item) {
item._id = null;
item.checklistId = newChecklistId;
item.cardId = _id;
ChecklistItems.insert(item);
});
}
Template.copyCardPopup.events({
'click .js-done'() {
const card = Cards.findOne(Session.get('currentCard'));
const oldId = card._id;
card._id = null;
const lSelect = $('.js-select-lists')[0];
card.listId = lSelect.options[lSelect.selectedIndex].value;
listId = lSelect.options[lSelect.selectedIndex].value;
const slSelect = $('.js-select-swimlanes')[0];
card.swimlaneId = slSelect.options[slSelect.selectedIndex].value;
const swimlaneId = slSelect.options[slSelect.selectedIndex].value;
const bSelect = $('.js-select-boards')[0];
card.boardId = bSelect.options[bSelect.selectedIndex].value;
const boardId = bSelect.options[bSelect.selectedIndex].value;
const textarea = $('#copy-card-title');
const title = textarea.val().trim();
// insert new card to the bottom of new list
@@ -490,38 +476,13 @@ Template.copyCardPopup.events({
if (title) {
card.title = title;
card.coverId = '';
const _id = Cards.insert(card);
const _id = card.copy(boardId, swimlaneId, listId);
// In case the filter is active we need to add the newly inserted card in
// the list of exceptions -- cards that are not filtered. Otherwise the
// card will disappear instantly.
// See https://github.com/wekan/wekan/issues/80
Filter.addException(_id);
// copy checklists
let cursor = Checklists.find({cardId: oldId});
cursor.forEach(function() {
cloneCheckList(_id, arguments[0]);
});
// copy subtasks
cursor = Cards.find({parentId: oldId});
cursor.forEach(function() {
'use strict';
const subtask = arguments[0];
subtask.parentId = _id;
subtask._id = null;
/* const newSubtaskId = */ Cards.insert(subtask);
});
// copy card comments
cursor = CardComments.find({cardId: oldId});
cursor.forEach(function () {
'use strict';
const comment = arguments[0];
comment.cardId = _id;
comment._id = null;
CardComments.insert(comment);
});
Popup.close();
}
},
@@ -558,9 +519,8 @@ Template.copyChecklistToManyCardsPopup.events({
Filter.addException(_id);
// copy checklists
let cursor = Checklists.find({cardId: oldId});
cursor.forEach(function() {
cloneCheckList(_id, arguments[0]);
Checklists.find({cardId: oldId}).forEach((ch) => {
ch.copy(_id);
});
// copy subtasks
@@ -574,13 +534,8 @@ Template.copyChecklistToManyCardsPopup.events({
});
// copy card comments
cursor = CardComments.find({cardId: oldId});
cursor.forEach(function () {
'use strict';
const comment = arguments[0];
comment.cardId = _id;
comment._id = null;
CardComments.insert(comment);
CardComments.find({cardId: oldId}).forEach((cmt) => {
cmt.copy(_id);
});
}
Popup.close();
@@ -625,11 +580,14 @@ BlazeComponent.extendComponent({
BlazeComponent.extendComponent({
onCreated() {
this.currentCard = this.currentData();
this.parentBoard = new ReactiveVar(null);
this.parentCard = this.currentCard.parentCard();
if (this.parentCard) {
this.parentBoard = this.parentCard.board();
const list = $('.js-field-parent-card');
list.val(this.parentCard._id);
this.parentBoard.set(this.parentCard.board()._id);
} else {
this.parentBoard = null;
this.parentBoard.set(null);
}
},
@@ -637,6 +595,9 @@ BlazeComponent.extendComponent({
const boards = Boards.find({
archived: false,
'members.userId': Meteor.userId(),
_id: {
$ne: Meteor.user().getTemplatesBoardId(),
},
}, {
sort: ['title'],
});
@@ -644,8 +605,12 @@ BlazeComponent.extendComponent({
},
cards() {
if (this.parentBoard) {
return this.parentBoard.cards();
const currentId = Session.get('currentCard');
if (this.parentBoard.get()) {
return Cards.find({
boardId: this.parentBoard.get(),
_id: {$ne: currentId},
});
} else {
return [];
}
@@ -653,8 +618,8 @@ BlazeComponent.extendComponent({
isParentBoard() {
const board = this.currentData();
if (this.parentBoard) {
return board._id === this.parentBoard;
if (this.parentBoard.get()) {
return board._id === this.parentBoard.get();
}
return false;
},
@@ -668,11 +633,10 @@ BlazeComponent.extendComponent({
},
setParentCardId(cardId) {
if (cardId === 'null') {
cardId = null;
this.parentCard = null;
} else {
if (cardId) {
this.parentCard = Cards.findOne(cardId);
} else {
this.parentCard = null;
}
this.currentCard.setParentId(cardId);
},
@@ -709,23 +673,14 @@ BlazeComponent.extendComponent({
'change .js-field-parent-board'(evt) {
const selection = $(evt.currentTarget).val();
const list = $('.js-field-parent-card');
list.empty();
if (selection === 'none') {
this.parentBoard = null;
list.prop('disabled', true);
this.parentBoard.set(null);
} else {
this.parentBoard = Boards.findOne(selection);
this.parentBoard.cards().forEach(function(card) {
list.append(
$('<option></option>').val(card._id).html(card.title)
);
});
subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.parentBoard.set(selection);
list.prop('disabled', false);
}
list.append(
`<option value='none' selected='selected'>${TAPi18n.__('custom-field-dropdown-none')}</option>`
);
this.setParentCardId('null');
this.setParentCardId(null);
},
'change .js-field-parent-card'(evt) {
const selection = $(evt.currentTarget).val();
+2 -1
View File
@@ -133,7 +133,8 @@ input[type="submit"].attachment-add-link-submit
.card-details-canvas
width: 100%
padding-left: 0px;
.card-details-header
.close-card-details
margin-right: 0px
+1 -1
View File
@@ -56,7 +56,7 @@ template(name="addChecklistItemForm")
a.fa.fa-times-thin.js-close-inlined-form
template(name="editChecklistItemForm")
textarea.js-edit-checklist-item(rows='1' autofocus)
textarea.js-edit-checklist-item(rows='1' autofocus dir="auto")
if $eq type 'item'
= item.title
else
+2 -1
View File
@@ -31,7 +31,8 @@ template(name="cardLabelsPopup")
a.card-label-edit-button.fa.fa-pencil.js-edit-label
span.card-label.card-label-selectable.js-select-label(class="card-label-{{color}}"
class="{{# if isLabelSelected ../_id }}active{{/if}}")
= name
+viewer
= name
if(isLabelSelected ../_id)
i.card-label-selectable-icon.fa.fa-check
if currentUser.isBoardAdmin
+2 -1
View File
@@ -58,7 +58,8 @@ template(name="minicard")
.minicard-custom-field
if definition.showLabelOnMiniCard
.minicard-custom-field-item
= definition.name
+viewer
= definition.name
.minicard-custom-field-item
+viewer
= trueValue
+3 -3
View File
@@ -50,13 +50,13 @@ template(name="subtaskDeleteDialog")
button.toggle-delete-subtask-dialog(type="button") {{_ 'cancel'}}
template(name="addSubtaskItemForm")
textarea.js-add-subtask-item(rows='1' autofocus)
textarea.js-add-subtask-item(rows='1' autofocus dir="auto")
.edit-controls.clearfix
button.primary.confirm.js-submit-add-subtask-item-form(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
template(name="editSubtaskItemForm")
textarea.js-edit-subtask-item(rows='1' autofocus)
textarea.js-edit-subtask-item(rows='1' autofocus dir="auto")
if $eq type 'item'
= item.title
else
@@ -76,7 +76,7 @@ template(name="subtasksItems")
else
+subtaskItemDetail(item = item subtasks = subtasks)
if canModifyCard
+inlinedForm(autoclose=false classNames="js-add-subtask-item" subtasks = subtasks)
+inlinedForm(autoclose=false classNames="js-add-subtask-item" subtasks = subtasks dir="auto")
+addSubtaskItemForm
else
a.add-subtask-item.js-open-inlined-form
+9 -3
View File
@@ -67,7 +67,13 @@ BlazeComponent.extendComponent({
const nCards = MultiSelection.isActive() ? MultiSelection.count() : 1;
const sortIndex = calculateIndex(prevCardDom, nextCardDom, nCards);
const listId = Blaze.getData(ui.item.parents('.list').get(0))._id;
const swimlaneId = Blaze.getData(ui.item.parents('.swimlane').get(0))._id;
const currentBoard = Boards.findOne(Session.get('currentBoard'));
let swimlaneId = '';
const boardView = (Meteor.user().profile || {}).boardView;
if (boardView === 'board-view-swimlanes' || currentBoard.isTemplatesBoard())
swimlaneId = Blaze.getData(ui.item.parents('.swimlane').get(0))._id;
else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal') || !boardView)
swimlaneId = currentBoard.getDefaultSwimline()._id;
// Normally the jquery-ui sortable library moves the dragged DOM element
// to its new position, which disrupts Blaze reactive updates mechanism
@@ -80,12 +86,12 @@ BlazeComponent.extendComponent({
if (MultiSelection.isActive()) {
Cards.find(MultiSelection.getMongoSelector()).forEach((card, i) => {
card.move(swimlaneId, listId, sortIndex.base + i * sortIndex.increment);
card.move(currentBoard._id, swimlaneId, listId, sortIndex.base + i * sortIndex.increment);
});
} else {
const cardDomElement = ui.item.get(0);
const card = Blaze.getData(cardDomElement);
card.move(swimlaneId, listId, sortIndex.base);
card.move(currentBoard._id, swimlaneId, listId, sortIndex.base);
}
boardComponent.setIsDragging(false);
},
+26 -3
View File
@@ -84,6 +84,7 @@
padding-left: 10px
color: #a6a6a6
.list-header-menu
position: absolute
padding: 27px 19px
@@ -98,6 +99,10 @@
.highlight
color: #ce1414
.cardCount
color: #8c8c8c
font-size: 0.8em
.list-body
flex: 1 1 auto
flex-direction: column
@@ -155,9 +160,12 @@
float: left
@media screen and (max-width: 800px)
.list-header-menu
margin-right: 30px
.mini-list
flex: 0 0 60px
height: 60px
height: auto
width: 100%
border-left: 0px
border-bottom: 1px solid darken(white, 20%)
@@ -166,6 +174,8 @@
display: block
width: 100%
border-left: 0px
&:first-child
margin-left: 0px
&.ui-sortable-helper
flex: 0 0 60px
@@ -184,8 +194,16 @@
border-left: 0px
border-bottom: 1px solid darken(white, 20%)
.list-header
.list-body
padding: 15px 19px;
.list-header
padding: 0 12px 0px
border-bottom: 0px solid #e4e4e4
height: 60px
margin-top: 10px
display: flex
align-items: center
.list-header-left-icon
display: inline
padding: 7px
@@ -197,8 +215,10 @@
.list-header-menu-icon
position: absolute
padding: 7px
top: -@padding
top: 50%
transform: translateY(-50%)
right: 17px
font-size: 20px
.link-board-wrapper
display: flex
@@ -211,6 +231,9 @@
max-height: 250px
overflow: hidden
.sk-spinner-list
margin-top: unset !important
list-header-color(background, color...)
border-bottom: 6px solid background
+63 -28
View File
@@ -4,7 +4,7 @@ template(name="listBody")
if cards.count
+inlinedForm(autoclose=false position="top")
+addCardForm(listId=_id position="top")
each (cards (idOrNull ../../_id))
each (cardsWithLimit (idOrNull ../../_id))
a.minicard-wrapper.js-minicard(href=absoluteUrl
class="{{#if cardIsSelected}}is-selected{{/if}}"
class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}")
@@ -12,6 +12,9 @@ template(name="listBody")
.materialCheckBox.multi-selection-checkbox.js-toggle-multi-selection(
class="{{#if MultiSelection.isSelected _id}}is-checked{{/if}}")
+minicard(this)
if (showSpinner (idOrNull ../../_id))
+spinnerList
if canSeeAddCard
+inlinedForm(autoclose=false position="bottom")
+addCardForm(listId=_id position="bottom")
@@ -20,13 +23,23 @@ template(name="listBody")
i.fa.fa-plus
| {{_ 'add-card'}}
template(name="spinnerList")
.sk-spinner.sk-spinner-wave.sk-spinner-list(
class=currentBoard.colorClass
id="showMoreResults")
.sk-rect1
.sk-rect2
.sk-rect3
.sk-rect4
.sk-rect5
template(name="addCardForm")
.minicard.minicard-composer.js-composer
if getLabels
.minicard-labels
each getLabels
.minicard-label(class="card-label-{{color}}" title="{{name}}")
textarea.minicard-composer-textarea.js-card-title(autofocus)
textarea.minicard-composer-textarea.js-card-title(autofocus dir="auto")
if members.get
.minicard-members.js-minicard-composer-members
each members.get
@@ -34,14 +47,19 @@ template(name="addCardForm")
.add-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
unless isSandstorm
span.quiet
| {{_ 'or'}}
a.js-link {{_ 'link'}}
span.quiet
| &nbsp;
| /
a.js-search {{_ 'search'}}
unless currentBoard.isTemplatesBoard
unless currentBoard.isTemplateBoard
span.quiet
| {{_ 'or'}}
a.js-link {{_ 'link'}}
span.quiet
| &nbsp;
| /
a.js-search {{_ 'search'}}
span.quiet
| &nbsp;
| /
a.js-card-template {{_ 'template'}}
template(name="autocompleteLabelLine")
.minicard-label(class="card-label-{{colorName}}" title=labelName)
@@ -51,11 +69,9 @@ template(name="linkCardPopup")
label {{_ 'boards'}}:
.link-board-wrapper
select.js-select-boards
option(value="")
each boards
if $eq _id currentBoard._id
option(value="{{_id}}" selected) {{_ 'current'}}
else
option(value="{{_id}}") {{title}}
option(value="{{_id}}") {{title}}
input.primary.confirm.js-link-board(type="button" value="{{_ 'link'}}")
label {{_ 'swimlanes'}}:
@@ -74,22 +90,41 @@ template(name="linkCardPopup")
option(value="{{getId}}") {{getTitle}}
.edit-controls.clearfix
unless isSandstorm
input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
input.primary.confirm.js-done(type="button" value="{{_ 'link'}}")
template(name="searchCardPopup")
label {{_ 'boards'}}:
.link-board-wrapper
select.js-select-boards
each boards
if $eq _id currentBoard._id
option(value="{{_id}}" selected) {{_ 'current'}}
else
template(name="searchElementPopup")
form
label
| {{_ 'title'}}
input.js-element-title(type="text" placeholder="{{_ 'title'}}" autofocus required dir="auto")
unless isTemplateSearch
label {{_ 'boards'}}:
.link-board-wrapper
select.js-select-boards
option(value="")
each boards
option(value="{{_id}}") {{title}}
form.js-search-term-form
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
.list-body.js-perfect-scrollbar.search-card-results
.minicards.clearfix.js-minicards
each results
a.minicard-wrapper.js-minicard
+minicard(this)
if isBoardTemplateSearch
each results
a.minicard-wrapper.js-minicard
+miniboard(this)
if isListTemplateSearch
each results
a.minicard-wrapper.js-minicard
+minilist(this)
if isSwimlaneTemplateSearch
each results
a.minicard-wrapper.js-minicard
+miniswimlane(this)
if isCardTemplateSearch
each results
a.minicard-wrapper.js-minicard
+minicard(this)
unless isTemplateSearch
each results
a.minicard-wrapper.js-minicard
+minicard(this)
+227 -71
View File
@@ -1,6 +1,12 @@
const subManager = new SubsManager();
const InfiniteScrollIter = 10;
BlazeComponent.extendComponent({
onCreated() {
// for infinite scrolling
this.cardlimit = new ReactiveVar(InfiniteScrollIter);
},
mixins() {
return [Mixins.PerfectScrollbar];
},
@@ -39,27 +45,56 @@ BlazeComponent.extendComponent({
const labelIds = formComponent.labels.get();
const customFields = formComponent.customFields.get();
const boardId = this.data().board();
const board = this.data().board();
let linkedId = '';
let swimlaneId = '';
const boardView = Meteor.user().profile.boardView;
if (boardView === 'board-view-swimlanes')
swimlaneId = this.parentComponent().parentComponent().data()._id;
else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal'))
swimlaneId = boardId.getDefaultSwimline()._id;
const boardView = (Meteor.user().profile || {}).boardView;
let cardType = 'cardType-card';
if (title) {
if (board.isTemplatesBoard()) {
swimlaneId = this.parentComponent().parentComponent().data()._id; // Always swimlanes view
const swimlane = Swimlanes.findOne(swimlaneId);
// If this is the card templates swimlane, insert a card template
if (swimlane.isCardTemplatesSwimlane())
cardType = 'template-card';
// If this is the board templates swimlane, insert a board template and a linked card
else if (swimlane.isBoardTemplatesSwimlane()) {
linkedId = Boards.insert({
title,
permission: 'private',
type: 'template-board',
});
Swimlanes.insert({
title: TAPi18n.__('default'),
boardId: linkedId,
});
cardType = 'cardType-linkedBoard';
}
} else if (boardView === 'board-view-swimlanes')
swimlaneId = this.parentComponent().parentComponent().data()._id;
else if ((boardView === 'board-view-lists') || (boardView === 'board-view-cal') || !boardView)
swimlaneId = board.getDefaultSwimline()._id;
const _id = Cards.insert({
title,
members,
labelIds,
customFields,
listId: this.data()._id,
boardId: boardId._id,
boardId: board._id,
sort: sortIndex,
swimlaneId,
type: 'cardType-card',
type: cardType,
linkedId,
});
// if the displayed card count is less than the total cards in the list,
// we need to increment the displayed card count to prevent the spinner
// to appear
const cardCount = this.data().cards(this.idOrNull(swimlaneId)).count();
if (this.cardlimit.get() < cardCount) {
this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
}
// In case the filter is active we need to add the newly inserted card in
// the list of exceptions -- cards that are not filtered. Otherwise the
@@ -92,9 +127,9 @@ BlazeComponent.extendComponent({
const methodName = evt.shiftKey ? 'toggleRange' : 'toggle';
MultiSelection[methodName](this.currentData()._id);
// If the card is already selected, we want to de-select it.
// XXX We should probably modify the minicard href attribute instead of
// overwriting the event in case the card is already selected.
// If the card is already selected, we want to de-select it.
// XXX We should probably modify the minicard href attribute instead of
// overwriting the event in case the card is already selected.
} else if (Session.equals('currentCard', this.currentData()._id)) {
evt.stopImmediatePropagation();
evt.preventDefault();
@@ -114,11 +149,31 @@ BlazeComponent.extendComponent({
idOrNull(swimlaneId) {
const currentUser = Meteor.user();
if (currentUser.profile.boardView === 'board-view-swimlanes')
if ((currentUser.profile || {}).boardView === 'board-view-swimlanes' ||
this.data().board().isTemplatesBoard())
return swimlaneId;
return undefined;
},
cardsWithLimit(swimlaneId) {
const limit = this.cardlimit.get();
const selector = {
listId: this.currentData()._id,
archived: false,
};
if (swimlaneId)
selector.swimlaneId = swimlaneId;
return Cards.find(Filter.mongoSelector(selector), {
sort: ['sort'],
limit,
});
},
showSpinner(swimlaneId) {
const list = Template.currentData();
return list.cards(swimlaneId).count() > this.cardlimit.get();
},
canSeeAddCard() {
return !this.reachedWipLimit() && Meteor.user() && Meteor.user().isBoardMember() && !Meteor.user().isCommentOnly();
},
@@ -179,7 +234,7 @@ BlazeComponent.extendComponent({
pressKey(evt) {
// Pressing Enter should submit the card
if (evt.keyCode === 13) {
if (evt.keyCode === 13 && !evt.shiftKey) {
evt.preventDefault();
const $form = $(evt.currentTarget).closest('form');
// XXX For some reason $form.submit() does not work (it's probably a bug
@@ -188,8 +243,8 @@ BlazeComponent.extendComponent({
// work.
$form.find('button[type=submit]').click();
// Pressing Tab should open the form of the next column, and Maj+Tab go
// in the reverse order
// Pressing Tab should open the form of the next column, and Maj+Tab go
// in the reverse order
} else if (evt.keyCode === 9) {
evt.preventDefault();
const isReverse = evt.shiftKey;
@@ -211,7 +266,8 @@ BlazeComponent.extendComponent({
return [{
keydown: this.pressKey,
'click .js-link': Popup.open('linkCard'),
'click .js-search': Popup.open('searchCard'),
'click .js-search': Popup.open('searchElement'),
'click .js-card-template': Popup.open('searchElement'),
}];
},
@@ -249,7 +305,7 @@ BlazeComponent.extendComponent({
const currentBoard = Boards.findOne(Session.get('currentBoard'));
callback($.map(currentBoard.labels, (label) => {
if (label.name.indexOf(term) > -1 ||
label.color.indexOf(term) > -1) {
label.color.indexOf(term) > -1) {
return label;
}
return null;
@@ -286,23 +342,13 @@ BlazeComponent.extendComponent({
BlazeComponent.extendComponent({
onCreated() {
// Prefetch first non-current board id
const boardId = Boards.findOne({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
}, {
sort: ['title'],
})._id;
// Subscribe to this board
subManager.subscribe('board', boardId);
this.selectedBoardId = new ReactiveVar(boardId);
this.selectedBoardId = new ReactiveVar('');
this.selectedSwimlaneId = new ReactiveVar('');
this.selectedListId = new ReactiveVar('');
this.boardId = Session.get('currentBoard');
// In order to get current board info
subManager.subscribe('board', this.boardId);
subManager.subscribe('board', this.boardId, false);
this.board = Boards.findOne(this.boardId);
// List where to insert card
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
@@ -310,10 +356,10 @@ BlazeComponent.extendComponent({
// Swimlane where to insert card
const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
this.swimlaneId = '';
const boardView = Meteor.user().profile.boardView;
const boardView = (Meteor.user().profile || {}).boardView;
if (boardView === 'board-view-swimlanes')
this.swimlaneId = Blaze.getData(swimlane[0])._id;
else if (boardView === 'board-view-lists')
else if (boardView === 'board-view-lists' || !boardView)
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
},
@@ -322,6 +368,7 @@ BlazeComponent.extendComponent({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
type: 'board',
}, {
sort: ['title'],
});
@@ -329,7 +376,7 @@ BlazeComponent.extendComponent({
},
swimlanes() {
if (!this.selectedBoardId) {
if (!this.selectedBoardId.get()) {
return [];
}
const swimlanes = Swimlanes.find({boardId: this.selectedBoardId.get()});
@@ -339,7 +386,7 @@ BlazeComponent.extendComponent({
},
lists() {
if (!this.selectedBoardId) {
if (!this.selectedBoardId.get()) {
return [];
}
const lists = Lists.find({boardId: this.selectedBoardId.get()});
@@ -360,13 +407,14 @@ BlazeComponent.extendComponent({
archived: false,
linkedId: {$nin: ownCardsIds},
_id: {$nin: ownCardsIds},
type: {$nin: ['template-card']},
});
},
events() {
return [{
'change .js-select-boards'(evt) {
subManager.subscribe('board', $(evt.currentTarget).val());
subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.selectedBoardId.set($(evt.currentTarget).val());
},
'change .js-select-swimlanes'(evt) {
@@ -427,35 +475,49 @@ BlazeComponent.extendComponent({
},
onCreated() {
// Prefetch first non-current board id
let board = Boards.findOne({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
});
this.isCardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-card-template');
this.isListTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-list-template');
this.isSwimlaneTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-open-add-swimlane-menu');
this.isBoardTemplateSearch = $(Popup._getTopStack().openerElement).hasClass('js-add-board');
this.isTemplateSearch = this.isCardTemplateSearch ||
this.isListTemplateSearch ||
this.isSwimlaneTemplateSearch ||
this.isBoardTemplateSearch;
let board = {};
if (this.isTemplateSearch) {
board = Boards.findOne((Meteor.user().profile || {}).templatesBoardId);
} else {
// Prefetch first non-current board id
board = Boards.findOne({
archived: false,
'members.userId': Meteor.userId(),
_id: {$nin: [Session.get('currentBoard'), (Meteor.user().profile || {}).templatesBoardId]},
});
}
if (!board) {
Popup.close();
return;
}
const boardId = board._id;
// Subscribe to this board
subManager.subscribe('board', boardId);
subManager.subscribe('board', boardId, false);
this.selectedBoardId = new ReactiveVar(boardId);
this.boardId = Session.get('currentBoard');
// In order to get current board info
subManager.subscribe('board', this.boardId);
board = Boards.findOne(this.boardId);
// List where to insert card
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
this.listId = Blaze.getData(list[0])._id;
// Swimlane where to insert card
const swimlane = $(Popup._getTopStack().openerElement).closest('.js-swimlane');
this.swimlaneId = '';
if (board.view === 'board-view-swimlanes')
this.swimlaneId = Blaze.getData(swimlane[0])._id;
else
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
if (!this.isBoardTemplateSearch) {
this.boardId = Session.get('currentBoard');
// In order to get current board info
subManager.subscribe('board', this.boardId, false);
this.swimlaneId = '';
// Swimlane where to insert card
const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
if ((Meteor.user().profile || {}).boardView === 'board-view-swimlanes')
this.swimlaneId = Blaze.getData(swimlane[0])._id;
else
this.swimlaneId = Swimlanes.findOne({boardId: this.boardId})._id;
// List where to insert card
const list = $(Popup._getTopStack().openerElement).closest('.js-list');
this.listId = Blaze.getData(list[0])._id;
}
this.term = new ReactiveVar('');
},
@@ -464,6 +526,7 @@ BlazeComponent.extendComponent({
archived: false,
'members.userId': Meteor.userId(),
_id: {$ne: Session.get('currentBoard')},
type: 'board',
}, {
sort: ['title'],
});
@@ -475,13 +538,27 @@ BlazeComponent.extendComponent({
return [];
}
const board = Boards.findOne(this.selectedBoardId.get());
return board.searchCards(this.term.get(), false);
if (!this.isTemplateSearch || this.isCardTemplateSearch) {
return board.searchCards(this.term.get(), false);
} else if (this.isListTemplateSearch) {
return board.searchLists(this.term.get());
} else if (this.isSwimlaneTemplateSearch) {
return board.searchSwimlanes(this.term.get());
} else if (this.isBoardTemplateSearch) {
const boards = board.searchBoards(this.term.get());
boards.forEach((board) => {
subManager.subscribe('board', board.linkedId, false);
});
return boards;
} else {
return [];
}
},
events() {
return [{
'change .js-select-boards'(evt) {
subManager.subscribe('board', $(evt.currentTarget).val());
subManager.subscribe('board', $(evt.currentTarget).val(), false);
this.selectedBoardId.set($(evt.currentTarget).val());
},
'submit .js-search-term-form'(evt) {
@@ -489,20 +566,99 @@ BlazeComponent.extendComponent({
this.term.set(evt.target.searchTerm.value);
},
'click .js-minicard'(evt) {
// LINK CARD
const card = Blaze.getData(evt.currentTarget);
const _id = Cards.insert({
title: card.title, //dummy
listId: this.listId,
swimlaneId: this.swimlaneId,
boardId: this.boardId,
sort: Lists.findOne(this.listId).cards().count(),
type: 'cardType-linkedCard',
linkedId: card.linkedId || card._id,
});
Filter.addException(_id);
// 0. Common
const title = $('.js-element-title').val().trim();
if (!title)
return;
const element = Blaze.getData(evt.currentTarget);
element.title = title;
let _id = '';
if (!this.isTemplateSearch || this.isCardTemplateSearch) {
// Card insertion
// 1. Common
element.sort = Lists.findOne(this.listId).cards().count();
// 1.A From template
if (this.isTemplateSearch) {
element.type = 'cardType-card';
element.linkedId = '';
_id = element.copy(this.boardId, this.swimlaneId, this.listId);
// 1.B Linked card
} else {
delete element._id;
element.type = 'cardType-linkedCard';
element.linkedId = element.linkedId || element._id;
_id = Cards.insert(element);
}
Filter.addException(_id);
// List insertion
} else if (this.isListTemplateSearch) {
element.sort = Swimlanes.findOne(this.swimlaneId).lists().count();
element.type = 'list';
_id = element.copy(this.boardId, this.swimlaneId);
} else if (this.isSwimlaneTemplateSearch) {
element.sort = Boards.findOne(this.boardId).swimlanes().count();
element.type = 'swimlalne';
_id = element.copy(this.boardId);
} else if (this.isBoardTemplateSearch) {
board = Boards.findOne(element.linkedId);
board.sort = Boards.find({archived: false}).count();
board.type = 'board';
board.title = element.title;
delete board.slug;
_id = board.copy();
}
Popup.close();
},
}];
},
}).register('searchCardPopup');
}).register('searchElementPopup');
BlazeComponent.extendComponent({
onCreated() {
this.cardlimit = this.parentComponent().cardlimit;
this.listId = this.parentComponent().data()._id;
this.swimlaneId = '';
const boardView = (Meteor.user().profile || {}).boardView;
if (boardView === 'board-view-swimlanes')
this.swimlaneId = this.parentComponent().parentComponent().parentComponent().data()._id;
},
onRendered() {
this.spinner = this.find('.sk-spinner-list');
this.container = this.$(this.spinner).parents('.js-perfect-scrollbar')[0];
$(this.container).on(`scroll.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
$(window).on(`resize.spinner_${this.swimlaneId}_${this.listId}`, () => this.updateList());
this.updateList();
},
onDestroyed() {
$(this.container).off(`scroll.spinner_${this.swimlaneId}_${this.listId}`);
$(window).off(`resize.spinner_${this.swimlaneId}_${this.listId}`);
},
updateList() {
if (this.spinnerInView()) {
this.cardlimit.set(this.cardlimit.get() + InfiniteScrollIter);
window.requestIdleCallback(() => this.updateList());
}
},
spinnerInView() {
const parentViewHeight = this.container.clientHeight;
const bottomViewPosition = this.container.scrollTop + parentViewHeight;
const threshold = this.spinner.offsetTop;
// spinner deleted
if (!this.spinner.offsetTop) {
return false;
}
return bottomViewPosition > threshold;
},
}).register('spinnerList');
+3 -2
View File
@@ -10,7 +10,8 @@ template(name="listHeader")
a.list-header-left-icon.fa.fa-angle-left.js-unselect-list
h2.list-header-name(
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
= title
+viewer
= title
if wipLimit.enabled
|&nbsp;(
span(class="{{#if reachedWipLimit}}highlight{{/if}}") {{cards.count}}
@@ -18,7 +19,7 @@ template(name="listHeader")
if showCardsCountForList cards.count
|&nbsp;
p.quiet.small {{cardsCount}} {{_ 'cards-count'}}
span(class="cardCount") {{cardsCount}} {{_ 'cards-count'}}
if isMiniScreen
if currentList
if isWatching
+1 -1
View File
@@ -30,7 +30,7 @@ BlazeComponent.extendComponent({
cardsCount() {
const list = Template.currentData();
let swimlaneId = '';
const boardView = Meteor.user().profile.boardView;
const boardView = (Meteor.user().profile || {}).boardView;
if (boardView === 'board-view-swimlanes')
swimlaneId = this.parentComponent().parentComponent().data()._id;
+8
View File
@@ -0,0 +1,8 @@
template(name="minilist")
.minicard(
class="minicard-{{colorClass}}")
.minicard-title
.handle
.fa.fa-arrows
+viewer
= title
+2 -1
View File
@@ -1,5 +1,6 @@
template(name="editor")
textarea.editor(
dir="auto"
class="{{class}}"
id=id
autofocus=autofocus
@@ -7,7 +8,7 @@ template(name="editor")
+Template.contentBlock
template(name="viewer")
.viewer
.viewer(dir="auto")
+mentions
+markdown
{{> UI.contentBlock }}
+3 -1
View File
@@ -36,7 +36,10 @@ import sanitizeXss from 'xss';
const at = HTML.CharRef({html: '&commat;', str: '@'});
Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
const view = this;
let content = Blaze.toHTML(view.templateContentBlock);
const currentBoard = Boards.findOne(Session.get('currentBoard'));
if (!currentBoard)
return HTML.Raw(sanitizeXss(content));
const knowedUsers = currentBoard.members.map((member) => {
const u = Users.findOne(member.userId);
if(u){
@@ -45,7 +48,6 @@ Blaze.Template.registerHelper('mentions', new Template('mentions', function() {
return member;
});
const mentionRegex = /\B@([\w.]*)/gi;
let content = Blaze.toHTML(view.templateContentBlock);
let currentMention;
while ((currentMention = mentionRegex.exec(content)) !== null) {
+33 -37
View File
@@ -4,39 +4,38 @@ template(name="header")
list all starred boards with a link to go there. This is inspired by the
Reddit "subreddit" bar.
The first link goes to the boards page.
unless isSandstorm
if currentUser
#header-quick-access(class=currentBoard.colorClass)
if isMiniScreen
ul
li
a(href="{{pathFor 'home'}}")
span.fa.fa-home
if currentUser
#header-quick-access(class=currentBoard.colorClass)
if isMiniScreen
ul
li
a(href="{{pathFor 'home'}}")
span.fa.fa-home
if currentList
each currentBoard.lists
li(class="{{#if $.Session.equals 'currentList' _id}}current{{/if}}")
a.js-select-list
= title
#header-new-board-icon
else
ul
li
a(href="{{pathFor 'home'}}")
span.fa.fa-home
| {{_ 'all-boards'}}
each currentUser.starredBoards
li.separator -
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
a(href="{{pathFor 'board' id=_id slug=slug}}")
if currentList
each currentBoard.lists
li(class="{{#if $.Session.equals 'currentList' _id}}current{{/if}}")
a.js-select-list
= title
else
li.current {{_ 'quick-access-description'}}
#header-new-board-icon
else
ul
li
a(href="{{pathFor 'home'}}")
span.fa.fa-home
| {{_ 'all-boards'}}
each currentUser.starredBoards
li.separator -
li(class="{{#if $.Session.equals 'currentBoard' _id}}current{{/if}}")
a(href="{{pathFor 'board' id=_id slug=slug}}")
= title
else
li.current {{_ 'quick-access-description'}}
a#header-new-board-icon.js-create-board
i.fa.fa-plus(title="Create a new board")
a#header-new-board-icon.js-create-board
i.fa.fa-plus(title="Create a new board")
+headerUserBar
+headerUserBar
#header(class=currentBoard.colorClass)
//-
@@ -46,19 +45,16 @@ template(name="header")
#header-main-bar(class="{{#if wrappedHeader}}wrapper{{/if}}")
+Template.dynamic(template=headerBar)
unless hideLogo
//unless hideLogo
//-
On sandstorm, the logo shouldn't be clickable, because we only have one
page/document on it, and we don't want to see the home page containing
the list of all boards.
if isSandstorm
.wekan-logo
img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
else
unless currentSetting.hideLogo
a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
img(src="{{pathFor '/wekan-logo-header.png'}}" alt="Wekan")
// unless currentSetting.hideLogo
// a.wekan-logo(href="{{pathFor 'home'}}" title="{{_ 'header-logo-title'}}")
// img(src="{{pathFor '/logo-header.png'}}" alt="")
if appIsOffline
+offlineWarning
+30 -26
View File
@@ -1,39 +1,32 @@
head
title Wekan
meta(name="viewport"
content="maximum-scale=1.0,width=device-width,initial-scale=1.0,user-scalable=0")
title
meta(name="viewport" content="maximum-scale=1.0,width=device-width,initial-scale=1.0,user-scalable=0")
meta(http-equiv="X-UA-Compatible" content="IE=edge")
//- XXX We should use pathFor in the following `href` to support the case
where the application is deployed with a path prefix, but it seems to be
difficult to do that cleanly with Blaze -- at least without adding extra
packages.
link(rel="shortcut icon" href="/public/wekan-favicon.png")
link(rel="apple-touch-icon" href="/public/wekan-favicon.png")
link(rel="mask-icon" href="/public/wekan-150.svg")
link(rel="manifest" href="/public/wekan-manifest.json")
link(rel="shortcut icon" href="/wekan-favicon.png")
link(rel="apple-touch-icon" href="/wekan-favicon.png")
link(rel="mask-icon" href="/wekan-logo-150.svg")
link(rel="manifest" href="/wekan-manifest.json")
template(name="userFormsLayout")
section.auth-layout
unless currentSetting.hideLogo
h1.at-form-landing-logo
img(src="{{pathFor '/wekan-logo.png'}}" alt="Wekan")
if currentSetting.hideLogo
h1
br
br
section.auth-dialog
+Template.dynamic(template=content)
+connectionMethod
if isCas
.at-form
button#cas(class='at-btn submit' type='submit') {{casSignInLabel}}
div.at-form-lang
select.select-lang.js-userform-set-language
each languages
if isCurrentLanguage
option(value="{{tag}}" selected="selected") {{name}}
else
option(value="{{tag}}") {{name}}
if isLoading
+loader
else
+Template.dynamic(template=content)
if currentSetting.displayAuthenticationMethod
+connectionMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod)
div.at-form-lang
select.select-lang.js-userform-set-language
each languages
if isCurrentLanguage
option(value="{{tag}}" selected="selected") {{name}}
else
option(value="{{tag}}") {{name}}
template(name="defaultLayout")
+header
@@ -66,3 +59,14 @@ template(name="message")
unless currentUser
with(pathFor route='atSignIn')
p {{{_ 'page-maybe-private' this}}}
template(name="loader")
h1.loadingText {{_ 'loading'}}
.lds-roller
div
div
div
div
div
div
div
+84 -59
View File
@@ -20,13 +20,20 @@ const validator = {
},
};
Template.userFormsLayout.onCreated(() => {
Meteor.subscribe('setting');
Template.userFormsLayout.onCreated(function() {
const instance = this;
instance.currentSetting = new ReactiveVar();
instance.isLoading = new ReactiveVar(false);
Meteor.subscribe('setting', {
onReady() {
instance.currentSetting.set(Settings.findOne());
return this.stop();
},
});
});
Template.userFormsLayout.onRendered(() => {
AccountsTemplates.state.form.keys = new Proxy(AccountsTemplates.state.form.keys, validator);
const i18nTag = navigator.language;
@@ -37,11 +44,13 @@ Template.userFormsLayout.onRendered(() => {
});
Template.userFormsLayout.helpers({
currentSetting() {
return Settings.findOne();
return Template.instance().currentSetting.get();
},
isLoading() {
return Template.instance().isLoading.get();
},
afterBodyStart() {
return currentSetting.customHTMLafterBodyStart;
@@ -59,6 +68,8 @@ Template.userFormsLayout.helpers({
name = 'Brezhoneg';
} else if (lang.name === 'ig') {
name = 'Igbo';
} else if (lang.name === 'oc') {
name = 'Occitan';
}
return { tag, name };
}).sort(function(a, b) {
@@ -75,17 +86,6 @@ Template.userFormsLayout.helpers({
const curLang = T9n.getLanguage() || 'en';
return t9nTag === curLang;
},
/*
isCas() {
return Meteor.settings.public &&
Meteor.settings.public.cas &&
Meteor.settings.public.cas.loginUrl;
},
casSignInLabel() {
return TAPi18n.__('casSignIn', {}, T9n.getLanguage() || 'en');
},
*/
});
Template.userFormsLayout.events({
@@ -94,49 +94,13 @@ Template.userFormsLayout.events({
T9n.setLanguage(i18nTagToT9n(i18nTag));
evt.preventDefault();
},
'click button#cas'() {
Meteor.loginWithCas(function() {
if (FlowRouter.getRouteName() === 'atSignIn') {
FlowRouter.go('/');
}
});
},
'click #at-btn'(event) {
/* All authentication method can be managed/called here.
!! DON'T FORGET to correctly fill the fields of the user during its creation if necessary authenticationMethod : String !!
*/
const authenticationMethodSelected = $('.select-authentication').val();
// Local account
if (authenticationMethodSelected === 'password') {
return;
}
// Stop submit #at-pwd-form
event.preventDefault();
event.stopImmediatePropagation();
const email = $('#at-field-username_and_email').val();
const password = $('#at-field-password').val();
// Ldap account
if (authenticationMethodSelected === 'ldap') {
// Check if the user can use the ldap connection
Meteor.subscribe('user-authenticationMethod', email, {
onReady() {
const user = Users.findOne();
if (user === undefined || user.authenticationMethod === 'ldap') {
// Use the ldap connection package
Meteor.loginWithLDAP(email, password, function(error) {
if (!error) {
// Connection
return FlowRouter.go('/');
}
return error;
});
}
return this.stop();
},
});
'click #at-btn'(event, instance) {
if (FlowRouter.getRouteName() === 'atSignIn') {
instance.isLoading.set(true);
authentication(event, instance)
.then(() => {
instance.isLoading.set(false);
});
}
},
});
@@ -146,3 +110,64 @@ Template.defaultLayout.events({
Modal.close();
},
});
async function authentication(event, instance) {
const match = $('#at-field-username_and_email').val();
const password = $('#at-field-password').val();
if (!match || !password) return undefined;
const result = await getAuthenticationMethod(instance.currentSetting.get(), match);
if (result === 'password') return undefined;
// Stop submit #at-pwd-form
event.preventDefault();
event.stopImmediatePropagation();
switch (result) {
case 'ldap':
return new Promise((resolve) => {
Meteor.loginWithLDAP(match, password, function() {
resolve(FlowRouter.go('/'));
});
});
case 'cas':
return new Promise((resolve) => {
Meteor.loginWithCas(match, password, function() {
resolve(FlowRouter.go('/'));
});
});
default:
return undefined;
}
}
function getAuthenticationMethod({displayAuthenticationMethod, defaultAuthenticationMethod}, match) {
if (displayAuthenticationMethod) {
return $('.select-authentication').val();
}
return getUserAuthenticationMethod(defaultAuthenticationMethod, match);
}
function getUserAuthenticationMethod(defaultAuthenticationMethod, match) {
return new Promise((resolve) => {
try {
Meteor.subscribe('user-authenticationMethod', match, {
onReady() {
const user = Users.findOne();
const authenticationMethod = user
? user.authenticationMethod
: defaultAuthenticationMethod;
resolve(authenticationMethod);
},
});
} catch(error) {
resolve(defaultAuthenticationMethod);
}
});
}
+102 -2
View File
@@ -61,7 +61,7 @@ body
display: block
float: right
font-size: 24px
.modal-content-wide
width: 800px
min-height: 0px
@@ -290,7 +290,7 @@ kbd
// Implement a thiner close icon as suggested in
// https://github.com/FortAwesome/Font-Awesome/issues/1540#issuecomment-68689950
.fa.fa-times-thin:before
content: '\00d7';
content: '\00d7'
.fa.fa-globe.colorful, .fa.fa-bell.colorful
color: #4caf50
@@ -399,3 +399,103 @@ a
height: 37px
margin: 8px 10px 0 0
width: 50px
.select-authentication
width: 100%
.auth-layout
display: flex
flex-direction: column
align-items: center
justify-content: center
height: 100%
.auth-dialog
margin: 0 !important
.loadingText
text-align: center
.lds-roller
display: block
margin: auto
position: relative
width: 64px
height: 64px
div
animation: lds-roller 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite
transform-origin: 32px 32px
div:after
content: " "
display: block
position: absolute
width: 6px
height: 6px
border-radius: 50%
background: #dedede
margin: -3px 0 0 -3px
div:nth-child(1)
animation-delay: -0.036s
div:nth-child(1):after
top: 50px
left: 50px
div:nth-child(2)
animation-delay: -0.072s
div:nth-child(2):after
top: 54px
left: 45px
div:nth-child(3)
animation-delay: -0.108s
div:nth-child(3):after
top: 57px
left: 39px
div:nth-child(4)
animation-delay: -0.144s
div:nth-child(4):after
top: 58px
left: 32px
div:nth-child(5)
animation-delay: -0.18s
div:nth-child(5):after
top: 57px
left: 25px
div:nth-child(6)
animation-delay: -0.216s
div:nth-child(6):after
top: 54px
left: 19px
div:nth-child(7)
animation-delay: -0.252s
div:nth-child(7):after
top: 50px
left: 14px
div:nth-child(8)
animation-delay: -0.288s
div:nth-child(8):after
top: 45px
left: 10px
@keyframes lds-roller
0%
transform: rotate(0deg)
100%
transform: rotate(360deg)
@@ -1,11 +1,44 @@
template(name="cardActions")
div.trigger-item
div.trigger-content
div.trigger-dropdown
select(id="setdate-action")
option(value="setDate") {{{_'r-set'}}}
option(value="updateDate") {{{_'r-update'}}}
div.trigger-text
| {{{_'r-datefield'}}}
div.trigger-dropdown
select(id="setdate-datefield")
option(value="startAt") {{{_'r-df-start-at'}}}
option(value="dueAt") {{{_'r-df-due-at'}}}
option(value="endAt") {{{_'r-df-end-at'}}}
option(value="receivedAt") {{{_'r-df-received-at'}}}
div.trigger-text
| {{{_'r-to-current-datetime'}}}
div.trigger-button.js-set-date-action.js-goto-rules
i.fa.fa-plus
div.trigger-item
div.trigger-content
div.trigger-text
| {{{_'r-remove-value-from'}}}
| {{{_'r-datefield'}}}
div.trigger-dropdown
select(id="setdate-removedatefieldvalue")
option(value="startAt") {{{_'r-df-start-at'}}}
option(value="dueAt") {{{_'r-df-due-at'}}}
option(value="endAt") {{{_'r-df-end-at'}}}
option(value="receivedAt") {{{_'r-df-received-at'}}}
div.trigger-button.js-remove-datevalue-action.js-goto-rules
i.fa.fa-plus
div.trigger-item
div.trigger-content
div.trigger-dropdown
select(id="label-action")
option(value="add") {{{_'r-add'}}}
option(value="remove") {{{_'r-remove'}}}
div.trigger-text
div.trigger-text
| {{{_'r-label'}}}
div.trigger-dropdown
select(id="label-id")
@@ -21,16 +54,16 @@ template(name="cardActions")
select(id="member-action")
option(value="add") {{{_'r-add'}}}
option(value="remove") {{{_'r-remove'}}}
div.trigger-text
div.trigger-text
| {{{_'r-member'}}}
div.trigger-dropdown
input(id="member-name",type=text,placeholder="{{{_'r-name'}}}")
input(id="member-name",type=text,placeholder="{{{_'r-name'}}}")
div.trigger-button.js-add-member-action.js-goto-rules
i.fa.fa-plus
div.trigger-item
div.trigger-content
div.trigger-text
div.trigger-text
| {{{_'r-remove-all'}}}
div.trigger-button.js-add-removeall-action.js-goto-rules
i.fa.fa-plus
@@ -29,6 +29,54 @@ BlazeComponent.extendComponent({
events() {
return [{
'click .js-set-date-action' (event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const triggerId = Triggers.insert(trigger);
const actionSelected = this.find('#setdate-action').value;
const dateFieldSelected = this.find('#setdate-datefield').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
const actionId = Actions.insert({
actionType: actionSelected,
dateField: dateFieldSelected,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
desc,
});
},
'click .js-remove-datevalue-action' (event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
const triggerId = Triggers.insert(trigger);
const dateFieldSelected = this.find('#setdate-removedatefieldvalue').value;
const boardId = Session.get('currentBoard');
const desc = Utils.getTriggerActionDesc(event, this);
const actionId = Actions.insert({
actionType: 'removeDate',
dateField: dateFieldSelected,
boardId,
desc,
});
Rules.insert({
title: ruleName,
triggerId,
actionId,
boardId,
desc,
});
},
'click .js-add-label-action' (event) {
const ruleName = this.data().ruleName.get();
const trigger = this.data().triggerVar.get();
+11 -1
View File
@@ -17,6 +17,10 @@ template(name="rulesList")
button.js-delete-rule
i.fa.fa-trash-o
| {{{_ 'r-delete-rule'}}}
else if currentUser.isBoardAdmin
button.js-delete-rule
i.fa.fa-trash-o
| {{{_ 'r-delete-rule'}}}
else
li.no-items-message {{{_ 'r-no-rules' }}}
if currentUser.isAdmin
@@ -24,4 +28,10 @@ template(name="rulesList")
button.js-goto-trigger
i.fa.fa-plus
| {{{_ 'r-add-rule'}}}
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
else if currentUser.isBoardAdmin
div.rules-add
button.js-goto-trigger
i.fa.fa-plus
| {{{_ 'r-add-rule'}}}
input(type=text,placeholder="{{{_ 'r-new-rule-name' }}}",id="ruleTitle")
@@ -64,8 +64,7 @@ template(name="boardTriggers")
div.trigger-text
| {{_'r-in-swimlane'}}
div.trigger-dropdown
input(id="create-swimlane-name",type=text,placeholder="{{_'r-swimlane-name'}}")
div.trigger-button.trigger-button-person.js-show-user-field
input(id="create-swimlane-name-2",type=text,placeholder="{{_'r-swimlane-name'}}")
div.trigger-button.trigger-button-person.js-show-user-field
i.fa.fa-user
div.user-details.hide-element
@@ -39,15 +39,18 @@ BlazeComponent.extendComponent({
'click .js-add-moved-trigger' (event) {
const datas = this.data();
const desc = Utils.getTriggerActionDesc(event, this);
const swimlaneName = this.find('#create-swimlane-name').value;
const swimlaneName = this.find('#create-swimlane-name-2').value;
const actionSelected = this.find('#move-action').value;
const listName = this.find('#move-list-name').value;
const boardId = Session.get('currentBoard');
const divId = $(event.currentTarget.parentNode).attr('id');
const cardTitle = this.cardTitleFilters[divId];
if (actionSelected === 'moved-to') {
datas.triggerVar.set({
activityType: 'moveCard',
boardId,
listName,
cardTitle,
swimlaneName,
'oldListName': '*',
desc,
@@ -57,6 +60,7 @@ BlazeComponent.extendComponent({
datas.triggerVar.set({
activityType: 'moveCard',
boardId,
cardTitle,
swimlaneName,
'listName': '*',
'oldListName': listName,
@@ -22,7 +22,7 @@ template(name="cardTriggers")
div.trigger-item
div.trigger-content
div.trigger-text
| {{_'r-when-the-label-is'}}
| {{_'r-when-the-label'}}
div.trigger-dropdown
select(id="spec-label")
each labels
@@ -2,5 +2,8 @@ template(name='connectionMethod')
div.at-form-authentication
label {{_ 'authentication-method'}}
select.select-authentication
each authentications
option(value="{{value}}") {{_ value}}
each authentications
if isSelected value
option(value="{{value}}" selected) {{_ value}}
else
option(value="{{value}}") {{_ value}}
@@ -31,4 +31,7 @@ Template.connectionMethod.helpers({
authentications() {
return Template.instance().authenticationMethods.get();
},
isSelected(match) {
return Template.instance().data.authenticationMethod === match;
},
});
+11 -3
View File
@@ -3,8 +3,13 @@ template(name="people")
unless currentUser.isAdmin
| {{_ 'error-notAuthorized'}}
else
.content-title
span {{_ 'people'}}
.content-title.ext-box
.ext-box-left
span {{_ 'people'}}
input#searchInput(placeholder="{{_ 'search'}}")
button#searchButton {{_ 'search'}}
.ext-box-right
span {{_ 'people-number'}} #{peopleNumber}
.content-body
.side-menu
ul
@@ -102,5 +107,8 @@ template(name="editUserPopup")
label
| {{_ 'password'}}
input.js-profile-password(type="password")
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
div
input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
input.primary.wide(type="submit" value="{{_ 'save'}}")
+44 -1
View File
@@ -8,6 +8,8 @@ BlazeComponent.extendComponent({
this.error = new ReactiveVar('');
this.loading = new ReactiveVar(false);
this.people = new ReactiveVar(true);
this.findUsersOptions = new ReactiveVar({});
this.number = new ReactiveVar(0);
this.page = new ReactiveVar(1);
this.loadNextPageLocked = false;
@@ -26,6 +28,33 @@ BlazeComponent.extendComponent({
});
});
},
events() {
return [{
'click #searchButton'() {
this.filterPeople();
},
'keydown #searchInput'(event) {
if (event.keyCode === 13 && !event.shiftKey) {
this.filterPeople();
}
},
}];
},
filterPeople() {
const value = $('#searchInput').first().val();
if (value === '') {
this.findUsersOptions.set({});
} else {
const regex = new RegExp(value, 'i');
this.findUsersOptions.set({
$or: [
{ username: regex },
{ 'profile.fullname': regex },
{ 'emails.address': regex },
],
});
}
},
loadNextPage() {
if (this.loadNextPageLocked === false) {
this.page.set(this.page.get() + 1);
@@ -49,9 +78,14 @@ BlazeComponent.extendComponent({
this.loading.set(w);
},
peopleList() {
return Users.find({}, {
const users = Users.find(this.findUsersOptions.get(), {
fields: {_id: true},
});
this.number.set(users.count());
return users;
},
peopleNumber() {
return this.number.get();
},
}).register('people');
@@ -64,6 +98,7 @@ Template.peopleRow.helpers({
Template.editUserPopup.onCreated(function() {
this.authenticationMethods = new ReactiveVar([]);
this.errorMessage = new ReactiveVar('');
Meteor.call('getAuthenticationsEnabled', (_, result) => {
if (result) {
@@ -95,6 +130,9 @@ Template.editUserPopup.helpers({
const selected = Users.findOne(userId).authenticationMethod;
return selected === 'ldap';
},
errorMessage() {
return Template.instance().errorMessage.get();
},
});
BlazeComponent.extendComponent({
@@ -186,4 +224,9 @@ Template.editUserPopup.events({
});
} else Popup.close();
},
'click #deleteButton'() {
Users.remove(this.userId);
Popup.close();
},
});
@@ -13,3 +13,36 @@ table
tr:nth-child(even)
background-color: #dddddd;
.ext-box
display: flex;
flex-direction: row;
height: 34px;
.ext-box-left
display: flex;
width: 40%
span
vertical-align: center;
line-height: 34px;
margin-right: 10px;
input, button
margin: 0 10px 0 0;
padding: 0;
button
min-width: 60px;
.content-wrapper
margin-top: 10px
.buttonsContainer
display: flex
input
margin: 0
div
margin: auto
+21 -2
View File
@@ -134,17 +134,27 @@ template(name='announcementSettings')
template(name='layoutSettings')
ul#layout-setting.setting-detail
li.layout-form
//li.layout-form
.title {{_ 'hide-logo'}}
.form-group.flex
input.form-control#hide-logo(type="radio" name="hideLogo" value="true" checked="{{#if currentSetting.hideLogo}}checked{{/if}}")
span {{_ 'yes'}}
input.form-control#hide-logo(type="radio" name="hideLogo" value="false" checked="{{#unless currentSetting.hideLogo}}checked{{/unless}}")
span {{_ 'no'}}
li.layout-form
.title {{_ 'display-authentication-method'}}
.form-group.flex
input.form-control#display-authentication-method(type="radio" name="displayAuthenticationMethod" value="true" checked="{{#if currentSetting.displayAuthenticationMethod}}checked{{/if}}")
span {{_ 'yes'}}
input.form-control#display-authentication-method(type="radio" name="displayAuthenticationMethod" value="false" checked="{{#unless currentSetting.displayAuthenticationMethod}}checked{{/unless}}")
span {{_ 'no'}}
li.layout-form
.title {{_ 'default-authentication-method'}}
+selectAuthenticationMethod(authenticationMethod=currentSetting.defaultAuthenticationMethod)
li.layout-form
.title {{_ 'custom-product-name'}}
.form-group
input.form-control#product-name(type="text", placeholder="Wekan" value="{{currentSetting.productName}}")
input.form-control#product-name(type="text", placeholder="" value="{{currentSetting.productName}}")
li.layout-form
.title {{_ 'add-custom-html-after-body-start'}}
textarea#customHTMLafterBodyStart.form-control= currentSetting.customHTMLafterBodyStart
@@ -153,3 +163,12 @@ template(name='layoutSettings')
textarea#customHTMLbeforeBodyEnd.form-control= currentSetting.customHTMLbeforeBodyEnd
li
button.js-save-layout.primary {{_ 'save'}}
template(name='selectAuthenticationMethod')
select#defaultAuthenticationMethod
each authentications
if isSelected value
option(value="{{value}}" selected) {{_ value}}
else
option(value="{{value}}") {{_ value}}
+36 -6
View File
@@ -62,6 +62,9 @@ BlazeComponent.extendComponent({
toggleHideLogo() {
$('#hide-logo').toggleClass('is-checked');
},
toggleDisplayAuthenticationMethod() {
$('#display-authentication-method').toggleClass('is-checked');
},
switchMenu(event) {
const target = $(event.target);
if (!target.hasClass('active')) {
@@ -87,7 +90,7 @@ BlazeComponent.extendComponent({
},
inviteThroughEmail() {
const emails = $('#email-to-invite').val().trim().split('\n').join(',').split(',');
const emails = $('#email-to-invite').val().toLowerCase().trim().split('\n').join(',').split(',');
const boardsToInvite = [];
$('.js-toggle-board-choose .materialCheckBox.is-checked').each(function () {
boardsToInvite.push($(this).data('id'));
@@ -140,17 +143,20 @@ BlazeComponent.extendComponent({
const productName = $('#product-name').val().trim();
const hideLogoChange = ($('input[name=hideLogo]:checked').val() === 'true');
const displayAuthenticationMethod = ($('input[name=displayAuthenticationMethod]:checked').val() === 'true');
const defaultAuthenticationMethod = $('#defaultAuthenticationMethod').val();
const customHTMLafterBodyStart = $('#customHTMLafterBodyStart').val().trim();
const customHTMLbeforeBodyEnd = $('#customHTMLbeforeBodyEnd').val().trim();
try {
Settings.update(Settings.findOne()._id, {
$set: {
productName,
hideLogo: hideLogoChange,
customHTMLafterBodyStart,
customHTMLbeforeBodyEnd,
displayAuthenticationMethod,
defaultAuthenticationMethod,
},
});
} catch (e) {
@@ -165,17 +171,14 @@ BlazeComponent.extendComponent({
sendSMTPTestEmail() {
Meteor.call('sendSMTPTestEmail', (err, ret) => {
if (!err && ret) { /* eslint-disable no-console */
if (!err && ret) {
const message = `${TAPi18n.__(ret.message)}: ${ret.email}`;
console.log(message);
alert(message);
} else {
const reason = err.reason || '';
const message = `${TAPi18n.__(err.error)}\n${reason}`;
console.log(message, err);
alert(message);
}
/* eslint-enable no-console */
});
},
@@ -190,6 +193,7 @@ BlazeComponent.extendComponent({
'click button.js-send-smtp-test-email': this.sendSMTPTestEmail,
'click a.js-toggle-hide-logo': this.toggleHideLogo,
'click button.js-save-layout': this.saveLayout,
'click a.js-toggle-display-authentication-method': this.toggleDisplayAuthenticationMethod,
}];
},
}).register('setting');
@@ -262,3 +266,29 @@ BlazeComponent.extendComponent({
}];
},
}).register('announcementSettings');
Template.selectAuthenticationMethod.onCreated(function() {
this.authenticationMethods = new ReactiveVar([]);
Meteor.call('getAuthenticationsEnabled', (_, result) => {
if (result) {
// TODO : add a management of different languages
// (ex {value: ldap, text: TAPi18n.__('ldap', {}, T9n.getLanguage() || 'en')})
this.authenticationMethods.set([
{value: 'password'},
// Gets only the authentication methods availables
...Object.entries(result).filter((e) => e[1]).map((e) => ({value: e[0]})),
]);
}
});
});
Template.selectAuthenticationMethod.helpers({
authentications() {
return Template.instance().authenticationMethods.get();
},
isSelected(match) {
return Template.instance().data.authenticationMethod === match;
},
});
@@ -52,6 +52,10 @@
.main-body
padding: 0.1em 1em
-webkit-user-select: auto // Safari 3.1+
-moz-user-select: auto // Firefox 2+
-ms-user-select: auto // IE 10+
user-select: auto // Standard syntax
ul
li
+15 -16
View File
@@ -4,22 +4,21 @@ template(name="settingHeaderBar")
.setting-header-btns.left
unless isMiniScreen
unless isSandstorm
if currentUser
a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
i.fa(class="fa-cog")
span {{_ 'settings'}}
if currentUser
a.setting-header-btn.settings(href="{{pathFor 'setting'}}")
i.fa(class="fa-cog")
span {{_ 'settings'}}
a.setting-header-btn.people(href="{{pathFor 'people'}}")
i.fa(class="fa-users")
span {{_ 'people'}}
a.setting-header-btn.people(href="{{pathFor 'people'}}")
i.fa(class="fa-users")
span {{_ 'people'}}
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
i.fa(class="fa-info-circle")
span {{_ 'info'}}
a.setting-header-btn.informations(href="{{pathFor 'information'}}")
i.fa(class="fa-info-circle")
span {{_ 'info'}}
else
a.setting-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
else
a.setting-header-btn.js-log-in(
title="{{_ 'log-in'}}")
i.fa.fa-sign-in
span {{_ 'log-in'}}
+145 -17
View File
@@ -1,17 +1,17 @@
template(name="sidebar")
.board-sidebar.sidebar(class="{{#if isOpen}}is-open{{/if}}")
a.sidebar-tongue.js-toggle-sidebar(
class="{{#if isTongueHidden}}is-hidden{{/if}}",
title="{{showTongueTitle}}")
i.fa.fa-angle-left
//a.sidebar-tongue.js-toggle-sidebar(
// class="{{#if isTongueHidden}}is-hidden{{/if}}",
// title="{{showTongueTitle}}")
// i.fa.fa-navicon
.sidebar-shadow
.sidebar-content.sidebar-shortcuts
a.board-header-btn.js-shortcuts
i.fa.fa-keyboard-o
span {{_ 'keyboard-shortcuts' }}
.sidebar-content.js-board-sidebar-content.js-perfect-scrollbar
a.hide-btn.js-hide-sidebar
i.fa.fa-angle-right
//a.hide-btn.js-hide-sidebar
// i.fa.fa-navicon
unless isDefaultView
h2
a.fa.fa-chevron-left.js-back-home
@@ -34,6 +34,9 @@ template(name="membersWidget")
h3
i.fa.fa-user
| {{_ 'members'}}
a.board-header-btn.js-open-board-menu(title="{{_ 'boardMenuPopup-title'}}").right
i.board-header-btn-icon.fa.fa-cog
.board-widget-content
each currentBoard.activeMembers
+userAvatar(userId=this.userId showStatus=true)
@@ -53,6 +56,130 @@ template(name="membersWidget")
button.js-member-invite-accept.primary {{_ 'accept'}}
button.js-member-invite-decline {{_ 'decline'}}
template(name="boardChangeColorPopup")
.board-backgrounds-list.clearfix
each backgroundColors
.board-background-select.js-select-background
span.background-box(class="board-color-{{this}}")
if isSelected
i.fa.fa-check
template(name="boardSubtaskSettingsPopup")
form.board-subtask-settings
h3 {{_ 'show-parent-in-minicard'}}
a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
span {{_ 'prefix-with-full-path'}}
a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
span {{_ 'prefix-with-parent'}}
a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
span {{_ 'subtext-with-full-path'}}
a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
span {{_ 'subtext-with-parent'}}
a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
span {{_ 'no-parent'}}
div
hr
div.check-div
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
span {{_ 'show-subtasks-field'}}
label
| {{_ 'deposit-subtasks-board'}}
select.js-field-deposit-board(disabled="{{#unless allowsSubtasks}}disabled{{/unless}}")
each boards
if isBoardSelected
option(value=_id selected="selected") {{title}}
else
option(value=_id) {{title}}
if isNullBoardSelected
option(value='null' selected="selected") {{_ 'custom-field-dropdown-none'}}
else
option(value='null') {{_ 'custom-field-dropdown-none'}}
div
hr
label
| {{_ 'deposit-subtasks-list'}}
select.js-field-deposit-list(disabled="{{#unless hasLists}}disabled{{/unless}}")
each lists
if isListSelected
option(value=_id selected="selected") {{title}}
else
option(value=_id) {{title}}
template(name="chooseBoardSource")
ul.pop-over-list
li
a(href="{{pathFor '/import/trello'}}") {{_ 'from-trello'}}
li
a(href="{{pathFor '/import/wekan'}}") {{_ 'from-wekan'}}
template(name="archiveBoardPopup")
p {{_ 'close-board-pop'}}
button.js-confirm.negate.full(type="submit") {{_ 'archive'}}
template(name="outgoingWebhooksPopup")
each integrations
form.integration-form
if title
h4 {{title}}
else
h4 {{_ 'no-name'}}
label
| URL
input.js-outgoing-webhooks-url(type="text" name="url" value=url)
input(type="hidden" value=_id name="id")
input.primary.wide(type="submit" value="{{_ 'save'}}")
form.integration-form
h4
| {{_ 'new-outgoing-webhook'}}
label
| URL
input.js-outgoing-webhooks-url(type="text" name="url" autofocus)
input.primary.wide(type="submit" value="{{_ 'save'}}")
template(name="boardMenuPopup")
ul.pop-over-list
li: a.js-custom-fields {{_ 'custom-fields'}}
li: a.js-open-archives {{_ 'archived-items'}}
if currentUser.isBoardAdmin
li: a.js-change-board-color {{_ 'board-change-color'}}
//-
XXX Language should be handled by sandstorm, but for now display a
language selection link in the board menu. This link is normally present
in the header bar that is not displayed on sandstorm.
if isSandstorm
li: a.js-change-language {{_ 'language'}}
unless isSandstorm
if currentUser.isBoardAdmin
hr
ul.pop-over-list
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
unless currentBoard.isTemplatesBoard
li: a.js-archive-board {{_ 'archive-board'}}
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
hr
ul.pop-over-list
li: a.js-subtask-settings {{_ 'subtask-settings'}}
if isSandstorm
hr
ul.pop-over-list
li: a(href="{{exportUrl}}", download="{{exportFilename}}") {{_ 'export-board'}}
li: a.js-import-board {{_ 'import-board-c'}}
li: a.js-archive-board {{_ 'archive-board'}}
li: a.js-outgoing-webhooks {{_ 'outgoing-webhooks'}}
hr
ul.pop-over-list
li: a.js-subtask-settings {{_ 'subtask-settings'}}
template(name="labelsWidget")
.board-widget.board-widget-labels
h3
@@ -62,7 +189,9 @@ template(name="labelsWidget")
each currentBoard.labels
a.card-label(class="card-label-{{color}}"
class="{{#if currentUser.isNotCommentOnly}}js-label{{/if}}")
span.card-label-name= name
span.card-label-name
+viewer
= name
if currentUser.isBoardAdmin
a.card-label.add-label.js-add-label
i.fa.fa-plus
@@ -83,17 +212,16 @@ template(name="memberPopup")
ul.pop-over-list
li
a.js-filter-member {{_ 'filter-cards'}}
unless isSandstorm
if currentUser.isBoardAdmin
li
a.js-change-role
| {{_ 'change-permissions'}}
span.quiet (#{memberType})
if currentUser.isBoardAdmin
li
if $eq currentUser._id userId
a.js-leave-member {{_ 'leave-board'}}
else if currentUser.isBoardAdmin
a.js-remove-member {{_ 'remove-from-board'}}
a.js-change-role
| {{_ 'change-permissions'}}
span.quiet (#{memberType})
li
if $eq currentUser._id userId
a.js-leave-member {{_ 'leave-board'}}
else if currentUser.isBoardAdmin
a.js-remove-member {{_ 'remove-from-board'}}
template(name="removeMemberPopup")
+224
View File
@@ -142,6 +142,52 @@ Template.memberPopup.helpers({
},
});
Template.boardMenuPopup.events({
'click .js-rename-board': Popup.open('boardChangeTitle'),
'click .js-custom-fields'() {
Sidebar.setView('customFields');
Popup.close();
},
'click .js-open-archives'() {
Sidebar.setView('archives');
Popup.close();
},
'click .js-change-board-color': Popup.open('boardChangeColor'),
'click .js-change-language': Popup.open('changeLanguage'),
'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() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
Popup.close();
Boards.remove(currentBoard._id);
FlowRouter.go('home');
}),
'click .js-outgoing-webhooks': Popup.open('outgoingWebhooks'),
'click .js-import-board': Popup.open('chooseBoardSource'),
'click .js-subtask-settings': Popup.open('boardSubtaskSettings'),
});
Template.boardMenuPopup.helpers({
exportUrl() {
const params = {
boardId: Session.get('currentBoard'),
};
const queryParams = {
authToken: Accounts._storedLoginToken(),
};
return FlowRouter.path('/api/boards/:boardId/export', params, queryParams);
},
exportFilename() {
const boardId = Session.get('currentBoard');
return `wekan-export-board-${boardId}.json`;
},
});
Template.memberPopup.events({
'click .js-filter-member'() {
Filter.members.toggle(this.userId);
@@ -190,7 +236,14 @@ Template.membersWidget.helpers({
Template.membersWidget.events({
'click .js-member': Popup.open('member'),
'click .js-open-board-menu': Popup.open('boardMenu'),
'click .js-manage-board-members': Popup.open('addMember'),
'click .js-import': Popup.open('boardImportBoard'),
submit: this.onSubmit,
'click .js-import-board': Popup.open('chooseBoardSource'),
'click .js-open-archived-board'() {
Modal.open('archivedBoards');
},
'click .sandstorm-powerbox-request-identity'() {
window.sandstormRequestIdentity();
},
@@ -209,6 +262,59 @@ Template.membersWidget.events({
},
});
BlazeComponent.extendComponent({
integrations() {
const boardId = Session.get('currentBoard');
return Integrations.find({ boardId: `${boardId}` }).fetch();
},
integration(id) {
const boardId = Session.get('currentBoard');
return Integrations.findOne({ _id: id, boardId: `${boardId}` });
},
events() {
return [{
'submit'(evt) {
evt.preventDefault();
const url = evt.target.url.value;
const boardId = Session.get('currentBoard');
let id = null;
let integration = null;
if (evt.target.id) {
id = evt.target.id.value;
integration = this.integration(id);
if (url) {
Integrations.update(integration._id, {
$set: {
url: `${url}`,
},
});
} else {
Integrations.remove(integration._id);
}
} else if (url) {
Integrations.insert({
userId: Meteor.userId(),
enabled: true,
type: 'outgoing-webhooks',
url: `${url}`,
boardId: `${boardId}`,
activities: ['all'],
});
}
Popup.close();
},
}];
},
}).register('outgoingWebhooksPopup');
BlazeComponent.extendComponent({
template() {
return 'chooseBoardSource';
},
}).register('chooseBoardSourcePopup');
Template.labelsWidget.events({
'click .js-label': Popup.open('editLabel'),
'click .js-add-label': Popup.open('createLabel'),
@@ -258,6 +364,124 @@ function draggableMembersLabelsWidgets() {
Template.membersWidget.onRendered(draggableMembersLabelsWidgets);
Template.labelsWidget.onRendered(draggableMembersLabelsWidgets);
BlazeComponent.extendComponent({
backgroundColors() {
return Boards.simpleSchema()._schema.color.allowedValues;
},
isSelected() {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
return currentBoard.color === this.currentData().toString();
},
events() {
return [{
'click .js-select-background'(evt) {
const currentBoard = Boards.findOne(Session.get('currentBoard'));
const newColor = this.currentData().toString();
currentBoard.setColor(newColor);
evt.preventDefault();
},
}];
},
}).register('boardChangeColorPopup');
BlazeComponent.extendComponent({
onCreated() {
this.currentBoard = Boards.findOne(Session.get('currentBoard'));
},
allowsSubtasks() {
return this.currentBoard.allowsSubtasks;
},
isBoardSelected() {
return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
},
isNullBoardSelected() {
return (this.currentBoard.subtasksDefaultBoardId === null) || (this.currentBoard.subtasksDefaultBoardId === undefined);
},
boards() {
return Boards.find({
archived: false,
'members.userId': Meteor.userId(),
}, {
sort: ['title'],
});
},
lists() {
return Lists.find({
boardId: this.currentBoard._id,
archived: false,
}, {
sort: ['title'],
});
},
hasLists() {
return this.lists().count() > 0;
},
isListSelected() {
return this.currentBoard.subtasksDefaultBoardId === this.currentData()._id;
},
presentParentTask() {
let result = this.currentBoard.presentParentTask;
if ((result === null) || (result === undefined)) {
result = 'no-parent';
}
return result;
},
events() {
return [{
'click .js-field-has-subtasks'(evt) {
evt.preventDefault();
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
$('.js-field-has-subtasks .materialCheckBox').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
$('.js-field-has-subtasks').toggleClass('is-checked', this.currentBoard.allowsSubtasks);
$('.js-field-deposit-board').prop('disabled', !this.currentBoard.allowsSubtasks);
},
'change .js-field-deposit-board'(evt) {
let value = evt.target.value;
if (value === 'null') {
value = null;
}
this.currentBoard.setSubtasksDefaultBoardId(value);
evt.preventDefault();
},
'change .js-field-deposit-list'(evt) {
this.currentBoard.setSubtasksDefaultListId(evt.target.value);
evt.preventDefault();
},
'click .js-field-show-parent-in-minicard'(evt) {
const value = evt.target.id || $(evt.target).parent()[0].id || $(evt.target).parent()[0].parent()[0].id;
const options = [
'prefix-with-full-path',
'prefix-with-parent',
'subtext-with-full-path',
'subtext-with-parent',
'no-parent'];
options.forEach(function(element) {
if (element !== value) {
$(`#${element} .materialCheckBox`).toggleClass('is-checked', false);
$(`#${element}`).toggleClass('is-checked', false);
}
});
$(`#${value} .materialCheckBox`).toggleClass('is-checked', true);
$(`#${value}`).toggleClass('is-checked', true);
this.currentBoard.setPresentParentTask(value);
evt.preventDefault();
},
}];
},
}).register('boardSubtaskSettingsPopup');
BlazeComponent.extendComponent({
onCreated() {
this.error = new ReactiveVar('');
+51 -33
View File
@@ -1,38 +1,56 @@
template(name="archivesSidebar")
+basicTabs(tabs=tabs)
+tabContent(slug="cards")
each archivedCards
.minicard-wrapper.js-minicard
+minicard(this)
if currentUser.isBoardMember
if isArchiveReady.get
+basicTabs(tabs=tabs)
+tabContent(slug="cards")
p.quiet
a.js-restore-card {{_ 'restore'}}
a.js-restore-all-cards {{_ 'restore-all'}}
| -
a.js-delete-card {{_ 'delete'}}
if cardIsInArchivedList
p.quiet.small ({{_ 'warn-list-archived'}})
else
p.no-items-message {{_ 'no-archived-cards'}}
+tabContent(slug="lists")
ul.archived-lists
each archivedLists
li.archived-lists-item
a.js-delete-all-cards {{_ 'delete-all'}}
each archivedCards
.minicard-wrapper.js-minicard
+minicard(this)
if currentUser.isBoardMember
button.js-restore-list
i.fa.fa-undo
= title
else
li.no-items-message {{_ 'no-archived-lists'}}
p.quiet
a.js-restore-card {{_ 'restore'}}
| -
a.js-delete-card {{_ 'delete'}}
if cardIsInArchivedList
p.quiet.small ({{_ 'warn-list-archived'}})
else
p.no-items-message {{_ 'no-archived-cards'}}
+tabContent(slug="swimlanes")
ul.archived-lists
each archivedSwimlanes
li.archived-lists-item
if currentUser.isBoardMember
button.js-restore-swimlane
i.fa.fa-undo
= title
else
li.no-items-message {{_ 'no-archived-swimlanes'}}
+tabContent(slug="lists")
p.quiet
a.js-restore-all-lists {{_ 'restore-all'}}
| -
a.js-delete-all-lists {{_ 'delete-all'}}
ul.archived-lists
each archivedLists
li.archived-lists-item
= title
if currentUser.isBoardMember
p.quiet
a.js-restore-list {{_ 'restore'}}
| -
a.js-delete-list {{_ 'delete'}}
else
li.no-items-message {{_ 'no-archived-lists'}}
+tabContent(slug="swimlanes")
p.quiet
a.js-restore-all-swimlanes {{_ 'restore-all'}}
| -
a.js-delete-all-swimlanes {{_ 'delete-all'}}
ul.archived-lists
each archivedSwimlanes
li.archived-lists-item
= title
if currentUser.isBoardMember
p.quiet
a.js-restore-swimlane {{_ 'restore'}}
| -
a.js-delete-swimlane {{_ 'delete'}}
else
li.no-items-message {{_ 'no-archived-swimlanes'}}
else
+spinner
@@ -1,4 +1,26 @@
const subManager = new SubsManager();
BlazeComponent.extendComponent({
onCreated() {
this.isArchiveReady = new ReactiveVar(false);
// The pattern we use to manually handle data loading is described here:
// https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/using-subs-manager
// XXX The boardId should be readed from some sort the component "props",
// unfortunatly, Blaze doesn't have this notion.
this.autorun(() => {
const currentBoardId = Session.get('currentBoard');
if (!currentBoardId)
return;
const handle = subManager.subscribe('board', currentBoardId, true);
Tracker.nonreactive(() => {
Tracker.autorun(() => {
this.isArchiveReady.set( handle.ready() );
});
});
});
},
tabs() {
return [
{ name: TAPi18n.__('cards'), slug: 'cards' },
@@ -44,19 +66,67 @@ BlazeComponent.extendComponent({
card.restore();
}
},
'click .js-restore-all-cards'() {
this.archivedCards().forEach((card) => {
if(card.canBeRestored()){
card.restore();
}
});
},
'click .js-delete-card': Popup.afterConfirm('cardDelete', function() {
const cardId = this._id;
Cards.remove(cardId);
Popup.close();
}),
'click .js-delete-all-cards': Popup.afterConfirm('cardDelete', () => {
this.archivedCards().forEach((card) => {
Cards.remove(card._id);
});
Popup.close();
}),
'click .js-restore-list'() {
const list = this.currentData();
list.restore();
},
'click .js-restore-all-lists'() {
this.archivedLists().forEach((list) => {
list.restore();
});
},
'click .js-delete-list': Popup.afterConfirm('listDelete', function() {
this.remove();
Popup.close();
}),
'click .js-delete-all-lists': Popup.afterConfirm('listDelete', () => {
this.archivedLists().forEach((list) => {
list.remove();
});
Popup.close();
}),
'click .js-restore-swimlane'() {
const swimlane = this.currentData();
swimlane.restore();
},
'click .js-restore-all-swimlanes'() {
this.archivedSwimlanes().forEach((swimlane) => {
swimlane.restore();
});
},
'click .js-delete-swimlane': Popup.afterConfirm('swimlaneDelete', function() {
this.remove();
Popup.close();
}),
'click .js-delete-all-swimlanes': Popup.afterConfirm('swimlaneDelete', () => {
this.archivedSwimlanes().forEach((swimlane) => {
swimlane.remove();
});
Popup.close();
}),
}];
},
}).register('archivesSidebar');
@@ -6,7 +6,9 @@ template(name="customFieldsSidebar")
div.minicard
a.fa.fa-pencil.js-edit-custom-field.minicard-edit-button
div.minicard-title
| {{ name }} ({{ type }})
+viewer
=name
| ({{ type }})
if currentUser.isBoardMember
hr
@@ -2,7 +2,7 @@ BlazeComponent.extendComponent({
customFields() {
return CustomFields.find({
boardId: Session.get('currentBoard'),
boardIds: {$in: [Session.get('currentBoard')]},
});
},
@@ -103,7 +103,6 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
evt.preventDefault();
const data = {
boardId: Session.get('currentBoard'),
name: this.find('.js-field-name').value.trim(),
type: this.type.get(),
settings: this.getSettings(),
@@ -114,6 +113,7 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
// insert or update
if (!this.data()._id) {
data.boardIds = [Session.get('currentBoard')];
CustomFields.insert(data);
} else {
CustomFields.update(this.data()._id, {$set: data});
@@ -122,8 +122,16 @@ const CreateCustomFieldPopup = BlazeComponent.extendComponent({
Popup.back();
},
'click .js-delete-custom-field': Popup.afterConfirm('deleteCustomField', function() {
const customFieldId = this._id;
CustomFields.remove(customFieldId);
const customField = CustomFields.findOne(this._id);
if (customField.boardIds.length > 1) {
CustomFields.update(customField._id, {
$pull: {
boardIds: Session.get('currentBoard'),
},
});
} else {
CustomFields.remove(customField._id);
}
Popup.close();
}),
}];
@@ -1,6 +1,6 @@
template(name="searchSidebar")
form.js-search-term-form
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus)
input(type="text" name="searchTerm" placeholder="{{_ 'search-example'}}" autofocus dir="auto")
.list-body.js-perfect-scrollbar
.minicards.clearfix.js-minicards
each (results)
@@ -0,0 +1,8 @@
template(name="miniswimlane")
.minicard(
class="minicard-{{colorClass}}")
.minicard-title
.handle
.fa.fa-arrows
+viewer
= title
+28 -12
View File
@@ -1,15 +1,21 @@
template(name="swimlaneHeader")
.swimlane-header-wrap.js-swimlane-header(class='{{#if colorClass}}swimlane-{{colorClass}}{{/if}}')
+inlinedForm
+editSwimlaneTitleForm
if this.isTemplateContainer
+swimlaneFixedHeader(this)
else
.swimlane-header(
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
= title
.swimlane-header-menu
unless currentUser.isCommentOnly
a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon
a.fa.fa-navicon.js-open-swimlane-menu
+inlinedForm
+editSwimlaneTitleForm
else
+swimlaneFixedHeader(this)
template(name="swimlaneFixedHeader")
.swimlane-header(
class="{{#if currentUser.isBoardMember}}js-open-inlined-form is-editable{{/if}}")
= title
.swimlane-header-menu
unless currentUser.isCommentOnly
a.fa.fa-plus.js-open-add-swimlane-menu.swimlane-header-plus-icon
a.fa.fa-navicon.js-open-swimlane-menu
template(name="editSwimlaneTitleForm")
.list-composer
@@ -22,9 +28,10 @@ template(name="swimlaneActionPopup")
unless currentUser.isCommentOnly
ul.pop-over-list
li: a.js-set-swimlane-color {{_ 'select-color'}}
hr
ul.pop-over-list
li: a.js-close-swimlane {{_ 'archive-swimlane'}}
unless this.isTemplateContainer
hr
ul.pop-over-list
li: a.js-close-swimlane {{_ 'archive-swimlane'}}
template(name="swimlaneAddPopup")
unless currentUser.isCommentOnly
@@ -33,6 +40,11 @@ template(name="swimlaneAddPopup")
autocomplete="off" autofocus)
.edit-controls.clearfix
button.primary.confirm(type="submit") {{_ 'add'}}
unless currentBoard.isTemplatesBoard
unless currentBoard.isTemplateBoard
span.quiet
| {{_ 'or'}}
a.js-swimlane-template {{_ 'template'}}
template(name="setSwimlaneColorPopup")
form.edit-label
@@ -42,3 +54,7 @@ template(name="setSwimlaneColorPopup")
i.fa.fa-check
button.primary.confirm.js-submit {{_ 'save'}}
button.js-remove-color.negate.wide.right {{_ 'unset-color'}}
template(name="swimlaneDeletePopup")
p {{_ "swimlane-delete-pop"}}
button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
@@ -47,12 +47,14 @@ BlazeComponent.extendComponent({
const titleInput = this.find('.swimlane-name-input');
const title = titleInput.value.trim();
const sortValue = calculateIndexData(this.currentSwimlane, nextSwimlane, 1);
const swimlaneType = (currentBoard.isTemplatesBoard())?'template-swimlane':'swimlane';
if (title) {
Swimlanes.insert({
title,
boardId: Session.get('currentBoard'),
sort: sortValue.base,
type: swimlaneType,
});
titleInput.value = '';
@@ -63,6 +65,7 @@ BlazeComponent.extendComponent({
// with a minimum of interactions
Popup.close();
},
'click .js-swimlane-template': Popup.open('searchElement'),
}];
},
}).register('swimlaneAddPopup');
+11 -7
View File
@@ -3,15 +3,15 @@ template(name="swimlane")
+swimlaneHeader
.swimlane.js-lists.js-swimlane
if isMiniScreen
if currentList
if currentListIsInThisSwimlane _id
+list(currentList)
else
each currentBoard.lists
unless currentList
each lists
+miniList(this)
if currentUser.isBoardMember
+addListForm
else
each currentBoard.lists
each lists
+list(this)
if currentCardIsInThisList _id ../_id
+cardDetails(currentCard)
@@ -24,12 +24,12 @@ template(name="listsGroup")
if currentList
+list(currentList)
else
each currentBoard.lists
each lists
+miniList(this)
if currentUser.isBoardMember
+addListForm
else
each currentBoard.lists
each lists
+list(this)
if currentCardIsInThisList _id null
+cardDetails(currentCard)
@@ -44,7 +44,11 @@ template(name="addListForm")
autocomplete="off" autofocus)
.edit-controls.clearfix
button.primary.confirm(type="submit") {{_ 'save'}}
a.fa.fa-times-thin.js-close-inlined-form
unless currentBoard.isTemplatesBoard
unless currentBoard.isTemplateBoard
span.quiet
| {{_ 'or'}}
a.js-list-template {{_ 'template'}}
else
a.open-list-composer.js-open-inlined-form
i.fa.fa-plus
+29 -7
View File
@@ -1,16 +1,25 @@
const { calculateIndex, enableClickOnTouch } = Utils;
function currentListIsInThisSwimlane(swimlaneId) {
const currentList = Lists.findOne(Session.get('currentList'));
return currentList && (currentList.swimlaneId === swimlaneId || currentList.swimlaneId === '');
}
function currentCardIsInThisList(listId, swimlaneId) {
const currentCard = Cards.findOne(Session.get('currentCard'));
const currentUser = Meteor.user();
if (currentUser.profile.boardView === 'board-view-lists')
return currentCard && currentCard.listId === listId;
else if (currentUser.profile.boardView === 'board-view-swimlanes')
if (currentUser && currentUser.profile && currentUser.profile.boardView === 'board-view-swimlanes')
return currentCard && currentCard.listId === listId && currentCard.swimlaneId === swimlaneId;
else if (currentUser.profile.boardView === 'board-view-cal')
return currentCard;
else
return false;
else // Default view: board-view-lists
return currentCard && currentCard.listId === listId;
// https://github.com/wekan/wekan/issues/1623
// https://github.com/ChronikEwok/wekan/commit/cad9b20451bb6149bfb527a99b5001873b06c3de
// TODO: In public board, if you would like to switch between List/Swimlane view, you could
// 1) If there is no view cookie, save to cookie board-view-lists
// board-view-lists / board-view-swimlanes / board-view-cal
// 2) If public user changes clicks board-view-lists then change view and
// then change view and save cookie with view value
// without using currentuser above, because currentuser is null.
}
function initSortable(boardComponent, $listsDom) {
@@ -110,6 +119,10 @@ BlazeComponent.extendComponent({
return currentCardIsInThisList(listId, swimlaneId);
},
currentListIsInThisSwimlane(swimlaneId) {
return currentListIsInThisSwimlane(swimlaneId);
},
events() {
return [{
// Click-and-drag action
@@ -149,6 +162,12 @@ BlazeComponent.extendComponent({
}).register('swimlane');
BlazeComponent.extendComponent({
onCreated() {
this.currentBoard = Boards.findOne(Session.get('currentBoard'));
this.isListTemplatesSwimlane = this.currentBoard.isTemplatesBoard() && this.currentData().isListTemplatesSwimlane();
this.currentSwimlane = this.currentData();
},
// Proxy
open() {
this.childComponents('inlinedForm')[0].open();
@@ -165,12 +184,15 @@ BlazeComponent.extendComponent({
title,
boardId: Session.get('currentBoard'),
sort: $('.list').length,
type: (this.isListTemplatesSwimlane)?'template-list':'list',
swimlaneId: (this.currentBoard.isTemplatesBoard())?this.currentSwimlane._id:'',
});
titleInput.value = '';
titleInput.focus();
}
},
'click .js-list-template': Popup.open('searchElement'),
}];
},
}).register('addListForm');
@@ -53,6 +53,9 @@
.list-group
height: 100%
.moving-swimlane
display: none
swimlane-color(background, color...)
background: background !important
if color
+17 -8
View File
@@ -4,10 +4,11 @@ template(name="headerUserBar")
.header-user-bar-avatar
+userAvatar(userId=currentUser._id)
unless isMiniScreen
if currentUser.profile.fullname
= currentUser.profile.fullname
else
= currentUser.username
unless isSandstorm
if currentUser.profile.fullname
= currentUser.profile.fullname
else
= currentUser.username
template(name="memberMenuPopup")
ul.pop-over-list
@@ -15,13 +16,18 @@ template(name="memberMenuPopup")
li: a.js-edit-profile {{_ 'edit-profile'}}
li: a.js-change-settings {{_ 'change-settings'}}
li: a.js-change-avatar {{_ 'edit-avatar'}}
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
unless isSandstorm
li: a.js-change-password {{_ 'changePasswordPopup-title'}}
li: a.js-change-language {{_ 'changeLanguagePopup-title'}}
if currentUser.isAdmin
li: a.js-go-setting(href="{{pathFor 'setting'}}") {{_ 'admin-panel'}}
hr
ul.pop-over-list
li: a.js-logout {{_ 'log-out'}}
li: a(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}") {{_ 'templates'}}
unless isSandstorm
hr
ul.pop-over-list
li: a.js-logout {{_ 'log-out'}}
template(name="editProfilePopup")
form
@@ -47,7 +53,10 @@ template(name="editProfilePopup")
input.js-profile-email(type="email" value="{{emails.[0].address}}")
else
input.js-profile-email(type="email" value="{{emails.[0].address}}" readonly)
input.primary.wide(type="submit" value="{{_ 'save'}}")
div.buttonsContainer
input.primary.wide(type="submit" value="{{_ 'save'}}")
div
input#deleteButton.primary.wide(type="button" value="{{_ 'delete'}}")
template(name="changePasswordPopup")
+atForm(state='changePwd')
+16
View File
@@ -3,6 +3,15 @@ Template.headerUserBar.events({
'click .js-change-avatar': Popup.open('changeAvatar'),
});
Template.memberMenuPopup.helpers({
templatesBoardId() {
return Meteor.user().getTemplatesBoardId();
},
templatesBoardSlug() {
return Meteor.user().getTemplatesBoardSlug();
},
});
Template.memberMenuPopup.events({
'click .js-edit-profile': Popup.open('editProfile'),
'click .js-change-settings': Popup.open('changeSettings'),
@@ -86,6 +95,11 @@ Template.editProfilePopup.events({
});
} else Popup.back();
},
'click #deleteButton'() {
Users.remove(Meteor.userId());
Popup.close();
AccountsTemplates.logout();
},
});
// XXX For some reason the useraccounts autofocus isnt working in this case.
@@ -105,6 +119,8 @@ Template.changeLanguagePopup.helpers({
name = 'Brezhoneg';
} else if (lang.name === 'ig') {
name = 'Igbo';
} else if (lang.name === 'oc') {
name = 'Occitan';
}
return { tag, name };
}).sort(function (a, b) {
+1 -1
View File
@@ -135,6 +135,6 @@ $(document).on('click', (evt) => {
}
});
$(document).on('click', 'a[href=#]', (evt) => {
$(document).on('click', 'a[href=\\#]', (evt) => {
evt.preventDefault();
});
+8 -8
View File
@@ -80,11 +80,11 @@ EscapeActions.register('inlinedForm',
);
// submit on click outside
document.addEventListener('click', function(evt) {
const openedForm = currentlyOpenedForm.get();
const isClickOutside = $(evt.target).closest('.js-inlined-form').length === 0;
if (openedForm && isClickOutside) {
$('.js-inlined-form button[type=submit]').click();
openedForm.close();
}
}, true);
//document.addEventListener('click', function(evt) {
// const openedForm = currentlyOpenedForm.get();
// const isClickOutside = $(evt.target).closest('.js-inlined-form').length === 0;
// if (openedForm && isClickOutside) {
// $('.js-inlined-form button[type=submit]').click();
// openedForm.close();
// }
//}, true);
+1 -1
View File
@@ -184,7 +184,7 @@ window.Popup = new class {
// positives.
const title = TAPi18n.__(translationKey);
// when popup showed as full of small screen, we need a default header to clearly see [X] button
const defaultTitle = Utils.isMiniScreen() ? 'Wekan' : false;
const defaultTitle = Utils.isMiniScreen() ? '' : false;
return title !== translationKey ? title : defaultTitle;
};
}
+191 -142
View File
@@ -90,8 +90,8 @@ services:
wekandb:
#-------------------------------------------------------------------------------------
# ==== MONGODB AND METEOR VERSION ====
# a) CURRENTLY BROKEN: For Wekan Meteor 1.8.x version at meteor-1.8 branch, use mongo 4.x
# image: mongo:4.0.4
# a) For Wekan Meteor 1.8.x version at meteor-1.8 branch, use mongo 4.x
#image: mongo:4.0.4
# b) For Wekan Meteor 1.6.x version at master/devel/edge branches.
# Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
image: mongo:3.2.21
@@ -110,12 +110,12 @@ services:
wekan:
#-------------------------------------------------------------------------------------
# ==== MONGODB AND METEOR VERSION ====
# a) CURRENTLY BROKEN: For Wekan Meteor 1.8.x version at meteor-1.8 branch,
# a) For Wekan Meteor 1.8.x version at meteor-1.8 branch,
# using https://quay.io/wekan/wekan automatic builds
# image: quay.io/wekan/wekan:meteor-1.8
#image: quay.io/wekan/wekan:meteor-1.8
# b) For Wekan Meteor 1.6.x version at master/devel/edge branches.
# Only for Snap and Sandstorm while they are not upgraded yet to Meteor 1.8.x
image: quay.io/wekan/wekan
image: quay.io/wekan/wekan:master
# c) Using specific Meteor 1.6.x version tag:
# image: quay.io/wekan/wekan:v1.95
# c) Using Docker Hub automatic builds https://hub.docker.com/r/wekanteam/wekan
@@ -169,8 +169,9 @@ services:
# For SSL in email, change smtp:// to smtps://
# NOTE: Special characters need to be url-encoded in MAIL_URL.
# You can encode those characters for example at: https://www.urlencoder.org
- MAIL_URL=smtp://user:pass@mailserver.example.com:25/
- MAIL_FROM='Example Wekan Support <support@example.com>'
#- MAIL_URL=smtp://user:pass@mailserver.example.com:25/
- MAIL_URL=smtp://<mail_url>:25/?ignoreTLS=true&tls={rejectUnauthorized:false}
- MAIL_FROM=Wekan Notifications <noreply.wekan@mydomain.com>
#---------------------------------------------------------------
# ==== OPTIONAL: MONGO OPLOG SETTINGS =====
# https://github.com/wekan/wekan-mongodb/issues/2#issuecomment-378343587
@@ -191,9 +192,12 @@ services:
# - MONGO_OPLOG_URL=mongodb://<username>:<password>@<mongoDbURL>/local?authSource=admin&replicaSet=rsWekan
#---------------------------------------------------------------
# ==== OPTIONAL: KADIRA PERFORMANCE MONITORING FOR METEOR ====
# https://github.com/smeijer/kadira
# https://github.com/edemaine/kadira-compose
# https://github.com/meteor/meteor-apm-agent
# https://blog.meteor.com/kadira-apm-is-now-open-source-490469ffc85f
# - export KADIRA_OPTIONS_ENDPOINT=http://127.0.0.1:11011
#- APM_OPTIONS_ENDPOINT=http://<kadira-ip>:11011
#- APM_APP_ID=
#- APM_APP_SECRET=
#---------------------------------------------------------------
# ==== OPTIONAL: LOGS AND STATS ====
# https://github.com/wekan/wekan/wiki/Logs
@@ -217,25 +221,39 @@ services:
# https://github.com/wekan/wekan-gogs
# If you disable Wekan API with false, Export Board does not work.
- WITH_API=true
#---------------------------------------------------------------
# ==== PASSWORD BRUTE FORCE PROTECTION ====
#https://atmospherejs.com/lucasantoniassi/accounts-lockout
#Defaults below. Uncomment to change. wekan/server/accounts-lockout.js
#- ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURES_BEFORE=3
#- ACCOUNTS_LOCKOUT_KNOWN_USERS_PERIOD=60
#- ACCOUNTS_LOCKOUT_KNOWN_USERS_FAILURE_WINDOW=15
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURES_BERORE=3
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_LOCKOUT_PERIOD=60
#- ACCOUNTS_LOCKOUT_UNKNOWN_USERS_FAILURE_WINDOW=15
#---------------------------------------------------------------
# ==== EMAIL NOTIFICATION TIMEOUT, ms =====
# Defaut: 30000 ms = 30s
#- EMAIL_NOTIFICATION_TIMEOUT=30000
#-----------------------------------------------------------------
# ==== CORS =====
# CORS: Set Access-Control-Allow-Origin header. Example: *
# CORS: Set Access-Control-Allow-Origin header.
#- CORS=*
# CORS_ALLOW_HEADERS: Set Access-Control-Allow-Headers header. "Authorization,Content-Type" is required for cross-origin use of the API.
#- CORS_ALLOW_HEADERS=Authorization,Content-Type
# CORS_EXPOSE_HEADERS: Set Access-Control-Expose-Headers header. This is not needed for typical CORS situations
#- CORS_EXPOSE_HEADERS=*
#-----------------------------------------------------------------
# ==== MATOMO INTEGRATION ====
# Optional: Integration with Matomo https://matomo.org that is installed to your server
# The address of the server where Matomo is hosted.
# example: - MATOMO_ADDRESS=https://example.com/matomo
#- MATOMO_ADDRESS=
#- MATOMO_ADDRESS=https://example.com/matomo
# The value of the site ID given in Matomo server for Wekan
# example: - MATOMO_SITE_ID=12345
#- MATOMO_SITE_ID=
#- MATOMO_SITE_ID=1
# The option do not track which enables users to not be tracked by matomo
# example: - MATOMO_DO_NOT_TRACK=false
#- MATOMO_DO_NOT_TRACK=
#- MATOMO_DO_NOT_TRACK=true
# The option that allows matomo to retrieve the username:
# example: MATOMO_WITH_USERNAME=true
#- MATOMO_WITH_USERNAME=false
#- MATOMO_WITH_USERNAME=true
#-----------------------------------------------------------------
# ==== BROWSER POLICY AND TRUSTED IFRAME URL ====
# Enable browser policy and allow one trusted URL that can have iframe that has Wekan embedded inside.
@@ -243,208 +261,233 @@ services:
# and allows all iframing etc. See wekan/server/policy.js
- BROWSER_POLICY_ENABLED=true
# When browser policy is enabled, HTML code at this Trusted URL can have iframe that embeds Wekan inside.
#- TRUSTED_URL=
#- TRUSTED_URL=https://intra.example.com
#-----------------------------------------------------------------
# ==== OUTGOING WEBHOOKS ====
# What to send to Outgoing Webhook, or leave out. Example, that includes all that are default: cardId,listId,oldListId,boardId,comment,user,card,commentId .
# example: WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
#- WEBHOOKS_ATTRIBUTES=
#- WEBHOOKS_ATTRIBUTES=cardId,listId,oldListId,boardId,comment,user,card,commentId
#-----------------------------------------------------------------
# ==== OAUTH2 ONLY WITH OIDC AND DOORKEEPER AS INDENTITY PROVIDER
# ==== Debug OIDC OAuth2 etc ====
#- DEBUG=true
#-----------------------------------------------------------------
# ==== OAUTH2 AZURE ====
# https://github.com/wekan/wekan/wiki/Azure
# 1) Register the application with Azure. Make sure you capture
# the application ID as well as generate a secret key.
# 2) Configure the environment variables. This differs slightly
# by installation type, but make sure you have the following:
#- OAUTH2_ENABLED=true
# OAuth2 login style: popup or redirect.
#- OAUTH2_LOGIN_STYLE=redirect
# Application GUID captured during app registration:
#- OAUTH2_CLIENT_ID=xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxx
# Secret key generated during app registration:
#- OAUTH2_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
#- OAUTH2_SERVER_URL=https://login.microsoftonline.com/
#- OAUTH2_AUTH_ENDPOINT=/oauth2/v2.0/authorize
#- OAUTH2_USERINFO_ENDPOINT=https://graph.microsoft.com/oidc/userinfo
#- OAUTH2_TOKEN_ENDPOINT=/oauth2/v2.0/token
# The claim name you want to map to the unique ID field:
#- OAUTH2_ID_MAP=email
# The claim name you want to map to the username field:
#- OAUTH2_USERNAME_MAP=email
# The claim name you want to map to the full name field:
#- OAUTH2_FULLNAME_MAP=name
# Tthe claim name you want to map to the email field:
#- OAUTH2_EMAIL_MAP=email
#-----------------------------------------------------------------
# ==== OAUTH2 KEYCLOAK ====
# https://github.com/wekan/wekan/wiki/Keycloak <== MAPPING INFO, REQUIRED
#- OAUTH2_ENABLED=true
# OAuth2 login style: popup or redirect.
#- OAUTH2_LOGIN_STYLE=redirect
#- OAUTH2_CLIENT_ID=<Keycloak create Client ID>
#- OAUTH2_SERVER_URL=<Keycloak server name>/auth
#- OAUTH2_AUTH_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/auth
#- OAUTH2_USERINFO_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/userinfo
#- OAUTH2_TOKEN_ENDPOINT=/realms/<keycloak realm>/protocol/openid-connect/token
#- OAUTH2_SECRET=<keycloak client secret>
#-----------------------------------------------------------------
# ==== OAUTH2 DOORKEEPER ====
# https://github.com/wekan/wekan/issues/1874
# https://github.com/wekan/wekan/wiki/OAuth2
# Enable the OAuth2 connection
# example: OAUTH2_ENABLED=true
#- OAUTH2_ENABLED=false
#- OAUTH2_ENABLED=true
# OAuth2 docs: https://github.com/wekan/wekan/wiki/OAuth2
# OAuth2 Client ID, for example from Rocket.Chat. Example: abcde12345
# example: OAUTH2_CLIENT_ID=abcde12345
#- OAUTH2_CLIENT_ID=
# OAuth2 Secret, for example from Rocket.Chat: Example: 54321abcde
# example: OAUTH2_SECRET=54321abcde
#- OAUTH2_SECRET=
# OAuth2 Server URL, for example Rocket.Chat. Example: https://chat.example.com
# example: OAUTH2_SERVER_URL=https://chat.example.com
#- OAUTH2_SERVER_URL=
# OAuth2 Authorization Endpoint. Example: /oauth/authorize
# example: OAUTH2_AUTH_ENDPOINT=/oauth/authorize
#- OAUTH2_AUTH_ENDPOINT=
# OAuth2 Userinfo Endpoint. Example: /oauth/userinfo
# example: OAUTH2_USERINFO_ENDPOINT=/oauth/userinfo
#- OAUTH2_USERINFO_ENDPOINT=
# OAuth2 Token Endpoint. Example: /oauth/token
# example: OAUTH2_TOKEN_ENDPOINT=/oauth/token
#- OAUTH2_TOKEN_ENDPOINT=
# OAuth2 login style: popup or redirect.
#- OAUTH2_LOGIN_STYLE=redirect
# OAuth2 Client ID.
#- OAUTH2_CLIENT_ID=abcde12345
# OAuth2 Secret.
#- OAUTH2_SECRET=54321abcde
# OAuth2 Server URL.
#- OAUTH2_SERVER_URL=https://chat.example.com
# OAuth2 Authorization Endpoint.
#- OAUTH2_AUTH_ENDPOINT=/oauth/authorize
# OAuth2 Userinfo Endpoint.
#- OAUTH2_USERINFO_ENDPOINT=/oauth/userinfo
# OAuth2 Token Endpoint.
#- OAUTH2_TOKEN_ENDPOINT=/oauth/token
# OAUTH2 ID Token Whitelist Fields.
#- OAUTH2_ID_TOKEN_WHITELIST_FIELDS=""
# OAUTH2 Request Permissions.
#- OAUTH2_REQUEST_PERMISSIONS=openid profile email
# OAuth2 ID Mapping
#- OAUTH2_ID_MAP=
# OAuth2 Username Mapping
#- OAUTH2_USERNAME_MAP=
# OAuth2 Fullname Mapping
#- OAUTH2_FULLNAME_MAP=
# OAuth2 Email Mapping
#- OAUTH2_EMAIL_MAP=
#-----------------------------------------------------------------
# ==== LDAP ====
# ==== LDAP: UNCOMMENT ALL TO ENABLE LDAP ====
# https://github.com/wekan/wekan/wiki/LDAP
# For Snap settings see https://github.com/wekan/wekan-snap/wiki/Supported-settings-keys
# Most settings work both on Snap and Docker below.
# Note: Do not add single quotes '' to variables. Having spaces still works without quotes where required.
#
# DEFAULT_AUTHENTICATION_METHOD : The default authentication method used if a user does not exist to create and authenticate. Can be set as ldap.
# example : DEFAULT_AUTHENTICATION_METHOD=ldap
#- DEFAULT_AUTHENTICATION_METHOD=
# The default authentication method used if a user does not exist to create and authenticate. Can be set as ldap.
#- DEFAULT_AUTHENTICATION_METHOD=ldap
#
# LDAP_ENABLE : Enable or not the connection by the LDAP
# example : LDAP_ENABLE=true
#- LDAP_ENABLE=false
# Enable or not the connection by the LDAP
#- LDAP_ENABLE=true
#
# LDAP_PORT : The port of the LDAP server
# example : LDAP_PORT=389
# The port of the LDAP server
#- LDAP_PORT=389
#
# LDAP_HOST : The host server for the LDAP server
# example : LDAP_HOST=localhost
#- LDAP_HOST=
# The host server for the LDAP server
#- LDAP_HOST=localhost
#
# LDAP_BASEDN : The base DN for the LDAP Tree
# example : LDAP_BASEDN=ou=user,dc=example,dc=org
#- LDAP_BASEDN=
# The base DN for the LDAP Tree
#- LDAP_BASEDN=ou=user,dc=example,dc=org
#
# LDAP_LOGIN_FALLBACK : Fallback on the default authentication method
# example : LDAP_LOGIN_FALLBACK=true
# Fallback on the default authentication method
#- LDAP_LOGIN_FALLBACK=false
#
# LDAP_RECONNECT : Reconnect to the server if the connection is lost
# example : LDAP_RECONNECT=false
# Reconnect to the server if the connection is lost
#- LDAP_RECONNECT=true
#
# LDAP_TIMEOUT : Overall timeout, in milliseconds
# example : LDAP_TIMEOUT=12345
# Overall timeout, in milliseconds
#- LDAP_TIMEOUT=10000
#
# LDAP_IDLE_TIMEOUT : Specifies the timeout for idle LDAP connections in milliseconds
# example : LDAP_IDLE_TIMEOUT=12345
# Specifies the timeout for idle LDAP connections in milliseconds
#- LDAP_IDLE_TIMEOUT=10000
#
# LDAP_CONNECT_TIMEOUT : Connection timeout, in milliseconds
# example : LDAP_CONNECT_TIMEOUT=12345
# Connection timeout, in milliseconds
#- LDAP_CONNECT_TIMEOUT=10000
#
# LDAP_AUTHENTIFICATION : If the LDAP needs a user account to search
# example : LDAP_AUTHENTIFICATION=true
#- LDAP_AUTHENTIFICATION=false
# If the LDAP needs a user account to search
#- LDAP_AUTHENTIFICATION=true
#
# LDAP_AUTHENTIFICATION_USERDN : The search user DN
# example : LDAP_AUTHENTIFICATION_USERDN=cn=admin,dc=example,dc=org
#- LDAP_AUTHENTIFICATION_USERDN=
# The search user DN
#- LDAP_AUTHENTIFICATION_USERDN=cn=wekan_adm,ou=serviceaccounts,ou=admin,ou=prod,dc=mydomain,dc=com
#
# LDAP_AUTHENTIFICATION_PASSWORD : The password for the search user
# example : AUTHENTIFICATION_PASSWORD=admin
#- LDAP_AUTHENTIFICATION_PASSWORD=
# The password for the search user
#- LDAP_AUTHENTIFICATION_PASSWORD=pwd
#
# LDAP_LOG_ENABLED : Enable logs for the module
# example : LDAP_LOG_ENABLED=true
#- LDAP_LOG_ENABLED=false
# Enable logs for the module
#- LDAP_LOG_ENABLED=true
#
# LDAP_BACKGROUND_SYNC : If the sync of the users should be done in the background
# example : LDAP_BACKGROUND_SYNC=true
# If the sync of the users should be done in the background
#- LDAP_BACKGROUND_SYNC=false
#
# LDAP_BACKGROUND_SYNC_INTERVAL : At which interval does the background task sync in milliseconds
# example : LDAP_BACKGROUND_SYNC_INTERVAL=12345
# At which interval does the background task sync in milliseconds
#- LDAP_BACKGROUND_SYNC_INTERVAL=100
#
# LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED :
# example : LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=true
#- LDAP_BACKGROUND_SYNC_KEEP_EXISTANT_USERS_UPDATED=false
#
# LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS :
# example : LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=true
#- LDAP_BACKGROUND_SYNC_IMPORT_NEW_USERS=false
#
# LDAP_ENCRYPTION : If using LDAPS
# example : LDAP_ENCRYPTION=ssl
# If using LDAPS: LDAP_ENCRYPTION=ssl
#- LDAP_ENCRYPTION=false
#
# LDAP_CA_CERT : The certification for the LDAPS server. Certificate needs to be included in this docker-compose.yml file.
# example : LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+zCCA+OgAwIBAgIkAhwR/6TVLmdRY6hHxvUFWc0+Enmu/Hu6cj+G2FIdAgIC...-----END CERTIFICATE-----
#- LDAP_CA_CERT=
# The certification for the LDAPS server. Certificate needs to be included in this docker-compose.yml file.
#- LDAP_CA_CERT=-----BEGIN CERTIFICATE-----MIIE+G2FIdAgIC...-----END CERTIFICATE-----
#
# LDAP_REJECT_UNAUTHORIZED : Reject Unauthorized Certificate
# example : LDAP_REJECT_UNAUTHORIZED=true
# Reject Unauthorized Certificate
#- LDAP_REJECT_UNAUTHORIZED=false
#
# LDAP_USER_SEARCH_FILTER : Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
# example : LDAP_USER_SEARCH_FILTER=
# Option to login to the LDAP server with the user's own username and password, instead of an administrator key. Default: false (use administrator key).
#- LDAP_USER_AUTHENTICATION="true"
#
# Optional extra LDAP filters. Don't forget the outmost enclosing parentheses if needed
#- LDAP_USER_SEARCH_FILTER=
#
# LDAP_USER_SEARCH_SCOPE : base (search only in the provided DN), one (search only in the provided DN and one level deep), or sub (search the whole subtree)
# example : LDAP_USER_SEARCH_SCOPE=one
#- LDAP_USER_SEARCH_SCOPE=
# base (search only in the provided DN), one (search only in the provided DN and one level deep), or sub (search the whole subtree)
#- LDAP_USER_SEARCH_SCOPE=one
#
# LDAP_USER_SEARCH_FIELD : Which field is used to find the user
# example : LDAP_USER_SEARCH_FIELD=uid
#- LDAP_USER_SEARCH_FIELD=
# Which field is used to find the user, like uid / sAMAccountName
#- LDAP_USER_SEARCH_FIELD=sAMAccountName
#
# LDAP_SEARCH_PAGE_SIZE : Used for pagination (0=unlimited)
# example : LDAP_SEARCH_PAGE_SIZE=12345
# Used for pagination (0=unlimited)
#- LDAP_SEARCH_PAGE_SIZE=0
#
# LDAP_SEARCH_SIZE_LIMIT : The limit number of entries (0=unlimited)
# example : LDAP_SEARCH_SIZE_LIMIT=12345
# The limit number of entries (0=unlimited)
#- LDAP_SEARCH_SIZE_LIMIT=0
#
# LDAP_GROUP_FILTER_ENABLE : Enable group filtering
# example : LDAP_GROUP_FILTER_ENABLE=true
# Enable group filtering
#- LDAP_GROUP_FILTER_ENABLE=false
#
# LDAP_GROUP_FILTER_OBJECTCLASS : The object class for filtering
# example : LDAP_GROUP_FILTER_OBJECTCLASS=group
# The object class for filtering. Example: group
#- LDAP_GROUP_FILTER_OBJECTCLASS=
#
# LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE :
# example :
#- LDAP_GROUP_FILTER_GROUP_ID_ATTRIBUTE=
#
# LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE :
# example :
#- LDAP_GROUP_FILTER_GROUP_MEMBER_ATTRIBUTE=
#
# LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT :
# example :
#- LDAP_GROUP_FILTER_GROUP_MEMBER_FORMAT=
#
# LDAP_GROUP_FILTER_GROUP_NAME :
# example :
#- LDAP_GROUP_FILTER_GROUP_NAME=
#
# LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier)
# example : LDAP_UNIQUE_IDENTIFIER_FIELD=guid
# LDAP_UNIQUE_IDENTIFIER_FIELD : This field is sometimes class GUID (Globally Unique Identifier). Example: guid
#- LDAP_UNIQUE_IDENTIFIER_FIELD=
#
# LDAP_UTF8_NAMES_SLUGIFY : Convert the username to utf8
# example : LDAP_UTF8_NAMES_SLUGIFY=false
#- LDAP_UTF8_NAMES_SLUGIFY=true
#
# LDAP_USERNAME_FIELD : Which field contains the ldap username
# example : LDAP_USERNAME_FIELD=username
#- LDAP_USERNAME_FIELD=
# LDAP_USERNAME_FIELD : Which field contains the ldap username. username / sAMAccountName
#- LDAP_USERNAME_FIELD=sAMAccountName
#
# LDAP_FULLNAME_FIELD : Which field contains the ldap fullname
# example : LDAP_FULLNAME_FIELD=fullname
#- LDAP_FULLNAME_FIELD=
# LDAP_FULLNAME_FIELD : Which field contains the ldap fullname. fullname / sAMAccountName
#- LDAP_FULLNAME_FIELD=fullname
#
# LDAP_MERGE_EXISTING_USERS :
# example : LDAP_MERGE_EXISTING_USERS=true
#- LDAP_MERGE_EXISTING_USERS=false
#
# Allow existing account matching by e-mail address when username does not match
#- LDAP_EMAIL_MATCH_ENABLE=true
#
# LDAP_EMAIL_MATCH_REQUIRE : require existing account matching by e-mail address when username does match
#- LDAP_EMAIL_MATCH_REQUIRE=true
#
# LDAP_EMAIL_MATCH_VERIFIED : require existing account email address to be verified for matching
#- LDAP_EMAIL_MATCH_VERIFIED=true
#
# LDAP_EMAIL_FIELD : which field contains the LDAP e-mail address
#- LDAP_EMAIL_FIELD=mail
#-----------------------------------------------------------------
# LDAP_SYNC_USER_DATA :
# example : LDAP_SYNC_USER_DATA=true
#- LDAP_SYNC_USER_DATA=false
#
# LDAP_SYNC_USER_DATA_FIELDMAP :
# example : LDAP_SYNC_USER_DATA_FIELDMAP={"cn":"name", "mail":"email"}
#- LDAP_SYNC_USER_DATA_FIELDMAP=
#- LDAP_SYNC_USER_DATA_FIELDMAP={"cn":"name", "mail":"email"}
#
# LDAP_SYNC_GROUP_ROLES :
# example :
#- LDAP_SYNC_GROUP_ROLES=
#- LDAP_SYNC_GROUP_ROLES=''
#
# LDAP_DEFAULT_DOMAIN : The default domain of the ldap it is used to create email if the field is not map correctly with the LDAP_SYNC_USER_DATA_FIELDMAP
# The default domain of the ldap it is used to create email if the field is not map correctly with the LDAP_SYNC_USER_DATA_FIELDMAP
# example :
#- LDAP_DEFAULT_DOMAIN=
#- LDAP_DEFAULT_DOMAIN=mydomain.com
#
# Enable/Disable syncing of admin status based on ldap groups:
#- LDAP_SYNC_ADMIN_STATUS=true
#
# Comma separated list of admin group names to sync.
#- LDAP_SYNC_ADMIN_GROUPS=group1,group2
#---------------------------------------------------------------------
# Login to LDAP automatically with HTTP header.
# In below example for siteminder, at right side of = is header name.
#- HEADER_LOGIN_ID=HEADERUID
#- HEADER_LOGIN_FIRSTNAME=HEADERFIRSTNAME
#- HEADER_LOGIN_LASTNAME=HEADERLASTNAME
#- HEADER_LOGIN_EMAIL=HEADEREMAILADDRESS
#---------------------------------------------------------------------
# ==== LOGOUT TIMER, probably does not work yet ====
# LOGOUT_WITH_TIMER : Enables or not the option logout with timer
@@ -506,9 +549,15 @@ services:
# - 80:80
# - 443:443
# volumes:
# - ./nginx/ssl:/etc/nginx/ssl/
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf
# - ./nginx/ssl:/etc/nginx/ssl/:ro
# - ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
## Alternative volume config:
## volumes:
## - ./nginx/nginx.conf:/etc/nginx/conf.d/default.conf:ro
## - ./nginx/ssl/ssl.conf:/etc/nginx/conf.d/ssl/ssl.conf:ro
## - ./nginx/ssl/testvm-ehu.crt:/etc/nginx/conf.d/ssl/certs/mycert.crt:ro
## - ./nginx/ssl/testvm-ehu.key:/etc/nginx/conf.d/ssl/certs/mykey.key:ro
## - ./nginx/ssl/pphrase:/etc/nginx/conf.d/ssl/pphrase:ro
volumes:
wekan-db:
+22
View File
@@ -0,0 +1,22 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
OWNERS
+13
View File
@@ -0,0 +1,13 @@
name: wekan
version: 1.0.0
appVersion: 2.x.x
kubeVersion: "^1.8.0-0"
description: Open Source kanban
home: https://wekan.github.io/
icon: https://wekan.github.io/wekan-logo.svg
sources:
- https://github.com/wekan/wekan
maintainers:
- name: technotaff
email: github@randall.cc
engine: gotpl
+4
View File
@@ -0,0 +1,4 @@
approvers:
- technotaff
reviewers:
- technotaff
+58
View File
@@ -0,0 +1,58 @@
# Helm Chart for Wekan
## Features
o Uses a MongoDB replica set by default - this allows fault-tolerant
and scalable MongoDB deployment (or just set the replicas to 1 for
a single server install)
o Optional Horizontal Pod Autoscaler (HPA), so that your Wekan pods
will scale automatically with increased CPU load.
## The configurable values (values.yaml)
Scaling Wekan:
```yaml
## Configuration for wekan component
##
replicaCount: 1
```
**replicaCount** Will set the initial number of replicas for the Wekan pod (and container)
```yaml
## Configure an horizontal pod autoscaler
##
autoscaling:
enabled: true
config:
minReplicas: 1
maxReplicas: 16
## Note: when setting this, a `resources.request.cpu` is required. You
## likely want to set it to `1` or some lower value.
##
targetCPUUtilizationPercentage: 80
```
This section (if *enabled* is set to **true**) will enable the Kubernetes Horizontal Pod Autoscaler (HPA).
**minReplicas:** this is the minimum number of pods to scale down to (We recommend setting this to the same value as **replicaCount**).
**maxReplicas:** this is the maximum number of pods to scale up to.
**targetCPUUtilizationPercentage:** This is the CPU at which the HPA will scale-out the number of Wekan pods.
```yaml
mongodb-replicaset:
enabled: true
replicas: 3
replicaSetName: rs0
securityContext:
runAsUser: 1000
fsGroup: 1000
runAsNonRoot: true
```
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.
+1
View File
@@ -0,0 +1 @@
+5
View File
@@ -0,0 +1,5 @@
dependencies:
- name: mongodb-replicaset
version: 3.6.x
repository: "https://kubernetes-charts.storage.googleapis.com/"
condition: mongodb-replicaset.enabled
+19
View File
@@ -0,0 +1,19 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range .Values.ingress.hosts }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "wekan.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w {{ template "wekan.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ template "wekan.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app={{ template "wekan.name" . }},release={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
echo "Visit http://127.0.0.1:8080 to use your application"
kubectl port-forward $POD_NAME 8080:8080
{{- end }}
+82
View File
@@ -0,0 +1,82 @@
{{/* vim: set filetype=mustache: */}}
{{/*
Expand the name of the chart.
*/}}
{{- define "wekan.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "wekan.fullname" -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create a default fully qualified name for the wekan data app.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "wekan.localdata.fullname" -}}
{{- if .Values.localdata.fullnameOverride -}}
{{- .Values.localdata.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- $name := default .Chart.Name .Values.nameOverride -}}
{{- if contains $name .Release.Name -}}
{{- printf "%s-localdata" .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s-localdata" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}
{{- end -}}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "wekan.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create the name of the service account to use for the api component
*/}}
{{- define "wekan.serviceAccountName" -}}
{{- if .Values.serviceAccounts.create -}}
{{ default (include "wekan.fullname" .) .Values.serviceAccounts.name }}
{{- else -}}
{{ default "default" .Values.serviceAccounts.name }}
{{- end -}}
{{- end -}}
{{/*
Create a default fully qualified mongodb-replicaset name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
*/}}
{{- define "wekan.mongodb-replicaset.fullname" -}}
{{- $name := default "mongodb-replicaset" (index .Values "mongodb-replicaset" "nameOverride") -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{/*
Create the MongoDB URL. If MongoDB is installed as part of this chart, use k8s service discovery,
else use user-provided URL.
*/}}
{{- define "mongodb-replicaset.url" -}}
{{- if (index .Values "mongodb-replicaset" "enabled") -}}
{{- $count := (int (index .Values "mongodb-replicaset" "replicas")) -}}
{{- $release := .Release.Name -}}
mongodb://{{- range $v := until $count }}{{ $release }}-mongodb-replicaset-{{ $v }}.{{ $release }}-mongodb-replicaset:27017{{ if ne $v (sub $count 1) }},{{- end -}}{{- end -}}?replicaSet={{ index .Values "mongodb-replicaset" "replicaSetName" }}
{{- else -}}
{{- index .Values "mongodb-replicaset" "url" -}}
{{- end -}}
{{- end -}}
+58
View File
@@ -0,0 +1,58 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "wekan.fullname" . }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
release: {{ .Release.Name }}
heritage: {{ .Release.Service }}
spec:
replicas: {{ .Values.replicaCount }}
selector:
matchLabels:
app: {{ template "wekan.name" . }}
component: wekan
release: {{ .Release.Name }}
template:
metadata:
annotations:
labels:
app: {{ template "wekan.name" . }}
component: wekan
release: {{ .Release.Name }}
spec:
serviceAccountName: {{ template "wekan.serviceAccountName" . }}
containers:
- name: {{ .Chart.Name }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
terminationMessagePolicy: FallbackToLogsOnError
ports:
- name: http
containerPort: 8080
env:
- name: ROOT_URL
value: {{ .Values.root_url | default "https://wekan.local" | quote }}
- name: MONGO_URL
value: "{{ template "mongodb-replicaset.url" . }}"
livenessProbe:
httpGet:
path: /
port: 8080
initialDelaySeconds: 60
resources:
{{ toYaml .Values.resources | indent 12 }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{ toYaml . | indent 8 }}
{{- end }}
{{- if .Values.affinity }}
affinity:
{{ toYaml .Values.affinity | indent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{ toYaml . | indent 8 }}
{{- end }}
+18
View File
@@ -0,0 +1,18 @@
{{- if .Values.autoscaling.enabled -}}
apiVersion: autoscaling/v1
kind: HorizontalPodAutoscaler
metadata:
name: {{ template "wekan.fullname" . }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ template "wekan.fullname" . }}
{{ toYaml .Values.autoscaling.config | indent 2 }}
{{- end -}}
+40
View File
@@ -0,0 +1,40 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "wekan.fullname" . -}}
{{- $servicePort := .Values.service.port -}}
{{- $ingressPath := .Values.ingress.path -}}
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
{{- with .Values.ingress.annotations }}
annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ . }}
http:
paths:
- path: {{ $ingressPath }}
backend:
serviceName: {{ $fullName }}
servicePort: http
{{- end }}
{{- end }}
+14
View File
@@ -0,0 +1,14 @@
apiVersion: v1
kind: Secret
metadata:
name: {{ template "wekan.fullname" . }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
type: Opaque
data:
accessKey: {{ .Values.credentials.accessKey | b64enc }}
secretKey: {{ .Values.credentials.secretKey | b64enc }}
+25
View File
@@ -0,0 +1,25 @@
apiVersion: v1
kind: Service
metadata:
{{- if .Values.service.annotations }}
annotations:
{{ toYaml .Values.service.annotations | indent 4 }}
{{- end }}
name: {{ template "wekan.fullname" . }}
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
app: {{ template "wekan.name" . }}
component: wekan
release: {{ .Release.Name }}
+12
View File
@@ -0,0 +1,12 @@
{{- if .Values.serviceAccounts.create }}
apiVersion: v1
kind: ServiceAccount
metadata:
labels:
app: {{ template "wekan.name" . }}
chart: {{ template "wekan.chart" . }}
component: wekan
heritage: {{ .Release.Service }}
release: {{ .Release.Name }}
name: {{ template "wekan.serviceAccountName" . }}
{{- end }}
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Pod
metadata:
name: {{ template "wekan.fullname" . }}-test
annotations:
"helm.sh/hook": test-success
spec:
containers:
- name: {{ template "wekan.fullname" . }}-test
imagePullPolicy: IfNotPresent
image: "docker.io/mesosphere/aws-cli:1.14.5"
command:
- sh
- -c
- aws s3 --endpoint-url=http://{{ include "wekan.fullname" . }} --region=us-east-1 ls
env:
- name: AWS_ACCESS_KEY_ID
valueFrom:
secretKeyRef:
name: {{ template "wekan.fullname" . }}
key: accessKey
- name: AWS_SECRET_ACCESS_KEY
valueFrom:
secretKeyRef:
name: {{ template "wekan.fullname" . }}
key: secretKey
restartPolicy: Never
+110
View File
@@ -0,0 +1,110 @@
# ------------------------------------------------------------------------------
# Wekan:
# ------------------------------------------------------------------------------
## Define serviceAccount names to create or use. Defaults to component's fully
## qualified name.
##
serviceAccounts:
create: true
name: ""
## Wekan image configuration
##
image:
repository: quay.io/wekan/wekan
tag: latest
pullPolicy: IfNotPresent
## Configuration for wekan component
##
replicaCount: 1
## Specify wekan credentials
##
credentials:
accessKey: access-key
secretKey: secret-key
## Specify additional environmental variables for the Deployment
##
env: {}
service:
type: NodePort
port: 80
annotations: {}
# prometheus.io/scrape: "true"
# prometheus.io/port: "8000"
# prometheus.io/path: "/_/monitoring/metrics"
## Comma-separated string of allowed virtual hosts for external access.
## This should match the ingress hosts
##
endpoint: wekan.local
ingress:
enabled: true
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
path: /*
# This must match 'endpoint', unless your client supports different
# hostnames.
hosts: [ wekan.local ]
# - wekan.local
tls: []
# - secretName: wekan-example-tls
# hosts:
# - wekan-example.local
resources:
requests:
memory: 128Mi
cpu: 300m
limits:
memory: 1Gi
cpu: 500m
## Node labels for pod assignment
## ref: https://kubernetes.io/docs/user-guide/node-selection/
##
nodeSelector: {}
## Tolerations for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/taint-and-toleration/
##
tolerations: []
## Affinity for pod assignment
## ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/#affinity-and-anti-affinity
##
affinity: {}
## Configure an horizontal pod autoscaler
##
autoscaling:
enabled: true
config:
minReplicas: 1
maxReplicas: 16
## Note: when setting this, a `resources.request.cpu` is required. You
## likely want to set it to `1` or some lower value.
##
targetCPUUtilizationPercentage: 80
# ------------------------------------------------------------------------------
# MongoDB:
# ------------------------------------------------------------------------------
mongodb-replicaset:
enabled: true
replicas: 3
replicaSetName: rs0
securityContext:
runAsUser: 1000
fsGroup: 1000
runAsNonRoot: true
#image:
# tag: 3.2.21
+67 -28
View File
@@ -1,28 +1,41 @@
{
"accept": "قبول",
"act-activity-notify": "اشعارات النشاط",
"act-addAttachment": "ربط __المرفق__ الى __بطاقة__",
"act-addSubtask": "تمة اضافة فرع المهمة __ قائمة التدقيق __ الى __ بطاقة",
"act-addChecklist": "تمة اضافة قائمة التدقيق __ قائمة التدقيق __ الى __ بطاقة",
"act-addChecklistItem": "تمة اضافة عنصر قائمة التدقيق __الى قائمة التدقيق __ قائمة التدقيق __ في __ بطاقة",
"act-addComment": "علق على __بطاقة__ : __تعليق__",
"act-createBoard": "احدث __لوحة__",
"act-createCard": "تمة اضافة __بطاقة__ الى __قائمة__",
"act-createCustomField": "احدث حقل مخصص __ حقل مخصص__",
"act-createList": "اضاف __قائمة__ الى __لوحة__",
"act-addBoardMember": "اضاف __member__ الى __board__",
"act-archivedBoard": "__ لوح __ انتقل إلى الأرشيف",
"act-archivedCard": "__ بطاقة __ انتقلت إلى الأرشيف",
"act-archivedList": "__ القائمة __ انتقلت إلى الأرشيف",
"act-archivedSwimlane": "__خط السباحة__انتقل إلى الأرشيف",
"act-importBoard": "إستورد __board__",
"act-importCard": "إستورد __card__",
"act-importList": "إستورد __list__",
"act-joinMember": "اضاف __member__ الى __card__",
"act-moveCard": "حوّل __card__ من __oldList__ إلى __list__",
"act-removeBoardMember": "أزال __member__ من __board__",
"act-restoredCard": "أعاد __card__ إلى __board__",
"act-unjoinMember": "أزال __member__ من __card__",
"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__",
"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__",
"act-removeLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removedLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklist": "added checklist __checklist__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklistItem": "added checklist item __checklistItem__ to checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklist": "removed checklist __checklist__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklistItem": "removed checklist item __checklistItem__ from checklist __checkList__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-checkedItem": "checked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncheckedItem": "unchecked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-completeChecklist": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncompleteChecklist": "uncompleted checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addComment": "commented on card __card__: __comment__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createBoard": "created board __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "created card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-createCustomField": "created custom field __customField__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createList": "added list __list__ to board __board__",
"act-addBoardMember": "added member __member__ to board __board__",
"act-archivedBoard": "Board __board__ moved to Archive",
"act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedList": "List __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedSwimlane": "Swimlane __swimlane__ at board __board__ moved to Archive",
"act-importBoard": "imported board __board__",
"act-importCard": "imported card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-importList": "imported list __list__ to swimlane __swimlane__ at board __board__",
"act-joinMember": "added member __member__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "moved card __card__ from list __oldList__ at swimlane __oldSwimlane__ at board __oldBoard__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoardMember": "removed member __member__ from board __board__",
"act-restoredCard": "restored card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-unjoinMember": "removed member __member__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-withBoardTitle": "__لوح__",
"act-withCardTitle": "[__board__] __card__",
"actions": "الإجراءات",
@@ -47,14 +60,14 @@
"activity-unchecked-item": "ازالة تحقق %s من قائمة التحقق %s من %s",
"activity-checklist-added": "أضاف قائمة تحقق إلى %s",
"activity-checklist-removed": "ازالة قائمة التحقق من %s",
"activity-checklist-completed": "تم انجاز قائمة التحقق %s من %s",
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted": "لم يتم انجاز قائمة التحقق %s من %s",
"activity-checklist-item-added": "تم اضافة عنصر قائمة التحقق الى '%s' في %s",
"activity-checklist-item-removed": "تم ازالة عنصر قائمة التحقق الى '%s' في %s",
"add": "أضف",
"activity-checked-item-card": "checked %s in checklist %s",
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "completed the checklist %s",
"activity-checklist-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",
"add-attachment": "إضافة مرفق",
"add-board": "إضافة لوحة",
@@ -92,6 +105,8 @@
"restore-board": "استعادة اللوحة",
"no-archived-boards": "لا توجد لوحات في الأرشيف.",
"archives": "أرشيف",
"template": "Template",
"templates": "Templates",
"assign-member": "تعيين عضو",
"attached": "أُرفق)",
"attachment": "مرفق",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "إعادة تسمية اللوحة",
"boardChangeVisibilityPopup-title": "تعديل وضوح الرؤية",
"boardChangeWatchPopup-title": "تغيير المتابعة",
"boardMenuPopup-title": "قائمة اللوحة",
"boardMenuPopup-title": "Board Settings",
"boards": "لوحات",
"board-view": "عرض اللوحات",
"board-view-cal": "التقويم",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "علامات",
"cardMembersPopup-title": "أعضاء",
"cardMorePopup-title": "المزيد",
"cardTemplatePopup-title": "Create template",
"cards": "بطاقات",
"cards-count": "بطاقات",
"casSignIn": "تسجيل الدخول مع CAS",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?",
"copy-card-link-to-clipboard": "نسخ رابط البطاقة إلى الحافظة",
"linkCardPopup-title": "ربط البطاقة",
"searchCardPopup-title": "Search Card",
"searchElementPopup-title": "بحث",
"copyCardPopup-title": "نسخ البطاقة",
"copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
"copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Milestone 1",
"welcome-list1": "المبادئ",
"welcome-list2": "متقدم",
"card-templates-swimlane": "Card Templates",
"list-templates-swimlane": "List Templates",
"board-templates-swimlane": "Board Templates",
"what-to-do": "ماذا تريد أن تنجز?",
"wipLimitErrorPopup-title": "Invalid WIP Limit",
"wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
@@ -552,6 +571,8 @@
"activity-added-label-card": "added label '%s'",
"activity-removed-label-card": "removed label '%s'",
"activity-delete-attach-card": "deleted an attachment",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Rule",
"r-add-trigger": "Add trigger",
"r-add-action": "Add action",
@@ -575,7 +596,7 @@
"r-unarchived": "Restored from Archive",
"r-a-card": "a card",
"r-when-a-label-is": "When a label is",
"r-when-the-label-is": "When the label is",
"r-when-the-label": "When the label",
"r-list-name": "list name",
"r-when-a-member": "When a member is",
"r-when-the-member": "When the member",
@@ -648,6 +669,15 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "When a card is moved to another list",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
@@ -659,5 +689,14 @@
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"error-undefined": "Something went wrong",
"error-ldap-login": "An error occurred while trying to login"
"error-ldap-login": "An error occurred while trying to login",
"display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
+67 -28
View File
@@ -1,28 +1,41 @@
{
"accept": "Приемам",
"act-activity-notify": "Activity Notification",
"act-addAttachment": "прикачи __attachment__ към __card__",
"act-addSubtask": "добави задача __checklist__ към __card__",
"act-addChecklist": "добави списък със задачи __checklist__ към __card__",
"act-addChecklistItem": "добави __checklistItem__ към списък със задачи __checklist__ в __card__",
"act-addComment": "Коментира в __card__: __comment__",
"act-createBoard": "създаде __board__",
"act-createCard": "добави __card__ към __list__",
"act-createCustomField": "създаде собствено поле __customField__",
"act-createList": "добави __list__ към __board__",
"act-addBoardMember": "добави __member__ към __board__",
"act-archivedBoard": "__board__ е преместен в Архива",
"act-archivedCard": "__card__ е преместена в Архива",
"act-archivedList": "__list__ е преместен в Архива",
"act-archivedSwimlane": "__swimlane__ е преместен в Архива",
"act-importBoard": "импортира __board__",
"act-importCard": "импортира __card__",
"act-importList": "импортира __list__",
"act-joinMember": "добави __member__ към __card__",
"act-moveCard": "премести __card__ от __oldList__ в __list__",
"act-removeBoardMember": "премахна __member__ от __board__",
"act-restoredCard": "възстанови __card__ в __board__",
"act-unjoinMember": "премахна __member__ от __card__",
"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__",
"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__",
"act-removeLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removedLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklist": "added checklist __checklist__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklistItem": "added checklist item __checklistItem__ to checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklist": "removed checklist __checklist__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklistItem": "removed checklist item __checklistItem__ from checklist __checkList__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-checkedItem": "checked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncheckedItem": "unchecked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-completeChecklist": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncompleteChecklist": "uncompleted checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addComment": "commented on card __card__: __comment__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createBoard": "created board __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "created card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-createCustomField": "created custom field __customField__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createList": "added list __list__ to board __board__",
"act-addBoardMember": "added member __member__ to board __board__",
"act-archivedBoard": "Board __board__ moved to Archive",
"act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedList": "List __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedSwimlane": "Swimlane __swimlane__ at board __board__ moved to Archive",
"act-importBoard": "imported board __board__",
"act-importCard": "imported card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-importList": "imported list __list__ to swimlane __swimlane__ at board __board__",
"act-joinMember": "added member __member__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "moved card __card__ from list __oldList__ at swimlane __oldSwimlane__ at board __oldBoard__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoardMember": "removed member __member__ from board __board__",
"act-restoredCard": "restored card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-unjoinMember": "removed member __member__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-withBoardTitle": "__board__ ",
"act-withCardTitle": "[__board__] __card__",
"actions": "Действия",
@@ -47,14 +60,14 @@
"activity-unchecked-item": "размаркира %s от списък със задачи %s на %s",
"activity-checklist-added": "добави списък със задачи към %s",
"activity-checklist-removed": "премахна списък със задачи от %s",
"activity-checklist-completed": "завърши списък със задачи %s на %s",
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted": "\"отзавърши\" чеклистта %s в %s",
"activity-checklist-item-added": "добави точка към '%s' в/във %s",
"activity-checklist-item-removed": "премахна точка от '%s' в %s",
"add": "Добави",
"activity-checked-item-card": "отбеляза %s в чеклист %s",
"activity-unchecked-item-card": "размаркира %s в чеклист %s",
"activity-checklist-completed-card": "завърши чеклиста %s",
"activity-checklist-completed-card": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted-card": "\"отзавърши\" чеклистта %s",
"add-attachment": "Добави прикачен файл",
"add-board": "Добави Табло",
@@ -92,6 +105,8 @@
"restore-board": "Възстанови Таблото",
"no-archived-boards": "Няма Табла в Архива.",
"archives": "Архив",
"template": "Template",
"templates": "Templates",
"assign-member": "Възложи на член от екипа",
"attached": "прикачен",
"attachment": "Прикаченн файл",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "Промени името на Таблото",
"boardChangeVisibilityPopup-title": "Change Visibility",
"boardChangeWatchPopup-title": "Промени наблюдаването",
"boardMenuPopup-title": "Меню на Таблото",
"boardMenuPopup-title": "Board Settings",
"boards": "Табла",
"board-view": "Board View",
"board-view-cal": "Календар",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "Етикети",
"cardMembersPopup-title": "Членове",
"cardMorePopup-title": "Още",
"cardTemplatePopup-title": "Create template",
"cards": "Карти",
"cards-count": "Карти",
"casSignIn": "Sign In with CAS",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Сигурни ли сте, че искате да изтриете този чеклист?",
"copy-card-link-to-clipboard": "Копирай връзката на картата в клипборда",
"linkCardPopup-title": "Свържи картата",
"searchCardPopup-title": "Търсене на карта",
"searchElementPopup-title": "Търсене",
"copyCardPopup-title": "Копирай картата",
"copyChecklistToManyCardsPopup-title": "Копирай чеклисти в други карти",
"copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Milestone 1",
"welcome-list1": "Basics",
"welcome-list2": "Advanced",
"card-templates-swimlane": "Card Templates",
"list-templates-swimlane": "List Templates",
"board-templates-swimlane": "Board Templates",
"what-to-do": "What do you want to do?",
"wipLimitErrorPopup-title": "Невалиден WIP лимит",
"wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
@@ -552,6 +571,8 @@
"activity-added-label-card": "добави етикет '%s'",
"activity-removed-label-card": "премахна етикет '%s'",
"activity-delete-attach-card": "изтри прикачения файл",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Правило",
"r-add-trigger": "Добави спусък",
"r-add-action": "Добави действие",
@@ -575,7 +596,7 @@
"r-unarchived": "Възстановено от Архива",
"r-a-card": "карта",
"r-when-a-label-is": "When a label is",
"r-when-the-label-is": "When the label is",
"r-when-the-label": "When the label",
"r-list-name": "list name",
"r-when-a-member": "When a member is",
"r-when-the-member": "When the member",
@@ -648,6 +669,15 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "When a card is moved to another list",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
@@ -659,5 +689,14 @@
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"error-undefined": "Something went wrong",
"error-ldap-login": "An error occurred while trying to login"
"error-ldap-login": "An error occurred while trying to login",
"display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
+67 -28
View File
@@ -1,28 +1,41 @@
{
"accept": "Asantiñ",
"act-activity-notify": "Activity Notification",
"act-addAttachment": "attached __attachment__ to __card__",
"act-addSubtask": "added subtask __checklist__ to __card__",
"act-addChecklist": "added checklist __checklist__ to __card__",
"act-addChecklistItem": "added __checklistItem__ to checklist __checklist__ on __card__",
"act-addComment": "commented on __card__: __comment__",
"act-createBoard": "created __board__",
"act-createCard": "added __card__ to __list__",
"act-createCustomField": "created custom field __customField__",
"act-createList": "added __list__ to __board__",
"act-addBoardMember": "added __member__ to __board__",
"act-archivedBoard": "__board__ moved to Archive",
"act-archivedCard": "__card__ moved to Archive",
"act-archivedList": "__list__ moved to Archive",
"act-archivedSwimlane": "__swimlane__ moved to Archive",
"act-importBoard": "imported __board__",
"act-importCard": "imported __card__",
"act-importList": "imported __list__",
"act-joinMember": "added __member__ to __card__",
"act-moveCard": "moved __card__ from __oldList__ to __list__",
"act-removeBoardMember": "removed __member__ from __board__",
"act-restoredCard": "restored __card__ to __board__",
"act-unjoinMember": "removed __member__ from __card__",
"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__",
"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__",
"act-removeLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removedLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklist": "added checklist __checklist__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklistItem": "added checklist item __checklistItem__ to checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklist": "removed checklist __checklist__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklistItem": "removed checklist item __checklistItem__ from checklist __checkList__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-checkedItem": "checked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncheckedItem": "unchecked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-completeChecklist": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncompleteChecklist": "uncompleted checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addComment": "commented on card __card__: __comment__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createBoard": "created board __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "created card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-createCustomField": "created custom field __customField__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createList": "added list __list__ to board __board__",
"act-addBoardMember": "added member __member__ to board __board__",
"act-archivedBoard": "Board __board__ moved to Archive",
"act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedList": "List __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedSwimlane": "Swimlane __swimlane__ at board __board__ moved to Archive",
"act-importBoard": "imported board __board__",
"act-importCard": "imported card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-importList": "imported list __list__ to swimlane __swimlane__ at board __board__",
"act-joinMember": "added member __member__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "moved card __card__ from list __oldList__ at swimlane __oldSwimlane__ at board __oldBoard__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoardMember": "removed member __member__ from board __board__",
"act-restoredCard": "restored card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-unjoinMember": "removed member __member__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-withBoardTitle": "__board__",
"act-withCardTitle": "[__board__] __card__",
"actions": "Oberoù",
@@ -47,14 +60,14 @@
"activity-unchecked-item": "unchecked %s in checklist %s of %s",
"activity-checklist-added": "added checklist to %s",
"activity-checklist-removed": "removed a checklist from %s",
"activity-checklist-completed": "completed the checklist %s of %s",
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted": "uncompleted the checklist %s of %s",
"activity-checklist-item-added": "added checklist item to '%s' in %s",
"activity-checklist-item-removed": "removed a checklist item from '%s' in %s",
"add": "Ouzhpenn",
"activity-checked-item-card": "checked %s in checklist %s",
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "completed the checklist %s",
"activity-checklist-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",
"add-attachment": "Add Attachment",
"add-board": "Add Board",
@@ -92,6 +105,8 @@
"restore-board": "Restore Board",
"no-archived-boards": "No Boards in Archive.",
"archives": "Archive",
"template": "Template",
"templates": "Templates",
"assign-member": "Assign member",
"attached": "attached",
"attachment": "Attachment",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "Rename Board",
"boardChangeVisibilityPopup-title": "Change Visibility",
"boardChangeWatchPopup-title": "Change Watch",
"boardMenuPopup-title": "Board Menu",
"boardMenuPopup-title": "Board Settings",
"boards": "Boards",
"board-view": "Board View",
"board-view-cal": "Calendar",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "Labels",
"cardMembersPopup-title": "Izili",
"cardMorePopup-title": "Muioc’h",
"cardTemplatePopup-title": "Create template",
"cards": "Kartennoù",
"cards-count": "Kartennoù",
"casSignIn": "Sign In with CAS",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"linkCardPopup-title": "Link Card",
"searchCardPopup-title": "Search Card",
"searchElementPopup-title": "Search",
"copyCardPopup-title": "Copy Card",
"copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
"copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Milestone 1",
"welcome-list1": "Basics",
"welcome-list2": "Advanced",
"card-templates-swimlane": "Card Templates",
"list-templates-swimlane": "List Templates",
"board-templates-swimlane": "Board Templates",
"what-to-do": "What do you want to do?",
"wipLimitErrorPopup-title": "Invalid WIP Limit",
"wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
@@ -552,6 +571,8 @@
"activity-added-label-card": "added label '%s'",
"activity-removed-label-card": "removed label '%s'",
"activity-delete-attach-card": "deleted an attachment",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Rule",
"r-add-trigger": "Add trigger",
"r-add-action": "Add action",
@@ -575,7 +596,7 @@
"r-unarchived": "Restored from Archive",
"r-a-card": "a card",
"r-when-a-label-is": "When a label is",
"r-when-the-label-is": "When the label is",
"r-when-the-label": "When the label",
"r-list-name": "list name",
"r-when-a-member": "When a member is",
"r-when-the-member": "When the member",
@@ -648,6 +669,15 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "When a card is moved to another list",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
@@ -659,5 +689,14 @@
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"error-undefined": "Something went wrong",
"error-ldap-login": "An error occurred while trying to login"
"error-ldap-login": "An error occurred while trying to login",
"display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
+67 -28
View File
@@ -1,28 +1,41 @@
{
"accept": "Accepta",
"act-activity-notify": "Notificació d'activitat",
"act-addAttachment": "afegit__adjunt__ a la __fitxa__",
"act-addSubtask": "added subtask __checklist__ to __card__",
"act-addChecklist": "afegida la checklist _checklist__ a __card__",
"act-addChecklistItem": "afegit __checklistItem__ a la checklist __checklist__ on __card__",
"act-addComment": "comentat a __card__: __comment__",
"act-createBoard": "nou __tauler__",
"act-createCard": "afegit/da __card__ a __list__",
"act-createCustomField": "created custom field __customField__",
"act-createList": "llista __afegida__ al __tauler__",
"act-addBoardMember": "usuari __afegit__ al __tauler__",
"act-archivedBoard": "__tauler__ mogut al Arxiu",
"act-archivedCard": "__fitxa__ moguda al Arxiu",
"act-archivedList": "__llista__ mogud al Arxiu",
"act-archivedSwimlane": "__swimlane__ moved to Archive",
"act-importBoard": "tauler __importat__",
"act-importCard": "__card__ importat",
"act-importList": "__list__ importat",
"act-joinMember": "afegit/da __member__ a __card__",
"act-moveCard": "mou __card__ de __oldList__ a __list__",
"act-removeBoardMember": "elimina __usuari__ del __tauler__",
"act-restoredCard": "fitxa __restaurada__ al __tauler__",
"act-unjoinMember": "elimina __member__ de __card__",
"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__",
"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__",
"act-removeLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removedLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklist": "added checklist __checklist__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklistItem": "added checklist item __checklistItem__ to checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklist": "removed checklist __checklist__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklistItem": "removed checklist item __checklistItem__ from checklist __checkList__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-checkedItem": "checked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncheckedItem": "unchecked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-completeChecklist": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncompleteChecklist": "uncompleted checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addComment": "commented on card __card__: __comment__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createBoard": "created board __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "created card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-createCustomField": "created custom field __customField__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createList": "added list __list__ to board __board__",
"act-addBoardMember": "added member __member__ to board __board__",
"act-archivedBoard": "Board __board__ moved to Archive",
"act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedList": "List __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedSwimlane": "Swimlane __swimlane__ at board __board__ moved to Archive",
"act-importBoard": "imported board __board__",
"act-importCard": "imported card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-importList": "imported list __list__ to swimlane __swimlane__ at board __board__",
"act-joinMember": "added member __member__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "moved card __card__ from list __oldList__ at swimlane __oldSwimlane__ at board __oldBoard__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoardMember": "removed member __member__ from board __board__",
"act-restoredCard": "restored card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-unjoinMember": "removed member __member__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-withBoardTitle": "__tauler__",
"act-withCardTitle": "[__tauler__] __fitxa__",
"actions": "Accions",
@@ -47,14 +60,14 @@
"activity-unchecked-item": "unchecked %s in checklist %s of %s",
"activity-checklist-added": "Checklist afegida a %s",
"activity-checklist-removed": "removed a checklist from %s",
"activity-checklist-completed": "completed the checklist %s of %s",
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted": "uncompleted the checklist %s of %s",
"activity-checklist-item-added": "afegida entrada de checklist de '%s' a %s",
"activity-checklist-item-removed": "removed a checklist item from '%s' in %s",
"add": "Afegeix",
"activity-checked-item-card": "checked %s in checklist %s",
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "completed the checklist %s",
"activity-checklist-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",
"add-attachment": "Afegeix adjunt",
"add-board": "Afegeix Tauler",
@@ -92,6 +105,8 @@
"restore-board": "Restaura Tauler",
"no-archived-boards": "No hi han Taulers al Arxiu.",
"archives": "Desa",
"template": "Template",
"templates": "Templates",
"assign-member": "Assignar membre",
"attached": "adjuntat",
"attachment": "Adjunt",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "Canvia el nom tauler",
"boardChangeVisibilityPopup-title": "Canvia visibilitat",
"boardChangeWatchPopup-title": "Canvia seguiment",
"boardMenuPopup-title": "Menú del tauler",
"boardMenuPopup-title": "Board Settings",
"boards": "Taulers",
"board-view": "Visió del tauler",
"board-view-cal": "Calendari",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "Etiquetes",
"cardMembersPopup-title": "Membres",
"cardMorePopup-title": "Més",
"cardTemplatePopup-title": "Create template",
"cards": "Fitxes",
"cards-count": "Fitxes",
"casSignIn": "Sign In with CAS",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?",
"copy-card-link-to-clipboard": "Copia l'enllaç de la ftixa al porta-retalls",
"linkCardPopup-title": "Link Card",
"searchCardPopup-title": "Buscar Fitxa",
"searchElementPopup-title": "Cerca",
"copyCardPopup-title": "Copia la fitxa",
"copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
"copyChecklistToManyCardsPopup-instructions": "Títols de fitxa i Descripcions de destí en aquest format JSON",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Objectiu 1",
"welcome-list1": "Bàsics",
"welcome-list2": "Avançades",
"card-templates-swimlane": "Card Templates",
"list-templates-swimlane": "List Templates",
"board-templates-swimlane": "Board Templates",
"what-to-do": "Què vols fer?",
"wipLimitErrorPopup-title": "Límit de Treball en Progrès invàlid",
"wipLimitErrorPopup-dialog-pt1": "El nombre de tasques en esta llista és superior al límit de Treball en Progrès que heu definit.",
@@ -552,6 +571,8 @@
"activity-added-label-card": "added label '%s'",
"activity-removed-label-card": "removed label '%s'",
"activity-delete-attach-card": "deleted an attachment",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Rule",
"r-add-trigger": "Add trigger",
"r-add-action": "Add action",
@@ -575,7 +596,7 @@
"r-unarchived": "Restored from Archive",
"r-a-card": "a card",
"r-when-a-label-is": "When a label is",
"r-when-the-label-is": "When the label is",
"r-when-the-label": "When the label",
"r-list-name": "list name",
"r-when-a-member": "When a member is",
"r-when-the-member": "When the member",
@@ -648,6 +669,15 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "When a card is moved to another list",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
@@ -659,5 +689,14 @@
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"error-undefined": "Something went wrong",
"error-ldap-login": "An error occurred while trying to login"
"error-ldap-login": "An error occurred while trying to login",
"display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
+101 -62
View File
@@ -1,28 +1,41 @@
{
"accept": "Přijmout",
"act-activity-notify": "Notifikace aktivit",
"act-addAttachment": "přiložen __attachment__ do __card__",
"act-addSubtask": "přidán podúkol __checklist__ do __card__",
"act-addChecklist": "přidán checklist __checklist__ do __card__",
"act-addChecklistItem": "přidán __checklistItem__ do checklistu __checklist__ v __card__",
"act-addComment": "komentář k __card__: __comment__",
"act-createBoard": "přidání __board__",
"act-createCard": "přidání __card__ do __list__",
"act-createCustomField": "vytvořeno vlastní pole __customField__",
"act-createList": "přidání __list__ do __board__",
"act-addBoardMember": "přidání __member__ do __board__",
"act-archivedBoard": "__board__ byl přesunut do archivu",
"act-archivedCard": "__card__ byla přesunuta do archivu",
"act-archivedList": "__list__ byl přesunut do archivu",
"act-archivedSwimlane": "__swimlane__ bylo přesunuto do archivu",
"act-importBoard": "import __board__",
"act-importCard": "import __card__",
"act-importList": "import __list__",
"act-joinMember": "přidání __member__ do __card__",
"act-moveCard": "přesun __card__ z __oldList__ do __list__",
"act-removeBoardMember": "odstranění __member__ z __board__",
"act-restoredCard": "obnovení __card__ do __board__",
"act-unjoinMember": "odstranění __member__ z __card__",
"act-addAttachment": "přidal(a) přílohu __attachment__ na kartu __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-deleteAttachment": "smazal(a) přílohu __attachment__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addSubtask": "přidal(a) podúkol __subtask__ na kartu __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addLabel": "Přídán štítek __label__ na kartu __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addedLabel": "Přídán štítek __label__ na kartu __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-removeLabel": "Odstraněn štítek __label__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-removedLabel": "Odstraněn štítek __label__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addChecklist": "přidal(a) zaškrtávací seznam __checklist__ na kartu __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addChecklistItem": "přidal(a) položku zaškrtávacího seznamu __checklistItem__ do zaškrtávacího seznamu __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-removeChecklist": "smazal(a) zaškrtávací seznam __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-removeChecklistItem": "smazal(a) položku zaškrtávacího seznamu __checklistItem__ ze zaškrtávacího seznamu __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-checkedItem": "zaškrtl(a) __checklistItem__ na zaškrtávacím seznamu __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-uncheckedItem": "zrušil(a) zaškrtnutí __checklistItem__ na zaškrtávacím seznamu __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-completeChecklist": "dokončil(a) zaškrtávací seznam __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-uncompleteChecklist": "zrušil(a) dokončení zaškrtávacího seznamu __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-addComment": "přidal(a) komentář na kartě __card__: __comment__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-createBoard": "přidal(a) tablo __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "přidal(a) kartu __card__ do sloupce __list__ ve swimlane __swimlane__ na tablu __board__",
"act-createCustomField": "vytvořil(a) vlastní pole __customField__ na kartu __card__ do sloupce __list__ ve swimlane __swimlane__ na tablu __board__",
"act-createList": "přidal(a) sloupec __list__ do tabla __board__",
"act-addBoardMember": "přidal(a) člena __member__ do tabla __board__",
"act-archivedBoard": "Tablo __board__ přesunuto do Archivu",
"act-archivedCard": "Karta __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__ přesunuta do Archivu",
"act-archivedList": "Sloupec __list__ ve swimlane __swimlane__ na tablu __board__ přesunut do Archivu",
"act-archivedSwimlane": "Swimlane __swimlane__ na tablu __board__ přesunut do Archivu",
"act-importBoard": "importoval(a) tablo __board__",
"act-importCard": "importoval(a) karta __card__ do sloupce __list__ ve swimlane __swimlane__ na tablu __board__",
"act-importList": "importoval(a) sloupec __list__ do swimlane __swimlane__ na tablu __board__",
"act-joinMember": "přidal(a) člena __member__ na kartu __card__ v seznamu __list__ ve swimlane __swimlane__ na tablu __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "přesunul(a) kartu __card__ ze sloupce __oldList__ ve swimlane __oldSwimlane__ na tablu __oldBoard__ do sloupce __list__ ve swimlane __swimlane__ na tablu __board__",
"act-removeBoardMember": "odstranil(a) člena __member__ z tabla __board__",
"act-restoredCard": "obnovil(a) kartu __card__ do sloupce __list__ ve swimlane __swimlane__ na tablu __board__",
"act-unjoinMember": "odstranil(a) člena __member__ z karty __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"act-withBoardTitle": "__board__",
"act-withCardTitle": "[__board__] __card__",
"actions": "Akce",
@@ -43,19 +56,19 @@
"activity-sent": "%s posláno na %s",
"activity-unjoined": "odpojen %s",
"activity-subtask-added": "podúkol přidán do %s",
"activity-checked-item": "checked %s in checklist %s of %s",
"activity-unchecked-item": "unchecked %s in checklist %s of %s",
"activity-checked-item": "dokončen %s v seznamu %s z %s",
"activity-unchecked-item": "nedokončen %s v seznamu %s z %s",
"activity-checklist-added": "přidán checklist do %s",
"activity-checklist-removed": "odstraněn checklist z %s",
"activity-checklist-completed": "dokončen checklist %s z %s",
"activity-checklist-uncompleted": "uncompleted the checklist %s of %s",
"activity-checklist-completed": "dokončil(a) zaškrtávací seznam __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"activity-checklist-uncompleted": "nedokončen seznam %s z %s",
"activity-checklist-item-added": "přidána položka checklist do '%s' v %s",
"activity-checklist-item-removed": "removed a checklist item from '%s' in %s",
"activity-checklist-item-removed": "odstraněna položka seznamu do '%s' v %s",
"add": "Přidat",
"activity-checked-item-card": "checked %s in checklist %s",
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "dokončen checklist %s",
"activity-checklist-uncompleted-card": "uncompleted the checklist %s",
"activity-checked-item-card": "dokončen %s v seznamu %s",
"activity-unchecked-item-card": "nedokončen %s v seznamu %s",
"activity-checklist-completed-card": "dokončil(a) zaškrtávací seznam __checklist__ na kartě __card__ ve sloupci __list__ ve swimlane __swimlane__ na tablu __board__",
"activity-checklist-uncompleted-card": "nedokončený seznam %s",
"add-attachment": "Přidat přílohu",
"add-board": "Přidat tablo",
"add-card": "Přidat kartu",
@@ -92,6 +105,8 @@
"restore-board": "Obnovit tablo",
"no-archived-boards": "V archivu nejsou žádná tabla.",
"archives": "Archiv",
"template": "Šablona",
"templates": "Šablony",
"assign-member": "Přiřadit člena",
"attached": "přiloženo",
"attachment": "Příloha",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "Přejmenovat tablo",
"boardChangeVisibilityPopup-title": "Upravit viditelnost",
"boardChangeWatchPopup-title": "Změnit sledování",
"boardMenuPopup-title": "Menu tabla",
"boardMenuPopup-title": "Nastavení Tabla",
"boards": "Tabla",
"board-view": "Náhled tabla",
"board-view-cal": "Kalendář",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "Štítky",
"cardMembersPopup-title": "Členové",
"cardMorePopup-title": "Více",
"cardTemplatePopup-title": "Vytvořit šablonu",
"cards": "Karty",
"cards-count": "Karty",
"casSignIn": "Přihlásit pomocí CAS",
@@ -166,33 +182,33 @@
"clipboard": "Schránka nebo potáhnout a pustit",
"close": "Zavřít",
"close-board": "Zavřít tablo",
"close-board-pop": "You will be able to restore the board by clicking the “Archive” button from the home header.",
"close-board-pop": "Budete moci obnovit tablo kliknutím na tlačítko \"Archiv\" v hlavním menu.",
"color-black": "černá",
"color-blue": "modrá",
"color-crimson": "crimson",
"color-darkgreen": "darkgreen",
"color-gold": "gold",
"color-gray": "gray",
"color-crimson": "karmínová",
"color-darkgreen": "tmavě zelená",
"color-gold": "zlatá",
"color-gray": "šedá",
"color-green": "zelená",
"color-indigo": "indigo",
"color-lime": "světlezelená",
"color-magenta": "magenta",
"color-magenta": "purpurová",
"color-mistyrose": "mistyrose",
"color-navy": "navy",
"color-navy": "tmavě modrá",
"color-orange": "oranžová",
"color-paleturquoise": "paleturquoise",
"color-peachpuff": "peachpuff",
"color-pink": "růžová",
"color-plum": "plum",
"color-plum": "švestková",
"color-purple": "fialová",
"color-red": "červená",
"color-saddlebrown": "saddlebrown",
"color-silver": "silver",
"color-silver": "stříbrná",
"color-sky": "nebeská",
"color-slateblue": "slateblue",
"color-white": "white",
"color-white": "bílá",
"color-yellow": "žlutá",
"unset-color": "Unset",
"unset-color": "Nenastaveno",
"comment": "Komentář",
"comment-placeholder": "Text komentáře",
"comment-only": "Pouze komentáře",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Opravdu chcete smazat tento checklist?",
"copy-card-link-to-clipboard": "Kopírovat adresu karty do mezipaměti",
"linkCardPopup-title": "Propojit kartu",
"searchCardPopup-title": "Hledat Kartu",
"searchElementPopup-title": "Hledat",
"copyCardPopup-title": "Kopírovat kartu",
"copyChecklistToManyCardsPopup-title": "Kopírovat checklist do více karet",
"copyChecklistToManyCardsPopup-instructions": "Názvy a popisy cílové karty v tomto formátu JSON",
@@ -332,13 +348,13 @@
"leaveBoardPopup-title": "Opustit tablo?",
"link-card": "Odkázat na tuto kartu",
"list-archive-cards": "Přesunout všechny karty v tomto seznamu do archivu.",
"list-archive-cards-pop": "This will remove all the cards in this list from the board. To view cards in Archive and bring them back to the board, click “Menu” > “Archive”.",
"list-archive-cards-pop": "Toto odstraní z tabla všechny karty z tohoto seznamu. Pro zobrazení karet v Archivu a jejich opětovné obnovení, klikni v \"Menu\" > \"Archiv\".",
"list-move-cards": "Přesunout všechny karty v tomto sloupci",
"list-select-cards": "Vybrat všechny karty v tomto sloupci",
"set-color-list": "Set Color",
"set-color-list": "Nastavit barvu",
"listActionPopup-title": "Vypsat akce",
"swimlaneActionPopup-title": "Akce swimlane",
"swimlaneAddPopup-title": "Add a Swimlane below",
"swimlaneAddPopup-title": "Přidat swimlane dolů",
"listImportCardPopup-title": "Importovat Trello kartu",
"listMorePopup-title": "Více",
"link-list": "Odkaz na tento sloupec",
@@ -416,7 +432,7 @@
"shortcut-show-shortcuts": "Otevřít tento seznam odkazů",
"shortcut-toggle-filterbar": "Přepnout lištu filtrování",
"shortcut-toggle-sidebar": "Přepnout lištu tabla",
"show-cards-minimum-count": "Zobrazit počet karet pokud sloupec obsahuje více než ",
"show-cards-minimum-count": "Zobrazit počet karet pokud sloupec obsahuje více než",
"sidebar-open": "Otevřít boční panel",
"sidebar-close": "Zavřít boční panel",
"signupPopup-title": "Vytvořit účet",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Milník 1",
"welcome-list1": "Základní",
"welcome-list2": "Pokročilé",
"card-templates-swimlane": "Šablony Karty",
"list-templates-swimlane": "Šablony Sloupce",
"board-templates-swimlane": "Šablony Tabla",
"what-to-do": "Co chcete dělat?",
"wipLimitErrorPopup-title": "Neplatný WIP Limit",
"wipLimitErrorPopup-dialog-pt1": "Počet úkolů v tomto sloupci je vyšší než definovaný WIP limit.",
@@ -498,7 +517,7 @@
"OS_Totalmem": "OS Celková paměť",
"OS_Type": "Typ OS",
"OS_Uptime": "OS Doba běhu systému",
"days": "days",
"days": "dní",
"hours": "hodin",
"minutes": "minut",
"seconds": "sekund",
@@ -519,10 +538,10 @@
"card-end-on": "Končí v",
"editCardReceivedDatePopup-title": "Změnit datum přijetí",
"editCardEndDatePopup-title": "Změnit datum konce",
"setCardColorPopup-title": "Set color",
"setCardActionsColorPopup-title": "Choose a color",
"setSwimlaneColorPopup-title": "Choose a color",
"setListColorPopup-title": "Choose a color",
"setCardColorPopup-title": "Nastav barvu",
"setCardActionsColorPopup-title": "Vyber barvu",
"setSwimlaneColorPopup-title": "Vyber barvu",
"setListColorPopup-title": "Vyber barvu",
"assigned-by": "Přidělil(a)",
"requested-by": "Vyžádal(a)",
"board-delete-notice": "Smazání je trvalé. Přijdete o všechny sloupce, karty a akce spojené s tímto tablem.",
@@ -535,7 +554,7 @@
"subtask-settings": "Nastavení podúkolů",
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů tabla",
"show-subtasks-field": "Karty mohou mít podúkoly",
"deposit-subtasks-board": "Deposit subtasks to this board:",
"deposit-subtasks-board": "Vložit podúkoly do tohoto tabla",
"deposit-subtasks-list": "Landing list for subtasks deposited here:",
"show-parent-in-minicard": "Ukázat předka na minikartě",
"prefix-with-full-path": "Prefix s celou cestou",
@@ -552,6 +571,8 @@
"activity-added-label-card": "přidán štítek '%s'",
"activity-removed-label-card": "odstraněn štítek '%s'",
"activity-delete-attach-card": "odstraněna příloha",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Pravidlo",
"r-add-trigger": "Přidat spoštěč",
"r-add-action": "Přidat akci",
@@ -575,7 +596,7 @@
"r-unarchived": "Obnoveno z archivu",
"r-a-card": "karta",
"r-when-a-label-is": "Pokud nějaký štítek je",
"r-when-the-label-is": "Pokud tento štítek je",
"r-when-the-label": "Pokud tento štítek je",
"r-list-name": "název seznamu",
"r-when-a-member": "Pokud nějaký člen je",
"r-when-the-member": "Pokud tento člen je",
@@ -590,8 +611,8 @@
"r-checked": "Zaškrtnuto",
"r-unchecked": "Odškrtnuto",
"r-move-card-to": "Přesunout kartu do",
"r-top-of": "Top of",
"r-bottom-of": "Bottom of",
"r-top-of": "Začátek",
"r-bottom-of": "Spodek",
"r-its-list": "toho sloupce",
"r-archive": "Přesunout do archivu",
"r-unarchive": "Obnovit z archivu",
@@ -601,7 +622,7 @@
"r-label": "štítek",
"r-member": "člen",
"r-remove-all": "Odstranit všechny členy z této karty",
"r-set-color": "Set color to",
"r-set-color": "Nastav barvu na",
"r-checklist": "zaškrtávací seznam",
"r-check-all": "Zaškrtnout vše",
"r-uncheck-all": "Odškrtnout vše",
@@ -648,16 +669,34 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "Když je karta přesunuta do jiného sloupce",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
"authentication-method": "Metoda autentizace",
"authentication-type": "Typ autentizace",
"custom-product-name": "Vlastní název produktu",
"layout": "uspořádání",
"layout": "Uspořádání",
"hide-logo": "Skrýt logo",
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"add-custom-html-after-body-start": "Přidej vlastní HTML za <body>",
"add-custom-html-before-body-end": "Přidej vlastní HTML před </body>",
"error-undefined": "Něco se pokazilo",
"error-ldap-login": "Během přihlašování nastala chyba"
"error-ldap-login": "Během přihlašování nastala chyba",
"display-authentication-method": "Zobraz způsob ověřování",
"default-authentication-method": "Zobraz způsob ověřování",
"duplicate-board": "Duplikovat tablo",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
+67 -28
View File
@@ -1,28 +1,41 @@
{
"accept": "Accepter",
"act-activity-notify": "Activity Notification",
"act-addAttachment": "tilføjede__vedhæftet fil__ til __kort__",
"act-addSubtask": "tilføjede delopgave __tjekliste__ til __kort__",
"act-addChecklist": "tilføjede tjekliste__tjekliste__ til __kort__",
"act-addChecklistItem": "tilføjede__tjeklistePunkt__ til tjekliste__tjekliste__ til__kort__",
"act-addComment": "commented on __card__: __comment__",
"act-createBoard": "created __board__",
"act-createCard": "added __card__ to __list__",
"act-createCustomField": "created custom field __customField__",
"act-createList": "added __list__ to __board__",
"act-addBoardMember": "added __member__ to __board__",
"act-archivedBoard": "__board__ moved to Archive",
"act-archivedCard": "__card__ moved to Archive",
"act-archivedList": "__list__ moved to Archive",
"act-archivedSwimlane": "__swimlane__ moved to Archive",
"act-importBoard": "imported __board__",
"act-importCard": "imported __card__",
"act-importList": "imported __list__",
"act-joinMember": "added __member__ to __card__",
"act-moveCard": "moved __card__ from __oldList__ to __list__",
"act-removeBoardMember": "removed __member__ from __board__",
"act-restoredCard": "restored __card__ to __board__",
"act-unjoinMember": "removed __member__ from __card__",
"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__",
"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__",
"act-removeLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removedLabel": "Removed label __label__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklist": "added checklist __checklist__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addChecklistItem": "added checklist item __checklistItem__ to checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklist": "removed checklist __checklist__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-removeChecklistItem": "removed checklist item __checklistItem__ from checklist __checkList__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-checkedItem": "checked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncheckedItem": "unchecked __checklistItem__ of checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-completeChecklist": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-uncompleteChecklist": "uncompleted checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-addComment": "commented on card __card__: __comment__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createBoard": "created board __board__",
"act-createSwimlane": "created swimlane __swimlane__ to board __board__",
"act-createCard": "created card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-createCustomField": "created custom field __customField__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-createList": "added list __list__ to board __board__",
"act-addBoardMember": "added member __member__ to board __board__",
"act-archivedBoard": "Board __board__ moved to Archive",
"act-archivedCard": "Card __card__ at list __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedList": "List __list__ at swimlane __swimlane__ at board __board__ moved to Archive",
"act-archivedSwimlane": "Swimlane __swimlane__ at board __board__ moved to Archive",
"act-importBoard": "imported board __board__",
"act-importCard": "imported card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-importList": "imported list __list__ to swimlane __swimlane__ at board __board__",
"act-joinMember": "added member __member__ to card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-moveCard": "moved card __card__ at board __board__ from list __oldList__ at swimlane __oldSwimlane__ to list __list__ at swimlane __swimlane__",
"act-moveCardToOtherBoard": "moved card __card__ from list __oldList__ at swimlane __oldSwimlane__ at board __oldBoard__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-removeBoardMember": "removed member __member__ from board __board__",
"act-restoredCard": "restored card __card__ to list __list__ at swimlane __swimlane__ at board __board__",
"act-unjoinMember": "removed member __member__ from card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"act-withBoardTitle": "__board__",
"act-withCardTitle": "[__board__] __card__",
"actions": "Actions",
@@ -47,14 +60,14 @@
"activity-unchecked-item": "unchecked %s in checklist %s of %s",
"activity-checklist-added": "added checklist to %s",
"activity-checklist-removed": "removed a checklist from %s",
"activity-checklist-completed": "completed the checklist %s of %s",
"activity-checklist-completed": "completed checklist __checklist__ at card __card__ at list __list__ at swimlane __swimlane__ at board __board__",
"activity-checklist-uncompleted": "uncompleted the checklist %s of %s",
"activity-checklist-item-added": "added checklist item to '%s' in %s",
"activity-checklist-item-removed": "removed a checklist item from '%s' in %s",
"add": "Add",
"activity-checked-item-card": "checked %s in checklist %s",
"activity-unchecked-item-card": "unchecked %s in checklist %s",
"activity-checklist-completed-card": "completed the checklist %s",
"activity-checklist-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",
"add-attachment": "Add Attachment",
"add-board": "Add Board",
@@ -92,6 +105,8 @@
"restore-board": "Restore Board",
"no-archived-boards": "No Boards in Archive.",
"archives": "Archive",
"template": "Template",
"templates": "Templates",
"assign-member": "Assign member",
"attached": "attached",
"attachment": "Attachment",
@@ -110,7 +125,7 @@
"boardChangeTitlePopup-title": "Rename Board",
"boardChangeVisibilityPopup-title": "Change Visibility",
"boardChangeWatchPopup-title": "Change Watch",
"boardMenuPopup-title": "Board Menu",
"boardMenuPopup-title": "Board Settings",
"boards": "Boards",
"board-view": "Board View",
"board-view-cal": "Calendar",
@@ -143,6 +158,7 @@
"cardLabelsPopup-title": "Labels",
"cardMembersPopup-title": "Members",
"cardMorePopup-title": "More",
"cardTemplatePopup-title": "Create template",
"cards": "Cards",
"cards-count": "Cards",
"casSignIn": "Sign In with CAS",
@@ -204,7 +220,7 @@
"confirm-checklist-delete-dialog": "Are you sure you want to delete checklist?",
"copy-card-link-to-clipboard": "Copy card link to clipboard",
"linkCardPopup-title": "Link Card",
"searchCardPopup-title": "Search Card",
"searchElementPopup-title": "Search",
"copyCardPopup-title": "Copy Card",
"copyChecklistToManyCardsPopup-title": "Copy Checklist Template to Many Cards",
"copyChecklistToManyCardsPopup-instructions": "Destination Card Titles and Descriptions in this JSON format",
@@ -453,6 +469,9 @@
"welcome-swimlane": "Milestone 1",
"welcome-list1": "Basics",
"welcome-list2": "Advanced",
"card-templates-swimlane": "Card Templates",
"list-templates-swimlane": "List Templates",
"board-templates-swimlane": "Board Templates",
"what-to-do": "What do you want to do?",
"wipLimitErrorPopup-title": "Invalid WIP Limit",
"wipLimitErrorPopup-dialog-pt1": "The number of tasks in this list is higher than the WIP limit you've defined.",
@@ -552,6 +571,8 @@
"activity-added-label-card": "added label '%s'",
"activity-removed-label-card": "removed label '%s'",
"activity-delete-attach-card": "deleted an attachment",
"activity-set-customfield": "set custom field '%s' to '%s' in %s",
"activity-unset-customfield": "unset custom field '%s' in %s",
"r-rule": "Rule",
"r-add-trigger": "Add trigger",
"r-add-action": "Add action",
@@ -575,7 +596,7 @@
"r-unarchived": "Restored from Archive",
"r-a-card": "a card",
"r-when-a-label-is": "When a label is",
"r-when-the-label-is": "When the label is",
"r-when-the-label": "When the label",
"r-list-name": "list name",
"r-when-a-member": "When a member is",
"r-when-the-member": "When the member",
@@ -648,6 +669,15 @@
"r-board-note": "Note: leave a field empty to match every possible value.",
"r-checklist-note": "Note: checklist's items have to be written as comma separated values.",
"r-when-a-card-is-moved": "When a card is moved to another list",
"r-set": "Set",
"r-update": "Update",
"r-datefield": "date field",
"r-df-start-at": "start",
"r-df-due-at": "due",
"r-df-end-at": "end",
"r-df-received-at": "received",
"r-to-current-datetime": "to current date/time",
"r-remove-value-from": "Remove value from",
"ldap": "LDAP",
"oauth2": "OAuth2",
"cas": "CAS",
@@ -659,5 +689,14 @@
"add-custom-html-after-body-start": "Add Custom HTML after <body> start",
"add-custom-html-before-body-end": "Add Custom HTML before </body> end",
"error-undefined": "Something went wrong",
"error-ldap-login": "An error occurred while trying to login"
"error-ldap-login": "An error occurred while trying to login",
"display-authentication-method": "Display Authentication Method",
"default-authentication-method": "Default Authentication Method",
"duplicate-board": "Duplicate Board",
"people-number": "The number of people is:",
"swimlaneDeletePopup-title": "Delete Swimlane ?",
"swimlane-delete-pop": "All actions will be removed from the activity feed and you won't be able to recover the swimlane. There is no undo.",
"restore-all": "Restore all",
"delete-all": "Delete all",
"loading": "Loading, please wait."
}
Loaded 100 of 555 files, more files were not shown because too many files have changed in this diff. Show more