Compare commits

...

131 commits
v8.09 ... main

Author SHA1 Message Date
Lauri Ojansivu
0ce8e8b74d
Merge pull request #6043 from wekan/dependabot/github_actions/actions/cache-5
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
Bump actions/cache from 4 to 5
2025-12-16 05:47:09 +02:00
Lauri Ojansivu
4ea53af76e
Merge pull request #6042 from wekan/dependabot/github_actions/actions/download-artifact-7
Bump actions/download-artifact from 6 to 7
2025-12-16 05:46:50 +02:00
Lauri Ojansivu
016f17d663
Merge pull request #6041 from wekan/dependabot/github_actions/actions/upload-artifact-6
Bump actions/upload-artifact from 5 to 6
2025-12-16 05:46:26 +02:00
dependabot[bot]
07f69950a7
Bump actions/cache from 4 to 5
Bumps [actions/cache](https://github.com/actions/cache) from 4 to 5.
- [Release notes](https://github.com/actions/cache/releases)
- [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md)
- [Commits](https://github.com/actions/cache/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/cache
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 20:13:04 +00:00
dependabot[bot]
cec625607d
Bump actions/download-artifact from 6 to 7
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 6 to 7.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '7'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 20:13:00 +00:00
dependabot[bot]
a290c7b34b
Bump actions/upload-artifact from 5 to 6
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-15 20:12:55 +00:00
Lauri Ojansivu
5b77ac1b44 Updated translations
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-12-11 03:33:17 +02:00
Lauri Ojansivu
41c635afb5
Merge pull request #6029 from MialLewis/add_archive_card_to_api
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
Add archive card to api
2025-12-04 11:58:44 +02:00
Lauri Ojansivu
adbf729cb2
Merge pull request #6032 from wekan/dependabot/github_actions/docker/metadata-action-5.10.0
Bump docker/metadata-action from 5.9.0 to 5.10.0
2025-12-04 11:58:02 +02:00
dependabot[bot]
88ea716d63
Bump docker/metadata-action from 5.9.0 to 5.10.0
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.9.0 to 5.10.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](318604b99e...c299e40c65)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 5.10.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-12-01 23:35:03 +00:00
Mial Lewis
003a07ebce change restore to unarchive 2025-11-27 22:00:43 +00:00
Mial Lewis
d3c237bc66 fix more indenting 2025-11-27 08:29:36 +00:00
Mial Lewis
bac0fa81fc correce indent 2025-11-27 08:27:38 +00:00
Mial Lewis
a42915614a add restore to wekan.yml 2025-11-27 08:25:59 +00:00
Mial Lewis
5ff9bf331f add restore to api 2025-11-27 08:23:56 +00:00
Mial Lewis
36d7b0f8a7 correct return values 2025-11-27 00:52:28 +00:00
Mial Lewis
67c8a98f20 add route to wekan.yml 2025-11-27 00:05:53 +00:00
Mial Lewis
a81a603031 update bool to boolean 2025-11-26 23:59:00 +00:00
Mial Lewis
e30ce78053 add archive card to api 2025-11-26 23:57:49 +00:00
Lauri Ojansivu
3d70de94c6
Merge pull request #6028 from wekan/dependabot/github_actions/actions/checkout-6
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
Bump actions/checkout from 5 to 6
2025-11-26 18:04:09 +02:00
dependabot[bot]
70975c2944
Bump actions/checkout from 5 to 6
Bumps [actions/checkout](https://github.com/actions/checkout) from 5 to 6.
- [Release notes](https://github.com/actions/checkout/releases)
- [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/checkout/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/checkout
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-24 20:03:19 +00:00
Lauri Ojansivu
960e2126b4 Updated ChangeLog.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-11-21 03:02:41 +02:00
Lauri Ojansivu
3db1305e58 Updated build script for Linux arm64 bundle.
Thanks to xet7 !
2025-11-21 02:44:50 +02:00
Lauri Ojansivu
f16780b5e3 Updated translations.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-11-19 09:34:57 +02:00
Lauri Ojansivu
37a3065f3c Updated translations.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-11-15 16:35:31 +02:00
Lauri Ojansivu
7ff1649d89 Updated security.md
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-11-14 07:47:31 +02:00
Lauri Ojansivu
a39ae31b45
Merge pull request #6012 from wekan/dependabot/github_actions/docker/metadata-action-5.9.0
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-11-13 17:19:00 +02:00
dependabot[bot]
6302a48221
Bump docker/metadata-action from 5.8.0 to 5.9.0
Bumps [docker/metadata-action](https://github.com/docker/metadata-action) from 5.8.0 to 5.9.0.
- [Release notes](https://github.com/docker/metadata-action/releases)
- [Commits](c1e51972af...318604b99e)

---
updated-dependencies:
- dependency-name: docker/metadata-action
  dependency-version: 5.9.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-10 20:02:19 +00:00
Lauri Ojansivu
c277bee9d2
Merge pull request #6009 from brlin-tw/patch-issue-6008
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
Fix Broken Strikethroughs in Markdown to HTML conversion.
2025-11-10 04:58:29 +02:00
Buo-ren Lin (OSSII)
c5f5ce126d
Fix Broken Strikethroughs in Markdown to HTML conversion.
Allow the s tag to be rendered.

Fixes #6008.

Signed-off-by: Buo-ren Lin (OSSII) <buoren.lin@ossii.com.tw>
2025-11-10 10:49:26 +08:00
Lauri Ojansivu
0004ae716b v8.17
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-11-06 04:00:04 +02:00
Lauri Ojansivu
7f53dfac3c Updated ChangeLog. 2025-11-06 03:33:46 +02:00
Lauri Ojansivu
18003900c2 Fix Worker Permissions does not allow for cards to be moved. - v8.15.
Thanks to xet7 !

Fixes #5990
2025-11-06 03:31:14 +02:00
Lauri Ojansivu
fe104791b5 Updated ChangeLog. 2025-11-06 03:08:51 +02:00
Lauri Ojansivu
6244657ca5 Fix Workspaces at All Boards to have correct count of remaining etc, while starred also at Starred/Favorites.
Thanks to xet7 !
2025-11-06 03:06:16 +02:00
Lauri Ojansivu
46866dac85 Updated ChangeLog. 2025-11-06 02:46:52 +02:00
Lauri Ojansivu
c829c073cf Remove not working Bookmark menu option.
Thanks to xet7 !
2025-11-06 02:44:30 +02:00
Lauri Ojansivu
0772ca4036 Updated ChangeLog. 2025-11-06 02:36:10 +02:00
Lauri Ojansivu
581733d605 Fix Regression - Show calendar popup at set due date.
Thanks to xet7 !

Fixes #5978
2025-11-06 02:32:34 +02:00
Lauri Ojansivu
b02af27ac3 Updated ChangeLog. 2025-11-06 01:06:19 +02:00
Lauri Ojansivu
20af0a2ef5 Try to fix Edit Custom Fields button not working. Removed duplicate option from Boards Settings.
Thanks to xet7 !

Fixes #5988
2025-11-06 01:04:20 +02:00
Lauri Ojansivu
c58ab5b07d Updated ChangeLog. 2025-11-06 00:37:42 +02:00
Lauri Ojansivu
e5e711c938 Fix Card emoji issues.
Thanks to xet7 !

Fixes #5995
2025-11-06 00:35:49 +02:00
Lauri Ojansivu
42594abe4e Updated ChangeLog. 2025-11-06 00:30:08 +02:00
Lauri Ojansivu
0afbdc95b4 Feature: Workspaces, at All Boards page.
Thanks to xet7 !
2025-11-06 00:26:35 +02:00
Lauri Ojansivu
16a74bb748 Updated ChangeLog.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-11-05 20:51:44 +02:00
Lauri Ojansivu
8711b476be Fix star board.
Thanks to xet7 !
2025-11-05 20:50:28 +02:00
Lauri Ojansivu
df9fba4765 Updated translations. 2025-11-05 20:26:29 +02:00
Lauri Ojansivu
7d27139aa9 Updated ChangeLog. 2025-11-05 20:25:07 +02:00
Lauri Ojansivu
e4638d5fbc Fixed sidebar migrations to be per-board, not global. Clarified translations.
Thanks to xet7 !
2025-11-05 20:22:56 +02:00
Lauri Ojansivu
bc5854dd29 Updated ChangeLog. 2025-11-05 19:04:47 +02:00
Lauri Ojansivu
ba49d4d140 Remove old translations and code not in use anymore.
Thanks to xet7 !
2025-11-05 19:03:21 +02:00
Lauri Ojansivu
71b7dcffb5 Updated ChangeLog. 2025-11-05 18:46:56 +02:00
Lauri Ojansivu
7713e613b4 Fix 8.16 Lists with no items are deleted every time when board is opened. Moved migrations to right sidebar.
Thanks to xet7 !

Fixes #5994
2025-11-05 18:44:48 +02:00
Lauri Ojansivu
91a0aa7387 Updated ChangeLog. 2025-11-05 17:08:52 +02:00
Lauri Ojansivu
fbd6b920ef Updated ChangeLog. 2025-11-05 17:08:10 +02:00
Lauri Ojansivu
1b25d1d572 Moved migrations from opening board to right sidebar / Migrations.
Thanks to xet7 !
2025-11-05 17:06:26 +02:00
Lauri Ojansivu
e93e72234c Updated ChangeLog. 2025-11-05 16:38:10 +02:00
Lauri Ojansivu
15d9b0ae3a Updated ChangeLog. 2025-11-05 16:38:03 +02:00
Lauri Ojansivu
550d87ac6c Fix 8.16: Switching Board View fails with 403 error.
Thanks to xet7 !
2025-11-05 16:35:29 +02:00
Lauri Ojansivu
f8e576e890 Try to fix Snap.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
Thanks to xet7 !
2025-11-02 22:23:16 +02:00
Lauri Ojansivu
fb8ef4d978 Try to fix Snap.
Thanks to xet7 !
2025-11-02 21:36:17 +02:00
Lauri Ojansivu
5127e87898 Try to fix Snap.
Thanks to xet7 !
2025-11-02 21:33:06 +02:00
Lauri Ojansivu
3f2d4444e4 Try to fix Snap. Part 2.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
Thanks to xet7 !
2025-11-02 16:14:45 +02:00
Lauri Ojansivu
9c7badb0eb Merge branch 'main' of github.com:wekan/wekan 2025-11-02 16:04:16 +02:00
Lauri Ojansivu
9d9f77a731 Try to fix Snap.
Thanks to xet7 !
2025-11-02 16:02:53 +02:00
Lauri Ojansivu
c400ce74b1 v8.16 2025-11-02 12:09:27 +02:00
Lauri Ojansivu
c2e20ee4a3 Updated ChangeLog.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-11-02 11:43:33 +02:00
Lauri Ojansivu
ccd9034339 Fix SECURITY ISSUE 5: Attachment API uses bearer value as userId and DoS (Low).
Thanks to Siam Thanat Hack (STH) and xet7 !
2025-11-02 11:42:07 +02:00
Lauri Ojansivu
0a1a075f31 Fix SECURITY ISSUE 4: Members can forge others’ votes (Low). Bonus: Similar fixes to planning poker too done by xet7.
Thanks to Siam Thanat Hack (STH) and xet7 !
2025-11-02 11:12:41 +02:00
Lauri Ojansivu
4aaeec9515 Updated ChangeLog. 2025-11-02 10:17:33 +02:00
Lauri Ojansivu
ea310d7508 Fix SECURITY ISSUE 3: Unauthenticated (or any) user can update board sort.
Thanks to Siam Thanat Hack (STH) !
2025-11-02 10:13:45 +02:00
Lauri Ojansivu
0a2e6a0c38 Updated ChangeLog. 2025-11-02 09:20:28 +02:00
Lauri Ojansivu
f26d582018 Fix SECURITY ISSUE 2: Access to boards of any Orgs/Teams, and avatar permissions.
Thanks to Siam Thanat Hack (STH) !
2025-11-02 09:11:50 +02:00
Lauri Ojansivu
e9a727301d Fix SECURITY ISSUE 1: File Attachments enables stored XSS (High).
Thanks to Siam Thanat Hack (STH) !
2025-11-02 08:36:29 +02:00
Lauri Ojansivu
d64d2f9c42 Updated translations. 2025-11-02 07:30:24 +02:00
Lauri Ojansivu
5c0d122e84 Updated funding 2025-11-02 06:15:08 +02:00
Lauri Ojansivu
5079c853a7 Updated translations.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-10-29 02:58:00 +02:00
Lauri Ojansivu
b039ba12a2
Merge pull request #5984 from wekan/dependabot/github_actions/actions/download-artifact-6
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
Bump actions/download-artifact from 5 to 6
2025-10-28 06:00:19 +02:00
Lauri Ojansivu
3323ac6ac1
Merge pull request #5983 from wekan/dependabot/github_actions/actions/upload-artifact-5
Bump actions/upload-artifact from 4 to 5
2025-10-28 05:59:59 +02:00
dependabot[bot]
3204311ac1
Bump actions/download-artifact from 5 to 6
Bumps [actions/download-artifact](https://github.com/actions/download-artifact) from 5 to 6.
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](https://github.com/actions/download-artifact/compare/v5...v6)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 23:12:09 +00:00
dependabot[bot]
0fc2ad97cd
Bump actions/upload-artifact from 4 to 5
Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 4 to 5.
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](https://github.com/actions/upload-artifact/compare/v4...v5)

---
updated-dependencies:
- dependency-name: actions/upload-artifact
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-10-27 20:32:10 +00:00
Lauri Ojansivu
30620d0ca4 Some migrations and mobile fixes.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
Thanks to xet7 !
2025-10-25 21:09:07 +03:00
Lauri Ojansivu
bccc22c5fe Updated ChangeLog. 2025-10-25 19:25:04 +03:00
Lauri Ojansivu
ecf2418347 Fix changing swimlane color to not reload webpage.
Thanks to xet7 !
2025-10-25 19:23:35 +03:00
Lauri Ojansivu
0c99cb3103 Updated ChangeLog. 2025-10-25 19:19:35 +03:00
Lauri Ojansivu
034dc08269 Disabled migrations that happen when opening board. Defaulting to per-swimlane lists and drag drop list to same or different swimlane.
Thanks to xet7 !
2025-10-25 19:17:09 +03:00
Lauri Ojansivu
d1a51b42f6 Updated translations.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-10-24 18:43:21 +03:00
Lauri Ojansivu
92bfbb2d0c Updated ChangeLog.
Some checks failed
Docker / build (push) Has been cancelled
Docker Image CI / build (push) Has been cancelled
Release Charts / release (push) Has been cancelled
Test suite / Meteor tests (push) Has been cancelled
Test suite / Coverage report (push) Has been cancelled
2025-10-23 05:54:25 +03:00
Lauri Ojansivu
91b846e2cd List menu / More / Delete duplicate lists that do not have any cards.
Thanks to xet7 !
2025-10-23 05:50:43 +03:00
Lauri Ojansivu
7fe7fb4c15 v8.15 2025-10-23 04:41:34 +03:00
Lauri Ojansivu
0cebd8aa4d Fix drag lists did not work. Part 2.
Thanks to xet7 !
2025-10-23 04:35:33 +03:00
Lauri Ojansivu
8662c96d1c Fix drag lists did not work.
Thanks to xet7 !
2025-10-23 04:33:34 +03:00
Lauri Ojansivu
0cbc9402f3 v8.14 2025-10-23 04:09:14 +03:00
Lauri Ojansivu
940df02456 Updated translations. 2025-10-23 04:08:49 +03:00
Lauri Ojansivu
b4b598f542 Fix board reloading page every second.
Thanks to xet7 !
2025-10-23 04:03:52 +03:00
Lauri Ojansivu
ef19c35b5a v8.12 2025-10-23 03:29:23 +03:00
Lauri Ojansivu
fc98120269 Updated translations. 2025-10-23 03:24:28 +03:00
Lauri Ojansivu
b8a3d6deaf Updated ChangeLog. 2025-10-23 03:17:13 +03:00
Lauri Ojansivu
45537ede87 Fix UI issues of Right Sidebar / Subtasks Settings and Card Settings.
Thanks to xet7 !

Fixes #5971
2025-10-23 03:15:26 +03:00
Lauri Ojansivu
29a9c5bc7b Updated ChangeLog. 2025-10-23 01:02:15 +03:00
Lauri Ojansivu
7ca81285b1 Fix opened card Date Format to be used at dates popups.
Thanks to xet7 !

Related #5971
2025-10-23 01:00:11 +03:00
Lauri Ojansivu
49a865cdbf Updated ChangeLog. 2025-10-23 00:48:31 +03:00
Lauri Ojansivu
a0c30c35ed Removed not needed | at left side of minicard badges.
Thanks to xet7 !
2025-10-23 00:47:18 +03:00
Lauri Ojansivu
de20424885 Updated translations. 2025-10-23 00:38:34 +03:00
Lauri Ojansivu
f7e09ae89c Updated ChangeLog. 2025-10-23 00:36:17 +03:00
Lauri Ojansivu
c6d4600683 Fix unable to add members to board.
Fixes #5972
2025-10-23 00:34:19 +03:00
Lauri Ojansivu
bd1837ee36 Updated ChangeLog. 2025-10-23 00:16:27 +03:00
Lauri Ojansivu
544b24ceb1 Fix Regression - unable to rearrange tasks within a checklist - v8.11.
Thanks to xet7 !

Fixes #5973
2025-10-23 00:14:30 +03:00
Lauri Ojansivu
0825374183 Updated translations.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-10-22 23:56:23 +03:00
Lauri Ojansivu
b053fb8e61 Updated ChangeLog. 2025-10-22 23:33:38 +03:00
Lauri Ojansivu
ae11e80bde Fix Regression - unable to view cards by due date v8.11.
Thanks to xet7 !

Fixes #5964
2025-10-22 23:31:36 +03:00
Lauri Ojansivu
8e296231ba Updated translations. 2025-10-22 22:59:35 +03:00
Lauri Ojansivu
49891eff36 Updated ChangeLog.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-10-21 15:34:07 +03:00
Lauri Ojansivu
58df525b49 Fix duplicated lists and do not show debug messages when env DEBUG is not true. Part 3.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:31:34 +03:00
Lauri Ojansivu
1761f43afa Merge newest changes.
Some checks are pending
Docker / build (push) Waiting to run
Docker Image CI / build (push) Waiting to run
Release Charts / release (push) Waiting to run
Test suite / Meteor tests (push) Waiting to run
Test suite / Coverage report (push) Blocked by required conditions
2025-10-21 15:22:55 +03:00
Lauri Ojansivu
37d7d938c5 Updated ChangeLog. 2025-10-21 15:21:25 +03:00
Lauri Ojansivu
b7ca2310b2 Fix duplicated lists.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:19:19 +03:00
Lauri Ojansivu
c562b3969a v8.11 2025-10-21 15:17:53 +03:00
Lauri Ojansivu
d1d553e8d7 Updated ChangeLog. 2025-10-21 15:15:15 +03:00
Lauri Ojansivu
b6e7b258e0 Fix duplicated lists.
Thanks to xet7 !

Fixes #5952
2025-10-21 15:14:01 +03:00
Lauri Ojansivu
c7bbe47221 Updated ChangeLog. 2025-10-21 15:10:07 +03:00
Lauri Ojansivu
347fa9e5cd Fix Regression - due date taking a while to load all cards v8.06.
Thanks to xet7 !

Fixes #5955
2025-10-21 15:08:50 +03:00
Lauri Ojansivu
07ce151508 Updated ChangeLog. 2025-10-21 15:04:01 +03:00
Lauri Ojansivu
665c9b5e52 Verify that due background colors are correct also at My Due Cards.
Thanks to xet7 !
2025-10-21 15:02:39 +03:00
Lauri Ojansivu
9399a0c545 Updated ChangeLog. 2025-10-21 14:59:48 +03:00
Lauri Ojansivu
a540b12895 Fix My Due Cards to be sorted by due date, oldest first.
Thanks to xet7 !

Fixes #5956
2025-10-21 14:57:57 +03:00
Lauri Ojansivu
e29d9dcd17 Updated ChangeLog. 2025-10-21 14:49:59 +03:00
Lauri Ojansivu
1aa0d84977 Fix due dates to use colors: red = overdue, amber = due soon, no shade = not due yet.
Thanks to xet7 !

Fixes #5963
2025-10-21 14:47:57 +03:00
Lauri Ojansivu
7f31d7c812 v8.10 2025-10-21 14:15:16 +03:00
Lauri Ojansivu
4987a95d8e Prevent opened board re-migrating and reloading every 5 seconds.
Thanks to xet7 !
2025-10-21 14:12:12 +03:00
243 changed files with 22949 additions and 3556 deletions

1
.github/FUNDING.yml vendored
View file

@ -1,3 +1,4 @@
# These are supported funding model platforms # These are supported funding model platforms
github: wekan
custom: ['https://wekan.fi/commercial-support/'] custom: ['https://wekan.fi/commercial-support/']

View file

@ -9,6 +9,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: 'Checkout Repository' - name: 'Checkout Repository'
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: 'Dependency Review' - name: 'Dependency Review'
uses: actions/dependency-review-action@v4 uses: actions/dependency-review-action@v4

View file

@ -32,7 +32,7 @@ jobs:
steps: steps:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@v5 uses: actions/checkout@v6
# Login against a Docker registry except on PR # Login against a Docker registry except on PR
# https://github.com/docker/login-action # https://github.com/docker/login-action
@ -48,7 +48,7 @@ jobs:
# https://github.com/docker/metadata-action # https://github.com/docker/metadata-action
- name: Extract Docker metadata - name: Extract Docker metadata
id: meta id: meta
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
with: with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

View file

@ -15,6 +15,6 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- uses: actions/checkout@v5 - uses: actions/checkout@v6
- name: Build the Docker image - name: Build the Docker image
run: docker build . --file Dockerfile --tag wekan:$(date +%s) run: docker build . --file Dockerfile --tag wekan:$(date +%s)

View file

@ -15,7 +15,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v6
with: with:
fetch-depth: 0 fetch-depth: 0

View file

@ -18,7 +18,7 @@ jobs:
# runs-on: ubuntu-latest # runs-on: ubuntu-latest
# steps: # steps:
# - name: checkout # - name: checkout
# uses: actions/checkout@v5 # uses: actions/checkout@v6
# #
# - name: setup node # - name: setup node
# uses: actions/setup-node@v1 # uses: actions/setup-node@v1
@ -42,7 +42,7 @@ jobs:
# needs: [lintcode] # needs: [lintcode]
# steps: # steps:
# - name: checkout # - name: checkout
# uses: actions/checkout@v5 # uses: actions/checkout@v6
# #
# - name: setup node # - name: setup node
# uses: actions/setup-node@v1 # uses: actions/setup-node@v1
@ -65,7 +65,7 @@ jobs:
# needs: [lintcode,lintstyle] # needs: [lintcode,lintstyle]
# steps: # steps:
# - name: checkout # - name: checkout
# uses: actions/checkout@v5 # uses: actions/checkout@v6
# #
# - name: setup node # - name: setup node
# uses: actions/setup-node@v1 # uses: actions/setup-node@v1
@ -90,12 +90,12 @@ jobs:
# CHECKOUTS # CHECKOUTS
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v6
# CACHING # CACHING
- name: Install Meteor - name: Install Meteor
id: cache-meteor-install id: cache-meteor-install
uses: actions/cache@v4 uses: actions/cache@v5
with: with:
path: ~/.meteor path: ~/.meteor
key: v1-meteor-${{ hashFiles('.meteor/versions') }} key: v1-meteor-${{ hashFiles('.meteor/versions') }}
@ -104,7 +104,7 @@ jobs:
- name: Cache NPM dependencies - name: Cache NPM dependencies
id: cache-meteor-npm id: cache-meteor-npm
uses: actions/cache@v4 uses: actions/cache@v5
with: with:
path: ~/.npm path: ~/.npm
key: v1-npm-${{ hashFiles('package-lock.json') }} key: v1-npm-${{ hashFiles('package-lock.json') }}
@ -113,7 +113,7 @@ jobs:
- name: Cache Meteor build - name: Cache Meteor build
id: cache-meteor-build id: cache-meteor-build
uses: actions/cache@v4 uses: actions/cache@v5
with: with:
path: | path: |
.meteor/local/resolver-result-cache.json .meteor/local/resolver-result-cache.json
@ -136,7 +136,7 @@ jobs:
run: sh ./test-wekan.sh -cv run: sh ./test-wekan.sh -cv
- name: Upload coverage - name: Upload coverage
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v6
with: with:
name: coverage-folder name: coverage-folder
path: .coverage/ path: .coverage/
@ -147,10 +147,10 @@ jobs:
needs: [tests] needs: [tests]
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v5 uses: actions/checkout@v6
- name: Download coverage - name: Download coverage
uses: actions/download-artifact@v5 uses: actions/download-artifact@v7
with: with:
name: coverage-folder name: coverage-folder
path: .coverage/ path: .coverage/

View file

@ -22,6 +22,157 @@ Fixing other platforms In Progress.
WeKan 8.00-8.06 had wrong raw database directory setting /var/snap/wekan/common/wekan and some cards were not visible. WeKan 8.00-8.06 had wrong raw database directory setting /var/snap/wekan/common/wekan and some cards were not visible.
Those are fixed at WeKan 8.07 where database directory is back to /var/snap/wekan/common and all cards are visible. Those are fixed at WeKan 8.07 where database directory is back to /var/snap/wekan/common and all cards are visible.
# Upcoming WeKan ® release
This release adds the following updates:
- [Update GitHub docker/metadata-action from 5.8.0 to 5.9.0](https://github.com/wekan/wekan/pull/6012).
Thanks to dependabot.
- [Updated security.md](https://github.com/wekan/wekan/commit/7ff1649d8909917cae590c68def6eecac0442f91).
Thanks to xet7.
- [Updated build script for Linux arm64 bundle](https://github.com/wekan/wekan/commit/3db1305e58168f7417023ccd8d54995026844b18).
Thanks to xet7.
and fixes the following bugs:
- [Fix Broken Strikethroughs in Markdown to HTML conversion](https://github.com/wekan/wekan/pull/6009).
Thanks to brlin-tw.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.17 2025-11-06 WeKan ® release
This release adds the following new feature:
- [Feature: Workspaces, at All Boards page](https://github.com/wekan/wekan/commit/0afbdc95b49537e06b4f9cf98f51a669ef249384).
Thanks to xet7.
and fixes the following bugs:
- [Fix 8.16: Switching Board View fails with 403 error](https://github.com/wekan/wekan/commit/550d87ac6cb3ec946600616485afdbd242983ab4).
Thanks to xet7.
- [Moved migrations from opening board to right sidebar / Migrations](https://github.com/wekan/wekan/commit/1b25d1d5720d4f486a10d2acce37e315cf9b6057).
Thanks to xet7.
- [Fix 8.16 Lists with no items are deleted every time when board is opened. Moved migrations to right sidebar](https://github.com/wekan/wekan/commit/7713e613b431e44dc13cee72e7a1e5f031473fa6).
Thanks to xet7.
- [Remove old translations and code not in use anymore](https://github.com/wekan/wekan/commit/ba49d4d140bc0d4cfb5a96db9ab077bc85db58f1).
Thanks to xet7.
- [Fixed sidebar migrations to be per-board, not global. Clarified translations](https://github.com/wekan/wekan/commit/e4638d5fbcbe004ac393462331805cac3ba25097).
Thanks to xet7.
- [Fix star board](https://github.com/wekan/wekan/commit/8711b476be30496b96b845529b5717bb6e685c27).
Thanks to xet7.
- [Fix Card emoji issues](https://github.com/wekan/wekan/commit/e5e711c938edcca23c974c3eec97296898bcf24e).
Thanks to xet7.
- [Try to fix Edit Custom Fields button not working. Removed duplicate option from Boards Settings](https://github.com/wekan/wekan/commit/20af0a2ef55b11e7205845859ee92a929616ce91).
Thanks to xet7.
- [Fix Regression - calendar popup to set due date has gone](https://github.com/wekan/wekan/commit/581733d605b7e0494e72229c45947cff134f6dd6).
Thanks to xet7.
- [Remove not working Bookmark menu option](https://github.com/wekan/wekan/commit/c829c073cf822e48b7cd84bbfb79d42867412517).
Thanks to xet7.
- [Fix Workspaces at All Boards to have correct count of remaining etc, while starred also at Starred/Favorites](https://github.com/wekan/wekan/commit/6244657ca53a54646ec01e702851a51d89bd0d55).
Thanks to xet7.
- [Fix Worker Permissions does not allow for cards to be moved. - v8.15. Removed buttons Worker should not use](https://github.com/wekan/wekan/commit/18003900c2d497c129793d1653d4d9872a2f19da).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.16 2025-11-02 WeKan ® release
This release fixes SpaceBleed that is the following CRITICAL SECURITY ISSUES:
- [Fix SECURITY ISSUE 1: File Attachments enables stored XSS (High)](https://github.com/wekan/wekan/commit/e9a727301d7b4f1689a703503df668c0f4f4cab8).
Thanks to Siam Thanat Hack (STH) and xet7.
- [Fix SECURITY ISSUE 2: Access to boards of any Orgs/Teams, and avatar permissions](https://github.com/wekan/wekan/commit/f26d58201855e861bab1cd1fda4d62c664efdb81).
Thanks to Siam Thanat Hack (STH) and xet7.
- [Fix SECURITY ISSUE 3: Unauthenticated (or any) user can update board sort](https://github.com/wekan/wekan/commit/ea310d7508b344512e5de0dfbc9bdfd38145c5c5).
Thanks to Siam Thanat Hack (STH) and xet7.
- [Fix SECURITY ISSUE 4: Members can forge others votes (Low). Bonus: Similar fixes to planning poker too done by xet7](https://github.com/wekan/wekan/commit/0a1a075f3153e71d9a858576f1c68d2925230d9c).
Thanks to Siam Thanat Hack (STH) and xet7.
- [Fix SECURITY ISSUE 5: Attachment API uses bearer value as userId and DoS (Low)](https://github.com/wekan/wekan/commit/ccd90343394f433b287733ad0a33c08e0a71f53c).
Thanks to Siam Thanat Hack (STH) and xet7.
and adds the following new features:
- [List menu / More / Delete duplicate lists that do not have any cards](https://github.com/wekan/wekan/commit/91b846e2cdee9154b045d11b4b4c1a7ae1d79016).
Thanks to xet7.
- [Disabled migrations that happen when opening board. Defaulting to per-swimlane lists and drag drop list to same or different swimlane](https://github.com/wekan/wekan/commit/034dc08269520ca31c780cce64e0150969e9228e).
Thanks to xet7.
and fixes the following bugs:
- [Fix changing swimlane color to not reload webpage](https://github.com/wekan/wekan/commit/ecf2418347cae4329deb292b534f68eb099d3f90).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.15 2025-10-23 WeKan ® release
This release fixes the following bugs:
- Fix drag lists did not work
[Part 1](https://github.com/wekan/wekan/commit/8662c96d1c8d4fa76ce7b31eb06678ad59c3ebe1),
[Part 2](https://github.com/wekan/wekan/commit/0cebd8aa4dbe0bf2418b814716744ab806b671c2).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.14 2025-10-23 WeKan ® release
This release fixes the following bugs:
- [Fix board reloading page every second](https://github.com/wekan/wekan/commit/b4b598f542d0cefc5f2d5d6c7286f0a312cf6a55).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.12 2025-10-23 WeKan ® release
This release fixes the following bugs:
- [Fix Regression - unable to view cards by due date v8.11](https://github.com/wekan/wekan/commit/ae11e80bde79d9ad412d185f20e5a7f802685260).
Thanks to xet7.
- [Fix Regression - unable to rearrange tasks within a checklist - v8.11](https://github.com/wekan/wekan/commit/544b24ceb1687e5b568d8c7b74403a5a2e3f6bc6).
Thanks to xet7.
- [Fix unable to add members to board](https://github.com/wekan/wekan/commit/c6d46006837a29fb311e444f94fa65f236e23bc7).
Thanks to xet7.
- [Removed not needed | at left side of minicard badges](https://github.com/wekan/wekan/commit/a0c30c35ed57113df041ef1020d3e9e5449f35e4).
Thanks to xet7.
- [Fix opened card Date Format to be used at dates popups](https://github.com/wekan/wekan/commit/7ca81285b14d1ec60d6e7e9c191d1194950f18c8).
Thanks to xet7.
- [Fix UI issues of Right Sidebar / Subtasks Settings and Card Settings](https://github.com/wekan/wekan/commit/45537ede870eca59ad72cd7ad013a12f60032df4).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.11 2025-10-21 WeKan ® release
This release fixes the following bugs:
- [Fix due dates to use colors: red = overdue, amber = due soon, no shade = not due yet](https://github.com/wekan/wekan/commit/1aa0d849775fbd0dfc83fa8e4cdca84d22a15042).
Thanks to xet7.
- [Fix My Due Cards to be sorted by due date, oldest first](https://github.com/wekan/wekan/commit/a540b12895520f398bce10bd244f733d221975d4).
Thanks to xet7.
- [Verify that due background colors are correct also at My Due Cards](https://github.com/wekan/wekan/commit/665c9b5e522e73115a1515ced066037110db84e1).
Thanks to xet7.
- [Fix Regression - due date taking a while to load all cards v8.06](https://github.com/wekan/wekan/commit/347fa9e5cd89d064ebb8ab544e20a41f52206db6).
Thanks to xet7.
- Fix duplicated lists.
[Part 1](https://github.com/wekan/wekan/commit/b6e7b258e0e8caecafc553dceb5771985992a0f9),
[Part 2](https://github.com/wekan/wekan/commit/b7ca2310b2cdec7db204229b2d5b9f95b6da8c7d),
[Part 3](https://github.com/wekan/wekan/commit/58df525b4915a99d0f603cc2536fd1fad1d20b29).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.10 2025-10-21 WeKan ® release
This release fixes the following bugs:
- [Prevent opened board re-migrating and reloading every 5 seconds](https://github.com/wekan/wekan/commit/4987a95d8e35fc4cd30010fd17722ee94037d7f2).
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.
# v8.09 2025-10-21 WeKan ® release # v8.09 2025-10-21 WeKan ® release
This release fixes the following bugs: This release fixes the following bugs:

View file

@ -249,9 +249,9 @@ cd /home/wekan/app
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc. # Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
#rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy #rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy
#mv /home/wekan/app_build/bundle /build #mv /home/wekan/app_build/bundle /build
wget "https://github.com/wekan/wekan/releases/download/v8.09/wekan-8.09-amd64.zip" wget "https://github.com/wekan/wekan/releases/download/v8.17/wekan-8.17-amd64.zip"
unzip wekan-8.09-amd64.zip unzip wekan-8.17-amd64.zip
rm wekan-8.09-amd64.zip rm wekan-8.17-amd64.zip
mv /home/wekan/app/bundle /build mv /home/wekan/app/bundle /build
# Put back the original tar # Put back the original tar

View file

@ -1,12 +1,20 @@
About money, see [CONTRIBUTING.md](CONTRIBUTING.md)
Security is very important to us. If you discover any issue regarding security, please disclose ## Responsible Security Disclosure
the information responsibly by sending an email from Protonmail to security@wekan.fi
that is Protomail email address, or by using this PGP key
[security-at-wekan.fi.asc](security-at-wekan.fi.asc) to security@wekan.fi
and not by creating a GitHub issue. We will respond swiftly to fix verifiable security issues.
We thank you with a place at our hall of fame page, that is at https://wekan.fi/hall-of-fame - To send email, use [ProtonMail](https://proton.me) email address or use PGP key [security-at-wekan.fi.asc](security-at-wekan.fi.asc)
- Send info about security issue ONLY to security@wekan.fi (that is Protomail email address). NOT TO ANYWHERE ELSE. NO CC, NO BCC.
- Wait for new WeKan release that fixes security issue
- If you approve, we thank you by adding you to Hall of Fame: https://wekan.fi/hall-of-fame/
## Bonus Points
- If you include code for fixing security issue
## Losing Points
- If you ask about [bounty](CONTRIBUTING.md). There is no bounty. WeKan is NOT Big Tech. WeKan is FLOSS.
- If you forget to include vulnerability details.
- If you send info about security issue to somewhere else than security@wekan.fi
## How should reports be formatted? ## How should reports be formatted?
@ -26,7 +34,7 @@ CWSS (optional): %cwss
Anyone who reports a unique security issue in scope and does not disclose it to Anyone who reports a unique security issue in scope and does not disclose it to
a third party before we have patched and updated may be upon their approval a third party before we have patched and updated may be upon their approval
added to the Wekan Hall of Fame. added to the WeKan Hall of Fame https://wekan.fi/hall-of-fame/
## Which domains are in scope? ## Which domains are in scope?
@ -63,11 +71,6 @@ and by by companies that have 30k users.
- If you are thinking about TLS MITM, look at https://github.com/caddyserver/caddy/issues/2530 - If you are thinking about TLS MITM, look at https://github.com/caddyserver/caddy/issues/2530
- Let's Encrypt TLS requires publicly accessible webserver, that Let's Encrypt TLS validation servers check. - Let's Encrypt TLS requires publicly accessible webserver, that Let's Encrypt TLS validation servers check.
- If firewall limits to only allowed IP addresses, you may need non-Let's Encrypt TLS cert. - If firewall limits to only allowed IP addresses, you may need non-Let's Encrypt TLS cert.
- For On Premise:
- https://caddyserver.com/docs/automatic-https#local-https
- https://github.com/wekan/wekan/wiki/Caddy-Webserver-Config
- https://github.com/wekan/wekan/wiki/Azure
- https://github.com/wekan/wekan/wiki/Traefik-and-self-signed-SSL-certs
## XSS ## XSS
@ -172,6 +175,57 @@ Meteor.startup(() => {
- https://github.com/wekan/wekan/blob/main/client/components/cards/attachments.js#L303-L312 - https://github.com/wekan/wekan/blob/main/client/components/cards/attachments.js#L303-L312
- https://wekan.github.io/hall-of-fame/filebleed/ - https://wekan.github.io/hall-of-fame/filebleed/
### Attachments: Forced download to prevent stored XSS
- To prevent browser-side execution of uploaded content under the app origin, all attachment downloads are served with safe headers:
- `Content-Type: application/octet-stream`
- `Content-Disposition: attachment`
- `X-Content-Type-Options: nosniff`
- A restrictive `Content-Security-Policy` with `sandbox`
- This means attachments are downloaded instead of rendered inline by default. This mitigates HTML/JS/SVG based stored XSS vectors.
- Avatars and inline images remain supported but SVG uploads are blocked and never rendered inline.
## Users: Client update restrictions
- Client-side updates to user documents are limited to safe fields only:
- `username`
- `profile.*`
- Sensitive fields are blocked from any client updates and can only be modified by server methods with authorization:
- `orgs`, `teams`, `roles`, `isAdmin`, `createdThroughApi`, `loginDisabled`, `authenticationMethod`, `services.*`, `emails.*`, `sessionData.*`
- Attempts to update forbidden fields from the client are denied.
- Admin operations like managing org/team membership or toggling flags must use server methods that check permissions.
## Voting: integrity and authorization
- Client updates to card `vote` fields are blocked to prevent forged votes and inconsistent policy enforcement.
- Voting is performed via a server method that enforces:
- Authentication and board membership, or an explicit per-card flag allowing non-members to vote.
- Only the caller's own userId is added/removed from `vote.positive`/`vote.negative`.
- This prevents members from fabricating other users' votes and ensures non-members cannot vote unless explicitly allowed.
## Planning Poker: integrity and authorization
- Client updates to card `poker` fields are blocked. All poker actions go through server methods that enforce:
- Authentication and board membership for configuration and results.
- For casting a poker vote, either board membership or an explicit per-card flag allowing non-members to participate.
- Only the caller's own userId is added/removed from the selected estimation bucket (e.g., one, two, five, etc.).
- Methods cover setting/unsetting poker question/end, casting votes, replaying, and setting final estimation.
## Attachment API: authentication and DoS prevention
- The attachment API (`/api/attachment/*`) requires proper authentication using `X-User-Id` and `X-Auth-Token` headers.
- Authentication validates tokens by hashing with `Accounts._hashLoginToken` and matching against stored login tokens, preventing identity spoofing.
- Request handlers implement:
- 30-second timeout to prevent hanging connections.
- Request body size limits (50MB for uploads, 10MB for metadata operations).
- Proper error handling and guaranteed response completion.
- Request error event handlers to clean up failed connections.
- This prevents:
- DoS attacks via concurrent unauthenticated or malformed requests.
- Identity spoofing by using arbitrary bearer tokens or user IDs.
- Resource exhaustion from hanging connections or excessive payloads.
- Access control: all attachment operations verify board membership before allowing access.
## Brute force login protection ## Brute force login protection
- https://github.com/wekan/wekan/commit/23e5e1e3bd081699ce39ce5887db7e612616014d - https://github.com/wekan/wekan/commit/23e5e1e3bd081699ce39ce5887db7e612616014d
@ -218,9 +272,4 @@ Typical already known or "no impact" bugs such as:
- Email spoofing, SPF, DMARC & DKIM. Wekan does not include email server. - Email spoofing, SPF, DMARC & DKIM. Wekan does not include email server.
Wekan is Open Source with MIT license, and free to use also for commercial use. Wekan is Open Source with MIT license, and free to use also for commercial use.
We welcome all fixes to improve security by email to security@wekan.team We welcome all fixes to improve security by email to security@wekan.fi
## Bonus Points
If your Responsible Security Disclosure includes code for fixing security issue,
you get bonus points, as seen on [Hall of Fame](https://wekan.github.io/hall-of-fame).

View file

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

View file

@ -15,3 +15,50 @@ import '/client/components/migrationProgress';
// Import cron settings // Import cron settings
import '/client/components/settings/cronSettings'; import '/client/components/settings/cronSettings';
// Mirror Meteor login token into a cookie for server-side file route auth
// This enables cookie-based auth for /cdn/storage/* without leaking ROOT_URL
// Token already lives in localStorage; cookie adds same-origin send-on-request semantics
Meteor.startup(() => {
const COOKIE_NAME = 'meteor_login_token';
const cookieAttrs = () => {
const attrs = ['Path=/', 'SameSite=Lax'];
try {
if (window.location && window.location.protocol === 'https:') {
attrs.push('Secure');
}
} catch (_) {}
return attrs.join('; ');
};
const setCookie = (name, value) => {
if (!value) return;
document.cookie = `${encodeURIComponent(name)}=${encodeURIComponent(value)}; ${cookieAttrs()}`;
};
const clearCookie = (name) => {
document.cookie = `${encodeURIComponent(name)}=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; ${cookieAttrs()}`;
};
const syncCookie = () => {
try {
const token = Accounts && typeof Accounts._storedLoginToken === 'function' ? Accounts._storedLoginToken() : null;
if (token) setCookie(COOKIE_NAME, token); else clearCookie(COOKIE_NAME);
} catch (e) {
// ignore
}
};
// Initial sync on startup
syncCookie();
// Keep cookie in sync on login/logout
if (Accounts && typeof Accounts.onLogin === 'function') Accounts.onLogin(syncCookie);
if (Accounts && typeof Accounts.onLogout === 'function') Accounts.onLogout(syncCookie);
// Sync across tabs/windows when localStorage changes
window.addEventListener('storage', (ev) => {
if (ev && typeof ev.key === 'string' && ev.key.indexOf('Meteor.loginToken') !== -1) {
syncCookie();
}
});
});

View file

@ -269,57 +269,71 @@
} }
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */ /* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
.board-wrapper.mobile-view { .board-wrapper.mobile-view {
width: 100% !important; width: 100vw !important;
min-width: 100% !important; max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
} }
.board-wrapper.mobile-view .board-canvas { .board-wrapper.mobile-view .board-canvas {
width: 100% !important; width: 100vw !important;
min-width: 100% !important; max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
} }
.board-wrapper.mobile-view .board-canvas.mobile-view .swimlane { .board-wrapper.mobile-view .board-canvas.mobile-view .swimlane {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: flex; display: block !important;
flex-direction: column; flex-direction: column;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-x: hidden; overflow-x: hidden !important;
overflow-y: auto; overflow-y: auto;
width: 100%; width: 100vw !important;
min-width: 100%; max-width: 100vw !important;
min-width: 100vw !important;
} }
@media screen and (max-width: 800px), @media screen and (max-width: 800px),
screen and (max-device-width: 932px) and (-webkit-min-device-pixel-ratio: 3) { screen and (max-device-width: 932px) and (-webkit-min-device-pixel-ratio: 3) {
.board-wrapper { .board-wrapper {
width: 100% !important; width: 100vw !important;
min-width: 100% !important; max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
} }
.board-wrapper .board-canvas { .board-wrapper .board-canvas {
width: 100% !important; width: 100vw !important;
min-width: 100% !important; max-width: 100vw !important;
min-width: 100vw !important;
left: 0 !important; left: 0 !important;
right: 0 !important; right: 0 !important;
overflow-x: hidden !important;
overflow-y: auto !important;
} }
.board-wrapper .board-canvas .swimlane { .board-wrapper .board-canvas .swimlane {
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: flex; display: block !important;
flex-direction: column; flex-direction: column;
margin: 0; margin: 0;
padding: 0; padding: 0;
overflow-x: hidden; overflow-x: hidden !important;
overflow-y: auto; overflow-y: auto;
width: 100%; width: 100vw !important;
min-width: 100%; max-width: 100vw !important;
min-width: 100vw !important;
} }
} }
.calendar-event-green { .calendar-event-green {

View file

@ -4,6 +4,7 @@ import dragscroll from '@wekanteam/dragscroll';
import { boardConverter } from '/client/lib/boardConverter'; import { boardConverter } from '/client/lib/boardConverter';
import { migrationManager } from '/client/lib/migrationManager'; import { migrationManager } from '/client/lib/migrationManager';
import { attachmentMigrationManager } from '/client/lib/attachmentMigrationManager'; import { attachmentMigrationManager } from '/client/lib/attachmentMigrationManager';
import { migrationProgressManager } from '/client/components/migrationProgress';
import Swimlanes from '/models/swimlanes'; import Swimlanes from '/models/swimlanes';
import Lists from '/models/lists'; import Lists from '/models/lists';
@ -17,6 +18,8 @@ BlazeComponent.extendComponent({
this.isConverting = new ReactiveVar(false); this.isConverting = new ReactiveVar(false);
this.isMigrating = new ReactiveVar(false); this.isMigrating = new ReactiveVar(false);
this._swimlaneCreated = new Set(); // Track boards where we've created swimlanes this._swimlaneCreated = new Set(); // Track boards where we've created swimlanes
this._boardProcessed = false; // Track if board has been processed
this._lastProcessedBoardId = null; // Track last processed board ID
// The pattern we use to manually handle data loading is described here: // 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 // https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/using-subs-manager
@ -28,21 +31,33 @@ BlazeComponent.extendComponent({
const handle = subManager.subscribe('board', currentBoardId, false); const handle = subManager.subscribe('board', currentBoardId, false);
Tracker.nonreactive(() => { // Use a separate autorun for subscription ready state to avoid reactive loops
Tracker.autorun(() => { this.subscriptionReadyAutorun = Tracker.autorun(() => {
if (handle.ready()) { if (handle.ready()) {
// Only run conversion/migration logic once per board
if (!this._boardProcessed || this._lastProcessedBoardId !== currentBoardId) {
this._boardProcessed = true;
this._lastProcessedBoardId = currentBoardId;
// Ensure default swimlane exists (only once per board) // Ensure default swimlane exists (only once per board)
this.ensureDefaultSwimlane(currentBoardId); this.ensureDefaultSwimlane(currentBoardId);
// Check if board needs conversion // Check if board needs conversion
this.checkAndConvertBoard(currentBoardId); this.checkAndConvertBoard(currentBoardId);
} else {
this.isBoardReady.set(false);
} }
}); } else {
this.isBoardReady.set(false);
}
}); });
}); });
}, },
onDestroyed() {
// Clean up the subscription ready autorun to prevent memory leaks
if (this.subscriptionReadyAutorun) {
this.subscriptionReadyAutorun.stop();
}
},
ensureDefaultSwimlane(boardId) { ensureDefaultSwimlane(boardId) {
// Only create swimlane once per board // Only create swimlane once per board
if (this._swimlaneCreated.has(boardId)) { if (this._swimlaneCreated.has(boardId)) {
@ -56,10 +71,17 @@ BlazeComponent.extendComponent({
const swimlanes = board.swimlanes(); const swimlanes = board.swimlanes();
if (swimlanes.length === 0) { if (swimlanes.length === 0) {
const swimlaneId = Swimlanes.insert({ // Check if any swimlane exists in the database to avoid race conditions
title: 'Default', const existingSwimlanes = ReactiveCache.getSwimlanes({ boardId });
boardId: boardId, if (existingSwimlanes.length === 0) {
}); const swimlaneId = Swimlanes.insert({
title: 'Default',
boardId: boardId,
});
if (process.env.DEBUG === 'true') {
console.log(`Created default swimlane ${swimlaneId} for board ${boardId}`);
}
}
this._swimlaneCreated.add(boardId); this._swimlaneCreated.add(boardId);
} else { } else {
this._swimlaneCreated.add(boardId); this._swimlaneCreated.add(boardId);
@ -77,49 +99,10 @@ BlazeComponent.extendComponent({
return; return;
} }
// Check if board needs migration based on migration version // Automatic migration disabled - migrations must be run manually from sidebar
const needsMigration = !board.migrationVersion || board.migrationVersion < 1; // Board admins can run migrations from the sidebar Migrations menu
this.isBoardReady.set(true);
if (needsMigration) {
// Start background migration for old boards
this.isMigrating.set(true);
await this.startBackgroundMigration(boardId);
this.isMigrating.set(false);
}
// Check if board needs conversion (for old structure)
if (boardConverter.isBoardConverted(boardId)) {
if (process.env.DEBUG === 'true') {
console.log(`Board ${boardId} has already been converted, skipping conversion`);
}
this.isBoardReady.set(true);
} else {
const needsConversion = boardConverter.needsConversion(boardId);
if (needsConversion) {
this.isConverting.set(true);
const success = await boardConverter.convertBoard(boardId);
this.isConverting.set(false);
if (success) {
this.isBoardReady.set(true);
} else {
console.error('Board conversion failed, setting ready to true anyway');
this.isBoardReady.set(true); // Still show board even if conversion failed
}
} else {
this.isBoardReady.set(true);
}
}
// Convert shared lists to per-swimlane lists if needed
await this.convertSharedListsToPerSwimlane(boardId);
// Fix missing lists migration (for cards with wrong listId references)
await this.fixMissingLists(boardId);
// Start attachment migration in background if needed
this.startAttachmentMigrationIfNeeded(boardId);
} catch (error) { } catch (error) {
console.error('Error during board conversion check:', error); console.error('Error during board conversion check:', error);
this.isConverting.set(false); this.isConverting.set(false);
@ -128,6 +111,136 @@ BlazeComponent.extendComponent({
} }
}, },
/**
* Check if board needs comprehensive migration
*/
async checkComprehensiveMigration(boardId) {
try {
return new Promise((resolve, reject) => {
Meteor.call('comprehensiveBoardMigration.needsMigration', boardId, (error, result) => {
if (error) {
console.error('Error checking comprehensive migration:', error);
reject(error);
} else {
resolve(result);
}
});
});
} catch (error) {
console.error('Error checking comprehensive migration:', error);
return false;
}
},
/**
* Execute comprehensive migration for a board
*/
async executeComprehensiveMigration(boardId) {
try {
// Start progress tracking
migrationProgressManager.startMigration();
// Simulate progress updates since we can't easily pass callbacks through Meteor methods
const progressSteps = [
{ step: 'analyze_board_structure', name: 'Analyze Board Structure', duration: 1000 },
{ step: 'fix_orphaned_cards', name: 'Fix Orphaned Cards', duration: 2000 },
{ step: 'convert_shared_lists', name: 'Convert Shared Lists', duration: 3000 },
{ step: 'ensure_per_swimlane_lists', name: 'Ensure Per-Swimlane Lists', duration: 1500 },
{ step: 'validate_migration', name: 'Validate Migration', duration: 1000 },
{ step: 'fix_avatar_urls', name: 'Fix Avatar URLs', duration: 1000 },
{ step: 'fix_attachment_urls', name: 'Fix Attachment URLs', duration: 1000 }
];
// Start the actual migration
const migrationPromise = new Promise((resolve, reject) => {
Meteor.call('comprehensiveBoardMigration.execute', boardId, (error, result) => {
if (error) {
console.error('Error executing comprehensive migration:', error);
migrationProgressManager.failMigration(error);
reject(error);
} else {
if (process.env.DEBUG === 'true') {
console.log('Comprehensive migration completed for board:', boardId, result);
}
resolve(result.success);
}
});
});
// Simulate progress updates
const progressPromise = this.simulateMigrationProgress(progressSteps);
// Wait for both to complete
const [migrationResult] = await Promise.all([migrationPromise, progressPromise]);
migrationProgressManager.completeMigration();
return migrationResult;
} catch (error) {
console.error('Error executing comprehensive migration:', error);
migrationProgressManager.failMigration(error);
return false;
}
},
/**
* Simulate migration progress updates
*/
async simulateMigrationProgress(progressSteps) {
const totalSteps = progressSteps.length;
for (let i = 0; i < progressSteps.length; i++) {
const step = progressSteps[i];
const stepProgress = Math.round(((i + 1) / totalSteps) * 100);
// Update progress for this step
migrationProgressManager.updateProgress({
overallProgress: stepProgress,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: 0,
stepStatus: `Starting ${step.name}...`,
stepDetails: null,
boardId: Session.get('currentBoard')
});
// Simulate step progress
const stepDuration = step.duration;
const updateInterval = 100; // Update every 100ms
const totalUpdates = stepDuration / updateInterval;
for (let j = 0; j < totalUpdates; j++) {
const stepStepProgress = Math.round(((j + 1) / totalUpdates) * 100);
migrationProgressManager.updateProgress({
overallProgress: stepProgress,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: stepStepProgress,
stepStatus: `Processing ${step.name}...`,
stepDetails: { progress: `${stepStepProgress}%` },
boardId: Session.get('currentBoard')
});
await new Promise(resolve => setTimeout(resolve, updateInterval));
}
// Complete the step
migrationProgressManager.updateProgress({
overallProgress: stepProgress,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: 100,
stepStatus: `${step.name} completed`,
stepDetails: { status: 'completed' },
boardId: Session.get('currentBoard')
});
}
},
async startBackgroundMigration(boardId) { async startBackgroundMigration(boardId) {
try { try {
// Start background migration using the cron system // Start background migration using the cron system
@ -177,7 +290,7 @@ BlazeComponent.extendComponent({
console.log(`Board ${boardId} has no shared lists to convert`); console.log(`Board ${boardId} has no shared lists to convert`);
} }
// Mark as processed even if no shared lists // Mark as processed even if no shared lists
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } }); Boards.update(boardId, { $set: { hasSharedListsConverted: true } });
return; return;
} }
@ -197,28 +310,41 @@ BlazeComponent.extendComponent({
}); });
if (!existingList) { if (!existingList) {
// Create a new list in this swimlane // Double-check to avoid race conditions
const newListData = { const doubleCheckList = ReactiveCache.getList({
title: sharedList.title,
boardId: boardId, boardId: boardId,
swimlaneId: swimlane._id, swimlaneId: swimlane._id,
sort: sharedList.sort || 0, title: sharedList.title
archived: sharedList.archived || false, // Preserve archived state from original list });
createdAt: new Date(),
modifiedAt: new Date()
};
// Copy other properties if they exist if (!doubleCheckList) {
if (sharedList.color) newListData.color = sharedList.color; // Create a new list in this swimlane
if (sharedList.wipLimit) newListData.wipLimit = sharedList.wipLimit; const newListData = {
if (sharedList.wipLimitEnabled) newListData.wipLimitEnabled = sharedList.wipLimitEnabled; title: sharedList.title,
if (sharedList.wipLimitSoft) newListData.wipLimitSoft = sharedList.wipLimitSoft; boardId: boardId,
swimlaneId: swimlane._id,
sort: sharedList.sort || 0,
archived: sharedList.archived || false, // Preserve archived state from original list
createdAt: new Date(),
modifiedAt: new Date()
};
Lists.insert(newListData); // Copy other properties if they exist
if (sharedList.color) newListData.color = sharedList.color;
if (process.env.DEBUG === 'true') { if (sharedList.wipLimit) newListData.wipLimit = sharedList.wipLimit;
const archivedStatus = sharedList.archived ? ' (archived)' : ' (active)'; if (sharedList.wipLimitEnabled) newListData.wipLimitEnabled = sharedList.wipLimitEnabled;
console.log(`Created list "${sharedList.title}"${archivedStatus} for swimlane ${swimlane.title || swimlane._id}`); if (sharedList.wipLimitSoft) newListData.wipLimitSoft = sharedList.wipLimitSoft;
Lists.insert(newListData);
if (process.env.DEBUG === 'true') {
const archivedStatus = sharedList.archived ? ' (archived)' : ' (active)';
console.log(`Created list "${sharedList.title}"${archivedStatus} for swimlane ${swimlane.title || swimlane._id}`);
}
} else {
if (process.env.DEBUG === 'true') {
console.log(`List "${sharedList.title}" already exists in swimlane ${swimlane.title || swimlane._id} (double-check), skipping`);
}
} }
} else { } else {
if (process.env.DEBUG === 'true') { if (process.env.DEBUG === 'true') {
@ -236,7 +362,7 @@ BlazeComponent.extendComponent({
} }
// Mark board as processed // Mark board as processed
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } }); Boards.update(boardId, { $set: { hasSharedListsConverted: true } });
if (process.env.DEBUG === 'true') { if (process.env.DEBUG === 'true') {
console.log(`Successfully converted ${sharedLists.length} shared lists to per-swimlane lists for board ${boardId}`); console.log(`Successfully converted ${sharedLists.length} shared lists to per-swimlane lists for board ${boardId}`);
@ -294,7 +420,9 @@ BlazeComponent.extendComponent({
}); });
if (result && result.success) { if (result && result.success) {
console.log(`Successfully fixed missing lists for board ${boardId}: created ${result.createdLists} lists, updated ${result.updatedCards} cards`); if (process.env.DEBUG === 'true') {
console.log(`Successfully fixed missing lists for board ${boardId}: created ${result.createdLists} lists, updated ${result.updatedCards} cards`);
}
} }
} catch (error) { } catch (error) {
@ -302,6 +430,55 @@ BlazeComponent.extendComponent({
} }
}, },
async fixDuplicateLists(boardId) {
try {
const board = ReactiveCache.getBoard(boardId);
if (!board) return;
// Check if board has already been processed for duplicate lists fix
if (board.fixDuplicateListsCompleted) {
if (process.env.DEBUG === 'true') {
console.log(`Board ${boardId} has already been processed for duplicate lists fix`);
}
return;
}
if (process.env.DEBUG === 'true') {
console.log(`Starting duplicate lists fix for board ${boardId}`);
}
// Execute the duplicate lists fix
const result = await new Promise((resolve, reject) => {
Meteor.call('fixDuplicateLists.fixBoard', boardId, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
if (result && result.fixed > 0) {
if (process.env.DEBUG === 'true') {
console.log(`Successfully fixed ${result.fixed} duplicate lists for board ${boardId}: ${result.fixedSwimlanes} swimlanes, ${result.fixedLists} lists`);
}
// Mark board as processed
Boards.update(boardId, { $set: { fixDuplicateListsCompleted: true } });
} else if (process.env.DEBUG === 'true') {
console.log(`No duplicate lists found for board ${boardId}`);
// Still mark as processed to avoid repeated checks
Boards.update(boardId, { $set: { fixDuplicateListsCompleted: true } });
} else {
// Still mark as processed to avoid repeated checks
Boards.update(boardId, { $set: { fixDuplicateListsCompleted: true } });
}
} catch (error) {
console.error('Error fixing duplicate lists:', error);
}
},
async startAttachmentMigrationIfNeeded(boardId) { async startAttachmentMigrationIfNeeded(boardId) {
try { try {
// Check if board has already been migrated // Check if board has already been migrated
@ -367,39 +544,50 @@ BlazeComponent.extendComponent({
this._isDragging = false; this._isDragging = false;
// Used to set the overlay // Used to set the overlay
this.mouseHasEnterCardDetails = false; this.mouseHasEnterCardDetails = false;
this._sortFieldsFixed = new Set(); // Track which boards have had sort fields fixed
// fix swimlanes sort field if there are null values // fix swimlanes sort field if there are null values
const currentBoardData = Utils.getCurrentBoard(); const currentBoardData = Utils.getCurrentBoard();
if (currentBoardData && Swimlanes) { if (currentBoardData && Swimlanes) {
const nullSortSwimlanes = currentBoardData.nullSortSwimlanes(); const boardId = currentBoardData._id;
if (nullSortSwimlanes.length > 0) { // Only fix sort fields once per board to prevent reactive loops
const swimlanes = currentBoardData.swimlanes(); if (!this._sortFieldsFixed.has(`swimlanes-${boardId}`)) {
let count = 0; const nullSortSwimlanes = currentBoardData.nullSortSwimlanes();
swimlanes.forEach(s => { if (nullSortSwimlanes.length > 0) {
Swimlanes.update(s._id, { const swimlanes = currentBoardData.swimlanes();
$set: { let count = 0;
sort: count, swimlanes.forEach(s => {
}, Swimlanes.update(s._id, {
$set: {
sort: count,
},
});
count += 1;
}); });
count += 1; }
}); this._sortFieldsFixed.add(`swimlanes-${boardId}`);
} }
} }
// fix lists sort field if there are null values // fix lists sort field if there are null values
if (currentBoardData && Lists) { if (currentBoardData && Lists) {
const nullSortLists = currentBoardData.nullSortLists(); const boardId = currentBoardData._id;
if (nullSortLists.length > 0) { // Only fix sort fields once per board to prevent reactive loops
const lists = currentBoardData.lists(); if (!this._sortFieldsFixed.has(`lists-${boardId}`)) {
let count = 0; const nullSortLists = currentBoardData.nullSortLists();
lists.forEach(l => { if (nullSortLists.length > 0) {
Lists.update(l._id, { const lists = currentBoardData.lists();
$set: { let count = 0;
sort: count, lists.forEach(l => {
}, Lists.update(l._id, {
$set: {
sort: count,
},
});
count += 1;
}); });
count += 1; }
}); this._sortFieldsFixed.add(`lists-${boardId}`);
} }
} }
}, },
@ -1183,9 +1371,13 @@ BlazeComponent.extendComponent({
const firstSwimlane = currentBoard.swimlanes()[0]; const firstSwimlane = currentBoard.swimlanes()[0];
Meteor.call('createCardWithDueDate', currentBoard._id, firstList._id, myTitle, startDate.toDate(), firstSwimlane._id, function(error, result) { Meteor.call('createCardWithDueDate', currentBoard._id, firstList._id, myTitle, startDate.toDate(), firstSwimlane._id, function(error, result) {
if (error) { if (error) {
console.log(error); if (process.env.DEBUG === 'true') {
console.log(error);
}
} else { } else {
console.log("Card Created", result); if (process.env.DEBUG === 'true') {
console.log("Card Created", result);
}
} }
}); });
closeModal(); closeModal();

View file

@ -505,73 +505,73 @@
flex-wrap: nowrap !important; flex-wrap: nowrap !important;
align-items: stretch !important; align-items: stretch !important;
justify-content: flex-start !important; justify-content: flex-start !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
overflow-x: hidden !important; overflow-x: hidden !important;
overflow-y: auto !important; overflow-y: auto !important;
} }
.mobile-mode .swimlane { .mobile-mode .swimlane {
display: block !important; display: block !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
margin: 0 0 2rem 0 !important; margin: 0 0 2rem 0 !important;
padding: 0 !important; padding: 0 !important;
float: none !important; float: none !important;
clear: both !important; clear: both !important;
} }
.mobile-mode .swimlane .swimlane-header { .mobile-mode .swimlane .swimlane-header {
display: block !important; display: block !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
margin: 0 0 1rem 0 !important; margin: 0 0 1rem 0 !important;
padding: 1rem !important; padding: 1rem !important;
font-size: clamp(18px, 2.5vw, 32px) !important; font-size: clamp(18px, 2.5vw, 32px) !important;
font-weight: bold !important; font-weight: bold !important;
border-bottom: 2px solid #ccc !important; border-bottom: 2px solid #ccc !important;
} }
.mobile-mode .swimlane .lists { .mobile-mode .swimlane .lists {
display: block !important; display: block !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
margin: 0 !important; margin: 0 !important;
padding: 0 !important; padding: 0 !important;
flex-direction: column !important; flex-direction: column !important;
flex-wrap: nowrap !important; flex-wrap: nowrap !important;
align-items: stretch !important; align-items: stretch !important;
justify-content: flex-start !important; justify-content: flex-start !important;
} }
.mobile-mode .list { .mobile-mode .list {
display: block !important; display: block !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
margin: 0 0 2rem 0 !important; margin: 0 0 2rem 0 !important;
padding: 0 !important; padding: 0 !important;
float: none !important; float: none !important;
clear: both !important; clear: both !important;
border-left: none !important; border-left: none !important;
border-right: none !important; border-right: none !important;
border-top: none !important; border-top: none !important;
border-bottom: 2px solid #ccc !important; border-bottom: 2px solid #ccc !important;
flex: none !important; flex: none !important;
flex-basis: auto !important; flex-basis: auto !important;
flex-grow: 0 !important; flex-grow: 0 !important;
flex-shrink: 0 !important; flex-shrink: 0 !important;
position: static !important; position: static !important;
left: auto !important; left: auto !important;
right: auto !important; right: auto !important;
top: auto !important; top: auto !important;
bottom: auto !important; bottom: auto !important;
transform: none !important; transform: none !important;
} }
.mobile-mode .list:first-child { .mobile-mode .list:first-child {
margin-left: 0 !important; margin-left: 0 !important;
@ -667,9 +667,9 @@
flex-wrap: nowrap !important; flex-wrap: nowrap !important;
align-items: stretch !important; align-items: stretch !important;
justify-content: flex-start !important; justify-content: flex-start !important;
width: 100% !important; width: 100vw !important;
max-width: 100% !important; max-width: 100vw !important;
min-width: 100% !important; min-width: 100vw !important;
overflow-x: hidden !important; overflow-x: hidden !important;
overflow-y: auto !important; overflow-y: auto !important;
} }

View file

@ -16,13 +16,6 @@ template(name="boardHeaderBar")
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title) a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title)
| ✏️ | ✏️
a.board-header-btn.js-star-board(class="{{#if isStarred}}is-active{{/if}}"
title="{{#if isStarred}}{{_ 'star-board-short-unstar'}}{{else}}{{_ 'star-board-short-star'}}{{/if}}" aria-label="{{#if isStarred}}{{_ 'star-board-short-unstar'}}{{else}}{{_ 'star-board-short-star'}}{{/if}}")
| {{#if isStarred}}⭐{{else}}☆{{/if}}
if showStarCounter
span
= currentBoard.stars
a.board-header-btn( a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}" class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}") title="{{_ currentBoard.permission}}")
@ -38,6 +31,13 @@ template(name="boardHeaderBar")
if $eq watchLevel "muted" if $eq watchLevel "muted"
| 🔕 | 🔕
span {{_ watchLevel}} span {{_ watchLevel}}
a.board-header-btn.js-star-board(title="{{_ 'star-board'}}")
if isStarred
| ⭐
else
| ☆
if showStarCounter
span.board-star-counter {{currentBoard.stars}}
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}") a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
| {{sortCardsIcon}} | {{sortCardsIcon}}
span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}} span {{#if isSortActive }}{{_ 'sort-is-on'}}{{else}}{{_ 'sort-cards'}}{{/if}}
@ -61,10 +61,6 @@ template(name="boardHeaderBar")
a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title) a.board-header-btn(class="{{#if currentUser.isBoardAdmin}}js-edit-board-title{{else}}is-disabled{{/if}}" title="{{_ 'edit'}}" value=title)
| ✏️ | ✏️
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'}}")
| {{#if isStarred}}⭐{{else}}☆{{/if}}
a.board-header-btn( a.board-header-btn(
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}" class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
title="{{_ currentBoard.permission}}") title="{{_ currentBoard.permission}}")
@ -78,6 +74,11 @@ template(name="boardHeaderBar")
| 🔔 | 🔔
if $eq watchLevel "muted" if $eq watchLevel "muted"
| 🔕 | 🔕
a.board-header-btn.js-star-board(title="{{_ 'star-board'}}")
if isStarred
| ⭐
else
| ☆
a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}") a.board-header-btn(title="{{_ 'sort-cards'}}" class="{{#if isSortActive }}emphasis{{else}} js-sort-cards {{/if}}")
| {{sortCardsIcon}} | {{sortCardsIcon}}
if isSortActive if isSortActive
@ -266,6 +267,36 @@ template(name="createBoardPopup")
| / | /
a.js-board-template {{_ 'template'}} a.js-board-template {{_ 'template'}}
// New popup for Template Container creation; shares the same form content
template(name="createTemplateContainerPopup")
form
label
| {{_ 'title'}}
input.js-new-board-title(type="text" placeholder="{{_ 'bucket-example'}}" autofocus required)
if visibilityMenuIsOpen.get
+boardVisibilityList
else
p.quiet
if $eq visibility.get 'public'
span 🌐
= " "
| {{{_ 'board-public-info'}}}
else
span 🔒
= " "
| {{{_ 'board-private-info'}}}
a.js-change-visibility {{_ 'change'}}.
a.flex.js-toggle-add-template-container
.materialCheckBox#add-template-container
span {{_ 'add-template-container'}}
input.primary.wide(type="submit" value="{{_ 'create'}}")
span.quiet
| {{_ 'or'}}
a.js-import-board {{_ 'import'}}
span.quiet
| /
a.js-board-template {{_ 'template'}}
//template(name="listsortPopup") //template(name="listsortPopup")
// h2 // h2
// | {{_ 'list-sort-by'}} // | {{_ 'list-sort-by'}}

View file

@ -72,7 +72,10 @@ BlazeComponent.extendComponent({
{ {
'click .js-edit-board-title': Popup.open('boardChangeTitle'), 'click .js-edit-board-title': Popup.open('boardChangeTitle'),
'click .js-star-board'() { 'click .js-star-board'() {
ReactiveCache.getCurrentUser().toggleBoardStar(Session.get('currentBoard')); const boardId = Session.get('currentBoard');
if (boardId) {
Meteor.call('toggleBoardStar', boardId);
}
}, },
'click .js-open-board-menu': Popup.open('boardMenu'), 'click .js-open-board-menu': Popup.open('boardMenu'),
'click .js-change-visibility': Popup.open('boardChangeVisibility'), 'click .js-change-visibility': Popup.open('boardChangeVisibility'),
@ -82,18 +85,26 @@ BlazeComponent.extendComponent({
}, },
'click .js-toggle-board-view': Popup.open('boardChangeView'), 'click .js-toggle-board-view': Popup.open('boardChangeView'),
'click .js-toggle-sidebar'() { 'click .js-toggle-sidebar'() {
console.log('Hamburger menu clicked'); if (process.env.DEBUG === 'true') {
console.log('Hamburger menu clicked');
}
// Use the same approach as keyboard shortcuts // Use the same approach as keyboard shortcuts
if (typeof Sidebar !== 'undefined' && Sidebar && typeof Sidebar.toggle === 'function') { if (typeof Sidebar !== 'undefined' && Sidebar && typeof Sidebar.toggle === 'function') {
console.log('Using Sidebar.toggle()'); if (process.env.DEBUG === 'true') {
console.log('Using Sidebar.toggle()');
}
Sidebar.toggle(); Sidebar.toggle();
} else { } else {
console.warn('Sidebar not available, trying alternative approach'); if (process.env.DEBUG === 'true') {
console.warn('Sidebar not available, trying alternative approach');
}
// Try to trigger the sidebar through the global Blaze helper // Try to trigger the sidebar through the global Blaze helper
if (typeof Blaze !== 'undefined' && Blaze._globalHelpers && Blaze._globalHelpers.Sidebar) { if (typeof Blaze !== 'undefined' && Blaze._globalHelpers && Blaze._globalHelpers.Sidebar) {
const sidebar = Blaze._globalHelpers.Sidebar(); const sidebar = Blaze._globalHelpers.Sidebar();
if (sidebar && typeof sidebar.toggle === 'function') { if (sidebar && typeof sidebar.toggle === 'function') {
console.log('Using Blaze helper Sidebar.toggle()'); if (process.env.DEBUG === 'true') {
console.log('Using Blaze helper Sidebar.toggle()');
}
sidebar.toggle(); sidebar.toggle();
} }
} }
@ -283,6 +294,15 @@ const CreateBoard = BlazeComponent.extendComponent({
}, },
); );
// Assign to space if one was selected
const spaceId = Session.get('createBoardInWorkspace');
if (spaceId) {
Meteor.call('assignBoardToWorkspace', this.boardId.get(), spaceId, (err) => {
if (err) console.error('Error assigning board to space:', err);
});
Session.set('createBoardInWorkspace', null); // Clear after use
}
Utils.goBoardId(this.boardId.get()); Utils.goBoardId(this.boardId.get());
} else { } else {
@ -301,6 +321,15 @@ const CreateBoard = BlazeComponent.extendComponent({
boardId: this.boardId.get(), boardId: this.boardId.get(),
}); });
// Assign to space if one was selected
const spaceId = Session.get('createBoardInWorkspace');
if (spaceId) {
Meteor.call('assignBoardToWorkspace', this.boardId.get(), spaceId, (err) => {
if (err) console.error('Error assigning board to space:', err);
});
Session.set('createBoardInWorkspace', null); // Clear after use
}
Utils.goBoardId(this.boardId.get()); Utils.goBoardId(this.boardId.get());
} }
}, },
@ -322,6 +351,13 @@ const CreateBoard = BlazeComponent.extendComponent({
}, },
}).register('createBoardPopup'); }).register('createBoardPopup');
(class CreateTemplateContainerPopup extends CreateBoard {
onRendered() {
// Always pre-check the template container checkbox for this popup
$('#add-template-container').addClass('is-checked');
}
}).register('createTemplateContainerPopup');
(class HeaderBarCreateBoard extends CreateBoard { (class HeaderBarCreateBoard extends CreateBoard {
onSubmit(event) { onSubmit(event) {
super.onSubmit(event); super.onSubmit(event);

View file

@ -8,6 +8,273 @@
padding: 1vh 0; padding: 1vh 0;
} }
/* Two-column layout for All Boards */
.boards-layout {
display: grid;
grid-template-columns: 260px 1fr;
gap: 16px;
}
.boards-left-menu {
border-right: 1px solid #e0e0e0;
padding-right: 12px;
}
.boards-left-menu ul.menu {
list-style: none;
padding: 0;
margin: 0 0 12px 0;
}
.boards-left-menu .menu-item {
margin: 4px 0;
}
.boards-left-menu .menu-item a {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 10px;
border-radius: 4px;
cursor: pointer;
}
.boards-left-menu .menu-item .menu-label {
flex: 1;
}
.boards-left-menu .menu-item .menu-count {
background: #ddd;
padding: 2px 8px;
border-radius: 12px;
font-size: 12px;
font-weight: bold;
margin-left: 8px;
}
.boards-left-menu .menu-item.active a,
.boards-left-menu .menu-item a:hover {
background: #f0f0f0;
}
.boards-left-menu .menu-item.active .menu-count {
background: #bbb;
}
/* Drag-over state for menu items (for dropping boards on Remaining) */
.boards-left-menu .menu-item a.drag-over {
background: #d0e8ff;
border: 2px dashed #2196F3;
}
.workspaces-header {
display: flex;
align-items: center;
justify-content: space-between;
font-weight: bold;
margin-top: 12px;
}
.workspaces-header .js-add-space {
text-decoration: none;
font-weight: bold;
border: 1px solid #ccc;
padding: 2px 8px;
border-radius: 4px;
}
.workspace-tree {
list-style: none;
padding-left: 10px;
}
.workspace-node {
margin: 2px 0;
position: relative;
}
.workspace-node-content {
display: flex;
align-items: center;
gap: 4px;
padding: 4px;
border-radius: 4px;
transition: background-color 0.2s;
}
.workspace-node.dragging > .workspace-node-content {
opacity: 0.5;
background: #e0e0e0;
}
.workspace-node.drag-over > .workspace-node-content {
background: #d0e8ff;
border: 2px dashed #2196F3;
}
.workspace-drag-handle {
cursor: grab;
color: #999;
font-size: 14px;
padding: 0 4px;
user-select: none;
}
.workspace-drag-handle:active {
cursor: grabbing;
}
.workspace-node .js-select-space {
display: flex;
align-items: center;
gap: 6px;
padding: 4px 8px;
border-radius: 4px;
cursor: pointer;
flex: 1;
text-decoration: none;
}
.workspace-node .workspace-icon {
font-size: 16px;
line-height: 1;
}
.workspace-node .workspace-name {
flex: 1;
}
.workspace-node .workspace-count {
background: #ddd;
padding: 2px 6px;
border-radius: 10px;
font-size: 11px;
font-weight: bold;
min-width: 20px;
text-align: center;
}
.workspace-node .js-edit-space,
.workspace-node .js-add-subspace {
padding: 2px 6px;
border-radius: 3px;
cursor: pointer;
text-decoration: none;
font-size: 14px;
opacity: 0.6;
transition: opacity 0.2s;
}
.workspace-node .js-edit-space:hover,
.workspace-node .js-add-subspace:hover {
opacity: 1;
background: #e0e0e0;
}
.workspace-node.active > .workspace-node-content .js-select-space,
.workspace-node > .workspace-node-content:hover .js-select-space {
background: #f0f0f0;
}
.workspace-node.active .workspace-count {
background: #bbb;
}
.boards-right-grid {
min-height: 200px;
}
.boards-path-header {
display: flex;
align-items: center;
justify-content: space-between;
gap: 8px;
padding: 12px 16px;
margin-bottom: 16px;
background: #f5f5f5;
border-radius: 6px;
font-size: 16px;
font-weight: 500;
}
.boards-path-header .path-left {
display: flex;
align-items: center;
gap: 8px;
flex: 1;
}
.boards-path-header .multiselection-hint {
background: #FFF3CD;
color: #856404;
padding: 4px 12px;
border-radius: 4px;
font-size: 13px;
font-weight: normal;
border: 1px solid #FFE69C;
animation: pulse 2s ease-in-out infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
.boards-path-header .path-right {
display: flex;
align-items: center;
gap: 8px;
}
.boards-path-header .path-icon {
font-size: 18px;
}
.boards-path-header .path-text {
color: #333;
}
.boards-path-header .board-header-btn {
padding: 6px 12px;
background: #fff;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
transition: all 0.2s;
}
.boards-path-header .board-header-btn:hover {
background: #f0f0f0;
border-color: #bbb;
}
.boards-path-header .board-header-btn.emphasis {
background: #2196F3;
color: #fff;
border-color: #2196F3;
font-weight: bold;
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.5);
transform: scale(1.05);
}
.boards-path-header .board-header-btn.emphasis:hover {
background: #1976D2;
box-shadow: 0 3px 12px rgba(33, 150, 243, 0.7);
}
.boards-path-header .board-header-btn-close {
padding: 4px 10px;
background: #f44336;
color: #000;
border: none;
border-radius: 4px;
cursor: pointer;
font-size: 16px;
margin-left: 10px; /* Extra space between MultiSelection toggle and Remove Filter */
}
.boards-path-header .board-header-btn-close:hover {
background: #d32f2f;
}
.zoom-controls { .zoom-controls {
display: flex; display: flex;
align-items: center; align-items: center;
@ -106,23 +373,35 @@
.board-list li.starred .is-star-active, .board-list li.starred .is-star-active,
.board-list li.starred .is-not-star-active { .board-list li.starred .is-not-star-active {
opacity: 1; opacity: 1;
color: #ffd700;
}
/* Show star icon on hover even for non-starred boards */
.board-list li:hover .is-star-active,
.board-list li:hover .is-not-star-active {
opacity: 1;
} }
.board-list .board-list-item { .board-list .board-list-item {
overflow: hidden; overflow: hidden;
background-color: #999; background-color: inherit; /* Inherit board color from parent li.js-board */
color: #f6f6f6; color: #f6f6f6;
min-height: 100px; min-height: 100px;
font-size: 16px; font-size: 16px;
line-height: 22px; line-height: 22px;
border-radius: 3px; border-radius: 0; /* No border-radius - parent .js-board has it */
display: block; display: block;
font-weight: 700; font-weight: 700;
padding: 8px; padding: 36px 8px 32px 8px; /* Top padding for drag handle, bottom for checkbox */
margin: 8px; margin: 0; /* No margin - moved to parent .js-board */
position: relative; position: relative;
text-decoration: none; text-decoration: none;
word-wrap: break-word; word-wrap: break-word;
} }
.board-list .board-list-item > .js-open-board {
text-decoration: none;
color: inherit;
display: block;
}
.board-list .board-list-item.template-container { .board-list .board-list-item.template-container {
border: 4px solid #fff; border: 4px solid #fff;
} }
@ -150,13 +429,20 @@
.board-list .js-add-board .label { .board-list .js-add-board .label {
font-weight: normal; font-weight: normal;
line-height: 56px; line-height: 56px;
min-height: 100px;
display: flex;
align-items: center;
justify-content: center;
background-color: #999; /* Darker background for better text contrast */
border-radius: 3px;
padding: 36px 8px 32px 8px;
} }
.board-list .js-add-board :hover { .board-list .js-add-board .label:hover {
background-color: #939393; background-color: #808080; /* Even darker on hover */
} }
.board-list .is-star-active, .board-list .is-star-active,
.board-list .is-not-star-active { .board-list .is-not-star-active {
bottom: 0; top: 0;
font-size: 14px; font-size: 14px;
height: 18px; height: 18px;
line-height: 18px; line-height: 18px;
@ -164,7 +450,6 @@
padding: 9px 9px; padding: 9px 9px;
position: absolute; position: absolute;
right: 0; right: 0;
top: 0;
transition-duration: 0.15s; transition-duration: 0.15s;
transition-property: color, font-size, background; transition-property: color, font-size, background;
} }
@ -238,6 +523,95 @@
.board-list li:hover a .is-not-star-active { .board-list li:hover a .is-not-star-active {
opacity: 1; opacity: 1;
} }
/* Board drag handle - always visible and positioned at top */
.board-list .board-handle {
position: absolute;
padding: 4px 6px;
top: 4px;
left: 50%;
transform: translateX(-50%);
font-size: 14px;
color: #fff;
background: rgba(0,0,0,0.4);
border-radius: 4px;
display: flex;
align-items: center;
justify-content: center;
z-index: 10;
transition: background-color 0.2s ease;
cursor: grab;
opacity: 1;
user-select: none;
}
.board-list .board-handle:active {
cursor: grabbing;
}
.board-list .board-handle:hover {
background: rgba(255, 255, 0, 0.8) !important;
color: #000;
}
/* Multiselection checkbox on board items */
.board-list .board-list-item .multi-selection-checkbox {
position: absolute !important;
bottom: 4px !important;
left: 4px !important;
top: auto !important;
width: 24px;
height: 24px;
border: 3px solid #fff;
background: rgba(0,0,0,0.5);
border-radius: 4px;
cursor: pointer;
z-index: 11;
display: flex;
align-items: center;
justify-content: center;
transition: all 0.2s;
box-shadow: 0 2px 4px rgba(0,0,0,0.3);
transform: none !important;
margin: 0 !important;
}
.board-list .board-list-item .multi-selection-checkbox:hover {
background: rgba(0,0,0,0.7);
transform: scale(1.15) !important;
box-shadow: 0 3px 6px rgba(0,0,0,0.5);
}
.board-list .board-list-item .multi-selection-checkbox.is-checked {
background: #2196F3;
border-color: #2196F3;
box-shadow: 0 2px 8px rgba(33, 150, 243, 0.6);
width: 24px !important;
height: 24px !important;
top: auto !important;
left: 4px !important;
transform: none !important;
border-radius: 4px !important;
}
.board-list .board-list-item .multi-selection-checkbox.is-checked::after {
content: '✓';
color: #fff;
font-size: 16px;
font-weight: bold;
}
.board-list.is-multiselection-active .js-board.is-checked {
outline: 4px solid #2196F3;
outline-offset: -4px;
box-shadow: 0 4px 12px rgba(33, 150, 243, 0.4);
}
/* Visual hint when multiselection is active */
.board-list.is-multiselection-active .board-list-item {
border: 2px dashed rgba(33, 150, 243, 0.3);
}
.board-backgrounds-list .board-background-select { .board-backgrounds-list .board-background-select {
box-sizing: border-box; box-sizing: border-box;
display: block; display: block;
@ -739,9 +1113,62 @@
#resetBtn { #resetBtn {
display: inline; display: inline;
} }
#resetBtn.filter-reset-btn {
background: #f44336;
color: #000;
border: none;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 6px;
transition: background 0.2s;
}
#resetBtn.filter-reset-btn:hover {
background: #d32f2f;
}
#resetBtn.filter-reset-btn .reset-icon {
font-size: 14px;
}
.js-board { .js-board {
display: block; display: block;
background-color: #999; /* Default gray background if no color class is applied */
border-radius: 3px; /* Rounded corners for board items */
overflow: hidden; /* Ensure children respect rounded corners */
margin: 8px; /* Space between board items */
} }
/* Reset background for add-board button */
.js-add-board {
background-color: transparent !important;
margin: 8px !important; /* Keep margin for add-board */
}
/* Apply board colors to li.js-board parent instead of just the link */
.board-list .board-color-nephritis { background-color: #27ae60; }
.board-list .board-color-pomegranate { background-color: #c0392b; }
.board-list .board-color-belize { background-color: #2980b9; }
.board-list .board-color-wisteria { background-color: #8e44ad; }
.board-list .board-color-midnight { background-color: #2c3e50; }
.board-list .board-color-pumpkin { background-color: #e67e22; }
.board-list .board-color-moderatepink { background-color: #cd5a91; }
.board-list .board-color-strongcyan { background-color: #00aecc; }
.board-list .board-color-limegreen { background-color: #4bbf6b; }
.board-list .board-color-dark { background-color: #2c3e51; }
.board-list .board-color-relax { background-color: #27ae61; }
.board-list .board-color-corteza { background-color: #568ba2; }
.board-list .board-color-clearblue { background-color: #3498db; }
.board-list .board-color-natural { background-color: #596557; }
.board-list .board-color-modern { background-color: #2a80b8; }
.board-list .board-color-moderndark { background-color: #2a2a2a; }
.board-list .board-color-exodark { background-color: #222; }
.minicard-members { .minicard-members {
padding: 6px 0 6px 8px; padding: 6px 0 6px 8px;
width: 100%; width: 100%;

View file

@ -2,151 +2,160 @@ template(name="boardList")
.wrapper .wrapper
.board-list-header .board-list-header
ul.AllBoardTeamsOrgs .boards-layout
li.AllBoardTeams // Left menu
if userHasTeams .boards-left-menu
select.js-AllBoardTeams#jsAllBoardTeams("multiple") ul.menu
option(value="-1") {{_ 'teams'}} : li(class="menu-item {{#if isSelectedMenu 'starred'}}active{{/if}}")
each teamsDatas a.js-select-menu(data-type="starred")
option(value="{{teamId}}") {{_ teamDisplayName}} span.menu-label ⭐ {{_ 'allboards.starred'}}
span.menu-count {{menuItemCount 'starred'}}
li(class="menu-item {{#if isSelectedMenu 'templates'}}active{{/if}}")
a.js-select-menu(data-type="templates")
span.menu-label 📋 {{_ 'allboards.templates'}}
span.menu-count {{menuItemCount 'templates'}}
li(class="menu-item {{#if isSelectedMenu 'remaining'}}active{{/if}}")
a.js-select-menu(data-type="remaining")
span.menu-label 📂 {{_ 'allboards.remaining'}}
span.menu-count {{menuItemCount 'remaining'}}
.workspaces-header
span 🗂️ {{_ 'allboards.workspaces'}}
a.js-add-workspace(title="{{_ 'allboards.add-workspace'}}") +
// Workspaces tree
+workspaceTree(nodes=workspacesTree selectedWorkspaceId=selectedWorkspaceId)
li.AllBoardOrgs // Existing filter by orgs/teams (kept)
if userHasOrgs ul.AllBoardTeamsOrgs
select.js-AllBoardOrgs#jsAllBoardOrgs("multiple") li.AllBoardTeams
option(value="-1") {{_ 'organizations'}} : if userHasTeams
each orgsDatas select.js-AllBoardTeams#jsAllBoardTeams("multiple")
option(value="{{orgId}}") {{orgDisplayName}} option(value="-1") {{_ 'teams'}} :
each teamsDatas
option(value="{{teamId}}") {{_ teamDisplayName}}
//li.AllBoardTemplates li.AllBoardOrgs
// if userHasTemplates if userHasOrgs
// select.js-AllBoardTemplates#jsAllBoardTemplates("multiple") select.js-AllBoardOrgs#jsAllBoardOrgs("multiple")
// option(value="-1") {{_ 'templates'}} : option(value="-1") {{_ 'organizations'}} :
// each templatesDatas each orgsDatas
// option(value="{{templateId}}") {{_ templateDisplayName}} option(value="{{orgId}}") {{orgDisplayName}}
li.AllBoardBtns li.AllBoardBtns
div.AllBoardButtonsContainer div.AllBoardButtonsContainer
if userHasOrgsOrTeams if userHasOrgsOrTeams
i.fa.fa-filter span 🔍
input#filterBtn(type="button" value="{{_ 'filter'}}") input#filterBtn(type="button" value="{{_ 'filter'}}")
input#resetBtn(type="button" value="{{_ 'filter-clear'}}") button#resetBtn.filter-reset-btn
span.reset-icon ❌
span {{_ 'filter-clear'}}
ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}}") // Right boards grid
li.js-add-board .boards-right-grid
a.board-list-item.label(title="{{_ 'add-board'}}") .boards-path-header
| {{_ 'add-board'}} .path-left
each boards span.path-icon {{currentMenuPath.icon}}
li(class="{{_id}}" class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board span.path-text {{currentMenuPath.text}}
if isInvited if BoardMultiSelection.isActive
.board-list-item span.multiselection-hint 📌 {{_ 'multi-selection-active'}}
span.details .path-right
span.board-list-item-name= title if canModifyBoards
i.fa.js-star-board( if hasBoardsSelected
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}" button.js-archive-selected-boards.board-header-btn
title="{{_ 'star-board-title'}}") span 📦
p.board-list-item-desc {{_ 'just-invited'}} span {{_ 'archive-board'}}
button.js-accept-invite.primary {{_ 'accept'}} button.js-duplicate-selected-boards.board-header-btn
button.js-decline-invite {{_ 'decline'}} span 📋
else span {{_ 'duplicate-board'}}
if $eq type "template-container" a.board-header-btn.js-multiselection-activate(
a.js-open-board.template-container.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}") title="{{#if BoardMultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
span.details class="{{#if BoardMultiSelection.isActive}}emphasis{{/if}}")
span.board-list-item-name(title="{{_ 'template-container'}}") | ☑️
+viewer if BoardMultiSelection.isActive
= title a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
i.fa.js-star-board( | ✖
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}" ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}} {{#if BoardMultiSelection.isActive}}is-multiselection-active{{/if}}")
title="{{_ 'star-board-title'}}") li.js-add-board
p.board-list-item-desc if isSelectedMenu 'templates'
+viewer a.board-list-item.label(title="{{_ 'add-template-container'}}")
= description | {{_ 'add-template-container'}}
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}}")
i.fa.board-handle(
class="fa-arrows"
title="{{_ 'drag-board'}}")
if isSandstorm
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
else if isAdministrable
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
else if currentUser.isAdmin
i.fa.js-clone-board(
class="fa-clone"
title="{{_ 'duplicate-board'}}")
i.fa.js-archive-board(
class="fa-archive"
title="{{_ 'archive-board'}}")
else else
a.js-open-board.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}") a.board-list-item.label(title="{{_ 'add-board'}}")
span.details | {{_ 'add-board'}}
span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}") each boards
+viewer li.js-board(class="{{_id}} {{#if isStarred}}starred{{/if}} {{colorClass}} {{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}", draggable="true")
= title if isInvited
unless currentSetting.hideBoardMemberList .board-list-item
if allowsBoardMemberList if BoardMultiSelection.isActive
.minicard-members .materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
each member in boardMembers _id class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
a.name span.details
+userAvatar(userId=member noRemove=true) span.board-list-item-name= title
unless currentSetting.hideCardCounterList span.js-star-board(
if allowsCardCounterList class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
.minicard-lists.flex.flex-wrap title="{{_ 'star-board-title'}}")
each list in boardLists _id | {{#if isStarred}}⭐{{else}}☆{{/if}}
.item p.board-list-item-desc {{_ 'just-invited'}}
| {{ list }} button.js-accept-invite.primary {{_ 'accept'}}
a.js-star-board( button.js-decline-invite {{_ 'decline'}}
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}" else
title="{{_ 'star-board-title'}}") if $eq type "template-container"
| {{#if isStarred}}⭐{{else}}☆{{/if}} .template-container.board-list-item
p.board-list-item-desc if BoardMultiSelection.isActive
+viewer .materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
= description class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
if hasSpentTimeCards span.board-handle(title="{{_ 'drag-board'}}") ↕️
i.fa.js-has-spenttime-cards( a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}" span.details
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}") span.board-list-item-name(title="{{_ 'template-container'}}")
i.fa.board-handle( +viewer
class="fa-arrows" = title
title="{{_ 'drag-board'}}") p.board-list-item-desc
if isSandstorm +viewer
a.js-clone-board( = description
class="fa-clone" if hasSpentTimeCards
title="{{_ 'duplicate-board'}}") span.js-has-spenttime-cards(
| 📋 class="{{#if hasOvertimeCards}}has-overtime-card-active{{else}}no-overtime-card-active{{/if}}"
a.js-archive-board( title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
class="fa-archive" | ⏱️
title="{{_ 'archive-board'}}") span.js-star-board(
| 📦 class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
else if isAdministrable title="{{_ 'star-board-title'}}")
a.js-clone-board( | {{#if isStarred}}⭐{{else}}☆{{/if}}
class="fa-clone" else
title="{{_ 'duplicate-board'}}") .board-list-item
| 📋 if BoardMultiSelection.isActive
a.js-archive-board( .materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
class="fa-archive" class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
title="{{_ 'archive-board'}}") span.board-handle(title="{{_ 'drag-board'}}") ↕️
| 📦 a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
else if currentUser.isAdmin span.details
a.js-clone-board( span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}")
class="fa-clone" +viewer
title="{{_ 'duplicate-board'}}") = title
| 📋 unless currentSetting.hideBoardMemberList
a.js-archive-board( if allowsBoardMemberList
class="fa-archive" .minicard-members
title="{{_ 'archive-board'}}") each member in boardMembers _id
| 📦 a.name
+userAvatar(userId=member noRemove=true)
unless currentSetting.hideCardCounterList
if allowsCardCounterList
.minicard-lists.flex.flex-wrap
each list in boardLists _id
.item
| {{ list }}
p.board-list-item-desc
+viewer
= description
if hasSpentTimeCards
span.js-has-spenttime-cards(
class="{{#if hasOvertimeCards}}has-overtime-card-active{{else}}no-overtime-card-active{{/if}}"
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
| ⏱️
a.js-star-board(
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
title="{{_ 'star-board-title'}}")
| {{#if isStarred}}⭐{{else}}☆{{/if}}
template(name="boardListHeaderBar") template(name="boardListHeaderBar")
h1 {{_ title }} h1 {{_ title }}
@ -157,3 +166,25 @@ template(name="boardListHeaderBar")
// a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}") // a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
// i.fa.fa-clone // i.fa.fa-clone
// span {{_ 'templates'}} // span {{_ 'templates'}}
// Recursive template for workspaces tree
template(name="workspaceTree")
if nodes
ul.workspace-tree.js-workspace-tree
each nodes
li.workspace-node(class="{{#if $eq id selectedWorkspaceId}}active{{/if}}" data-workspace-id="{{id}}" draggable="true")
.workspace-node-content
span.workspace-drag-handle ↕️
a.js-select-workspace(data-id="{{id}}")
span.workspace-icon
if icon
+viewer
= icon
else
| 📁
span.workspace-name= name
a.js-edit-workspace(data-id="{{id}}" title="{{_ 'allboards.edit-workspace'}}") ✏️
span.workspace-count {{workspaceCount id}}
a.js-add-subworkspace(data-id="{{id}}" title="{{_ 'allboards.add-subworkspace'}}") +
if children
+workspaceTree(nodes=children selectedWorkspaceId=selectedWorkspaceId)

View file

@ -14,6 +14,9 @@ Template.boardList.helpers({
return Utils.isMiniScreen() && Session.get('currentBoard'); */ return Utils.isMiniScreen() && Session.get('currentBoard'); */
return true; return true;
}, },
BoardMultiSelection() {
return BoardMultiSelection;
},
}) })
Template.boardListHeaderBar.events({ Template.boardListHeaderBar.events({
@ -45,6 +48,9 @@ BlazeComponent.extendComponent({
onCreated() { onCreated() {
Meteor.subscribe('setting'); Meteor.subscribe('setting');
Meteor.subscribe('tableVisibilityModeSettings'); Meteor.subscribe('tableVisibilityModeSettings');
this.selectedMenu = new ReactiveVar('starred');
this.selectedWorkspaceIdVar = new ReactiveVar(null);
this.workspacesTreeVar = new ReactiveVar([]);
let currUser = ReactiveCache.getCurrentUser(); let currUser = ReactiveCache.getCurrentUser();
let userLanguage; let userLanguage;
if (currUser && currUser.profile) { if (currUser && currUser.profile) {
@ -53,9 +59,72 @@ BlazeComponent.extendComponent({
if (userLanguage) { if (userLanguage) {
TAPi18n.setLanguage(userLanguage); TAPi18n.setLanguage(userLanguage);
} }
// Load workspaces tree reactively
this.autorun(() => {
const u = ReactiveCache.getCurrentUser();
const tree = (u && u.profile && u.profile.boardWorkspacesTree) || [];
this.workspacesTreeVar.set(tree);
});
},
reorderWorkspaces(draggedSpaceId, targetSpaceId) {
const tree = this.workspacesTreeVar.get();
// Helper to remove a space from tree
const removeSpace = (nodes, id) => {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].id === id) {
const removed = nodes.splice(i, 1)[0];
return { tree: nodes, removed };
}
if (nodes[i].children) {
const result = removeSpace(nodes[i].children, id);
if (result.removed) {
return { tree: nodes, removed: result.removed };
}
}
}
return { tree: nodes, removed: null };
};
// Helper to insert a space after target
const insertAfter = (nodes, targetId, spaceToInsert) => {
for (let i = 0; i < nodes.length; i++) {
if (nodes[i].id === targetId) {
nodes.splice(i + 1, 0, spaceToInsert);
return true;
}
if (nodes[i].children) {
if (insertAfter(nodes[i].children, targetId, spaceToInsert)) {
return true;
}
}
}
return false;
};
// Clone the tree
const newTree = EJSON.clone(tree);
// Remove the dragged space
const { tree: treeAfterRemoval, removed } = removeSpace(newTree, draggedSpaceId);
if (removed) {
// Insert after target
insertAfter(treeAfterRemoval, targetSpaceId, removed);
// Save the new tree
Meteor.call('setWorkspacesTree', treeAfterRemoval, (err) => {
if (err) console.error(err);
});
}
}, },
onRendered() { onRendered() {
// jQuery sortable is disabled in favor of HTML5 drag-and-drop for space management
// The old sortable code has been removed to prevent conflicts
/* OLD SORTABLE CODE - DISABLED
const itemsSelector = '.js-board:not(.placeholder)'; const itemsSelector = '.js-board:not(.placeholder)';
const $boards = this.$('.js-boards'); const $boards = this.$('.js-boards');
@ -73,27 +142,20 @@ BlazeComponent.extendComponent({
EscapeActions.executeUpTo('popup-close'); EscapeActions.executeUpTo('popup-close');
}, },
stop(evt, ui) { stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following card -- if any.
const prevBoardDom = ui.item.prev('.js-board').get(0); const prevBoardDom = ui.item.prev('.js-board').get(0);
const nextBoardBom = ui.item.next('.js-board').get(0); const nextBoardDom = ui.item.next('.js-board').get(0);
const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardBom, 1); const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardDom, 1);
const boardDomElement = ui.item.get(0); const boardDomElement = ui.item.get(0);
const board = Blaze.getData(boardDomElement); const board = Blaze.getData(boardDomElement);
// Normally the jquery-ui sortable library moves the dragged DOM element
// to its new position, which disrupts Blaze reactive updates mechanism
// (especially when we move the last card of a list, or when multiple
// users move some cards at the same time). To prevent these UX glitches
// we ask sortable to gracefully cancel the move, and to put back the
// DOM in its initial state. The card move is then handled reactively by
// Blaze with the below query.
$boards.sortable('cancel'); $boards.sortable('cancel');
board.move(sortIndex.base); const currentUser = ReactiveCache.getCurrentUser();
if (currentUser && typeof currentUser.setBoardSortIndex === 'function') {
currentUser.setBoardSortIndex(board._id, sortIndex.base);
}
}, },
}); });
// Disable drag-dropping if the current user is not a board member or is comment only
this.autorun(() => { this.autorun(() => {
if (Utils.isTouchScreenOrShowDesktopDragHandles()) { if (Utils.isTouchScreenOrShowDesktopDragHandles()) {
$boards.sortable({ $boards.sortable({
@ -101,6 +163,7 @@ BlazeComponent.extendComponent({
}); });
} }
}); });
*/
}, },
userHasTeams() { userHasTeams() {
if (ReactiveCache.getCurrentUser()?.teams?.length > 0) if (ReactiveCache.getCurrentUser()?.teams?.length > 0)
@ -132,6 +195,41 @@ BlazeComponent.extendComponent({
const ret = this.userHasOrgs() || this.userHasTeams(); const ret = this.userHasOrgs() || this.userHasTeams();
return ret; return ret;
}, },
currentMenuPath() {
const sel = this.selectedMenu.get();
const currentUser = ReactiveCache.getCurrentUser();
// Helper to find space by id in tree
const findSpaceById = (nodes, targetId, path = []) => {
for (const node of nodes) {
if (node.id === targetId) {
return [...path, node];
}
if (node.children && node.children.length > 0) {
const result = findSpaceById(node.children, targetId, [...path, node]);
if (result) return result;
}
}
return null;
};
if (sel === 'starred') {
return { icon: '⭐', text: TAPi18n.__('allboards.starred') };
} else if (sel === 'templates') {
return { icon: '📋', text: TAPi18n.__('allboards.templates') };
} else if (sel === 'remaining') {
return { icon: '📂', text: TAPi18n.__('allboards.remaining') };
} else {
// sel is a workspaceId, build path
const tree = this.workspacesTreeVar.get();
const spacePath = findSpaceById(tree, sel);
if (spacePath && spacePath.length > 0) {
const pathText = spacePath.map(s => s.name).join(' / ');
return { icon: '🗂️', text: `${TAPi18n.__('allboards.workspaces')} / ${pathText}` };
}
return { icon: '🗂️', text: TAPi18n.__('allboards.workspaces') };
}
},
boards() { boards() {
let query = { let query = {
// { type: 'board' }, // { type: 'board' },
@ -184,10 +282,33 @@ BlazeComponent.extendComponent({
}; };
} }
const ret = ReactiveCache.getBoards(query, { const boards = ReactiveCache.getBoards(query, {});
sort: { sort: 1 /* boards default sorting */ }, const currentUser = ReactiveCache.getCurrentUser();
}); let list = boards;
return ret; // Apply left menu filtering
const sel = this.selectedMenu.get();
const assignments = (currentUser && currentUser.profile && currentUser.profile.boardWorkspaceAssignments) || {};
if (sel === 'starred') {
list = list.filter(b => currentUser && currentUser.hasStarred(b._id));
} else if (sel === 'templates') {
list = list.filter(b => b.type === 'template-container');
} else if (sel === 'remaining') {
// Show boards not in any workspace AND not templates
// Keep starred boards visible in Remaining too
list = list.filter(b =>
!assignments[b._id] &&
b.type !== 'template-container'
);
} else {
// assume sel is a workspaceId
// Keep starred boards visible in their workspace too
list = list.filter(b => assignments[b._id] === sel);
}
if (currentUser && typeof currentUser.sortBoardsForUser === 'function') {
return currentUser.sortBoardsForUser(list);
}
return list.slice().sort((a, b) => (a.title || '').localeCompare(b.title || ''));
}, },
boardLists(boardId) { boardLists(boardId) {
/* Bug Board icons random dance https://github.com/wekan/wekan/issues/4214 /* Bug Board icons random dance https://github.com/wekan/wekan/issues/4214
@ -235,11 +356,65 @@ BlazeComponent.extendComponent({
events() { events() {
return [ return [
{ {
'click .js-add-board': Popup.open('createBoard'), 'click .js-select-menu'(evt) {
'click .js-star-board'(evt) { const type = evt.currentTarget.getAttribute('data-type');
const boardId = this.currentData()._id; this.selectedWorkspaceIdVar.set(null);
ReactiveCache.getCurrentUser().toggleBoardStar(boardId); this.selectedMenu.set(type);
},
'click .js-select-workspace'(evt) {
const id = evt.currentTarget.getAttribute('data-id');
this.selectedWorkspaceIdVar.set(id);
this.selectedMenu.set(id);
},
'click .js-add-workspace'(evt) {
evt.preventDefault(); evt.preventDefault();
const name = prompt(TAPi18n.__('allboards.add-workspace-prompt') || 'New Space name');
if (name && name.trim()) {
Meteor.call('createWorkspace', { parentId: null, name: name.trim() }, (err, res) => {
if (err) console.error(err);
});
}
},
'click .js-add-board'(evt) {
// Store the currently selected workspace/menu for board creation
const selectedWorkspaceId = this.selectedWorkspaceIdVar.get();
const selectedMenu = this.selectedMenu.get();
if (selectedWorkspaceId) {
Session.set('createBoardInWorkspace', selectedWorkspaceId);
} else {
Session.set('createBoardInWorkspace', null);
}
// Open different popup based on context
if (selectedMenu === 'templates') {
Popup.open('createTemplateContainer')(evt);
} else {
Popup.open('createBoard')(evt);
}
},
'click .js-star-board'(evt) {
evt.preventDefault();
evt.stopPropagation();
const boardId = this.currentData()._id;
if (boardId) {
Meteor.call('toggleBoardStar', boardId);
}
},
// HTML5 DnD from boards to spaces
'dragstart .js-board'(evt) {
const boardId = this.currentData()._id;
// Support multi-drag
if (BoardMultiSelection.isActive() && BoardMultiSelection.isSelected(boardId)) {
const selectedIds = BoardMultiSelection.getSelectedBoardIds();
try {
evt.originalEvent.dataTransfer.setData('text/plain', JSON.stringify(selectedIds));
evt.originalEvent.dataTransfer.setData('application/x-board-multi', 'true');
} catch (e) {}
} else {
try { evt.originalEvent.dataTransfer.setData('text/plain', boardId); } catch (e) {}
}
}, },
'click .js-clone-board'(evt) { 'click .js-clone-board'(evt) {
if (confirm(TAPi18n.__('duplicate-board-confirm'))) { if (confirm(TAPi18n.__('duplicate-board-confirm'))) {
@ -290,6 +465,58 @@ BlazeComponent.extendComponent({
} }
}); });
}, },
'click .js-multiselection-activate'(evt) {
evt.preventDefault();
if (BoardMultiSelection.isActive()) {
BoardMultiSelection.disable();
} else {
BoardMultiSelection.activate();
}
},
'click .js-multiselection-reset'(evt) {
evt.preventDefault();
BoardMultiSelection.disable();
},
'click .js-toggle-board-multi-selection'(evt) {
evt.preventDefault();
evt.stopPropagation();
const boardId = this.currentData()._id;
BoardMultiSelection.toogle(boardId);
},
'click .js-archive-selected-boards'(evt) {
evt.preventDefault();
const selectedBoards = BoardMultiSelection.getSelectedBoardIds();
if (selectedBoards.length > 0 && confirm(TAPi18n.__('archive-board-confirm'))) {
selectedBoards.forEach(boardId => {
Meteor.call('archiveBoard', boardId);
});
BoardMultiSelection.reset();
}
},
'click .js-duplicate-selected-boards'(evt) {
evt.preventDefault();
const selectedBoards = BoardMultiSelection.getSelectedBoardIds();
if (selectedBoards.length > 0 && confirm(TAPi18n.__('duplicate-board-confirm'))) {
selectedBoards.forEach(boardId => {
const board = ReactiveCache.getBoard(boardId);
if (board) {
Meteor.call(
'copyBoard',
boardId,
{
sort: ReactiveCache.getBoards({ archived: false }).length,
type: 'board',
title: board.title,
},
(err, res) => {
if (err) console.error(err);
}
);
}
});
BoardMultiSelection.reset();
}
},
'click #resetBtn'(event) { 'click #resetBtn'(event) {
let allBoards = document.getElementsByClassName("js-board"); let allBoards = document.getElementsByClassName("js-board");
let currBoard; let currBoard;
@ -356,7 +583,260 @@ BlazeComponent.extendComponent({
} }
} }
}, },
'click .js-edit-workspace'(evt) {
evt.preventDefault();
evt.stopPropagation();
const workspaceId = evt.currentTarget.getAttribute('data-id');
// Find the space in the tree
const findSpace = (nodes, id) => {
for (const node of nodes) {
if (node.id === id) return node;
if (node.children) {
const found = findSpace(node.children, id);
if (found) return found;
}
}
return null;
};
const tree = this.workspacesTreeVar.get();
const space = findSpace(tree, workspaceId);
if (space) {
const newName = prompt(TAPi18n.__('allboards.edit-workspace-name') || 'Space name:', space.name);
const newIcon = prompt(TAPi18n.__('allboards.edit-workspace-icon') || 'Space icon (markdown):', space.icon || '📁');
if (newName !== null && newName.trim()) {
// Update space in tree
const updateSpaceInTree = (nodes, id, updates) => {
return nodes.map(node => {
if (node.id === id) {
return { ...node, ...updates };
}
if (node.children) {
return { ...node, children: updateSpaceInTree(node.children, id, updates) };
}
return node;
});
};
const updatedTree = updateSpaceInTree(tree, workspaceId, {
name: newName.trim(),
icon: newIcon || '📁'
});
Meteor.call('setWorkspacesTree', updatedTree, (err) => {
if (err) console.error(err);
});
}
}
},
'click .js-add-subworkspace'(evt) {
evt.preventDefault();
evt.stopPropagation();
const parentId = evt.currentTarget.getAttribute('data-id');
const name = prompt(TAPi18n.__('allboards.add-subworkspace-prompt') || 'Subspace name:');
if (name && name.trim()) {
Meteor.call('createWorkspace', { parentId, name: name.trim() }, (err) => {
if (err) console.error(err);
});
}
},
'dragstart .workspace-node'(evt) {
const workspaceId = evt.currentTarget.getAttribute('data-workspace-id');
evt.originalEvent.dataTransfer.effectAllowed = 'move';
evt.originalEvent.dataTransfer.setData('application/x-workspace-id', workspaceId);
// Create a better drag image
const dragImage = evt.currentTarget.cloneNode(true);
dragImage.style.position = 'absolute';
dragImage.style.top = '-9999px';
dragImage.style.opacity = '0.8';
document.body.appendChild(dragImage);
evt.originalEvent.dataTransfer.setDragImage(dragImage, 0, 0);
setTimeout(() => document.body.removeChild(dragImage), 0);
evt.currentTarget.classList.add('dragging');
},
'dragend .workspace-node'(evt) {
evt.currentTarget.classList.remove('dragging');
document.querySelectorAll('.workspace-node').forEach(el => {
el.classList.remove('drag-over');
});
},
'dragover .workspace-node'(evt) {
evt.preventDefault();
evt.stopPropagation();
const draggingEl = document.querySelector('.workspace-node.dragging');
const targetEl = evt.currentTarget;
// Allow dropping boards on any space
// Or allow dropping spaces on other spaces (but not on itself or descendants)
if (!draggingEl || (targetEl !== draggingEl && !draggingEl.contains(targetEl))) {
evt.originalEvent.dataTransfer.dropEffect = 'move';
targetEl.classList.add('drag-over');
}
},
'dragleave .workspace-node'(evt) {
evt.currentTarget.classList.remove('drag-over');
},
'drop .workspace-node'(evt) {
evt.preventDefault();
evt.stopPropagation();
const targetEl = evt.currentTarget;
targetEl.classList.remove('drag-over');
// Check what's being dropped - board or workspace
const draggedWorkspaceId = evt.originalEvent.dataTransfer.getData('application/x-workspace-id');
const isMultiBoard = evt.originalEvent.dataTransfer.getData('application/x-board-multi');
const boardData = evt.originalEvent.dataTransfer.getData('text/plain');
if (draggedWorkspaceId && !boardData) {
// This is a workspace reorder operation
const targetWorkspaceId = targetEl.getAttribute('data-workspace-id');
if (draggedWorkspaceId !== targetWorkspaceId) {
this.reorderWorkspaces(draggedWorkspaceId, targetWorkspaceId);
}
} else if (boardData) {
// This is a board assignment operation
// Get the workspace ID directly from the dropped workspace-node's data-workspace-id attribute
const workspaceId = targetEl.getAttribute('data-workspace-id');
if (workspaceId) {
if (isMultiBoard) {
// Multi-board drag
try {
const boardIds = JSON.parse(boardData);
boardIds.forEach(boardId => {
Meteor.call('assignBoardToWorkspace', boardId, workspaceId);
});
} catch (e) {
// Error parsing multi-board data
}
} else {
// Single board drag
Meteor.call('assignBoardToWorkspace', boardData, workspaceId);
}
}
}
},
'dragover .js-select-menu'(evt) {
evt.preventDefault();
evt.stopPropagation();
const menuType = evt.currentTarget.getAttribute('data-type');
// Only allow drop on "remaining" menu to unassign boards from spaces
if (menuType === 'remaining') {
evt.originalEvent.dataTransfer.dropEffect = 'move';
evt.currentTarget.classList.add('drag-over');
}
},
'dragleave .js-select-menu'(evt) {
evt.currentTarget.classList.remove('drag-over');
},
'drop .js-select-menu'(evt) {
evt.preventDefault();
evt.stopPropagation();
const menuType = evt.currentTarget.getAttribute('data-type');
evt.currentTarget.classList.remove('drag-over');
// Only handle drops on "remaining" menu
if (menuType !== 'remaining') return;
const isMultiBoard = evt.originalEvent.dataTransfer.getData('application/x-board-multi');
const boardData = evt.originalEvent.dataTransfer.getData('text/plain');
if (boardData) {
if (isMultiBoard) {
// Multi-board drag - unassign all from workspaces
try {
const boardIds = JSON.parse(boardData);
boardIds.forEach(boardId => {
Meteor.call('unassignBoardFromWorkspace', boardId);
});
} catch (e) {
// Error parsing multi-board data
}
} else {
// Single board drag - unassign from workspace
Meteor.call('unassignBoardFromWorkspace', boardData);
}
}
},
}, },
]; ];
}, },
// Helpers for templates
workspacesTree() {
return this.workspacesTreeVar.get();
},
selectedWorkspaceId() {
return this.selectedWorkspaceIdVar.get();
},
isSelectedMenu(type) {
return this.selectedMenu.get() === type;
},
isSpaceSelected(id) {
return this.selectedWorkspaceIdVar.get() === id;
},
menuItemCount(type) {
const currentUser = ReactiveCache.getCurrentUser();
const assignments = (currentUser && currentUser.profile && currentUser.profile.boardWorkspaceAssignments) || {};
// Get all boards for counting
let query = {
$and: [
{ archived: false },
{ type: { $in: ['board', 'template-container'] } },
{ $or: [{ 'members.userId': Meteor.userId() }] },
{ title: { $not: { $regex: /^\^.*\^$/ } } }
]
};
const allBoards = ReactiveCache.getBoards(query, {});
if (type === 'starred') {
return allBoards.filter(b => currentUser && currentUser.hasStarred(b._id)).length;
} else if (type === 'templates') {
return allBoards.filter(b => b.type === 'template-container').length;
} else if (type === 'remaining') {
// Count boards not in any workspace AND not templates
// Include starred boards (they appear in both Starred and Remaining)
return allBoards.filter(b =>
!assignments[b._id] &&
b.type !== 'template-container'
).length;
}
return 0;
},
workspaceCount(workspaceId) {
const currentUser = ReactiveCache.getCurrentUser();
const assignments = (currentUser && currentUser.profile && currentUser.profile.boardWorkspaceAssignments) || {};
// Get all boards for counting
let query = {
$and: [
{ archived: false },
{ type: { $in: ['board', 'template-container'] } },
{ $or: [{ 'members.userId': Meteor.userId() }] },
{ title: { $not: { $regex: /^\^.*\^$/ } } }
]
};
const allBoards = ReactiveCache.getBoards(query, {});
// Count boards directly assigned to this space (not including children)
return allBoards.filter(b => assignments[b._id] === workspaceId).length;
},
canModifyBoards() {
const currentUser = ReactiveCache.getCurrentUser();
return currentUser && !currentUser.isCommentOnly();
},
hasBoardsSelected() {
return BoardMultiSelection.count() > 0;
},
}).register('boardList'); }).register('boardList');

View file

@ -8,39 +8,72 @@
.card-date.is-active { .card-date.is-active {
background-color: #b3b3b3; background-color: #b3b3b3;
} }
.card-date.current, /* Date status colors - red = overdue, amber = due soon, no shade = not due */
.card-date.almost-due, .card-date.overdue {
.card-date.due, background-color: #ff4444; /* Red for overdue */
.card-date.long-overdue {
color: #fff; color: #fff;
} }
.card-date.overdue:hover,
.card-date.overdue.is-active {
background-color: #cc3333;
}
.card-date.due-soon {
background-color: #ffaa00; /* Amber for due soon */
color: #000;
}
.card-date.due-soon:hover,
.card-date.due-soon.is-active {
background-color: #e69900;
}
.card-date.not-due {
/* No special background - uses default date type colors */
}
.card-date.current { .card-date.current {
background-color: #5ba639; background-color: #5ba639; /* Green for current/active */
color: #fff;
} }
.card-date.current:hover, .card-date.current:hover,
.card-date.current.is-active { .card-date.current.is-active {
background-color: #46802c; background-color: #46802c;
} }
.card-date.almost-due {
background-color: #edc909; .card-date.completed {
background-color: #90ee90; /* Light green for completed */
color: #000;
} }
.card-date.almost-due:hover, .card-date.completed:hover,
.card-date.almost-due.is-active { .card-date.completed.is-active {
background-color: #bc9f07; background-color: #7dd87d;
} }
.card-date.due {
background-color: #fa3f00; .card-date.completed-early {
background-color: #4caf50; /* Green for completed early */
color: #fff;
} }
.card-date.due:hover, .card-date.completed-early:hover,
.card-date.due.is-active { .card-date.completed-early.is-active {
background-color: #c73200; background-color: #45a049;
} }
.card-date.long-overdue {
background-color: #fd5d47; .card-date.completed-late {
background-color: #ff9800; /* Orange for completed late */
color: #fff;
} }
.card-date.long-overdue:hover, .card-date.completed-late:hover,
.card-date.long-overdue.is-active { .card-date.completed-late.is-active {
background-color: #fd3e24; background-color: #f57c00;
}
.card-date.completed-on-time {
background-color: #2196f3; /* Blue for completed on time */
color: #fff;
}
.card-date.completed-on-time:hover,
.card-date.completed-on-time.is-active {
background-color: #1976d2;
} }
/* Date type specific colors */ /* Date type specific colors */

View file

@ -97,6 +97,12 @@ template(name="minicardCustomFieldDate")
template(name="editCardReceivedDatePopup") template(name="editCardReceivedDatePopup")
form.edit-card-received-date form.edit-card-received-date
.datepicker .datepicker
// Date input field (existing)
// Insert calendar selector right after date input
.calendar-selector
label(for="calendar-received") 🗓️
input#calendar-received.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -106,6 +112,11 @@ template(name="editCardReceivedDatePopup")
template(name="editCardStartDatePopup") template(name="editCardStartDatePopup")
form.edit-card-start-date form.edit-card-start-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-start") 🗓️
input#calendar-start.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -115,6 +126,11 @@ template(name="editCardStartDatePopup")
template(name="editCardDueDatePopup") template(name="editCardDueDatePopup")
form.edit-card-due-date form.edit-card-due-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-due") 🗓️
input#calendar-due.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions
@ -124,6 +140,11 @@ template(name="editCardDueDatePopup")
template(name="editCardEndDatePopup") template(name="editCardEndDatePopup")
form.edit-card-end-date form.edit-card-end-date
.datepicker .datepicker
// Date input field (existing)
.calendar-selector
label(for="calendar-end") 🗓️
input#calendar-end.js-calendar-date(type="date")
// Time input field (if present)
.clear-date .clear-date
a.js-clear-date {{_ 'clear'}} a.js-clear-date {{_ 'clear'}}
.datepicker-actions .datepicker-actions

View file

@ -50,6 +50,17 @@ import {
onRendered() { onRendered() {
super.onRendered(); super.onRendered();
// DatePicker base class handles initialization with native HTML inputs // DatePicker base class handles initialization with native HTML inputs
const self = this;
this.$('.js-calendar-date').on('change', function(evt) {
const currentUser = ReactiveCache.getCurrentUser && ReactiveCache.getCurrentUser();
const dateFormat = currentUser ? currentUser.getDateFormat() : 'YYYY-MM-DD';
const value = evt.target.value;
if (value) {
// Format date according to user preference
const formatted = formatDateByUserPreference(new Date(value), dateFormat, true);
self._storeDate(new Date(value));
}
});
} }
_storeDate(date) { _storeDate(date) {
@ -157,14 +168,18 @@ class CardReceivedDate extends CardDate {
const endAt = this.data().getEnd(); const endAt = this.data().getEnd();
const startAt = this.data().getStart(); const startAt = this.data().getStart();
const theDate = this.date.get(); const theDate = this.date.get();
// if dueAt, endAt and startAt exist & are > receivedAt, receivedAt doesn't need to be flagged const now = this.now.get();
// Received date logic: if received date is after start, due, or end dates, it's overdue
if ( if (
(startAt && isAfter(theDate, startAt)) || (startAt && isAfter(theDate, startAt)) ||
(endAt && isAfter(theDate, endAt)) || (endAt && isAfter(theDate, endAt)) ||
(dueAt && isAfter(theDate, dueAt)) (dueAt && isAfter(theDate, dueAt))
) ) {
classes += 'long-overdue'; classes += 'overdue';
else classes += 'current'; } else {
classes += 'not-due';
}
return classes; return classes;
} }
@ -193,16 +208,22 @@ class CardStartDate extends CardDate {
} }
classes() { classes() {
let classes = 'start-date' + ' '; let classes = 'start-date ';
const dueAt = this.data().getDue(); const dueAt = this.data().getDue();
const endAt = this.data().getEnd(); const endAt = this.data().getEnd();
const theDate = this.date.get(); const theDate = this.date.get();
const now = this.now.get(); const now = this.now.get();
// if dueAt or endAt exist & are > startAt, startAt doesn't need to be flagged
if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) // Start date logic: if start date is after due or end dates, it's overdue
classes += 'long-overdue'; if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) {
else if (isAfter(theDate, now)) classes += ''; classes += 'overdue';
else classes += 'current'; } else if (isAfter(theDate, now)) {
// Start date is in the future - not due yet
classes += 'not-due';
} else {
// Start date is today or in the past - current/active
classes += 'current';
}
return classes; return classes;
} }
@ -231,17 +252,35 @@ class CardDueDate extends CardDate {
} }
classes() { classes() {
let classes = 'due-date' + ' '; let classes = 'due-date ';
const endAt = this.data().getEnd(); const endAt = this.data().getEnd();
const theDate = this.date.get(); const theDate = this.date.get();
const now = this.now.get(); const now = this.now.get();
// if the due date is after the end date, green - done early
if (endAt && isAfter(theDate, endAt)) classes += 'current'; // If there's an end date and it's before the due date, task is completed early
// if there is an end date, don't need to flag the due date if (endAt && isBefore(endAt, theDate)) {
else if (endAt) classes += ''; classes += 'completed-early';
else if (diff(now, theDate, 'days') >= 2) classes += 'long-overdue'; }
else if (diff(now, theDate, 'minute') >= 0) classes += 'due'; // If there's an end date, don't show due date status since task is completed
else if (diff(now, theDate, 'days') >= -1) classes += 'almost-due'; else if (endAt) {
classes += 'completed';
}
// Due date logic based on current time
else {
const daysDiff = diff(theDate, now, 'days');
if (daysDiff < 0) {
// Due date is in the past - overdue
classes += 'overdue';
} else if (daysDiff <= 1) {
// Due today or tomorrow - due soon
classes += 'due-soon';
} else {
// Due date is more than 1 day away - not due yet
classes += 'not-due';
}
}
return classes; return classes;
} }
@ -270,12 +309,23 @@ class CardEndDate extends CardDate {
} }
classes() { classes() {
let classes = 'end-date' + ' '; let classes = 'end-date ';
const dueAt = this.data().getDue(); const dueAt = this.data().getDue();
const theDate = this.date.get(); const theDate = this.date.get();
if (!dueAt) classes += '';
else if (isBefore(theDate, dueAt)) classes += 'current'; if (!dueAt) {
else if (isAfter(theDate, dueAt)) classes += 'due'; // No due date set - just show as completed
classes += 'completed';
} else if (isBefore(theDate, dueAt)) {
// End date is before due date - completed early
classes += 'completed-early';
} else if (isAfter(theDate, dueAt)) {
// End date is after due date - completed late
classes += 'completed-late';
} else {
// End date equals due date - completed on time
classes += 'completed-on-time';
}
return classes; return classes;
} }

View file

@ -191,7 +191,7 @@ template(name="cardDetails")
if currentBoard.allowsMembers if currentBoard.allowsMembers
.card-details-item.card-details-item-members .card-details-item.card-details-item-members
h3.card-details-item-title h3.card-details-item-title
| 👤s | &#x1F465;
| {{_ 'members'}} | {{_ 'members'}}
each userId in getMembers each userId in getMembers
+userAvatar(userId=userId cardId=_id) +userAvatar(userId=userId cardId=_id)
@ -242,7 +242,7 @@ template(name="cardDetails")
if currentBoard.allowsAssignedBy if currentBoard.allowsAssignedBy
.card-details-item.card-details-item-name .card-details-item.card-details-item-name
h3.card-details-item-title h3.card-details-item-title
| 👤-plus | ✍️
| {{_ 'assigned-by'}} | {{_ 'assigned-by'}}
if canModifyCard if canModifyCard
unless currentUser.isWorker unless currentUser.isWorker

View file

@ -430,56 +430,57 @@ BlazeComponent.extendComponent({
) { ) {
newState = forIt; newState = forIt;
} }
this.data().setVote(Meteor.userId(), newState); // Use secure server method; direct client updates to vote are blocked
Meteor.call('cards.vote', this.data()._id, newState);
}, },
'click .js-poker'(e) { 'click .js-poker'(e) {
let newState = null; let newState = null;
if ($(e.target).hasClass('js-poker-vote-one')) { if ($(e.target).hasClass('js-poker-vote-one')) {
newState = 'one'; newState = 'one';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-two')) { if ($(e.target).hasClass('js-poker-vote-two')) {
newState = 'two'; newState = 'two';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-three')) { if ($(e.target).hasClass('js-poker-vote-three')) {
newState = 'three'; newState = 'three';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-five')) { if ($(e.target).hasClass('js-poker-vote-five')) {
newState = 'five'; newState = 'five';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-eight')) { if ($(e.target).hasClass('js-poker-vote-eight')) {
newState = 'eight'; newState = 'eight';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-thirteen')) { if ($(e.target).hasClass('js-poker-vote-thirteen')) {
newState = 'thirteen'; newState = 'thirteen';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-twenty')) { if ($(e.target).hasClass('js-poker-vote-twenty')) {
newState = 'twenty'; newState = 'twenty';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-forty')) { if ($(e.target).hasClass('js-poker-vote-forty')) {
newState = 'forty'; newState = 'forty';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-one-hundred')) { if ($(e.target).hasClass('js-poker-vote-one-hundred')) {
newState = 'oneHundred'; newState = 'oneHundred';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
if ($(e.target).hasClass('js-poker-vote-unsure')) { if ($(e.target).hasClass('js-poker-vote-unsure')) {
newState = 'unsure'; newState = 'unsure';
this.data().setPoker(Meteor.userId(), newState); Meteor.call('cards.pokerVote', this.data()._id, newState);
} }
}, },
'click .js-poker-finish'(e) { 'click .js-poker-finish'(e) {
if ($(e.target).hasClass('js-poker-finish')) { if ($(e.target).hasClass('js-poker-finish')) {
e.preventDefault(); e.preventDefault();
const now = formatDateTime(new Date()); const now = new Date();
this.data().setPokerEnd(now); Meteor.call('cards.setPokerEnd', this.data()._id, now);
} }
}, },
@ -487,9 +488,9 @@ BlazeComponent.extendComponent({
if ($(e.target).hasClass('js-poker-replay')) { if ($(e.target).hasClass('js-poker-replay')) {
e.preventDefault(); e.preventDefault();
this.currentCard = this.currentData(); this.currentCard = this.currentData();
this.currentCard.replayPoker(); Meteor.call('cards.replayPoker', this.currentCard._id);
this.data().unsetPokerEnd(); Meteor.call('cards.unsetPokerEnd', this.currentCard._id);
this.data().unsetPokerEstimation(); Meteor.call('cards.unsetPokerEstimation', this.currentCard._id);
} }
}, },
'click .js-poker-estimation'(event) { 'click .js-poker-estimation'(event) {
@ -500,9 +501,9 @@ BlazeComponent.extendComponent({
this.find('#pokerEstimation').value = ''; this.find('#pokerEstimation').value = '';
if (ruleTitle) { if (ruleTitle) {
this.data().setPokerEstimation(parseInt(ruleTitle, 10)); Meteor.call('cards.setPokerEstimation', this.data()._id, parseInt(ruleTitle, 10));
} else { } else {
this.data().setPokerEstimation(''); Meteor.call('cards.unsetPokerEstimation', this.data()._id);
} }
} }
}, },
@ -1105,20 +1106,15 @@ BlazeComponent.extendComponent({
'is-checked', 'is-checked',
); );
const endString = this.currentCard.getVoteEnd(); const endString = this.currentCard.getVoteEnd();
Meteor.call('cards.setVoteQuestion', this.currentCard._id, voteQuestion, publicVote, allowNonBoardMembers);
this.currentCard.setVoteQuestion(
voteQuestion,
publicVote,
allowNonBoardMembers,
);
if (endString) { if (endString) {
this.currentCard.setVoteEnd(endString); Meteor.call('cards.setVoteEnd', this.currentCard._id, endString);
} }
Popup.back(); Popup.back();
}, },
'click .js-remove-vote': Popup.afterConfirm('deleteVote', () => { 'click .js-remove-vote': Popup.afterConfirm('deleteVote', () => {
event.preventDefault(); event.preventDefault();
this.currentCard.unsetVote(); Meteor.call('cards.unsetVote', this.currentCard._id);
Popup.back(); Popup.back();
}), }),
'click a.js-toggle-vote-public'(event) { 'click a.js-toggle-vote-public'(event) {
@ -1317,10 +1313,10 @@ BlazeComponent.extendComponent({
]; ];
} }
_storeDate(newDate) { _storeDate(newDate) {
this.card.setVoteEnd(newDate); Meteor.call('cards.setVoteEnd', this.card._id, newDate);
} }
_deleteDate() { _deleteDate() {
this.card.unsetVoteEnd(); Meteor.call('cards.unsetVoteEnd', this.card._id);
} }
}.register('editVoteEndDatePopup')); }.register('editVoteEndDatePopup'));
@ -1342,17 +1338,14 @@ BlazeComponent.extendComponent({
); );
const endString = this.currentCard.getPokerEnd(); const endString = this.currentCard.getPokerEnd();
this.currentCard.setPokerQuestion( Meteor.call('cards.setPokerQuestion', this.currentCard._id, pokerQuestion, allowNonBoardMembers);
pokerQuestion,
allowNonBoardMembers,
);
if (endString) { if (endString) {
this.currentCard.setPokerEnd(endString); Meteor.call('cards.setPokerEnd', this.currentCard._id, new Date(endString));
} }
Popup.back(); Popup.back();
}, },
'click .js-remove-poker': Popup.afterConfirm('deletePoker', (event) => { 'click .js-remove-poker': Popup.afterConfirm('deletePoker', (event) => {
this.currentCard.unsetPoker(); Meteor.call('cards.unsetPoker', this.currentCard._id);
Popup.back(); Popup.back();
}), }),
'click a.js-toggle-poker-allow-non-members'(event) { 'click a.js-toggle-poker-allow-non-members'(event) {
@ -1573,10 +1566,10 @@ BlazeComponent.extendComponent({
]; ];
} }
_storeDate(newDate) { _storeDate(newDate) {
this.card.setPokerEnd(newDate); Meteor.call('cards.setPokerEnd', this.card._id, newDate);
} }
_deleteDate() { _deleteDate() {
this.card.unsetPokerEnd(); Meteor.call('cards.unsetPokerEnd', this.card._id);
} }
}.register('editPokerEndDatePopup')); }.register('editPokerEndDatePopup'));

View file

@ -72,6 +72,10 @@ textarea.js-edit-checklist-item {
padding-top: 3px; padding-top: 3px;
float: left; float: left;
} }
.checklist-title span.fa.checklist-handle.fa-arrows::before {
content: "↕️" !important;
font-family: inherit !important;
}
#card-details-overlay { #card-details-overlay {
top: 0; top: 0;
bottom: -600px; bottom: -600px;
@ -148,6 +152,10 @@ textarea.js-edit-checklist-item {
padding-top: 2px; padding-top: 2px;
padding-right: 10px; padding-right: 10px;
} }
.checklist-item span.fa.checklistitem-handle.fa-arrows::before {
content: "↕️" !important;
font-family: inherit !important;
}
.js-delete-checklist-item, .js-delete-checklist-item,
.js-convert-checklist-item-to-card { .js-convert-checklist-item-to-card {
margin: 0 0 0.5em 1.33em; margin: 0 0 0.5em 1.33em;

View file

@ -69,6 +69,7 @@ template(name="addChecklistItemForm")
.edit-controls.clearfix .edit-controls.clearfix
button.primary.confirm.js-submit-add-checklist-item-form(type="submit") {{_ 'save'}} button.primary.confirm.js-submit-add-checklist-item-form(type="submit") {{_ 'save'}}
a.js-close-inlined-form(title="{{_ 'close-add-checklist-item'}}") a.js-close-inlined-form(title="{{_ 'close-add-checklist-item'}}")
| ❌
if showNewlineBecomesNewChecklistItem if showNewlineBecomesNewChecklistItem
.material-toggle-switch(title="{{_ 'newlineBecomesNewChecklistItem'}}") .material-toggle-switch(title="{{_ 'newlineBecomesNewChecklistItem'}}")
input.toggle-switch(type="checkbox" id="toggleNewlineBecomesNewChecklistItem") input.toggle-switch(type="checkbox" id="toggleNewlineBecomesNewChecklistItem")
@ -91,6 +92,7 @@ template(name="editChecklistItemForm")
.edit-controls.clearfix .edit-controls.clearfix
button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}} button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}}
a.js-close-inlined-form(title="{{_ 'close-edit-checklist-item'}}") a.js-close-inlined-form(title="{{_ 'close-edit-checklist-item'}}")
| ❌
span(title=createdAt) {{ moment createdAt }} span(title=createdAt) {{ moment createdAt }}
if canModifyCard if canModifyCard
a.js-delete-checklist-item {{_ "delete"}}... a.js-delete-checklist-item {{_ "delete"}}...

View file

@ -229,6 +229,74 @@
background-color: #ff9999; background-color: #ff9999;
} }
/* Date status colors for minicards - matching cardDate.css */
.minicard .card-date.overdue {
background-color: #ff4444 !important; /* Red for overdue */
color: #fff !important;
}
.minicard .card-date.overdue:hover,
.minicard .card-date.overdue.is-active {
background-color: #cc3333 !important;
}
.minicard .card-date.due-soon {
background-color: #ffaa00 !important; /* Amber for due soon */
color: #000 !important;
}
.minicard .card-date.due-soon:hover,
.minicard .card-date.due-soon.is-active {
background-color: #e69900 !important;
}
.minicard .card-date.not-due {
/* No special background - uses default date type colors */
}
.minicard .card-date.current {
background-color: #5ba639 !important; /* Green for current/active */
color: #fff !important;
}
.minicard .card-date.current:hover,
.minicard .card-date.current.is-active {
background-color: #46802c !important;
}
.minicard .card-date.completed {
background-color: #90ee90 !important; /* Light green for completed */
color: #000 !important;
}
.minicard .card-date.completed:hover,
.minicard .card-date.completed.is-active {
background-color: #7dd87d !important;
}
.minicard .card-date.completed-early {
background-color: #4caf50 !important; /* Green for completed early */
color: #fff !important;
}
.minicard .card-date.completed-early:hover,
.minicard .card-date.completed-early.is-active {
background-color: #45a049 !important;
}
.minicard .card-date.completed-late {
background-color: #ff9800 !important; /* Orange for completed late */
color: #fff !important;
}
.minicard .card-date.completed-late:hover,
.minicard .card-date.completed-late.is-active {
background-color: #f57c00 !important;
}
.minicard .card-date.completed-on-time {
background-color: #2196f3 !important; /* Blue for completed on time */
color: #fff !important;
}
.minicard .card-date.completed-on-time:hover,
.minicard .card-date.completed-on-time.is-active {
background-color: #1976d2 !important;
}
/* Font Awesome icons in minicard dates */ /* Font Awesome icons in minicard dates */
.minicard .card-date i.fa { .minicard .card-date i.fa {
margin-right: 0.3vw; margin-right: 0.3vw;

View file

@ -5,6 +5,7 @@ template(name="minicard")
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}") class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}")
if canModifyCard if canModifyCard
a.minicard-details-menu-with-handle.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") ☰ a.minicard-details-menu-with-handle.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") ☰
if canMoveCard
.handle .handle
| ↕️ | ↕️
.dates .dates
@ -141,7 +142,7 @@ template(name="minicard")
if canModifyCard if canModifyCard
if comments.length if comments.length
.badge(title="{{_ 'card-comments-title' comments.length }}") .badge(title="{{_ 'card-comments-title' comments.length }}")
span.badge-icon.badge-comment.badge-text | 💬 span.badge-icon.badge-comment.badge-text 💬
= ' ' = ' '
= comments.length = comments.length
//span.badge-comment.badge-text //span.badge-comment.badge-text
@ -149,36 +150,36 @@ template(name="minicard")
if getDescription if getDescription
unless currentBoard.allowsDescriptionTextOnMinicard unless currentBoard.allowsDescriptionTextOnMinicard
.badge.badge-state-image-only(title=getDescription) .badge.badge-state-image-only(title=getDescription)
span.badge-icon | 📝 span.badge-icon 📝
if getVoteQuestion if getVoteQuestion
.badge.badge-state-image-only(title=getVoteQuestion) .badge.badge-state-image-only(title=getVoteQuestion)
span.badge-icon(class="{{#if voteState}}text-green{{/if}}") | 👍 span.badge-icon(class="{{#if voteState}}text-green{{/if}}") 👍
span.badge-text {{ voteCountPositive }} span.badge-text {{ voteCountPositive }}
span.badge-icon(class="{{#if $eq voteState false}}text-red{{/if}}") | 👎 span.badge-icon(class="{{#if $eq voteState false}}text-red{{/if}}") 👎
span.badge-text {{ voteCountNegative }} span.badge-text {{ voteCountNegative }}
if getPokerQuestion if getPokerQuestion
.badge.badge-state-image-only(title=getPokerQuestion) .badge.badge-state-image-only(title=getPokerQuestion)
span.badge-icon(class="{{#if pokerState}}text-green{{/if}}") | span.badge-icon(class="{{#if pokerState}}text-green{{/if}}") ✅
if expiredPoker if expiredPoker
span.badge-text {{ getPokerEstimation }} span.badge-text {{ getPokerEstimation }}
if attachments.length if attachments.length
if currentBoard.allowsBadgeAttachmentOnMinicard if currentBoard.allowsBadgeAttachmentOnMinicard
.badge .badge
span.badge-icon | 📎 span.badge-icon 📎
span.badge-text= attachments.length span.badge-text= attachments.length
if checklists.length if checklists.length
.badge(class="{{#if checklistFinished}}is-finished{{/if}}") .badge(class="{{#if checklistFinished}}is-finished{{/if}}")
span.badge-icon | ☑️ span.badge-icon ☑️
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}} span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
if allSubtasks.count if allSubtasks.count
.badge .badge
span.badge-icon | 🌐 span.badge-icon 🌐
span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}} span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}}
//{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down //{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down
if currentBoard.allowsCardSortingByNumber if currentBoard.allowsCardSortingByNumber
if currentBoard.allowsCardSortingByNumberOnMinicard if currentBoard.allowsCardSortingByNumberOnMinicard
.badge .badge
span.badge-icon | 🔢 span.badge-icon 🔢
span.badge-text.check-list-sort {{ sort }} span.badge-text.check-list-sort {{ sort }}
if currentBoard.allowsDescriptionTextOnMinicard if currentBoard.allowsDescriptionTextOnMinicard
if getDescription if getDescription

View file

@ -56,17 +56,17 @@ template(name="importMapMembersAddPopup")
p p
| {{_ 'import-user-select'}} | {{_ 'import-user-select'}}
.js-map-member .js-map-member
+EasySearch.Input(index=searchIndex) input.js-search-member-input(type="text" placeholder="{{_ 'search-users'}}")
ul.pop-over-list ul.pop-over-list
+EasySearch.Each(index=searchIndex) each searchResults
li.item.js-member-item li.item.js-member-item
a.name.js-select-import(title="{{profile.fullname}} ({{username}})" data-id="{{__originalId}}") a.name.js-select-import(title="{{profile.fullname}} ({{username}})" data-id="{{_id}}")
+userAvatar(userId=__originalId) +userAvatar(userId=_id)
span.full-name span.full-name
= profile.fullname = profile.fullname
| (<span class="username">{{username}}</span>) | (<span class="username">{{username}}</span>)
+EasySearch.IfSearching(index=searchIndex) if searching.get
+spinner +spinner
+EasySearch.IfNoResults(index=searchIndex) if noResults.get
.manage-member-section .manage-member-section
p.quiet {{_ 'no-results'}} p.quiet {{_ 'no-results'}}

View file

@ -311,6 +311,73 @@ BlazeComponent.extendComponent({
}, },
}).register('importMapMembersAddPopup'); }).register('importMapMembersAddPopup');
// Global reactive variables for import member popup
const importMemberPopupState = {
searching: new ReactiveVar(false),
searchResults: new ReactiveVar([]),
noResults: new ReactiveVar(false),
searchTimeout: null
};
BlazeComponent.extendComponent({
onCreated() {
// Use global state
this.searching = importMemberPopupState.searching;
this.searchResults = importMemberPopupState.searchResults;
this.noResults = importMemberPopupState.noResults;
this.searchTimeout = importMemberPopupState.searchTimeout;
},
onRendered() {
this.find('.js-search-member-input').focus();
},
performSearch(query) {
if (!query || query.length < 2) {
this.searchResults.set([]);
this.noResults.set(false);
return;
}
this.searching.set(true);
this.noResults.set(false);
const results = UserSearchIndex.search(query, { limit: 20 }).fetch();
this.searchResults.set(results);
this.searching.set(false);
if (results.length === 0) {
this.noResults.set(true);
}
},
events() {
return [
{
'keyup .js-search-member-input'(event) {
const query = event.target.value.trim();
if (this.searchTimeout) {
clearTimeout(this.searchTimeout);
}
this.searchTimeout = setTimeout(() => {
this.performSearch(query);
}, 300);
},
},
];
},
}).register('importMapMembersAddPopupSearch');
Template.importMapMembersAddPopup.helpers({ Template.importMapMembersAddPopup.helpers({
searchIndex: () => UserSearchIndex, searchResults() {
return importMemberPopupState.searchResults.get();
},
searching() {
return importMemberPopupState.searching;
},
noResults() {
return importMemberPopupState.noResults;
}
}) })

View file

@ -378,9 +378,6 @@ body.list-resizing-active * {
position: relative; position: relative;
text-overflow: ellipsis; text-overflow: ellipsis;
white-space: nowrap; white-space: nowrap;
}
.list-header .list-rotated {
} }
.list-header .list-header-watch-icon { .list-header .list-header-watch-icon {
padding-left: 10px; padding-left: 10px;
@ -644,17 +641,22 @@ body.list-resizing-active * {
.mini-list.mobile-view { .mini-list.mobile-view {
flex: 0 0 60px; flex: 0 0 60px;
height: auto; height: auto;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list.mobile-view { .list.mobile-view {
display: contents; display: block !important;
flex-basis: auto; flex-basis: auto;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
margin: 0 !important;
padding: 0 !important;
} }
.list.mobile-view:first-child { .list.mobile-view:first-child {
margin-left: 0px; margin-left: 0px;
@ -662,9 +664,11 @@ body.list-resizing-active * {
.list.mobile-view.ui-sortable-helper { .list.mobile-view.ui-sortable-helper {
flex: 0 0 60px; flex: 0 0 60px;
height: 60px; height: 60px;
width: 100%; width: 100vw;
max-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list.mobile-view.ui-sortable-helper .list-header.ui-sortable-handle { .list.mobile-view.ui-sortable-helper .list-header.ui-sortable-handle {
cursor: grabbing; cursor: grabbing;
@ -672,14 +676,17 @@ body.list-resizing-active * {
.list.mobile-view.placeholder { .list.mobile-view.placeholder {
flex: 0 0 60px; flex: 0 0 60px;
height: 60px; height: 60px;
width: 100%; width: 100vw;
max-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list.mobile-view .list-body { .list.mobile-view .list-body {
padding: 15px 19px; padding: 15px 19px;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
} }
.list.mobile-view .list-header { .list.mobile-view .list-header {
/*Updated padding values for mobile devices, this should fix text grouping issue*/ /*Updated padding values for mobile devices, this should fix text grouping issue*/
@ -688,8 +695,9 @@ body.list-resizing-active * {
min-height: 30px; min-height: 30px;
margin-top: 10px; margin-top: 10px;
align-items: center; align-items: center;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
/* Force grid layout for iPhone */ /* Force grid layout for iPhone */
display: grid !important; display: grid !important;
grid-template-columns: 30px 1fr auto auto !important; grid-template-columns: 30px 1fr auto auto !important;
@ -770,17 +778,22 @@ body.list-resizing-active * {
.mini-list { .mini-list {
flex: 0 0 60px; flex: 0 0 60px;
height: auto; height: auto;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list { .list {
display: contents; display: block !important;
flex-basis: auto; flex-basis: auto;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
margin: 0 !important;
padding: 0 !important;
} }
.list:first-child { .list:first-child {
margin-left: 0px; margin-left: 0px;
@ -788,9 +801,11 @@ body.list-resizing-active * {
.list.ui-sortable-helper { .list.ui-sortable-helper {
flex: 0 0 60px; flex: 0 0 60px;
height: 60px; height: 60px;
width: 100%; width: 100vw;
max-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list.ui-sortable-helper .list-header.ui-sortable-handle { .list.ui-sortable-helper .list-header.ui-sortable-handle {
cursor: grabbing; cursor: grabbing;
@ -798,14 +813,17 @@ body.list-resizing-active * {
.list.placeholder { .list.placeholder {
flex: 0 0 60px; flex: 0 0 60px;
height: 60px; height: 60px;
width: 100%; width: 100vw;
max-width: 100vw;
border-left: 0px !important; border-left: 0px !important;
border-bottom: 1px solid #ccc; border-bottom: 1px solid #ccc;
display: block !important;
} }
.list-body { .list-body {
padding: 15px 19px; padding: 15px 19px;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
} }
.list-header { .list-header {
/*Updated padding values for mobile devices, this should fix text grouping issue*/ /*Updated padding values for mobile devices, this should fix text grouping issue*/
@ -814,8 +832,9 @@ body.list-resizing-active * {
min-height: 30px; min-height: 30px;
margin-top: 10px; margin-top: 10px;
align-items: center; align-items: center;
width: 100%; width: 100vw;
min-width: 100%; max-width: 100vw;
min-width: 100vw;
} }
.list-header .list-header-left-icon { .list-header .list-header-left-icon {
padding: 7px; padding: 7px;

View file

@ -55,7 +55,8 @@ template(name="listHeader")
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰ a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰
else else
a.list-header-menu-icon.js-select-list ▶️ a.list-header-menu-icon.js-select-list ▶️
a.list-header-handle.handle.js-list-handle ↕️ unless currentUser.isWorker
a.list-header-handle.handle.js-list-handle ↕️
else if currentUser.isBoardMember else if currentUser.isBoardMember
if isWatching if isWatching
i.list-header-watch-icon | 👁️ i.list-header-watch-icon | 👁️
@ -72,7 +73,8 @@ template(name="listHeader")
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰ a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰
if currentUser.isBoardMember if currentUser.isBoardMember
unless currentUser.isCommentOnly unless currentUser.isCommentOnly
a.list-header-handle.handle.js-list-handle ↕️ unless currentUser.isWorker
a.list-header-handle.handle.js-list-handle ↕️
template(name="editListTitleForm") template(name="editListTitleForm")
.list-composer .list-composer

View file

@ -32,7 +32,16 @@ template(name="dueCards")
span.global-search-error-messages span.global-search-error-messages
= msg = msg
else else
+resultsPaged(this) .due-cards-results-header
h1
= resultsText
each card in dueCardsList
+resultCard(card)
else
.global-search-results-list-wrapper
.no-results
h3 {{_ 'dueCards-noResults-title'}}
p {{_ 'dueCards-noResults-description'}}
template(name="dueCardsViewChangePopup") template(name="dueCardsViewChangePopup")
if currentUser if currentUser

View file

@ -1,13 +1,6 @@
import { ReactiveCache } from '/imports/reactiveCache'; import { ReactiveCache } from '/imports/reactiveCache';
import { CardSearchPagedComponent } from '../../lib/cardSearch'; import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
import { import { TAPi18n } from '/imports/i18n';
OPERATOR_HAS,
OPERATOR_SORT,
OPERATOR_USER,
ORDER_ASCENDING,
PREDICATE_DUE_AT,
} from '../../../config/search-const';
import { QueryParams } from '../../../config/query-classes';
// const subManager = new SubsManager(); // const subManager = new SubsManager();
@ -31,6 +24,47 @@ Template.dueCards.helpers({
userId() { userId() {
return Meteor.userId(); return Meteor.userId();
}, },
dueCardsList() {
const component = BlazeComponent.getComponentForElement(this.firstNode);
if (component && component.dueCardsList) {
return component.dueCardsList();
}
return [];
},
hasResults() {
const component = BlazeComponent.getComponentForElement(this.firstNode);
if (component && component.hasResults) {
return component.hasResults.get();
}
return false;
},
searching() {
const component = BlazeComponent.getComponentForElement(this.firstNode);
if (component && component.isLoading) {
return component.isLoading.get();
}
return true; // Show loading by default
},
hasQueryErrors() {
return false; // No longer using search, so always false
},
errorMessages() {
return []; // No longer using search, so always empty
},
cardsCount() {
const component = BlazeComponent.getComponentForElement(this.firstNode);
if (component && component.cardsCount) {
return component.cardsCount();
}
return 0;
},
resultsText() {
const component = BlazeComponent.getComponentForElement(this.firstNode);
if (component && component.resultsText) {
return component.resultsText();
}
return '';
},
}); });
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
@ -55,71 +89,50 @@ BlazeComponent.extendComponent({
}, },
}).register('dueCardsViewChangePopup'); }).register('dueCardsViewChangePopup');
class DueCardsComponent extends CardSearchPagedComponent { class DueCardsComponent extends BlazeComponent {
onCreated() { onCreated() {
super.onCreated(); super.onCreated();
// Add a small delay to ensure ReactiveCache is ready this._cachedCards = null;
this.searchRetryCount = 0; this._cachedTimestamp = null;
this.maxRetries = 3; this.subscriptionHandle = null;
this.isLoading = new ReactiveVar(true);
this.hasResults = new ReactiveVar(false);
this.searching = new ReactiveVar(false);
// Use a timeout to ensure the search runs after the component is fully initialized // Subscribe to the optimized due cards publication
Meteor.setTimeout(() => { this.autorun(() => {
this.performSearch(); const allUsers = this.dueCardsView() === 'all';
}, 100); if (this.subscriptionHandle) {
} this.subscriptionHandle.stop();
performSearch() {
if (process.env.DEBUG === 'true') {
console.log('Performing due cards search, attempt:', this.searchRetryCount + 1);
}
// Check if user is authenticated
const currentUser = ReactiveCache.getCurrentUser();
if (!currentUser) {
if (process.env.DEBUG === 'true') {
console.log('User not authenticated, waiting...');
} }
Meteor.setTimeout(() => { this.subscriptionHandle = Meteor.subscribe('dueCards', allUsers);
this.performSearch();
}, 1000); // Update loading state based on subscription
return; this.autorun(() => {
} if (this.subscriptionHandle && this.subscriptionHandle.ready()) {
if (process.env.DEBUG === 'true') {
if (process.env.DEBUG === 'true') { console.log('dueCards: subscription ready, loading data...');
console.log('User authenticated:', currentUser.username); }
} this.isLoading.set(false);
const cards = this.dueCardsList();
const queryParams = new QueryParams(); this.hasResults.set(cards && cards.length > 0);
queryParams.addPredicate(OPERATOR_HAS, { } else {
field: PREDICATE_DUE_AT, if (process.env.DEBUG === 'true') {
exists: true, console.log('dueCards: subscription not ready, showing loading...');
}); }
// queryParams[OPERATOR_LIMIT] = 5; this.isLoading.set(true);
queryParams.addPredicate(OPERATOR_SORT, { this.hasResults.set(false);
name: PREDICATE_DUE_AT, }
order: ORDER_ASCENDING, });
}); });
}
// Note: User filtering is handled server-side based on board membership onDestroyed() {
// The OPERATOR_USER filter is too restrictive as it only shows cards where super.onDestroyed();
// the user is assigned or a member of the card, not the board if (this.subscriptionHandle) {
// if (Utils && Utils.dueCardsView && Utils.dueCardsView() !== 'all') { this.subscriptionHandle.stop();
// const currentUser = ReactiveCache.getCurrentUser();
// if (currentUser && currentUser.username) {
// queryParams.addPredicate(OPERATOR_USER, currentUser.username);
// }
// }
// Debug: Log the query parameters
if (process.env.DEBUG === 'true') {
console.log('Due cards query params:', queryParams.params);
console.log('Due cards query text:', queryParams.text);
console.log('Due cards has predicates:', queryParams.getPredicates('has'));
console.log('Due cards sort predicates:', queryParams.getPredicates('sort'));
} }
this.runGlobalSearch(queryParams);
} }
dueCardsView() { dueCardsView() {
@ -132,29 +145,106 @@ class DueCardsComponent extends CardSearchPagedComponent {
return this.dueCardsView() === 'board'; return this.dueCardsView() === 'board';
} }
hasResults() {
return this.hasResults.get();
}
cardsCount() {
const cards = this.dueCardsList();
return cards ? cards.length : 0;
}
resultsText() {
const count = this.cardsCount();
if (count === 1) {
return TAPi18n.__('one-card-found');
} else {
// Get the translated text and manually replace %s with the count
const baseText = TAPi18n.__('n-cards-found');
const result = baseText.replace('%s', count);
if (process.env.DEBUG === 'true') {
console.log('dueCards: base text:', baseText, 'count:', count, 'result:', result);
}
return result;
}
}
dueCardsList() { dueCardsList() {
const results = this.getResults(); // Check if subscription is ready
console.log('results:', results); if (!this.subscriptionHandle || !this.subscriptionHandle.ready()) {
const cards = []; if (process.env.DEBUG === 'true') {
if (results) { console.log('dueCards client: subscription not ready');
results.forEach(card => { }
cards.push(card); return [];
}
// Use cached results if available to avoid expensive re-sorting
if (this._cachedCards && this._cachedTimestamp && (Date.now() - this._cachedTimestamp < 5000)) {
if (process.env.DEBUG === 'true') {
console.log('dueCards client: using cached results,', this._cachedCards.length, 'cards');
}
return this._cachedCards;
}
// Get cards directly from the subscription (already sorted by the publication)
const cards = ReactiveCache.getCards({
type: 'cardType-card',
archived: false,
dueAt: { $exists: true, $nin: [null, ''] }
});
if (process.env.DEBUG === 'true') {
console.log('dueCards client: found', cards.length, 'cards with due dates');
console.log('dueCards client: cards details:', cards.map(c => ({
id: c._id,
title: c.title,
dueAt: c.dueAt,
boardId: c.boardId,
members: c.members,
assignees: c.assignees,
userId: c.userId
})));
}
// Filter cards based on user view preference
const allUsers = this.dueCardsView() === 'all';
const currentUser = ReactiveCache.getCurrentUser();
let filteredCards = cards;
if (process.env.DEBUG === 'true') {
console.log('dueCards client: current user:', currentUser ? currentUser._id : 'none');
console.log('dueCards client: showing all users:', allUsers);
}
if (!allUsers && currentUser) {
filteredCards = cards.filter(card => {
const isMember = card.members && card.members.includes(currentUser._id);
const isAssignee = card.assignees && card.assignees.includes(currentUser._id);
const isAuthor = card.userId === currentUser._id;
const matches = isMember || isAssignee || isAuthor;
if (process.env.DEBUG === 'true' && matches) {
console.log('dueCards client: card matches user:', card.title, { isMember, isAssignee, isAuthor });
}
return matches;
}); });
} }
cards.sort((a, b) => { if (process.env.DEBUG === 'true') {
const x = a.dueAt === null ? new Date('2100-12-31') : a.dueAt; console.log('dueCards client: filtered to', filteredCards.length, 'cards');
const y = b.dueAt === null ? new Date('2100-12-31') : b.dueAt; }
if (x > y) return 1; // Cache the results for 5 seconds to avoid re-filtering on every render
else if (x < y) return -1; this._cachedCards = filteredCards;
this._cachedTimestamp = Date.now();
return 0; // Update reactive variables
}); this.hasResults.set(filteredCards && filteredCards.length > 0);
this.isLoading.set(false);
// eslint-disable-next-line no-console return filteredCards;
console.log('cards:', cards);
return cards;
} }
} }

View file

@ -83,10 +83,6 @@ template(name="header")
i.mobile-icon(class="{{#if mobileMode}}active{{/if}}") 📱 i.mobile-icon(class="{{#if mobileMode}}active{{/if}}") 📱
i.desktop-icon(class="{{#unless mobileMode}}active{{/unless}}") 🖥️ i.desktop-icon(class="{{#unless mobileMode}}active{{/unless}}") 🖥️
// Bookmarks button - desktop opens popup, mobile routes to page
a.board-header-btn.js-open-bookmarks(title="{{_ 'bookmarks'}}")
| 🔖
// Notifications // Notifications
+notifications +notifications

View file

@ -293,6 +293,8 @@
overflow-y: auto !important; overflow-y: auto !important;
} }
.pop-over[data-popup="editCardReceivedDatePopup"] .edit-date button, .pop-over[data-popup="editCardReceivedDatePopup"] .edit-date button,
.pop-over[data-popup="editCardStartDatePopup"] .edit-date button, .pop-over[data-popup="editCardStartDatePopup"] .edit-date button,
.pop-over[data-popup="editCardDueDatePopup"] .edit-date button, .pop-over[data-popup="editCardDueDatePopup"] .edit-date button,
@ -387,9 +389,6 @@
margin: 0; margin: 0;
visibility: hidden; visibility: hidden;
} }
.pop-over .quiet {
/* padding: 6px 6px 4px;*/
}
.pop-over.search-over { .pop-over.search-over {
background: #f0f0f0; background: #f0f0f0;
min-height: 14vh; min-height: 14vh;

View file

@ -1,38 +1,33 @@
/* Migration Progress Styles */ /* Migration Progress Styles */
.migration-overlay { .migration-progress-overlay {
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
width: 100%; right: 0;
height: 100%; bottom: 0;
background-color: rgba(0, 0, 0, 0.8); background: rgba(0, 0, 0, 0.7);
z-index: 10000; z-index: 9999;
display: none; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
overflow-y: auto; backdrop-filter: blur(2px);
} }
.migration-overlay.active { .migration-progress-modal {
display: flex;
}
.migration-modal {
background: white; background: white;
border-radius: 12px; border-radius: 8px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4); box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
max-width: 800px; max-width: 500px;
width: 95%; width: 90%;
max-height: 90vh; max-height: 80vh;
overflow: hidden; overflow: hidden;
animation: slideInScale 0.4s ease-out; animation: migrationModalSlideIn 0.3s ease-out;
margin: 20px;
} }
@keyframes slideInScale { @keyframes migrationModalSlideIn {
from { from {
opacity: 0; opacity: 0;
transform: translateY(-30px) scale(0.95); transform: translateY(-20px) scale(0.95);
} }
to { to {
opacity: 1; opacity: 1;
@ -40,333 +35,235 @@
} }
} }
.migration-header { .migration-progress-header {
padding: 24px 32px 20px;
border-bottom: 2px solid #e0e0e0;
text-align: center;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white; color: white;
padding: 20px;
display: flex;
justify-content: space-between;
align-items: center;
} }
.migration-header h3 { .migration-progress-title {
margin: 0 0 8px 0; margin: 0;
font-size: 24px; font-size: 18px;
font-weight: 600; font-weight: 600;
} }
.migration-header h3 i { .migration-progress-close {
margin-right: 12px; cursor: pointer;
color: #FFD700;
}
.migration-header p {
margin: 0;
font-size: 16px; font-size: 16px;
opacity: 0.9; opacity: 0.8;
transition: opacity 0.2s ease;
} }
.migration-content { .migration-progress-close:hover {
padding: 24px 32px; opacity: 1;
max-height: 60vh;
overflow-y: auto;
} }
.migration-overview { .migration-progress-content {
margin-bottom: 32px; padding: 30px;
padding: 20px;
background: #f8f9fa;
border-radius: 8px;
border-left: 4px solid #667eea;
} }
.overall-progress { .migration-progress-overall {
margin-bottom: 20px; margin-bottom: 25px;
} }
.progress-bar { .migration-progress-overall-label {
width: 100%; font-weight: 600;
height: 12px; color: #333;
background-color: #e0e0e0;
border-radius: 6px;
overflow: hidden;
margin-bottom: 8px; margin-bottom: 8px;
position: relative; font-size: 14px;
} }
.progress-fill { .migration-progress-overall-bar {
background: #e9ecef;
border-radius: 10px;
height: 12px;
overflow: hidden;
margin-bottom: 5px;
}
.migration-progress-overall-fill {
background: linear-gradient(90deg, #28a745, #20c997);
height: 100%; height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2); border-radius: 10px;
border-radius: 6px;
transition: width 0.3s ease; transition: width 0.3s ease;
position: relative; position: relative;
} }
.progress-fill::after { .migration-progress-overall-fill::after {
content: ''; content: '';
position: absolute; position: absolute;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
background: linear-gradient( background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
90deg, animation: migrationProgressShimmer 2s infinite;
transparent,
rgba(255, 255, 255, 0.4),
transparent
);
animation: shimmer 2s infinite;
} }
@keyframes shimmer { @keyframes migrationProgressShimmer {
0% { 0% { transform: translateX(-100%); }
transform: translateX(-100%); 100% { transform: translateX(100%); }
}
100% {
transform: translateX(100%);
}
} }
.progress-text { .migration-progress-overall-percentage {
text-align: center;
font-weight: 700;
color: #667eea;
font-size: 18px;
}
.progress-label {
text-align: center;
color: #666;
font-size: 14px;
margin-top: 4px;
}
.current-step {
text-align: center;
color: #333;
font-size: 16px;
font-weight: 500;
margin-bottom: 16px;
}
.current-step i {
margin-right: 8px;
color: #667eea;
}
.estimated-time {
text-align: center;
color: #666;
font-size: 14px;
background-color: #fff3cd;
padding: 8px 12px;
border-radius: 4px;
border: 1px solid #ffeaa7;
}
.estimated-time i {
margin-right: 6px;
color: #f39c12;
}
.migration-steps {
margin-bottom: 24px;
}
.migration-steps h4 {
margin: 0 0 16px 0;
color: #333;
font-size: 18px;
font-weight: 600;
}
.steps-list {
max-height: 300px;
overflow-y: auto;
border: 1px solid #e0e0e0;
border-radius: 8px;
}
.migration-step {
padding: 16px 20px;
border-bottom: 1px solid #f0f0f0;
transition: all 0.3s ease;
}
.migration-step:last-child {
border-bottom: none;
}
.migration-step.completed {
background-color: #d4edda;
border-left: 4px solid #28a745;
}
.migration-step.current {
background-color: #cce7ff;
border-left: 4px solid #667eea;
animation: pulse 2s infinite;
}
@keyframes pulse {
0% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0.4);
}
70% {
box-shadow: 0 0 0 10px rgba(102, 126, 234, 0);
}
100% {
box-shadow: 0 0 0 0 rgba(102, 126, 234, 0);
}
}
.step-header {
display: flex;
align-items: center;
margin-bottom: 8px;
}
.step-icon {
margin-right: 12px;
font-size: 18px;
width: 24px;
text-align: center;
}
.step-icon i.fa-check-circle {
color: #28a745;
}
.step-icon i.fa-cog.fa-spin {
color: #667eea;
}
.step-icon i.fa-circle-o {
color: #ccc;
}
.step-info {
flex: 1;
}
.step-name {
font-weight: 600;
color: #333;
font-size: 14px;
margin-bottom: 2px;
}
.step-description {
color: #666;
font-size: 12px;
line-height: 1.3;
}
.step-progress {
text-align: right; text-align: right;
min-width: 40px;
}
.step-progress .progress-text {
font-size: 12px; font-size: 12px;
color: #666;
font-weight: 600; font-weight: 600;
} }
.step-progress-bar { .migration-progress-current-step {
width: 100%; margin-bottom: 25px;
height: 4px;
background-color: #e0e0e0;
border-radius: 2px;
overflow: hidden;
margin-top: 8px;
} }
.step-progress-bar .progress-fill { .migration-progress-step-label {
font-weight: 600;
color: #333;
margin-bottom: 8px;
font-size: 14px;
}
.migration-progress-step-bar {
background: #e9ecef;
border-radius: 8px;
height: 8px;
overflow: hidden;
margin-bottom: 5px;
}
.migration-progress-step-fill {
background: linear-gradient(90deg, #007bff, #0056b3);
height: 100%; height: 100%;
background: linear-gradient(90deg, #667eea, #764ba2); border-radius: 8px;
border-radius: 2px;
transition: width 0.3s ease; transition: width 0.3s ease;
} }
.migration-status { .migration-progress-step-percentage {
text-align: center; text-align: right;
color: #333; font-size: 12px;
font-size: 16px; color: #666;
background-color: #e3f2fd; font-weight: 600;
padding: 12px 16px; }
.migration-progress-status {
margin-bottom: 20px;
padding: 15px;
background: #f8f9fa;
border-radius: 6px; border-radius: 6px;
border: 1px solid #bbdefb; border-left: 4px solid #007bff;
margin-bottom: 16px;
} }
.migration-status i { .migration-progress-status-label {
margin-right: 8px; font-weight: 600;
color: #2196f3; color: #333;
margin-bottom: 5px;
font-size: 13px;
} }
.migration-footer { .migration-progress-status-text {
padding: 16px 32px 24px; color: #555;
border-top: 1px solid #e0e0e0; font-size: 14px;
background-color: #f8f9fa; line-height: 1.4;
} }
.migration-info { .migration-progress-details {
margin-bottom: 20px;
padding: 12px;
background: #e3f2fd;
border-radius: 6px;
border-left: 4px solid #2196f3;
}
.migration-progress-details-label {
font-weight: 600;
color: #1976d2;
margin-bottom: 5px;
font-size: 13px;
}
.migration-progress-details-text {
color: #1565c0;
font-size: 13px;
line-height: 1.4;
}
.migration-progress-footer {
padding: 20px 30px;
background: #f8f9fa;
border-top: 1px solid #e9ecef;
}
.migration-progress-note {
text-align: center; text-align: center;
color: #666; color: #666;
font-size: 13px; font-size: 13px;
line-height: 1.4; font-style: italic;
margin-bottom: 8px;
}
.migration-info i {
margin-right: 6px;
color: #667eea;
}
.migration-warning {
text-align: center;
color: #856404;
font-size: 12px;
line-height: 1.3;
background-color: #fff3cd;
padding: 8px 12px;
border-radius: 4px;
border: 1px solid #ffeaa7;
}
.migration-warning i {
margin-right: 6px;
color: #f39c12;
} }
/* Responsive design */ /* Responsive design */
@media (max-width: 768px) { @media (max-width: 600px) {
.migration-modal { .migration-progress-modal {
width: 98%; width: 95%;
margin: 10px; margin: 20px;
} }
.migration-header, .migration-progress-content {
.migration-content, padding: 20px;
.migration-footer {
padding-left: 16px;
padding-right: 16px;
} }
.migration-header h3 { .migration-progress-header {
font-size: 20px; padding: 15px;
} }
.step-header { .migration-progress-title {
flex-direction: column; font-size: 16px;
align-items: flex-start;
}
.step-progress {
text-align: left;
margin-top: 8px;
}
.steps-list {
max-height: 200px;
} }
} }
/* Dark mode support */
@media (prefers-color-scheme: dark) {
.migration-progress-modal {
background: #2d3748;
color: #e2e8f0;
}
.migration-progress-overall-label,
.migration-progress-step-label,
.migration-progress-status-label {
color: #e2e8f0;
}
.migration-progress-status {
background: #4a5568;
border-left-color: #63b3ed;
}
.migration-progress-status-text {
color: #cbd5e0;
}
.migration-progress-details {
background: #2b6cb0;
border-left-color: #4299e1;
}
.migration-progress-details-label {
color: #bee3f8;
}
.migration-progress-details-text {
color: #90cdf4;
}
.migration-progress-footer {
background: #4a5568;
border-top-color: #718096;
}
.migration-progress-note {
color: #a0aec0;
}
}

View file

@ -1,63 +1,43 @@
template(name="migrationProgress") template(name="migrationProgress")
.migration-overlay(class="{{#if isMigrating}}active{{/if}}") if isMigrating
.migration-modal .migration-progress-overlay
.migration-header .migration-progress-modal
h3 .migration-progress-header
| 🗄️ h3.migration-progress-title
| {{_ 'database-migration'}} | 🔄 Board Migration in Progress
p {{_ 'database-migration-description'}} .migration-progress-close.js-close-migration-progress
| ❌
.migration-content
.migration-overview
.overall-progress
.progress-bar
.progress-fill(style="width: {{migrationProgress}}%")
.progress-text {{migrationProgress}}%
.progress-label {{_ 'overall-progress'}}
.current-step
| ⚙️
| {{migrationCurrentStep}}
.estimated-time(style="{{#unless migrationEstimatedTime}}display: none;{{/unless}}")
| ⏰
| {{_ 'estimated-time-remaining'}}: {{migrationEstimatedTime}}
.migration-steps .migration-progress-content
h4 {{_ 'migration-steps'}} .migration-progress-overall
.steps-list .migration-progress-overall-label
each migrationSteps | Overall Progress: {{currentStep}} of {{totalSteps}} steps
.migration-step(class="{{#if completed}}completed{{/if}}" class="{{#if isCurrentStep}}current{{/if}}") .migration-progress-overall-bar
.step-header .migration-progress-overall-fill(style="{{progressBarStyle}}")
.step-icon .migration-progress-overall-percentage
if completed | {{overallProgress}}%
| ✅
else if isCurrentStep .migration-progress-current-step
| ⚙️ .migration-progress-step-label
else | Current Step: {{stepNameFormatted}}
| ⭕ .migration-progress-step-bar
.step-info .migration-progress-step-fill(style="{{stepProgressBarStyle}}")
.step-name {{name}} .migration-progress-step-percentage
.step-description {{description}} | {{stepProgress}}%
.step-progress
if completed .migration-progress-status
.progress-text 100% .migration-progress-status-label
else if isCurrentStep | Status:
.progress-text {{progress}}% .migration-progress-status-text
else | {{stepStatus}}
.progress-text 0%
if isCurrentStep if stepDetailsFormatted
.step-progress-bar .migration-progress-details
.progress-fill(style="width: {{progress}}%") .migration-progress-details-label
| Details:
.migration-progress-details-text
| {{stepDetailsFormatted}}
.migration-status .migration-progress-footer
| .migration-progress-note
| {{migrationStatus}} | Please wait while we migrate your board to the latest structure...
.migration-footer
.migration-info
| 💡
| {{_ 'migration-info-text'}}
.migration-warning
| ⚠️
| {{_ 'migration-warning-text'}}

View file

@ -1,54 +1,212 @@
import { Template } from 'meteor/templating'; /**
import { * Migration Progress Component
migrationManager, * Displays detailed progress for comprehensive board migration
isMigrating, */
migrationProgress,
migrationStatus,
migrationCurrentStep,
migrationEstimatedTime,
migrationSteps
} from '/client/lib/migrationManager';
import { ReactiveVar } from 'meteor/reactive-var';
import { ReactiveCache } from '/imports/reactiveCache';
// Reactive variables for migration progress
export const migrationProgress = new ReactiveVar(0);
export const migrationStatus = new ReactiveVar('');
export const migrationStepName = new ReactiveVar('');
export const migrationStepProgress = new ReactiveVar(0);
export const migrationStepStatus = new ReactiveVar('');
export const migrationStepDetails = new ReactiveVar(null);
export const migrationCurrentStep = new ReactiveVar(0);
export const migrationTotalSteps = new ReactiveVar(0);
export const isMigrating = new ReactiveVar(false);
class MigrationProgressManager {
constructor() {
this.progressHistory = [];
}
/**
* Update migration progress
*/
updateProgress(progressData) {
const {
overallProgress,
currentStep,
totalSteps,
stepName,
stepProgress,
stepStatus,
stepDetails,
boardId
} = progressData;
// Update reactive variables
migrationProgress.set(overallProgress);
migrationCurrentStep.set(currentStep);
migrationTotalSteps.set(totalSteps);
migrationStepName.set(stepName);
migrationStepProgress.set(stepProgress);
migrationStepStatus.set(stepStatus);
migrationStepDetails.set(stepDetails);
// Store in history
this.progressHistory.push({
timestamp: new Date(),
...progressData
});
// Update overall status
migrationStatus.set(`${stepName}: ${stepStatus}`);
}
/**
* Start migration
*/
startMigration() {
isMigrating.set(true);
migrationProgress.set(0);
migrationStatus.set('Starting migration...');
migrationStepName.set('');
migrationStepProgress.set(0);
migrationStepStatus.set('');
migrationStepDetails.set(null);
migrationCurrentStep.set(0);
migrationTotalSteps.set(0);
this.progressHistory = [];
}
/**
* Complete migration
*/
completeMigration() {
isMigrating.set(false);
migrationProgress.set(100);
migrationStatus.set('Migration completed successfully!');
// Clear step details after a delay
setTimeout(() => {
migrationStepName.set('');
migrationStepProgress.set(0);
migrationStepStatus.set('');
migrationStepDetails.set(null);
migrationCurrentStep.set(0);
migrationTotalSteps.set(0);
}, 3000);
}
/**
* Fail migration
*/
failMigration(error) {
isMigrating.set(false);
migrationStatus.set(`Migration failed: ${error.message || error}`);
migrationStepStatus.set('Error occurred');
}
/**
* Get progress history
*/
getProgressHistory() {
return this.progressHistory;
}
/**
* Clear progress
*/
clearProgress() {
isMigrating.set(false);
migrationProgress.set(0);
migrationStatus.set('');
migrationStepName.set('');
migrationStepProgress.set(0);
migrationStepStatus.set('');
migrationStepDetails.set(null);
migrationCurrentStep.set(0);
migrationTotalSteps.set(0);
this.progressHistory = [];
}
}
// Export singleton instance
export const migrationProgressManager = new MigrationProgressManager();
// Template helpers
Template.migrationProgress.helpers({ Template.migrationProgress.helpers({
isMigrating() { isMigrating() {
return isMigrating.get(); return isMigrating.get();
}, },
migrationProgress() { overallProgress() {
return migrationProgress.get(); return migrationProgress.get();
}, },
migrationStatus() { overallStatus() {
return migrationStatus.get(); return migrationStatus.get();
}, },
migrationCurrentStep() { currentStep() {
return migrationCurrentStep.get(); return migrationCurrentStep.get();
}, },
migrationEstimatedTime() { totalSteps() {
return migrationEstimatedTime.get(); return migrationTotalSteps.get();
}, },
migrationSteps() { stepName() {
const steps = migrationSteps.get(); return migrationStepName.get();
const currentStep = migrationCurrentStep.get(); },
stepProgress() {
return migrationStepProgress.get();
},
stepStatus() {
return migrationStepStatus.get();
},
stepDetails() {
return migrationStepDetails.get();
},
progressBarStyle() {
const progress = migrationProgress.get();
return `width: ${progress}%`;
},
stepProgressBarStyle() {
const progress = migrationStepProgress.get();
return `width: ${progress}%`;
},
stepNameFormatted() {
const stepName = migrationStepName.get();
if (!stepName) return '';
return steps.map(step => ({ // Convert snake_case to Title Case
...step, return stepName
isCurrentStep: step.name === currentStep .split('_')
})); .map(word => word.charAt(0).toUpperCase() + word.slice(1))
.join(' ');
},
stepDetailsFormatted() {
const details = migrationStepDetails.get();
if (!details) return '';
const formatted = [];
for (const [key, value] of Object.entries(details)) {
const formattedKey = key
.split(/(?=[A-Z])/)
.join(' ')
.toLowerCase()
.replace(/^\w/, c => c.toUpperCase());
formatted.push(`${formattedKey}: ${value}`);
}
return formatted.join(', ');
} }
}); });
Template.migrationProgress.onCreated(function() { // Template events
// Subscribe to migration state changes Template.migrationProgress.events({
this.autorun(() => { 'click .js-close-migration-progress'() {
isMigrating.get(); migrationProgressManager.clearProgress();
migrationProgress.get(); }
migrationStatus.get(); });
migrationCurrentStep.get();
migrationEstimatedTime.get();
migrationSteps.get();
});
});

View file

@ -48,6 +48,59 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
} }
/* Use checklist-style green checkboxes for all sidebar checkboxes */
.sidebar .materialCheckBox.is-checked,
.boardCardSettingsPopup .materialCheckBox.is-checked,
.boardSubtaskSettingsPopup .materialCheckBox.is-checked {
top: -4px !important;
left: -3px !important;
width: 7px !important;
height: 15px !important;
margin-right: 6px !important;
border-top: 2px solid transparent !important;
border-left: 2px solid transparent !important;
border-bottom: 2px solid #3cb500 !important;
border-right: 2px solid #3cb500 !important;
transform: rotate(40deg) !important;
-webkit-backface-visibility: hidden !important;
backface-visibility: hidden !important;
transform-origin: 100% 100% !important;
}
/* Card Settings 3-column grid layout */
.card-settings-grid {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
gap: 10px;
margin-bottom: 10px;
}
.card-settings-row {
display: grid;
grid-template-columns: 1fr 1fr 2fr;
gap: 10px;
align-items: center;
padding: 5px 0;
border-bottom: 1px solid #eee;
}
.card-settings-column {
display: flex;
align-items: center;
justify-content: center;
}
.card-settings-column:last-child {
justify-content: flex-start;
}
.card-settings-column h4 {
margin: 0;
font-size: 12px;
font-weight: bold;
text-align: center;
}
.sidebar .sidebar-content ul.sidebar-list li > a { .sidebar .sidebar-content ul.sidebar-list li > a {
display: flex; display: flex;
height: 30px; height: 30px;

View file

@ -34,32 +34,26 @@ template(name='homeSidebar')
hr hr
ul#cards.label-text-hidden ul#cards.label-text-hidden
a.flex.js-toggle-minicard-label-text(title="{{_ 'hide-minicard-label-text'}}") a.flex.js-toggle-minicard-label-text(title="{{_ 'hide-minicard-label-text'}}")
span {{#if hiddenMinicardLabelText}}✅{{else}}⬜{{/if}}
span {{_ 'hide-minicard-label-text'}} span {{_ 'hide-minicard-label-text'}}
b &nbsp;
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
if currentUser if currentUser
ul#cards.vertical-scrollbars-toggle ul#cards.vertical-scrollbars-toggle
a.flex.js-vertical-scrollbars-toggle(title="{{_ 'enable-vertical-scrollbars'}}") a.flex.js-vertical-scrollbars-toggle(title="{{_ 'enable-vertical-scrollbars'}}")
span {{#if isVerticalScrollbars}}✅{{else}}⬜{{/if}}
span {{_ 'enable-vertical-scrollbars'}} span {{_ 'enable-vertical-scrollbars'}}
b &nbsp;
.materialCheckBox(class="{{#if isVerticalScrollbars}}is-checked{{/if}}")
ul#cards.show-week-of-year-toggle ul#cards.show-week-of-year-toggle
a.flex.js-show-week-of-year-toggle(title="{{_ 'show-week-of-year'}}") a.flex.js-show-week-of-year-toggle(title="{{_ 'show-week-of-year'}}")
span {{#if isShowWeekOfYear}}✅{{else}}⬜{{/if}}
span {{_ 'show-week-of-year'}} span {{_ 'show-week-of-year'}}
b &nbsp;
.materialCheckBox(class="{{#if isShowWeekOfYear}}is-checked{{/if}}")
hr hr
unless currentUser.isNoComments unless currentUser.isNoComments
h3.activity-title h3.activity-title
| 💬 | 💬
| {{_ 'activities'}} | {{_ 'activities'}}
.material-toggle-switch(title="{{_ 'show-activities'}}") a.flex.js-toggle-show-activities(title="{{_ 'show-activities'}}")
if showActivities span {{#if showActivities}}✅{{else}}⬜{{/if}}
input.toggle-switch(type="checkbox" id="toggleShowActivitiesBoard" checked="checked") span {{_ 'show-activities'}}
else
input.toggle-switch(type="checkbox" id="toggleShowActivitiesBoard")
label.toggle-label(for="toggleShowActivitiesBoard")
+activities(mode="board") +activities(mode="board")
template(name="membersWidget") template(name="membersWidget")
@ -185,165 +179,282 @@ template(name="boardInfoOnMyBoardsPopup")
unless currentSetting.hideCardCounterList unless currentSetting.hideCardCounterList
div.check-div div.check-div
a.flex.js-field-has-cardcounterlist(class="{{#if allowsCardCounterList}}is-checked{{/if}}") a.flex.js-field-has-cardcounterlist(class="{{#if allowsCardCounterList}}is-checked{{/if}}")
.materialCheckBox(class="{{#if allowsCardCounterList}}is-checked{{/if}}") span {{#if allowsCardCounterList}}✅{{else}}⬜{{/if}}
span span
| 🚪 | 🚪
| {{_ 'show-card-counter-per-list'}} | {{_ 'show-card-counter-per-list'}}
unless currentSetting.hideBoardMemberList unless currentSetting.hideBoardMemberList
div.check-div div.check-div
a.flex.js-field-has-boardmemberlist(class="{{#if allowsBoardMemberList}}is-checked{{/if}}") a.flex.js-field-has-boardmemberlist(class="{{#if allowsBoardMemberList}}is-checked{{/if}}")
.materialCheckBox(class="{{#if allowsBoardMemberList}}is-checked{{/if}}") span {{#if allowsBoardMemberList}}✅{{else}}⬜{{/if}}
span span
| ⏳ | ⏳
| {{_ 'show-board_members-avatar'}} | {{_ 'show-board_members-avatar'}}
template(name="boardCardSettingsPopup") template(name="boardCardSettingsPopup")
form.board-card-settings form.board-card-settings
h3 {{_ 'show-on-card'}}, {{_ 'show-on-minicard'}} .card-settings-grid
div.check-div .card-settings-column
a.flex.js-field-has-receiveddate(class="{{#if allowsReceivedDate}}is-checked{{/if}}") h4 {{_ 'show-on-card'}}
.materialCheckBox(class="{{#if allowsReceivedDate}}is-checked{{/if}}") .card-settings-column
h4 {{_ 'show-on-minicard'}}
.card-settings-column
h4 {{_ 'description'}}
.card-settings-row
.card-settings-column
a.flex.js-field-has-receiveddate(title="{{_ 'card-received'}}" class="{{#if allowsReceivedDate}}is-checked{{/if}}")
span {{#if allowsReceivedDate}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-receiveddate(title="{{_ 'card-received'}}" class="{{#if allowsReceivedDate}}is-checked{{/if}}")
span {{#if allowsReceivedDate}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🚪 | 🚪
| {{_ 'card-received'}} | {{_ 'card-received'}}
div.check-div .card-settings-row
a.flex.js-field-has-startdate(class="{{#if allowsStartDate}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsStartDate}}is-checked{{/if}}") a.flex.js-field-has-startdate(title="{{_ 'card-start'}}" class="{{#if allowsStartDate}}is-checked{{/if}}")
span {{#if allowsStartDate}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-startdate(title="{{_ 'card-start'}}" class="{{#if allowsStartDate}}is-checked{{/if}}")
span {{#if allowsStartDate}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| ⏳ | ⏳
| {{_ 'card-start'}} | {{_ 'card-start'}}
div.check-div .card-settings-row
a.flex.js-field-has-duedate(class="{{#if allowsDueDate}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsDueDate}}is-checked{{/if}}") a.flex.js-field-has-duedate(title="{{_ 'card-due'}}" class="{{#if allowsDueDate}}is-checked{{/if}}")
span {{#if allowsDueDate}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-duedate(title="{{_ 'card-due'}}" class="{{#if allowsDueDate}}is-checked{{/if}}")
span {{#if allowsDueDate}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🚪 | 🚪
| {{_ 'card-due'}} | {{_ 'card-due'}}
div.check-div .card-settings-row
a.flex.js-field-has-enddate(class="{{#if allowsEndDate}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsEndDate}}is-checked{{/if}}") a.flex.js-field-has-enddate(title="{{_ 'card-end'}}" class="{{#if allowsEndDate}}is-checked{{/if}}")
span {{#if allowsEndDate}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-enddate(title="{{_ 'card-end'}}" class="{{#if allowsEndDate}}is-checked{{/if}}")
span {{#if allowsEndDate}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| ⏰ | ⏰
| {{_ 'card-end'}} | {{_ 'card-end'}}
div.check-div .card-settings-row
a.flex.js-field-has-members(class="{{#if allowsMembers}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsMembers}}is-checked{{/if}}") a.flex.js-field-has-members(title="{{_ 'members'}}" class="{{#if allowsMembers}}is-checked{{/if}}")
span {{#if allowsMembers}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-members(title="{{_ 'members'}}" class="{{#if allowsMembers}}is-checked{{/if}}")
span {{#if allowsMembers}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 👥 | 👥
| {{_ 'members'}} | {{_ 'members'}}
div.check-div .card-settings-row
a.flex.js-field-has-creator(class="{{#if allowsCreator}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCreator}}is-checked{{/if}}") a.flex.js-field-has-creator(title="{{_ 'creator'}}" class="{{#if allowsCreator}}is-checked{{/if}}")
span {{#if allowsCreator}}✅{{else}}⬜{{/if}}
.card-settings-column
span
.card-settings-column
span span
| 👤 | 👤
| {{_ 'creator'}} | {{_ 'creator'}}
div.check-div .card-settings-row
a.flex.js-field-has-creator-on-minicard(class="{{#if allowsCreatorOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCreatorOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-creator-on-minicard(title="{{_ 'creator-on-minicard'}}" class="{{#if allowsCreatorOnMinicard}}is-checked{{/if}}")
span {{#if allowsCreatorOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 👤 | 👤
| {{_ 'creator-on-minicard'}} | {{_ 'creator-on-minicard'}}
div.check-div .card-settings-row
a.flex.js-field-has-assignee(class="{{#if allowsAssignee}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsAssignee}}is-checked{{/if}}") a.flex.js-field-has-assignee(title="{{_ 'assignee'}}" class="{{#if allowsAssignee}}is-checked{{/if}}")
span {{#if allowsAssignee}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-assignee(title="{{_ 'assignee'}}" class="{{#if allowsAssignee}}is-checked{{/if}}")
span {{#if allowsAssignee}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 👤 | 👤
| {{_ 'assignee'}} | {{_ 'assignee'}}
div.check-div .card-settings-row
a.flex.js-field-has-assigned-by(class="{{#if allowsAssignedBy}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsAssignedBy}}is-checked{{/if}}") a.flex.js-field-has-assigned-by(title="{{_ 'assigned-by'}}" class="{{#if allowsAssignedBy}}is-checked{{/if}}")
span {{#if allowsAssignedBy}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-assigned-by(title="{{_ 'assigned-by'}}" class="{{#if allowsAssignedBy}}is-checked{{/if}}")
span {{#if allowsAssignedBy}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🛒 | 🛒
| {{_ 'assigned-by'}} | {{_ 'assigned-by'}}
div.check-div .card-settings-row
a.flex.js-field-has-requested-by(class="{{#if allowsRequestedBy}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsRequestedBy}}is-checked{{/if}}") a.flex.js-field-has-requested-by(title="{{_ 'requested-by'}}" class="{{#if allowsRequestedBy}}is-checked{{/if}}")
span {{#if allowsRequestedBy}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-requested-by(title="{{_ 'requested-by'}}" class="{{#if allowsRequestedBy}}is-checked{{/if}}")
span {{#if allowsRequestedBy}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 👤➕ | 👤➕
| {{_ 'requested-by'}} | {{_ 'requested-by'}}
div.check-div .card-settings-row
a.flex.js-field-has-card-sorting-by-number(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}") a.flex.js-field-has-card-sorting-by-number(title="{{_ 'card-sorting-by-number'}}" class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}")
span {{#if allowsCardSortingByNumber}}✅{{else}}⬜{{/if}}
.card-settings-column
span
.card-settings-column
span span
| 🔢 | 🔢
| {{_ 'card-sorting-by-number'}} | {{_ 'card-sorting-by-number'}}
div.check-div .card-settings-row
a.flex.js-field-has-card-sorting-by-number-on-minicard(class="{{#if allowsCardSortingByNumberOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCardSortingByNumberOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-card-sorting-by-number-on-minicard(title="{{_ 'card-sorting-by-number-on-minicard'}}" class="{{#if allowsCardSortingByNumberOnMinicard}}is-checked{{/if}}")
span {{#if allowsCardSortingByNumberOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🔢 | 🔢
| {{_ 'card-sorting-by-number-on-minicard'}} | {{_ 'card-sorting-by-number-on-minicard'}}
div.check-div .card-settings-row
a.flex.js-field-has-card-show-lists(class="{{#if allowsShowLists}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsShowLists}}is-checked{{/if}}") a.flex.js-field-has-card-show-lists(title="{{_ 'card-show-lists'}}" class="{{#if allowsShowLists}}is-checked{{/if}}")
span {{#if allowsShowLists}}✅{{else}}⬜{{/if}}
.card-settings-column
span
.card-settings-column
span span
| 📋 | 📋
| {{_ 'card-show-lists'}} | {{_ 'card-show-lists'}}
div.check-div .card-settings-row
a.flex.js-field-has-labels(class="{{#if allowsLabels}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsLabels}}is-checked{{/if}}") a.flex.js-field-has-labels(title="{{_ 'labels'}}" class="{{#if allowsLabels}}is-checked{{/if}}")
span {{#if allowsLabels}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-labels(title="{{_ 'labels'}}" class="{{#if allowsLabels}}is-checked{{/if}}")
span {{#if allowsLabels}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🏷️ | 🏷️
| {{_ 'labels'}} | {{_ 'labels'}}
div.check-div .card-settings-row
a.flex.js-field-has-card-show-lists-on-minicard(class="{{#if allowsShowListsOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsShowListsOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-card-show-lists-on-minicard(title="{{_ 'card-show-lists-on-minicard'}}" class="{{#if allowsShowListsOnMinicard}}is-checked{{/if}}")
span {{#if allowsShowListsOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📋 | 📋
| {{_ 'card-show-lists-on-minicard'}} | {{_ 'card-show-lists-on-minicard'}}
div.check-div .card-settings-row
a.flex.js-field-has-card-number(class="{{#if allowsCardNumber}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCardNumber}}is-checked{{/if}}") a.flex.js-field-has-card-number(title="{{_ 'card'}} {{_ 'number'}}" class="{{#if allowsCardNumber}}is-checked{{/if}}")
span {{#if allowsCardNumber}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-card-number(title="{{_ 'card'}} {{_ 'number'}}" class="{{#if allowsCardNumber}}is-checked{{/if}}")
span {{#if allowsCardNumber}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| #️⃣ | #️⃣
| {{_ 'card'}} | {{_ 'card'}}
| {{_ 'number'}} | {{_ 'number'}}
div.check-div .card-settings-row
a.flex.js-field-has-description-title(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}") a.flex.js-field-has-description-title(title="{{_ 'description'}} {{_ 'title'}}" class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
span {{#if allowsDescriptionTitle}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-description-title(title="{{_ 'description'}} {{_ 'title'}}" class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
span {{#if allowsDescriptionTitle}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📝 | 📝
| {{_ 'description'}} | {{_ 'description'}}
| {{_ 'title'}} | {{_ 'title'}}
div.check-div .card-settings-row
a.flex.js-field-has-description-text(class="{{#if allowsDescriptionText}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsDescriptionText}}is-checked{{/if}}") a.flex.js-field-has-description-text(title="{{_ 'description'}} {{_ 'custom-field-text'}}" class="{{#if allowsDescriptionText}}is-checked{{/if}}")
span {{#if allowsDescriptionText}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-description-text(title="{{_ 'description'}} {{_ 'custom-field-text'}}" class="{{#if allowsDescriptionText}}is-checked{{/if}}")
span {{#if allowsDescriptionText}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📝 | 📝
| {{_ 'description'}} | {{_ 'description'}}
| {{_ 'custom-field-text'}} | {{_ 'custom-field-text'}}
div.check-div .card-settings-row
a.flex.js-field-has-description-text-on-minicard(class="{{#if allowsDescriptionTextOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsDescriptionTextOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-description-text-on-minicard(title="{{_ 'description-on-minicard'}}" class="{{#if allowsDescriptionTextOnMinicard}}is-checked{{/if}}")
span {{#if allowsDescriptionTextOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📝 | 📝
| {{_ 'description-on-minicard'}} | {{_ 'description-on-minicard'}}
div.check-div .card-settings-row
a.flex.js-field-has-checklists(class="{{#if allowsChecklists}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsChecklists}}is-checked{{/if}}") a.flex.js-field-has-checklists(title="{{_ 'checklists'}}" class="{{#if allowsChecklists}}is-checked{{/if}}")
span {{#if allowsChecklists}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-checklists(title="{{_ 'checklists'}}" class="{{#if allowsChecklists}}is-checked{{/if}}")
span {{#if allowsChecklists}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| ✅ | ✅
| {{_ 'checklists'}} | {{_ 'checklists'}}
div.check-div .card-settings-row
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}") a.flex.js-field-has-subtasks(title="{{_ 'subtasks'}}" class="{{#if allowsSubtasks}}is-checked{{/if}}")
span {{#if allowsSubtasks}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-subtasks(title="{{_ 'subtasks'}}" class="{{#if allowsSubtasks}}is-checked{{/if}}")
span {{#if allowsSubtasks}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 🌐 | 🌐
| {{_ 'subtasks'}} | {{_ 'subtasks'}}
div.check-div .card-settings-row
a.flex.js-field-has-attachments(class="{{#if allowsAttachments}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsAttachments}}is-checked{{/if}}") a.flex.js-field-has-attachments(title="{{_ 'attachments'}}" class="{{#if allowsAttachments}}is-checked{{/if}}")
span {{#if allowsAttachments}}✅{{else}}⬜{{/if}}
.card-settings-column
a.flex.js-field-has-attachments(title="{{_ 'attachments'}}" class="{{#if allowsAttachments}}is-checked{{/if}}")
span {{#if allowsAttachments}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📎 | 📎
| {{_ 'attachments'}} | {{_ 'attachments'}}
div.check-div .card-settings-row
a.flex.js-field-has-badge-attachment-on-minicard(class="{{#if allowsBadgeAttachmentOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsBadgeAttachmentOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-badge-attachment-on-minicard(title="{{_ 'badge-attachment-on-minicard'}}" class="{{#if allowsBadgeAttachmentOnMinicard}}is-checked{{/if}}")
span {{#if allowsBadgeAttachmentOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📎 | 📎
| {{_ 'badge-attachment-on-minicard'}} | {{_ 'badge-attachment-on-minicard'}}
div.check-div .card-settings-row
a.flex.js-field-has-cover-attachment-on-minicard(class="{{#if allowsCoverAttachmentOnMinicard}}is-checked{{/if}}") .card-settings-column
.materialCheckBox(class="{{#if allowsCoverAttachmentOnMinicard}}is-checked{{/if}}") span
.card-settings-column
a.flex.js-field-has-cover-attachment-on-minicard(title="{{_ 'cover-attachment-on-minicard'}}" class="{{#if allowsCoverAttachmentOnMinicard}}is-checked{{/if}}")
span {{#if allowsCoverAttachmentOnMinicard}}✅{{else}}⬜{{/if}}
.card-settings-column
span span
| 📖 | 📖
| 🖼️ | 🖼️
@ -364,27 +475,27 @@ template(name="boardCardSettingsPopup")
template(name="boardSubtaskSettingsPopup") template(name="boardSubtaskSettingsPopup")
form.board-subtask-settings form.board-subtask-settings
h3 {{_ 'show-parent-in-minicard'}} 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}}") a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(title="{{_ 'prefix-with-full-path'}}" class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}") span {{#if $eq presentParentTask 'prefix-with-full-path'}}✅{{else}}⬜{{/if}}
span {{_ 'prefix-with-full-path'}} 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}}") a#prefix-with-parent.flex.js-field-show-parent-in-minicard(title="{{_ 'prefix-with-parent'}}" class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}") span {{#if $eq presentParentTask 'prefix-with-parent'}}✅{{else}}⬜{{/if}}
span {{_ 'prefix-with-parent'}} 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}}") a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(title="{{_ 'subtext-with-full-path'}}" class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}") span {{#if $eq presentParentTask 'subtext-with-full-path'}}✅{{else}}⬜{{/if}}
span {{_ 'subtext-with-full-path'}} 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}}") a#subtext-with-parent.flex.js-field-show-parent-in-minicard(title="{{_ 'subtext-with-parent'}}" class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}") span {{#if $eq presentParentTask 'subtext-with-parent'}}✅{{else}}⬜{{/if}}
span {{_ 'subtext-with-parent'}} span {{_ 'subtext-with-parent'}}
a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}") a#no-parent.flex.js-field-show-parent-in-minicard(title="{{_ 'no-parent'}}" class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
.materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}") span {{#if $eq presentParentTask 'no-parent'}}✅{{else}}⬜{{/if}}
span {{_ 'no-parent'}} span {{_ 'no-parent'}}
div div
hr hr
div.check-div div.check-div
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}") a.flex.js-field-has-subtasks(title="{{_ 'show-subtasks-field'}}" class="{{#if allowsSubtasks}}is-checked{{/if}}")
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}") span {{#if allowsSubtasks}}✅{{else}}⬜{{/if}}
span {{_ 'show-subtasks-field'}} span {{_ 'show-subtasks-field'}}
label label
@ -426,13 +537,18 @@ template(name="archiveBoardPopup")
| 📦 | 📦
| {{_ 'archive'}} | {{_ 'archive'}}
template(name="deleteDuplicateListsPopup")
p {{_ 'delete-duplicate-lists-confirm'}}
button.js-confirm.negate.full(type="submit")
| 🗑️
| {{_ 'delete'}}
template(name="outgoingWebhooksPopup") template(name="outgoingWebhooksPopup")
each integrations each integrations
form.integration-form form.integration-form
a.flex a.flex
span {{#unless enabled}}✅{{else}}⬜{{/unless}}
span {{_ 'disable-webhook'}} span {{_ 'disable-webhook'}}
b &nbsp;
.materialCheckBox(class="{{#unless enabled}}is-checked{{/unless}}")
input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" value=title) input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" value=title)
input.js-outgoing-webhooks-url(type="text" name="url" value=url) input.js-outgoing-webhooks-url(type="text" name="url" value=url)
input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" value=token name="token") input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" value=token name="token")
@ -471,6 +587,10 @@ template(name="boardMenuPopup")
| 📦 | 📦
| {{_ 'archived-items'}} | {{_ 'archived-items'}}
if currentUser.isBoardAdmin if currentUser.isBoardAdmin
li
a.js-open-migrations
| 🔧
| {{_ 'migrations'}}
li li
a.js-change-board-color a.js-change-board-color
| 🎨 | 🎨
@ -511,6 +631,10 @@ template(name="boardMenuPopup")
if currentUser.isBoardAdmin if currentUser.isBoardAdmin
hr hr
ul.pop-over-list ul.pop-over-list
// li
// a.js-delete-duplicate-lists
// | 🗑️
// | {{_ 'delete-duplicate-lists'}}
li li
a.js-archive-board a.js-archive-board
| ➡️📦 | ➡️📦
@ -631,7 +755,7 @@ template(name="removeBoardTeamPopup")
template(name="addMemberPopup") template(name="addMemberPopup")
.js-search-member .js-search-member
+EasySearch.Input(index=searchIndex) input.js-search-member-input(type="text" placeholder="{{_ 'email-address'}}")
if loading.get if loading.get
+spinner +spinner
@ -639,25 +763,38 @@ template(name="addMemberPopup")
.warning {{_ error.get}} .warning {{_ error.get}}
else else
ul.pop-over-list ul.pop-over-list
+EasySearch.Each(index=searchIndex) each searchResults
li.item.js-member-item(class="{{#if isBoardMember}}disabled{{/if}}") li.item.js-member-item(class="{{#if isBoardMember}}disabled{{/if}}")
a.name.js-select-member(title="{{profile.fullname}} ({{username}})") a.name.js-select-member(title="{{profile.fullname}} ({{username}})")
+userAvatar(userId=__originalId) +userAvatar(userId=_id)
span.full-name span.full-name
= profile.fullname = profile.fullname
| (<span class="username">{{username}}</span>) | (<span class="username">{{username}}</span>)
if isBoardMember if isBoardMember
.quiet ({{_ 'joined'}}) .quiet ({{_ 'joined'}})
+EasySearch.IfSearching(index=searchIndex) if searching.get
+spinner +spinner
+EasySearch.IfNoResults(index=searchIndex) if noResults.get
.manage-member-section .manage-member-section
p.quiet {{_ 'no-results'}} p.quiet {{_ 'no-results'}}
button.js-email-invite.primary.full {{_ 'email-invite'}} button.js-email-invite.primary.full {{_ 'email-invite'}}
template(name="addMemberPopupTest")
.js-search-member
input.js-search-member-input(type="text" placeholder="{{_ 'email-address'}}")
ul.pop-over-list
each searchResults
li.item.js-member-item
a.name.js-select-member(title="{{profile.fullname}} ({{username}})")
+userAvatar(userId=_id)
span.full-name
= profile.fullname
| (<span class="username">{{username}}</span>)
button.js-email-invite.primary.full {{_ 'email-invite'}}
template(name="changePermissionsPopup") template(name="changePermissionsPopup")
ul.pop-over-list ul.pop-over-list
li li

View file

@ -13,6 +13,7 @@ const viewTitles = {
multiselection: 'multi-selection', multiselection: 'multi-selection',
customFields: 'custom-fields', customFields: 'custom-fields',
archives: 'archives', archives: 'archives',
migrations: 'migrations',
}; };
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
@ -195,7 +196,7 @@ BlazeComponent.extendComponent({
events() { events() {
return [ return [
{ {
'click #toggleShowActivitiesBoard'() { 'click .js-toggle-show-activities'() {
Utils.getCurrentBoard().toggleShowActivities(); Utils.getCurrentBoard().toggleShowActivities();
}, },
}, },
@ -271,10 +272,53 @@ Template.boardMenuPopup.events({
Sidebar.setView('archives'); Sidebar.setView('archives');
Popup.back(); Popup.back();
}, },
'click .js-open-migrations'() {
Sidebar.setView('migrations');
Popup.back();
},
'click .js-change-board-color': Popup.open('boardChangeColor'), 'click .js-change-board-color': Popup.open('boardChangeColor'),
'click .js-change-background-image': Popup.open('boardChangeBackgroundImage'), 'click .js-change-background-image': Popup.open('boardChangeBackgroundImage'),
'click .js-board-info-on-my-boards': Popup.open('boardInfoOnMyBoards'), 'click .js-board-info-on-my-boards': Popup.open('boardInfoOnMyBoards'),
'click .js-change-language': Popup.open('changeLanguage'), 'click .js-change-language': Popup.open('changeLanguage'),
'click .js-delete-duplicate-lists': Popup.afterConfirm('deleteDuplicateLists', function() {
const currentBoard = Utils.getCurrentBoard();
if (!currentBoard) return;
// Get all lists in the current board
const allLists = ReactiveCache.getLists({ boardId: currentBoard._id, archived: false });
// Group lists by title to find duplicates
const listsByTitle = {};
allLists.forEach(list => {
if (!listsByTitle[list.title]) {
listsByTitle[list.title] = [];
}
listsByTitle[list.title].push(list);
});
// Find and delete duplicate lists that have no cards
let deletedCount = 0;
Object.keys(listsByTitle).forEach(title => {
const listsWithSameTitle = listsByTitle[title];
if (listsWithSameTitle.length > 1) {
// Keep the first list, delete the rest if they have no cards
for (let i = 1; i < listsWithSameTitle.length; i++) {
const list = listsWithSameTitle[i];
const cardsInList = ReactiveCache.getCards({ listId: list._id, archived: false });
if (cardsInList.length === 0) {
Lists.remove(list._id);
deletedCount++;
}
}
}
});
// Show notification
if (deletedCount > 0) {
// You could add a toast notification here if available
}
}),
'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() { 'click .js-archive-board ': Popup.afterConfirm('archiveBoard', function() {
const currentBoard = Utils.getCurrentBoard(); const currentBoard = Utils.getCurrentBoard();
currentBoard.archive(); currentBoard.archive();
@ -822,7 +866,11 @@ BlazeComponent.extendComponent({
}, },
allowsSubtasks() { allowsSubtasks() {
return this.currentBoard.allowsSubtasks; // Get the current board reactively using board ID from Session
const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
const result = currentBoard ? currentBoard.allowsSubtasks : false;
return result;
}, },
allowsReceivedDate() { allowsReceivedDate() {
@ -874,7 +922,11 @@ BlazeComponent.extendComponent({
}, },
presentParentTask() { presentParentTask() {
let result = this.currentBoard.presentParentTask; // Get the current board reactively using board ID from Session
const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
let result = currentBoard ? currentBoard.presentParentTask : null;
if (result === null || result === undefined) { if (result === null || result === undefined) {
result = 'no-parent'; result = 'no-parent';
} }
@ -886,19 +938,11 @@ BlazeComponent.extendComponent({
{ {
'click .js-field-has-subtasks'(evt) { 'click .js-field-has-subtasks'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks; const newValue = !this.currentBoard.allowsSubtasks;
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks); Boards.update(this.currentBoard._id, { $set: { allowsSubtasks: newValue } });
$(`.js-field-has-subtasks ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsSubtasks,
);
$('.js-field-has-subtasks').toggleClass(
CKCLS,
this.currentBoard.allowsSubtasks,
);
$('.js-field-deposit-board').prop( $('.js-field-deposit-board').prop(
'disabled', 'disabled',
!this.currentBoard.allowsSubtasks, !newValue,
); );
}, },
'change .js-field-deposit-board'(evt) { 'change .js-field-deposit-board'(evt) {
@ -914,28 +958,13 @@ BlazeComponent.extendComponent({
evt.preventDefault(); evt.preventDefault();
}, },
'click .js-field-show-parent-in-minicard'(evt) { 'click .js-field-show-parent-in-minicard'(evt) {
const value = // Get the ID from the anchor element, not the span
evt.target.id || const anchorElement = $(evt.target).closest('.js-field-show-parent-in-minicard')[0];
$(evt.target).parent()[0].id || const value = anchorElement ? anchorElement.id : null;
$(evt.target)
.parent()[0] if (value) {
.parent()[0].id; Boards.update(this.currentBoard._id, { $set: { presentParentTask: value } });
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} ${MCB}`).toggleClass(CKCLS, false);
$(`#${element}`).toggleClass(CKCLS, false);
}
});
$(`#${value} ${MCB}`).toggleClass(CKCLS, true);
$(`#${value}`).toggleClass(CKCLS, true);
this.currentBoard.setPresentParentTask(value);
evt.preventDefault(); evt.preventDefault();
}, },
}, },
@ -949,115 +978,168 @@ BlazeComponent.extendComponent({
}, },
allowsReceivedDate() { allowsReceivedDate() {
return this.currentBoard.allowsReceivedDate; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsReceivedDate : false;
}, },
allowsStartDate() { allowsStartDate() {
return this.currentBoard.allowsStartDate; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsStartDate : false;
}, },
allowsDueDate() { allowsDueDate() {
return this.currentBoard.allowsDueDate; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsDueDate : false;
}, },
allowsEndDate() { allowsEndDate() {
return this.currentBoard.allowsEndDate; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsEndDate : false;
}, },
allowsSubtasks() { allowsSubtasks() {
return this.currentBoard.allowsSubtasks; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsSubtasks : false;
}, },
allowsCreator() { allowsCreator() {
return this.currentBoard.allowsCreator ?? false; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? (currentBoard.allowsCreator ?? false) : false;
}, },
allowsCreatorOnMinicard() { allowsCreatorOnMinicard() {
return this.currentBoard.allowsCreatorOnMinicard ?? false; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? (currentBoard.allowsCreatorOnMinicard ?? false) : false;
}, },
allowsMembers() { allowsMembers() {
return this.currentBoard.allowsMembers; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsMembers : false;
}, },
allowsAssignee() { allowsAssignee() {
return this.currentBoard.allowsAssignee; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsAssignee : false;
}, },
allowsAssignedBy() { allowsAssignedBy() {
return this.currentBoard.allowsAssignedBy; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsAssignedBy : false;
}, },
allowsRequestedBy() { allowsRequestedBy() {
return this.currentBoard.allowsRequestedBy; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsRequestedBy : false;
}, },
allowsCardSortingByNumber() { allowsCardSortingByNumber() {
return this.currentBoard.allowsCardSortingByNumber; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsCardSortingByNumber : false;
}, },
allowsShowLists() { allowsShowLists() {
return this.currentBoard.allowsShowLists; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsShowLists : false;
}, },
allowsLabels() { allowsLabels() {
return this.currentBoard.allowsLabels; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsLabels : false;
}, },
allowsShowListsOnMinicard() { allowsShowListsOnMinicard() {
return this.currentBoard.allowsShowListsOnMinicard; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsShowListsOnMinicard : false;
}, },
allowsChecklists() { allowsChecklists() {
return this.currentBoard.allowsChecklists; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsChecklists : false;
}, },
allowsAttachments() { allowsAttachments() {
return this.currentBoard.allowsAttachments; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsAttachments : false;
}, },
allowsComments() { allowsComments() {
return this.currentBoard.allowsComments; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsComments : false;
}, },
allowsCardNumber() { allowsCardNumber() {
return this.currentBoard.allowsCardNumber; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsCardNumber : false;
}, },
allowsDescriptionTitle() { allowsDescriptionTitle() {
return this.currentBoard.allowsDescriptionTitle; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsDescriptionTitle : false;
}, },
allowsDescriptionText() { allowsDescriptionText() {
return this.currentBoard.allowsDescriptionText; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsDescriptionText : false;
}, },
isBoardSelected() { isBoardSelected() {
return this.currentBoard.dateSettingsDefaultBoardID; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.dateSettingsDefaultBoardID : false;
}, },
isNullBoardSelected() { isNullBoardSelected() {
return ( const boardId = Session.get('currentBoard');
this.currentBoard.dateSettingsDefaultBoardId === null || const currentBoard = ReactiveCache.getBoard(boardId);
this.currentBoard.dateSettingsDefaultBoardId === undefined return currentBoard ? (
); currentBoard.dateSettingsDefaultBoardId === null ||
currentBoard.dateSettingsDefaultBoardId === undefined
) : true;
}, },
allowsDescriptionTextOnMinicard() { allowsDescriptionTextOnMinicard() {
return this.currentBoard.allowsDescriptionTextOnMinicard; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsDescriptionTextOnMinicard : false;
}, },
allowsCoverAttachmentOnMinicard() { allowsCoverAttachmentOnMinicard() {
return this.currentBoard.allowsCoverAttachmentOnMinicard; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsCoverAttachmentOnMinicard : false;
}, },
allowsBadgeAttachmentOnMinicard() { allowsBadgeAttachmentOnMinicard() {
return this.currentBoard.allowsBadgeAttachmentOnMinicard; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsBadgeAttachmentOnMinicard : false;
}, },
allowsCardSortingByNumberOnMinicard() { allowsCardSortingByNumberOnMinicard() {
return this.currentBoard.allowsCardSortingByNumberOnMinicard; const boardId = Session.get('currentBoard');
const currentBoard = ReactiveCache.getBoard(boardId);
return currentBoard ? currentBoard.allowsCardSortingByNumberOnMinicard : false;
}, },
boards() { boards() {
@ -1100,203 +1182,73 @@ BlazeComponent.extendComponent({
{ {
'click .js-field-has-receiveddate'(evt) { 'click .js-field-has-receiveddate'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsReceivedDate = !this.currentBoard const newValue = !this.currentBoard.allowsReceivedDate;
.allowsReceivedDate; Boards.update(this.currentBoard._id, { $set: { allowsReceivedDate: newValue } });
this.currentBoard.setAllowsReceivedDate(
this.currentBoard.allowsReceivedDate,
);
$(`.js-field-has-receiveddate ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsReceivedDate,
);
$('.js-field-has-receiveddate').toggleClass(
CKCLS,
this.currentBoard.allowsReceivedDate,
);
}, },
'click .js-field-has-startdate'(evt) { 'click .js-field-has-startdate'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsStartDate = !this.currentBoard const newValue = !this.currentBoard.allowsStartDate;
.allowsStartDate; Boards.update(this.currentBoard._id, { $set: { allowsStartDate: newValue } });
this.currentBoard.setAllowsStartDate(
this.currentBoard.allowsStartDate,
);
$(`.js-field-has-startdate ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsStartDate,
);
$('.js-field-has-startdate').toggleClass(
CKCLS,
this.currentBoard.allowsStartDate,
);
}, },
'click .js-field-has-enddate'(evt) { 'click .js-field-has-enddate'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsEndDate = !this.currentBoard.allowsEndDate; const newValue = !this.currentBoard.allowsEndDate;
this.currentBoard.setAllowsEndDate(this.currentBoard.allowsEndDate); Boards.update(this.currentBoard._id, { $set: { allowsEndDate: newValue } });
$(`.js-field-has-enddate ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsEndDate,
);
$('.js-field-has-enddate').toggleClass(
CKCLS,
this.currentBoard.allowsEndDate,
);
}, },
'click .js-field-has-duedate'(evt) { 'click .js-field-has-duedate'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsDueDate = !this.currentBoard.allowsDueDate; const newValue = !this.currentBoard.allowsDueDate;
this.currentBoard.setAllowsDueDate(this.currentBoard.allowsDueDate); Boards.update(this.currentBoard._id, { $set: { allowsDueDate: newValue } });
$(`.js-field-has-duedate ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsDueDate,
);
$('.js-field-has-duedate').toggleClass(
CKCLS,
this.currentBoard.allowsDueDate,
);
}, },
'click .js-field-has-subtasks'(evt) { 'click .js-field-has-subtasks'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks; const newValue = !this.currentBoard.allowsSubtasks;
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks); Boards.update(this.currentBoard._id, { $set: { allowsSubtasks: newValue } });
$(`.js-field-has-subtasks ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsSubtasks,
);
$('.js-field-has-subtasks').toggleClass(
CKCLS,
this.currentBoard.allowsSubtasks,
);
}, },
'click .js-field-has-creator'(evt) { 'click .js-field-has-creator'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsCreator = !this.currentBoard.allowsCreator; const newValue = !this.currentBoard.allowsCreator;
this.currentBoard.setAllowsCreator(this.currentBoard.allowsCreator); Boards.update(this.currentBoard._id, { $set: { allowsCreator: newValue } });
$(`.js-field-has-creator ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsCreator,
);
$('.js-field-has-creator').toggleClass(
CKCLS,
this.currentBoard.allowsCreator,
);
}, },
'click .js-field-has-creator-on-minicard'(evt) { 'click .js-field-has-creator-on-minicard'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsCreatorOnMinicard = !this.currentBoard.allowsCreatorOnMinicard; const newValue = !this.currentBoard.allowsCreatorOnMinicard;
this.currentBoard.setAllowsCreatorOnMinicard(this.currentBoard.allowsCreatorOnMinicard); Boards.update(this.currentBoard._id, { $set: { allowsCreatorOnMinicard: newValue } });
$(`.js-field-has-creator-on-minicard ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsCreatorOnMinicard,
);
$('.js-field-has-creator-on-minicard').toggleClass(
CKCLS,
this.currentBoard.allowsCreatorOnMinicard,
);
}, },
'click .js-field-has-members'(evt) { 'click .js-field-has-members'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsMembers = !this.currentBoard.allowsMembers; const newValue = !this.currentBoard.allowsMembers;
this.currentBoard.setAllowsMembers(this.currentBoard.allowsMembers); Boards.update(this.currentBoard._id, { $set: { allowsMembers: newValue } });
$(`.js-field-has-members ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsMembers,
);
$('.js-field-has-members').toggleClass(
CKCLS,
this.currentBoard.allowsMembers,
);
}, },
'click .js-field-has-assignee'(evt) { 'click .js-field-has-assignee'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsAssignee = !this.currentBoard.allowsAssignee; const newValue = !this.currentBoard.allowsAssignee;
this.currentBoard.setAllowsAssignee(this.currentBoard.allowsAssignee); Boards.update(this.currentBoard._id, { $set: { allowsAssignee: newValue } });
$(`.js-field-has-assignee ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsAssignee,
);
$('.js-field-has-assignee').toggleClass(
CKCLS,
this.currentBoard.allowsAssignee,
);
}, },
'click .js-field-has-assigned-by'(evt) { 'click .js-field-has-assigned-by'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsAssignedBy = !this.currentBoard const newValue = !this.currentBoard.allowsAssignedBy;
.allowsAssignedBy; Boards.update(this.currentBoard._id, { $set: { allowsAssignedBy: newValue } });
this.currentBoard.setAllowsAssignedBy(
this.currentBoard.allowsAssignedBy,
);
$(`.js-field-has-assigned-by ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsAssignedBy,
);
$('.js-field-has-assigned-by').toggleClass(
CKCLS,
this.currentBoard.allowsAssignedBy,
);
}, },
'click .js-field-has-requested-by'(evt) { 'click .js-field-has-requested-by'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsRequestedBy = !this.currentBoard const newValue = !this.currentBoard.allowsRequestedBy;
.allowsRequestedBy; Boards.update(this.currentBoard._id, { $set: { allowsRequestedBy: newValue } });
this.currentBoard.setAllowsRequestedBy(
this.currentBoard.allowsRequestedBy,
);
$(`.js-field-has-requested-by ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsRequestedBy,
);
$('.js-field-has-requested-by').toggleClass(
CKCLS,
this.currentBoard.allowsRequestedBy,
);
}, },
'click .js-field-has-card-sorting-by-number'(evt) { 'click .js-field-has-card-sorting-by-number'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsCardSortingByNumber = !this.currentBoard const newValue = !this.currentBoard.allowsCardSortingByNumber;
.allowsCardSortingByNumber; Boards.update(this.currentBoard._id, { $set: { allowsCardSortingByNumber: newValue } });
this.currentBoard.setAllowsCardSortingByNumber(
this.currentBoard.allowsCardSortingByNumber,
);
$(`.js-field-has-card-sorting-by-number ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsCardSortingByNumber,
);
$('.js-field-has-card-sorting-by-number').toggleClass(
CKCLS,
this.currentBoard.allowsCardSortingByNumber,
);
}, },
'click .js-field-has-card-show-lists'(evt) { 'click .js-field-has-card-show-lists'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsShowLists = !this.currentBoard const newValue = !this.currentBoard.allowsShowLists;
.allowsShowLists; Boards.update(this.currentBoard._id, { $set: { allowsShowLists: newValue } });
this.currentBoard.setAllowsShowLists(
this.currentBoard.allowsShowLists,
);
$(`.js-field-has-card-show-lists ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsShowLists,
);
$('.js-field-has-card-show-lists').toggleClass(
CKCLS,
this.currentBoard.allowsShowLists,
);
}, },
'click .js-field-has-labels'(evt) { 'click .js-field-has-labels'(evt) {
evt.preventDefault(); evt.preventDefault();
this.currentBoard.allowsLabels = !this.currentBoard.allowsLabels; const newValue = !this.currentBoard.allowsLabels;
this.currentBoard.setAllowsLabels(this.currentBoard.allowsLabels); Boards.update(this.currentBoard._id, { $set: { allowsLabels: newValue } });
$(`.js-field-has-labels ${MCB}`).toggleClass(
CKCLS,
this.currentBoard.allowsLabels,
);
$('.js-field-has-labels').toggleClass(
CKCLS,
this.currentBoard.allowsLabels,
);
}, },
'click .js-field-has-card-show-lists-on-minicard'(evt) { 'click .js-field-has-card-show-lists-on-minicard'(evt) {
evt.preventDefault(); evt.preventDefault();
@ -1492,19 +1444,27 @@ BlazeComponent.extendComponent({
}, },
}).register('boardCardSettingsPopup'); }).register('boardCardSettingsPopup');
// Use Session variables instead of global ReactiveVars
Session.setDefault('addMemberPopup.searchResults', []);
Session.setDefault('addMemberPopup.searching', false);
Session.setDefault('addMemberPopup.noResults', false);
Session.setDefault('addMemberPopup.loading', false);
Session.setDefault('addMemberPopup.error', '');
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({
onCreated() { onCreated() {
this.error = new ReactiveVar(''); // Use Session variables
this.loading = new ReactiveVar(false); this.searchTimeout = null;
}, },
onRendered() { onRendered() {
this.find('.js-search-member input').focus(); this.find('.js-search-member-input').focus();
this.setLoading(false); this.setLoading(false);
}, },
isBoardMember() { isBoardMember() {
const userId = this.currentData().__originalId; const userId = this.currentData()._id;
const user = ReactiveCache.getUser(userId); const user = ReactiveCache.getUser(userId);
return user && user.isBoardMember(); return user && user.isBoardMember();
}, },
@ -1514,15 +1474,35 @@ BlazeComponent.extendComponent({
}, },
setError(error) { setError(error) {
this.error.set(error); Session.set('addMemberPopup.error', error);
}, },
setLoading(w) { setLoading(w) {
this.loading.set(w); Session.set('addMemberPopup.loading', w);
}, },
isLoading() { isLoading() {
return this.loading.get(); return Session.get('addMemberPopup.loading');
},
performSearch(query) {
if (!query || query.length < 2) {
Session.set('addMemberPopup.searchResults', []);
Session.set('addMemberPopup.noResults', false);
return;
}
Session.set('addMemberPopup.searching', true);
Session.set('addMemberPopup.noResults', false);
// Use the fallback search
const results = UserSearchIndex.search(query, { limit: 20 }).fetch();
Session.set('addMemberPopup.searchResults', results);
Session.set('addMemberPopup.searching', false);
if (results.length === 0) {
Session.set('addMemberPopup.noResults', true);
}
}, },
inviteUser(idNameEmail) { inviteUser(idNameEmail) {
@ -1540,18 +1520,30 @@ BlazeComponent.extendComponent({
events() { events() {
return [ return [
{ {
'keyup input'() { 'keyup .js-search-member-input'(event) {
this.setError(''); this.setError('');
const query = event.target.value.trim();
this.searchQuery.set(query);
// Clear previous timeout
if (this.searchTimeout) {
clearTimeout(this.searchTimeout);
}
// Debounce search
this.searchTimeout = setTimeout(() => {
this.performSearch(query);
}, 300);
}, },
'click .js-select-member'() { 'click .js-select-member'() {
const userId = this.currentData().__originalId; const userId = this.currentData()._id;
const currentBoard = Utils.getCurrentBoard(); const currentBoard = Utils.getCurrentBoard();
if (!currentBoard.hasMember(userId)) { if (!currentBoard.hasMember(userId)) {
this.inviteUser(userId); this.inviteUser(userId);
} }
}, },
'click .js-email-invite'() { 'click .js-email-invite'() {
const idNameEmail = $('.js-search-member input').val(); const idNameEmail = $('.js-search-member-input').val();
if (idNameEmail.indexOf('@') < 0 || this.isValidEmail(idNameEmail)) { if (idNameEmail.indexOf('@') < 0 || this.isValidEmail(idNameEmail)) {
this.inviteUser(idNameEmail); this.inviteUser(idNameEmail);
} else this.setError('email-invalid'); } else this.setError('email-invalid');
@ -1562,7 +1554,35 @@ BlazeComponent.extendComponent({
}).register('addMemberPopup'); }).register('addMemberPopup');
Template.addMemberPopup.helpers({ Template.addMemberPopup.helpers({
searchIndex: () => UserSearchIndex, searchResults() {
const results = Session.get('addMemberPopup.searchResults');
console.log('searchResults helper called, returning:', results);
return results;
},
searching() {
return Session.get('addMemberPopup.searching');
},
noResults() {
return Session.get('addMemberPopup.noResults');
},
loading() {
return Session.get('addMemberPopup.loading');
},
error() {
return Session.get('addMemberPopup.error');
},
isBoardMember() {
const userId = this._id;
const user = ReactiveCache.getUser(userId);
return user && user.isBoardMember();
}
})
Template.addMemberPopupTest.helpers({
searchResults() {
console.log('addMemberPopupTest searchResults helper called');
return Session.get('addMemberPopup.searchResults') || [];
}
}) })
BlazeComponent.extendComponent({ BlazeComponent.extendComponent({

View file

@ -95,3 +95,7 @@ template(name="createCustomFieldPopup")
template(name="deleteCustomFieldPopup") template(name="deleteCustomFieldPopup")
p {{_ "custom-field-delete-pop"}} p {{_ "custom-field-delete-pop"}}
button.js-confirm.negate.full(type="submit") {{_ 'delete'}} button.js-confirm.negate.full(type="submit") {{_ 'delete'}}
// Reuse the create form for editing to satisfy popup template lookup
template(name="editCustomFieldPopup")
+Template.dynamic(template="createCustomFieldPopup")

View file

@ -0,0 +1,109 @@
template(name='migrationsSidebar')
if currentUser.isBoardAdmin
.sidebar-migrations
h3
| 🔧
| {{_ 'migrations'}}
p.quiet {{_ 'migrations-description'}}
.migrations-list
h4 {{_ 'board-migrations'}}
.migration-item
a.js-run-migration(data-migration="comprehensive")
.migration-name
| {{_ 'comprehensive-board-migration'}}
.migration-status
if comprehensiveMigrationNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="fixMissingLists")
.migration-name
| {{_ 'fix-missing-lists-migration'}}
.migration-status
if fixMissingListsNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="deleteDuplicateEmptyLists")
.migration-name
| {{_ 'delete-duplicate-empty-lists-migration'}}
.migration-status
if deleteDuplicateEmptyListsNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="restoreLostCards")
.migration-name
| {{_ 'restore-lost-cards-migration'}}
.migration-status
if restoreLostCardsNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="restoreAllArchived")
.migration-name
| {{_ 'restore-all-archived-migration'}}
.migration-status
if restoreAllArchivedNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="fixAvatarUrls")
.migration-name
| {{_ 'fix-avatar-urls-migration'}}
.migration-status
if fixAvatarUrlsNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
.migration-item
a.js-run-migration(data-migration="fixAllFileUrls")
.migration-name
| {{_ 'fix-all-file-urls-migration'}}
.migration-status
if fixAllFileUrlsNeeded
span.badge.badge-warning {{_ 'migration-needed'}}
else
span.badge.badge-success {{_ 'migration-complete'}}
else
p.quiet {{_ 'migrations-admin-only'}}
template(name='runComprehensiveMigrationPopup')
p {{_ 'run-comprehensive-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runFixMissingListsMigrationPopup')
p {{_ 'run-fix-missing-lists-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runDeleteDuplicateEmptyListsMigrationPopup')
p {{_ 'run-delete-duplicate-empty-lists-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runRestoreLostCardsMigrationPopup')
p {{_ 'run-restore-lost-cards-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runRestoreAllArchivedMigrationPopup')
p {{_ 'run-restore-all-archived-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runFixAvatarUrlsMigrationPopup')
p {{_ 'run-fix-avatar-urls-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}
template(name='runFixAllFileUrlsMigrationPopup')
p {{_ 'run-fix-all-file-urls-migration-confirm'}}
button.js-confirm.primary.full(type="submit") {{_ 'run-migration'}}

View file

@ -0,0 +1,341 @@
import { ReactiveCache } from '/imports/reactiveCache';
import { TAPi18n } from '/imports/i18n';
import { migrationProgressManager } from '/client/components/migrationProgress';
BlazeComponent.extendComponent({
onCreated() {
this.migrationStatuses = new ReactiveVar({});
this.loadMigrationStatuses();
},
loadMigrationStatuses() {
const boardId = Session.get('currentBoard');
if (!boardId) return;
// Check comprehensive migration
Meteor.call('comprehensiveBoardMigration.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.comprehensive = res;
this.migrationStatuses.set(statuses);
}
});
// Check fix missing lists migration
Meteor.call('fixMissingListsMigration.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.fixMissingLists = res;
this.migrationStatuses.set(statuses);
}
});
// Check delete duplicate empty lists migration
Meteor.call('deleteDuplicateEmptyLists.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.deleteDuplicateEmptyLists = res;
this.migrationStatuses.set(statuses);
}
});
// Check restore lost cards migration
Meteor.call('restoreLostCards.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.restoreLostCards = res;
this.migrationStatuses.set(statuses);
}
});
// Check restore all archived migration
Meteor.call('restoreAllArchived.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.restoreAllArchived = res;
this.migrationStatuses.set(statuses);
}
});
// Check fix avatar URLs migration (board-specific)
Meteor.call('fixAvatarUrls.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.fixAvatarUrls = res;
this.migrationStatuses.set(statuses);
}
});
// Check fix all file URLs migration (board-specific)
Meteor.call('fixAllFileUrls.needsMigration', boardId, (err, res) => {
if (!err) {
const statuses = this.migrationStatuses.get();
statuses.fixAllFileUrls = res;
this.migrationStatuses.set(statuses);
}
});
},
comprehensiveMigrationNeeded() {
return this.migrationStatuses.get().comprehensive === true;
},
fixMissingListsNeeded() {
return this.migrationStatuses.get().fixMissingLists === true;
},
deleteDuplicateEmptyListsNeeded() {
return this.migrationStatuses.get().deleteDuplicateEmptyLists === true;
},
restoreLostCardsNeeded() {
return this.migrationStatuses.get().restoreLostCards === true;
},
restoreAllArchivedNeeded() {
return this.migrationStatuses.get().restoreAllArchived === true;
},
fixAvatarUrlsNeeded() {
return this.migrationStatuses.get().fixAvatarUrls === true;
},
fixAllFileUrlsNeeded() {
return this.migrationStatuses.get().fixAllFileUrls === true;
},
// Simulate migration progress updates using the global progress popup
async simulateMigrationProgress(progressSteps) {
const totalSteps = progressSteps.length;
for (let i = 0; i < progressSteps.length; i++) {
const step = progressSteps[i];
const overall = Math.round(((i + 1) / totalSteps) * 100);
// Start step
migrationProgressManager.updateProgress({
overallProgress: overall,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: 0,
stepStatus: `Starting ${step.name}...`,
stepDetails: null,
boardId: Session.get('currentBoard'),
});
const stepDuration = step.duration;
const updateInterval = 100;
const totalUpdates = Math.max(1, Math.floor(stepDuration / updateInterval));
for (let j = 0; j < totalUpdates; j++) {
const per = Math.round(((j + 1) / totalUpdates) * 100);
migrationProgressManager.updateProgress({
overallProgress: overall,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: per,
stepStatus: `Processing ${step.name}...`,
stepDetails: { progress: `${per}%` },
boardId: Session.get('currentBoard'),
});
// eslint-disable-next-line no-await-in-loop
await new Promise((r) => setTimeout(r, updateInterval));
}
// Complete step
migrationProgressManager.updateProgress({
overallProgress: overall,
currentStep: i + 1,
totalSteps,
stepName: step.step,
stepProgress: 100,
stepStatus: `${step.name} completed`,
stepDetails: { status: 'completed' },
boardId: Session.get('currentBoard'),
});
}
},
runMigration(migrationType) {
const boardId = Session.get('currentBoard');
let methodName;
let methodArgs = [];
switch (migrationType) {
case 'comprehensive':
methodName = 'comprehensiveBoardMigration.execute';
methodArgs = [boardId];
break;
case 'fixMissingLists':
methodName = 'fixMissingListsMigration.execute';
methodArgs = [boardId];
break;
case 'deleteDuplicateEmptyLists':
methodName = 'deleteDuplicateEmptyLists.execute';
methodArgs = [boardId];
break;
case 'restoreLostCards':
methodName = 'restoreLostCards.execute';
methodArgs = [boardId];
break;
case 'restoreAllArchived':
methodName = 'restoreAllArchived.execute';
methodArgs = [boardId];
break;
case 'fixAvatarUrls':
methodName = 'fixAvatarUrls.execute';
methodArgs = [boardId];
break;
case 'fixAllFileUrls':
methodName = 'fixAllFileUrls.execute';
methodArgs = [boardId];
break;
}
if (methodName) {
// Define simulated steps per migration type
const stepsByType = {
comprehensive: [
{ step: 'analyze_board_structure', name: 'Analyze Board Structure', duration: 800 },
{ step: 'fix_orphaned_cards', name: 'Fix Orphaned Cards', duration: 1200 },
{ step: 'convert_shared_lists', name: 'Convert Shared Lists', duration: 1000 },
{ step: 'ensure_per_swimlane_lists', name: 'Ensure Per-Swimlane Lists', duration: 800 },
{ step: 'validate_migration', name: 'Validate Migration', duration: 800 },
{ step: 'fix_avatar_urls', name: 'Fix Avatar URLs', duration: 600 },
{ step: 'fix_attachment_urls', name: 'Fix Attachment URLs', duration: 600 },
],
fixMissingLists: [
{ step: 'analyze_lists', name: 'Analyze Lists', duration: 600 },
{ step: 'create_missing_lists', name: 'Create Missing Lists', duration: 900 },
{ step: 'update_cards', name: 'Update Cards', duration: 900 },
{ step: 'finalize', name: 'Finalize', duration: 400 },
],
deleteDuplicateEmptyLists: [
{ step: 'convert_shared_lists', name: 'Convert Shared Lists', duration: 700 },
{ step: 'delete_duplicate_empty_lists', name: 'Delete Duplicate Empty Lists', duration: 800 },
],
restoreLostCards: [
{ step: 'ensure_lost_cards_swimlane', name: 'Ensure Lost Cards Swimlane', duration: 600 },
{ step: 'restore_lists', name: 'Restore Lists', duration: 800 },
{ step: 'restore_cards', name: 'Restore Cards', duration: 1000 },
],
restoreAllArchived: [
{ step: 'restore_swimlanes', name: 'Restore Swimlanes', duration: 800 },
{ step: 'restore_lists', name: 'Restore Lists', duration: 900 },
{ step: 'restore_cards', name: 'Restore Cards', duration: 1000 },
{ step: 'fix_missing_ids', name: 'Fix Missing IDs', duration: 600 },
],
fixAvatarUrls: [
{ step: 'scan_users', name: 'Checking board member avatars', duration: 500 },
{ step: 'fix_urls', name: 'Fixing avatar URLs', duration: 900 },
],
fixAllFileUrls: [
{ step: 'scan_files', name: 'Checking board file attachments', duration: 600 },
{ step: 'fix_urls', name: 'Fixing file URLs', duration: 1000 },
],
};
const steps = stepsByType[migrationType] || [
{ step: 'running', name: 'Running Migration', duration: 1000 },
];
// Kick off popup and simulated progress
migrationProgressManager.startMigration();
const progressPromise = this.simulateMigrationProgress(steps);
// Start migration call
const callPromise = new Promise((resolve, reject) => {
Meteor.call(methodName, ...methodArgs, (err, result) => {
if (err) return reject(err);
return resolve(result);
});
});
Promise.allSettled([callPromise, progressPromise]).then(([callRes]) => {
if (callRes.status === 'rejected') {
migrationProgressManager.failMigration(callRes.reason);
} else {
const result = callRes.value;
// Summarize result details in the popup
let summary = {};
if (result && result.results) {
// Comprehensive returns {success, results}
const r = result.results;
summary = {
totalCardsProcessed: r.totalCardsProcessed,
totalListsProcessed: r.totalListsProcessed,
totalListsCreated: r.totalListsCreated,
};
} else if (result && result.changes) {
// Many migrations return a changes string array
summary = { changes: result.changes.join(' | ') };
} else if (result && typeof result === 'object') {
summary = result;
}
migrationProgressManager.updateProgress({
overallProgress: 100,
currentStep: steps.length,
totalSteps: steps.length,
stepName: 'completed',
stepProgress: 100,
stepStatus: 'Migration completed',
stepDetails: summary,
boardId: Session.get('currentBoard'),
});
migrationProgressManager.completeMigration();
// Refresh status badges slightly after
Meteor.setTimeout(() => {
this.loadMigrationStatuses();
}, 1000);
}
});
}
},
events() {
const self = this; // Capture component reference
return [
{
'click .js-run-migration[data-migration="comprehensive"]': Popup.afterConfirm('runComprehensiveMigration', function() {
self.runMigration('comprehensive');
Popup.back();
}),
'click .js-run-migration[data-migration="fixMissingLists"]': Popup.afterConfirm('runFixMissingListsMigration', function() {
self.runMigration('fixMissingLists');
Popup.back();
}),
'click .js-run-migration[data-migration="deleteDuplicateEmptyLists"]': Popup.afterConfirm('runDeleteDuplicateEmptyListsMigration', function() {
self.runMigration('deleteDuplicateEmptyLists');
Popup.back();
}),
'click .js-run-migration[data-migration="restoreLostCards"]': Popup.afterConfirm('runRestoreLostCardsMigration', function() {
self.runMigration('restoreLostCards');
Popup.back();
}),
'click .js-run-migration[data-migration="restoreAllArchived"]': Popup.afterConfirm('runRestoreAllArchivedMigration', function() {
self.runMigration('restoreAllArchived');
Popup.back();
}),
'click .js-run-migration[data-migration="fixAvatarUrls"]': Popup.afterConfirm('runFixAvatarUrlsMigration', function() {
self.runMigration('fixAvatarUrls');
Popup.back();
}),
'click .js-run-migration[data-migration="fixAllFileUrls"]': Popup.afterConfirm('runFixAllFileUrlsMigration', function() {
self.runMigration('fixAllFileUrls');
Popup.back();
}),
},
];
},
}).register('migrationsSidebar');

View file

@ -25,25 +25,26 @@ template(name="swimlaneFixedHeader")
.swimlane-header-menu .swimlane-header-menu
if currentUser if currentUser
unless currentUser.isCommentOnly unless currentUser.isCommentOnly
a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}") unless currentUser.isWorker
| a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}")
a.js-open-swimlane-menu(title="{{_ 'swimlaneActionPopup-title'}}") |
| ☰ a.js-open-swimlane-menu(title="{{_ 'swimlaneActionPopup-title'}}")
//// TODO: Collapse Swimlane: make button working, etc. | ☰
//unless collapsed //// TODO: Collapse Swimlane: make button working, etc.
// a.js-collapse-swimlane(title="{{_ 'collapse'}}") //unless collapsed
// i.fa.fa-arrow-down.swimlane-header-collapse-down // a.js-collapse-swimlane(title="{{_ 'collapse'}}")
// ⬆️.swimlane-header-collapse-up // i.fa.fa-arrow-down.swimlane-header-collapse-down
//if collapsed // ⬆️.swimlane-header-collapse-up
// a.js-collapse-swimlane(title="{{_ 'uncollapse'}}") //if collapsed
// ⬆️.swimlane-header-collapse-up // a.js-collapse-swimlane(title="{{_ 'uncollapse'}}")
// i.fa.fa-arrow-down.swimlane-header-collapse-down // ⬆️.swimlane-header-collapse-up
unless isTouchScreen // i.fa.fa-arrow-down.swimlane-header-collapse-down
a.swimlane-header-handle.handle.js-swimlane-header-handle unless isTouchScreen
| ↕️ a.swimlane-header-handle.handle.js-swimlane-header-handle
if isTouchScreen | ↕️
a.swimlane-header-miniscreen-handle.handle.js-swimlane-header-handle if isTouchScreen
| ↕️ a.swimlane-header-miniscreen-handle.handle.js-swimlane-header-handle
| ↕️
template(name="editSwimlaneTitleForm") template(name="editSwimlaneTitleForm")
.list-composer .list-composer

View file

@ -178,6 +178,11 @@ BlazeComponent.extendComponent({
events() { events() {
return [ return [
{ {
'submit form'(event) {
event.preventDefault();
this.currentSwimlane.setColor(this.currentColor.get());
Popup.back();
},
'click .js-palette-color'() { 'click .js-palette-color'() {
this.currentColor.set(this.currentData().color); this.currentColor.set(this.currentData().color);
}, },

View file

@ -112,7 +112,7 @@
padding: 7px; padding: 7px;
top: 50%; top: 50%;
transform: translateY(-50%); transform: translateY(-50%);
left: 87vw; right: 10px;
font-size: 24px; font-size: 24px;
cursor: move; cursor: move;
z-index: 15; z-index: 15;

View file

@ -228,10 +228,8 @@ function initSortable(boardComponent, $listsDom) {
// Don't cancel the sortable when moving to a different swimlane // Don't cancel the sortable when moving to a different swimlane
// The DOM move should be allowed to complete // The DOM move should be allowed to complete
} else {
// If staying in the same swimlane, cancel the sortable to prevent DOM manipulation issues
$listsDom.sortable('cancel');
} }
// Allow reordering within the same swimlane by not canceling the sortable
try { try {
Lists.update(list._id, { Lists.update(list._id, {
@ -682,6 +680,11 @@ Template.swimlane.helpers({
canSeeAddList() { canSeeAddList() {
return ReactiveCache.getCurrentUser().isBoardAdmin(); return ReactiveCache.getCurrentUser().isBoardAdmin();
}, },
lists() {
// Return per-swimlane lists for this swimlane
return this.myLists();
}
}); });
// Initialize sortable on DOM elements // Initialize sortable on DOM elements
@ -722,6 +725,89 @@ setTimeout(() => {
} }
}, },
stop(evt, ui) { stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following list -- if any.
const prevListDom = ui.item.prev('.js-list').get(0);
const nextListDom = ui.item.next('.js-list').get(0);
const sortIndex = calculateIndex(prevListDom, nextListDom, 1);
const listDomElement = ui.item.get(0);
if (!listDomElement) {
return;
}
let list;
try {
list = Blaze.getData(listDomElement);
} catch (error) {
return;
}
if (!list) {
return;
}
// Detect if the list was dropped in a different swimlane
const targetSwimlaneDom = ui.item.closest('.js-swimlane');
let targetSwimlaneId = null;
if (targetSwimlaneDom.length > 0) {
// List was dropped in a swimlane
try {
targetSwimlaneId = targetSwimlaneDom.attr('id').replace('swimlane-', '');
} catch (error) {
return;
}
} else {
// List was dropped in lists view (not swimlanes view)
// In this case, assign to the default swimlane
const currentBoard = ReactiveCache.getBoard(Session.get('currentBoard'));
if (currentBoard) {
const defaultSwimlane = currentBoard.getDefaultSwimline();
if (defaultSwimlane) {
targetSwimlaneId = defaultSwimlane._id;
}
}
}
// Get the original swimlane ID of the list (handle backward compatibility)
const originalSwimlaneId = list.getEffectiveSwimlaneId ? list.getEffectiveSwimlaneId() : (list.swimlaneId || null);
// Prepare update object
const updateData = {
sort: sortIndex.base,
};
// Check if the list was dropped in a different swimlane
const isDifferentSwimlane = targetSwimlaneId && targetSwimlaneId !== originalSwimlaneId;
// If the list was dropped in a different swimlane, update the swimlaneId
if (isDifferentSwimlane) {
updateData.swimlaneId = targetSwimlaneId;
// Move all cards in the list to the new swimlane
const cardsInList = ReactiveCache.getCards({
listId: list._id,
archived: false
});
cardsInList.forEach(card => {
card.move(list.boardId, targetSwimlaneId, list._id);
});
// Don't cancel the sortable when moving to a different swimlane
// The DOM move should be allowed to complete
}
// Allow reordering within the same swimlane by not canceling the sortable
try {
Lists.update(list._id, {
$set: updateData,
});
} catch (error) {
return;
}
// Try to get board component // Try to get board component
try { try {
const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]); const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]);
@ -731,6 +817,18 @@ setTimeout(() => {
} catch (e) { } catch (e) {
// Silent fail // Silent fail
} }
// Re-enable dragscroll after list dragging is complete
try {
dragscroll.reset();
} catch (e) {
// Silent fail
}
// Re-enable dragscroll on all swimlanes
$('.js-swimlane').each(function() {
$(this).addClass('dragscroll');
});
} }
}); });
} }
@ -769,6 +867,89 @@ setTimeout(() => {
} }
}, },
stop(evt, ui) { stop(evt, ui) {
// To attribute the new index number, we need to get the DOM element
// of the previous and the following list -- if any.
const prevListDom = ui.item.prev('.js-list').get(0);
const nextListDom = ui.item.next('.js-list').get(0);
const sortIndex = calculateIndex(prevListDom, nextListDom, 1);
const listDomElement = ui.item.get(0);
if (!listDomElement) {
return;
}
let list;
try {
list = Blaze.getData(listDomElement);
} catch (error) {
return;
}
if (!list) {
return;
}
// Detect if the list was dropped in a different swimlane
const targetSwimlaneDom = ui.item.closest('.js-swimlane');
let targetSwimlaneId = null;
if (targetSwimlaneDom.length > 0) {
// List was dropped in a swimlane
try {
targetSwimlaneId = targetSwimlaneDom.attr('id').replace('swimlane-', '');
} catch (error) {
return;
}
} else {
// List was dropped in lists view (not swimlanes view)
// In this case, assign to the default swimlane
const currentBoard = ReactiveCache.getBoard(Session.get('currentBoard'));
if (currentBoard) {
const defaultSwimlane = currentBoard.getDefaultSwimline();
if (defaultSwimlane) {
targetSwimlaneId = defaultSwimlane._id;
}
}
}
// Get the original swimlane ID of the list (handle backward compatibility)
const originalSwimlaneId = list.getEffectiveSwimlaneId ? list.getEffectiveSwimlaneId() : (list.swimlaneId || null);
// Prepare update object
const updateData = {
sort: sortIndex.base,
};
// Check if the list was dropped in a different swimlane
const isDifferentSwimlane = targetSwimlaneId && targetSwimlaneId !== originalSwimlaneId;
// If the list was dropped in a different swimlane, update the swimlaneId
if (isDifferentSwimlane) {
updateData.swimlaneId = targetSwimlaneId;
// Move all cards in the list to the new swimlane
const cardsInList = ReactiveCache.getCards({
listId: list._id,
archived: false
});
cardsInList.forEach(card => {
card.move(list.boardId, targetSwimlaneId, list._id);
});
// Don't cancel the sortable when moving to a different swimlane
// The DOM move should be allowed to complete
}
// Allow reordering within the same swimlane by not canceling the sortable
try {
Lists.update(list._id, {
$set: updateData,
});
} catch (error) {
return;
}
// Try to get board component // Try to get board component
try { try {
const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]); const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]);
@ -778,6 +959,18 @@ setTimeout(() => {
} catch (e) { } catch (e) {
// Silent fail // Silent fail
} }
// Re-enable dragscroll after list dragging is complete
try {
dragscroll.reset();
} catch (e) {
// Silent fail
}
// Re-enable dragscroll on all swimlanes
$('.js-swimlane').each(function() {
$(this).addClass('dragscroll');
});
} }
}); });
} }

View file

@ -1,7 +1,7 @@
template(name="userAvatar") template(name="userAvatar")
a.member(class="js-{{#if assignee}}assignee{{else}}member{{/if}}" title="{{userData.profile.fullname}} ({{userData.username}}) {{_ memberType}}") a.member(class="js-{{#if assignee}}assignee{{else}}member{{/if}}" title="{{userData.profile.fullname}} ({{userData.username}}) {{_ memberType}}")
if userData.profile.avatarUrl if userData.profile.avatarUrl
img.avatar.avatar-image(src="{{userData.profile.avatarUrl}}") img.avatar.avatar-image(src="{{avatarUrl}}")
else else
+userAvatarInitials(userId=userData._id) +userAvatarInitials(userId=userData._id)
@ -87,7 +87,7 @@ template(name="changeAvatarPopup")
each uploadedAvatars each uploadedAvatars
li: a.js-select-avatar li: a.js-select-avatar
.member .member
img.avatar.avatar-image(src="{{link}}?auth=false&brokenIsFine=true") img.avatar.avatar-image(src="{{link}}")
| {{_ 'uploaded-avatar'}} | {{_ 'uploaded-avatar'}}
if isSelected if isSelected
| ✅ | ✅

View file

@ -15,6 +15,21 @@ Template.userAvatar.helpers({
}); });
}, },
avatarUrl() {
const user = ReactiveCache.getUser(this.userId, { fields: { profile: 1 } });
const base = (user && user.profile && user.profile.avatarUrl) || '';
if (!base) return '';
// Append current boardId when available so public viewers can access avatars on public boards
try {
const boardId = Utils.getCurrentBoardId && Utils.getCurrentBoardId();
if (boardId) {
const sep = base.includes('?') ? '&' : '?';
return `${base}${sep}boardId=${encodeURIComponent(boardId)}`;
}
} catch (_) {}
return base;
},
memberType() { memberType() {
const user = ReactiveCache.getUser(this.userId); const user = ReactiveCache.getUser(this.userId);
return user && user.isBoardAdmin() ? 'admin' : 'normal'; return user && user.isBoardAdmin() ? 'admin' : 'normal';
@ -179,7 +194,7 @@ BlazeComponent.extendComponent({
isSelected() { isSelected() {
const userProfile = ReactiveCache.getCurrentUser().profile; const userProfile = ReactiveCache.getCurrentUser().profile;
const avatarUrl = userProfile && userProfile.avatarUrl; const avatarUrl = userProfile && userProfile.avatarUrl;
const currentAvatarUrl = `${this.currentData().link()}?auth=false&brokenIsFine=true`; const currentAvatarUrl = this.currentData().link();
return avatarUrl === currentAvatarUrl; return avatarUrl === currentAvatarUrl;
}, },
@ -220,7 +235,7 @@ BlazeComponent.extendComponent({
} }
}, },
'click .js-select-avatar'() { 'click .js-select-avatar'() {
const avatarUrl = `${this.currentData().link()}?auth=false&brokenIsFine=true`; const avatarUrl = this.currentData().link();
this.setAvatar(avatarUrl); this.setAvatar(avatarUrl);
}, },
'click .js-select-initials'() { 'click .js-select-initials'() {

View file

@ -12,11 +12,6 @@ template(name="headerUserBar")
template(name="memberMenuPopup") template(name="memberMenuPopup")
ul.pop-over-list ul.pop-over-list
// Bookmarks at the very top
li
a.js-open-bookmarks
| 🔖
| {{_ 'bookmarks'}}
with currentUser with currentUser
li li
a.js-my-cards(href="{{pathFor 'my-cards'}}") a.js-my-cards(href="{{pathFor 'my-cards'}}")
@ -32,6 +27,7 @@ template(name="memberMenuPopup")
| {{_ 'globalSearch-title'}} | {{_ 'globalSearch-title'}}
li li
a(href="{{pathFor 'home'}}") a(href="{{pathFor 'home'}}")
| 🏠
| 🏠 | 🏠
| {{_ 'all-boards'}} | {{_ 'all-boards'}}
li li

View file

@ -73,6 +73,10 @@ Blaze.registerHelper('canModifyCard', () =>
Utils.canModifyCard(), Utils.canModifyCard(),
); );
Blaze.registerHelper('canMoveCard', () =>
Utils.canMoveCard(),
);
Blaze.registerHelper('canModifyBoard', () => Blaze.registerHelper('canModifyBoard', () =>
Utils.canModifyBoard(), Utils.canModifyBoard(),
); );

View file

@ -0,0 +1,73 @@
import { ReactiveCache } from '/imports/reactiveCache';
BoardMultiSelection = {
_selectedBoards: new ReactiveVar([]),
_isActive: new ReactiveVar(false),
reset() {
this._selectedBoards.set([]);
},
isActive() {
return this._isActive.get();
},
count() {
return this._selectedBoards.get().length;
},
isEmpty() {
return this.count() === 0;
},
getSelectedBoardIds() {
return this._selectedBoards.get();
},
activate() {
if (!this.isActive()) {
this._isActive.set(true);
Tracker.flush();
}
},
disable() {
if (this.isActive()) {
this._isActive.set(false);
this.reset();
}
},
add(boardIds) {
return this.toggle(boardIds, { add: true, remove: false });
},
remove(boardIds) {
return this.toggle(boardIds, { add: false, remove: true });
},
toogle(boardIds) {
return this.toggle(boardIds, { add: true, remove: true });
},
toggle(boardIds, { add, remove } = {}) {
boardIds = _.isString(boardIds) ? [boardIds] : boardIds;
let selectedBoards = this._selectedBoards.get();
boardIds.forEach(boardId => {
const index = selectedBoards.indexOf(boardId);
if (index > -1 && remove) {
selectedBoards = selectedBoards.filter(id => id !== boardId);
} else if (index === -1 && add) {
selectedBoards.push(boardId);
}
});
this._selectedBoards.set(selectedBoards);
},
isSelected(boardId) {
return this._selectedBoards.get().includes(boardId);
},
};

View file

@ -179,11 +179,16 @@ export class CardSearchPagedComponent extends BlazeComponent {
console.log('getResults - no sessionData or no cards array, trying direct card search'); console.log('getResults - no sessionData or no cards array, trying direct card search');
} }
// Fallback: try to get cards directly from the client-side collection // Fallback: try to get cards directly from the client-side collection
// Use a more efficient query with limit and sort
const selector = { const selector = {
type: 'cardType-card', type: 'cardType-card',
dueAt: { $exists: true, $nin: [null, ''] } dueAt: { $exists: true, $nin: [null, ''] }
}; };
const allCards = Cards.find(selector).fetch(); const options = {
sort: { dueAt: 1 }, // Sort by due date ascending (oldest first)
limit: 100 // Limit to 100 cards for performance
};
const allCards = Cards.find(selector, options).fetch();
if (process.env.DEBUG === 'true') { if (process.env.DEBUG === 'true') {
console.log('getResults - direct card search found:', allCards ? allCards.length : 0, 'cards'); console.log('getResults - direct card search found:', allCards ? allCards.length : 0, 'cards');
} }
@ -191,9 +196,6 @@ export class CardSearchPagedComponent extends BlazeComponent {
if (allCards && allCards.length > 0) { if (allCards && allCards.length > 0) {
allCards.forEach(card => { allCards.forEach(card => {
if (card && card._id) { if (card && card._id) {
if (process.env.DEBUG === 'true') {
console.log('getResults - direct card:', card._id, card.title);
}
cards.push(card); cards.push(card);
} }
}); });

View file

@ -1,32 +1,27 @@
import { ReactiveCache } from '/imports/reactiveCache'; import { ReactiveCache } from '/imports/reactiveCache';
import { TAPi18n } from '/imports/i18n'; import { TAPi18n } from '/imports/i18n';
import {
formatDateTime,
formatDate,
formatTime,
getISOWeek,
isValidDate,
isBefore,
isAfter,
isSame,
add,
subtract,
startOf,
endOf,
format,
parseDate,
now,
createDate,
fromNow,
calendar
} from '/imports/lib/dateUtils';
// Helper function to get time format for 24 hours // Helper to check if a date is valid
function adjustedTimeFormat() { function isValidDate(date) {
return 'HH:mm'; return date instanceof Date && !isNaN(date);
} }
// .replace(/HH/i, 'H'); // Format date as YYYY-MM-DD
function formatDate(date) {
if (!isValidDate(date)) return '';
const year = date.getFullYear();
const month = String(date.getMonth() + 1).padStart(2, '0');
const day = String(date.getDate()).padStart(2, '0');
return `${year}-${month}-${day}`;
}
// Format time as HH:mm
function formatTime(date) {
if (!isValidDate(date)) return '';
const hours = String(date.getHours()).padStart(2, '0');
const minutes = String(date.getMinutes()).padStart(2, '0');
return `${hours}:${minutes}`;
}
export class DatePicker extends BlazeComponent { export class DatePicker extends BlazeComponent {
template() { template() {
@ -76,10 +71,10 @@ export class DatePicker extends BlazeComponent {
return ''; return '';
} }
dateFormat() { dateFormat() {
return 'L'; return 'YYYY-MM-DD';
} }
timeFormat() { timeFormat() {
return 'LT'; return 'HH:mm';
} }
events() { events() {
@ -89,7 +84,8 @@ export class DatePicker extends BlazeComponent {
// Native HTML date input validation // Native HTML date input validation
const dateValue = this.find('#date').value; const dateValue = this.find('#date').value;
if (dateValue) { if (dateValue) {
const dateObj = new Date(dateValue); // HTML date input format is always YYYY-MM-DD
const dateObj = new Date(dateValue + 'T12:00:00');
if (isValidDate(dateObj)) { if (isValidDate(dateObj)) {
this.error.set(''); this.error.set('');
} else { } else {
@ -101,7 +97,8 @@ export class DatePicker extends BlazeComponent {
// Native HTML time input validation // Native HTML time input validation
const timeValue = this.find('#time').value; const timeValue = this.find('#time').value;
if (timeValue) { if (timeValue) {
const timeObj = new Date(`1970-01-01T${timeValue}`); // HTML time input format is always HH:mm
const timeObj = new Date(`1970-01-01T${timeValue}:00`);
if (isValidDate(timeObj)) { if (isValidDate(timeObj)) {
this.error.set(''); this.error.set('');
} else { } else {
@ -121,7 +118,9 @@ export class DatePicker extends BlazeComponent {
return; return;
} }
const newCompleteDate = new Date(`${dateValue}T${timeValue}`); // Combine date and time: HTML date input is YYYY-MM-DD, time input is HH:mm
const dateTimeString = `${dateValue}T${timeValue}:00`;
const newCompleteDate = new Date(dateTimeString);
if (!isValidDate(newCompleteDate)) { if (!isValidDate(newCompleteDate)) {
this.error.set('invalid'); this.error.set('invalid');

View file

@ -0,0 +1,94 @@
import { Meteor } from 'meteor/meteor';
/**
* Client-side interface for fixing duplicate lists
*/
export const fixDuplicateLists = {
/**
* Get a report of all boards with duplicate lists/swimlanes
*/
async getReport() {
try {
const result = await Meteor.callAsync('fixDuplicateLists.getReport');
return result;
} catch (error) {
console.error('Error getting duplicate lists report:', error);
throw error;
}
},
/**
* Fix duplicate lists for a specific board
*/
async fixBoard(boardId) {
try {
const result = await Meteor.callAsync('fixDuplicateLists.fixBoard', boardId);
console.log(`Fixed duplicate lists for board ${boardId}:`, result);
return result;
} catch (error) {
console.error(`Error fixing board ${boardId}:`, error);
throw error;
}
},
/**
* Fix duplicate lists for all boards
*/
async fixAllBoards() {
try {
console.log('Starting fix for all boards...');
const result = await Meteor.callAsync('fixDuplicateLists.fixAllBoards');
console.log('Fix completed:', result);
return result;
} catch (error) {
console.error('Error fixing all boards:', error);
throw error;
}
},
/**
* Interactive fix with user confirmation
*/
async interactiveFix() {
try {
// Get report first
console.log('Getting duplicate lists report...');
const report = await this.getReport();
if (report.boardsWithDuplicates === 0) {
console.log('No duplicate lists found!');
return { message: 'No duplicate lists found!' };
}
console.log(`Found ${report.boardsWithDuplicates} boards with duplicate lists:`);
report.report.forEach(board => {
console.log(`- Board "${board.boardTitle}" (${board.boardId}): ${board.duplicateSwimlanes} duplicate swimlanes, ${board.duplicateLists} duplicate lists`);
});
// Ask for confirmation
const confirmed = confirm(
`Found ${report.boardsWithDuplicates} boards with duplicate lists. ` +
`This will fix ${report.report.reduce((sum, board) => sum + board.duplicateSwimlanes + board.duplicateLists, 0)} duplicates. ` +
'Continue?'
);
if (!confirmed) {
return { message: 'Fix cancelled by user' };
}
// Perform the fix
const result = await this.fixAllBoards();
return result;
} catch (error) {
console.error('Error in interactive fix:', error);
throw error;
}
}
};
// Make it available globally for console access
if (typeof window !== 'undefined') {
window.fixDuplicateLists = fixDuplicateLists;
}

View file

@ -646,6 +646,23 @@ class MigrationManager {
} }
} }
/**
* Fix boards that are stuck in migration loop
*/
fixStuckBoards() {
try {
Meteor.call('boardMigration.fixStuckBoards', (error, result) => {
if (error) {
console.error('Failed to fix stuck boards:', error);
} else {
console.log('Fix stuck boards result:', result);
}
});
} catch (error) {
console.error('Error fixing stuck boards:', error);
}
}
/** /**
* Start migration process using cron system * Start migration process using cron system
*/ */

View file

@ -4,7 +4,7 @@ import DOMPurify from 'dompurify';
export function getSecureDOMPurifyConfig() { export function getSecureDOMPurifyConfig() {
return { return {
// Allow common markdown elements including anchor tags // Allow common markdown elements including anchor tags
ALLOWED_TAGS: ['a', 'p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'img', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'hr', 'div', 'span'], ALLOWED_TAGS: ['a', 'p', 'br', 'strong', 'em', 'u', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'ul', 'ol', 'li', 'blockquote', 'pre', 'code', 'img', 'table', 'thead', 'tbody', 'tr', 'th', 'td', 'hr', 'div', 'span', 's'],
// Allow safe attributes including href for anchor tags // Allow safe attributes including href for anchor tags
ALLOWED_ATTR: ['href', 'title', 'alt', 'src', 'width', 'height', 'target', 'rel'], ALLOWED_ATTR: ['href', 'title', 'alt', 'src', 'width', 'height', 'target', 'rel'],
// Allow safe protocols for links // Allow safe protocols for links
@ -44,7 +44,7 @@ export function getSecureDOMPurifyConfig() {
} }
return false; return false;
} }
// Additional check for base64 encoded SVG with script tags // Additional check for base64 encoded SVG with script tags
if (src.startsWith('data:image/svg+xml;base64,')) { if (src.startsWith('data:image/svg+xml;base64,')) {
try { try {

View file

@ -214,6 +214,15 @@ Utils = {
); );
return ret; return ret;
}, },
canMoveCard() {
const currentUser = ReactiveCache.getCurrentUser();
const ret = (
currentUser &&
currentUser.isBoardMember() &&
!currentUser.isCommentOnly()
);
return ret;
},
canModifyBoard() { canModifyBoard() {
const currentUser = ReactiveCache.getCurrentUser(); const currentUser = ReactiveCache.getCurrentUser();
const ret = ( const ret = (
@ -231,9 +240,21 @@ Utils = {
window.location.reload(); window.location.reload();
}, },
setBoardView(view) { setBoardView(view) {
currentUser = ReactiveCache.getCurrentUser(); const currentUser = ReactiveCache.getCurrentUser();
if (currentUser) { if (currentUser) {
ReactiveCache.getCurrentUser().setBoardView(view); // Update localStorage first
window.localStorage.setItem('boardView', view);
// Update user profile via Meteor method
Meteor.call('setBoardView', view, (error) => {
if (error) {
console.error('[setBoardView] Update failed:', error);
} else {
// Reload to apply the view change
Utils.reload();
}
});
} else if (view === 'board-view-swimlanes') { } else if (view === 'board-view-swimlanes') {
window.localStorage.setItem('boardView', 'board-view-swimlanes'); //true window.localStorage.setItem('boardView', 'board-view-swimlanes'); //true
Utils.reload(); Utils.reload();

View file

@ -0,0 +1,103 @@
# Building the Wekan snap without timeouts
This guide focuses on macOS hosts (Multipass VM) and common timeout fixes. It also applies to Linux hosts with LXD.
## Quick options
- Fastest: use Canonical builders (no local VM)
```zsh
# One-time: login to the store (required for remote-build)
snapcraft login
# Build for amd64 on Canonical builders
snapcraft remote-build --build-for=amd64
```
- Local VM (macOS + Multipass): increase resources and build verbosely
```zsh
# Give the builder more CPU/RAM/disk to avoid sluggish downloads
export SNAPCRAFT_BUILD_ENVIRONMENT=hosted-multipass
export SNAPCRAFT_BUILD_ENVIRONMENT_CPU=4
export SNAPCRAFT_BUILD_ENVIRONMENT_MEMORY=8G
export SNAPCRAFT_BUILD_ENVIRONMENT_DISK=40G
# Clean previous state and build
snapcraft clean
snapcraft --verbose --debug
```
## What changed to reduce timeouts
- Downloads in `wekan` part now retry with exponential backoff.
- `caddy` part now attempts APT with retries and falls back to a static binary from the official GitHub release if APT is slow or unreachable.
These changes make the build resilient to transient network issues and slow mirrors.
## Diagnosing where it stalls
- Run a single step for a part to reproduce:
```zsh
snapcraft pull wekan -v
snapcraft build wekan -v
```
- Drop into the build environment when it fails:
```zsh
snapcraft --debug
# Then run the failing commands manually
```
## Tips for macOS + Multipass
- Check networking:
```zsh
multipass list
multipass exec snapcraft-*-wekan -- ping -c2 github.com
```
- If the instance looks wedged, recreate it:
```zsh
snapcraft clean --use-lxd || true # harmless on macOS
snapcraft clean --step pull
multipass delete --purge $(multipass list | awk '/snapcraft-/{print $1}')
snapcraft --verbose
```
## Linux hosts (optional)
On Linux, using LXD is often faster and more reliable than Multipass:
```bash
sudo snap install lxd --channel=5.21/stable
newgrp lxd
snapcraft --use-lxd -v
```
## Common environment knobs
- Proxy/mirror environments inside the build VM if needed:
```zsh
export http_proxy=http://proxy.example:3128
export https_proxy=$http_proxy
export SNAPCRAFT_PROXY_HTTP=$http_proxy
export SNAPCRAFT_PROXY_HTTPS=$https_proxy
```
- Speed up apt by pinning retries (already set in the recipe) or switching to a closer mirror by customizing sources in an override if needed.
## Cleaning up caches
If repeated attempts keep hitting corrupt downloads, clean Snapcraft caches:
```zsh
snapcraft clean --destructive-mode || true
rm -rf ~/.cache/snapcraft/*
```
## Reporting
If you still hit timeouts, capture and share:
- The exact step (pull/build/stage/prime) and part name
- Output of `snapcraft --verbose --debug`
- Host OS and Snapcraft version: `snapcraft --version`
- Multipass resources: `multipass list`

View file

@ -10,7 +10,7 @@ This is without container (without Docker or Snap).
Right click and download files 1-4: Right click and download files 1-4:
1. [wekan-8.09-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v8.09/wekan-8.09-amd64-windows.zip) 1. [wekan-8.17-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v8.17/wekan-8.17-amd64-windows.zip)
2. [node.exe](https://nodejs.org/dist/latest-v14.x/win-x64/node.exe) 2. [node.exe](https://nodejs.org/dist/latest-v14.x/win-x64/node.exe)
@ -22,7 +22,7 @@ Right click and download files 1-4:
6. Double click `mongodb-windows-x86_64-7.0.25-signed.msi` . In installer, uncheck downloading MongoDB compass. 6. Double click `mongodb-windows-x86_64-7.0.25-signed.msi` . In installer, uncheck downloading MongoDB compass.
7. Unzip `wekan-8.09-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files: 7. Unzip `wekan-8.17-amd64-windows.zip` , inside it is directory `bundle`, to it copy other files:
``` ```
bundle (directory) bundle (directory)

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "تعليق محذوف %s", "activity-deleteComment": "تعليق محذوف %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "نماذج",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "إضافة مرفق", "add-attachment": "إضافة مرفق",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "إنشاء", "create": "إنشاء",
"createBoardPopup-title": "إنشاء لوحة", "createBoardPopup-title": "إنشاء لوحة",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "استيراد لوحة", "chooseBoardSourcePopup-title": "استيراد لوحة",
"createLabelPopup-title": "إنشاء علامة", "createLabelPopup-title": "إنشاء علامة",
"createCustomField": "انشاء حقل", "createCustomField": "انشاء حقل",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "تاريخ", "date": "تاريخ",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "صورة شخصية افتراضية", "default-avatar": "صورة شخصية افتراضية",
"delete": "حذف", "delete": "حذف",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "تصحيح الإشعار", "editNotificationPopup-title": "تصحيح الإشعار",
"editProfilePopup-title": "تعديل الملف الشخصي", "editProfilePopup-title": "تعديل الملف الشخصي",
"email": "البريد الإلكتروني", "email": "البريد الإلكتروني",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "انا", "dueCardsViewChange-choice-me": "انا",
"dueCardsViewChange-choice-all": "كل المستخدمين", "dueCardsViewChange-choice-all": "كل المستخدمين",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "تفاصيل",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "изтрит коментар %s", "activity-deleteComment": "изтрит коментар %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Шаблони",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Добави прикачен файл", "add-attachment": "Добави прикачен файл",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Създай", "create": "Създай",
"createBoardPopup-title": "Създай Табло", "createBoardPopup-title": "Създай Табло",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Импортирай Табло", "chooseBoardSourcePopup-title": "Импортирай Табло",
"createLabelPopup-title": "Създай Табло", "createLabelPopup-title": "Създай Табло",
"createCustomField": "Създай Поле", "createCustomField": "Създай Поле",
@ -357,9 +370,9 @@
"custom-fields": "Собствени полета", "custom-fields": "Собствени полета",
"date": "Дата", "date": "Дата",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Отказ", "decline": "Отказ",
"default-avatar": "Основен аватар", "default-avatar": "Основен аватар",
"delete": "Изтрий", "delete": "Изтрий",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Промени известията", "editNotificationPopup-title": "Промени известията",
"editProfilePopup-title": "Промяна на профила", "editProfilePopup-title": "Промяна на профила",
"email": "Имейл", "email": "Имейл",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ваш профил беше създаден на __siteName__", "email-enrollAccount-subject": "Ваш профил беше създаден на __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Неуспешно изпращане на имейла", "email-fail": "Неуспешно изпращане на имейла",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Всички списъци, карти, имена и действия ще бъдат изтрити и няма да можете да възстановите съдържанието на дъската. Няма връщане назад.", "delete-board-confirm-popup": "Всички списъци, карти, имена и действия ще бъдат изтрити и няма да можете да възстановите съдържанието на дъската. Няма връщане назад.",
"boardDeletePopup-title": "Изтриване на Таблото?", "boardDeletePopup-title": "Изтриване на Таблото?",
"delete-board": "Изтрий таблото", "delete-board": "Изтрий таблото",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Подзадачи за табло __board__", "default-subtasks-board": "Подзадачи за табло __board__",
"default": "по подразбиране", "default": "по подразбиране",
"defaultdefault": "по подразбиране", "defaultdefault": "по подразбиране",
@ -761,7 +777,7 @@
"subtask-settings": "Настройки на Подзадачите", "subtask-settings": "Настройки на Подзадачите",
"card-settings": "Настройки на Карта", "card-settings": "Настройки на Карта",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Настройки за Подзадачите за това Табло", "boardSubtaskSettingsPopup-title": "Настройки на Подзадачите",
"boardCardSettingsPopup-title": "Настройки на Карта", "boardCardSettingsPopup-title": "Настройки на Карта",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Вложете под-задачи към тази дъска:", "deposit-subtasks-board": "Вложете под-задачи към тази дъска:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Състояние",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Завършено", "completed": "Завършено",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Krouiñ", "create": "Krouiñ",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Diverkañ", "delete": "Diverkañ",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "Ha esborrar el comentari %s", "activity-deleteComment": "Ha esborrar el comentari %s",
"activity-receivedDate": "editat la data de recepció a %s de %s", "activity-receivedDate": "editat la data de recepció a %s de %s",
"activity-startDate": "data d'inici editada a %s de %s", "activity-startDate": "data d'inici editada a %s de %s",
"allboards.starred": "Starred",
"allboards.templates": "Plantilles",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "data de venciment editada a %s de %s", "activity-dueDate": "data de venciment editada a %s de %s",
"activity-endDate": "data de finalització editada a %s de %s", "activity-endDate": "data de finalització editada a %s de %s",
"add-attachment": "Afegeix adjunt", "add-attachment": "Afegeix adjunt",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Títol de la primera fitxa\", \"description\":\"Descripció de la primera fitxa\"}, {\"title\":\"Títol de la segona fitxa\",\"description\":\"Descripció de la segona fitxa \"},{\"title\":\"Títol de l'última fitxa\",\"description\":\"Descripció de l'última fitxa\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Títol de la primera fitxa\", \"description\":\"Descripció de la primera fitxa\"}, {\"title\":\"Títol de la segona fitxa\",\"description\":\"Descripció de la segona fitxa \"},{\"title\":\"Títol de l'última fitxa\",\"description\":\"Descripció de l'última fitxa\"} ]",
"create": "Crea", "create": "Crea",
"createBoardPopup-title": "Crea tauler", "createBoardPopup-title": "Crea tauler",
"createTemplateContainerPopup-title": "Afegeix un Contenidor de plantilles",
"chooseBoardSourcePopup-title": "Importa tauler", "chooseBoardSourcePopup-title": "Importa tauler",
"createLabelPopup-title": "Crea etiqueta", "createLabelPopup-title": "Crea etiqueta",
"createCustomField": "Crear campament", "createCustomField": "Crear campament",
@ -357,9 +370,9 @@
"custom-fields": "Camps Personalitzats", "custom-fields": "Camps Personalitzats",
"date": "Dades", "date": "Dades",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Declina", "decline": "Declina",
"default-avatar": "Avatar per defecte", "default-avatar": "Avatar per defecte",
"delete": "Esborra", "delete": "Esborra",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edita la notificació", "editNotificationPopup-title": "Edita la notificació",
"editProfilePopup-title": "Edita el teu Perfil", "editProfilePopup-title": "Edita el teu Perfil",
"email": "Correu electrònic", "email": "Correu electrònic",
"email-address": "Email Address",
"email-enrollAccount-subject": "Un compte creat per a tu a __siteName__", "email-enrollAccount-subject": "Un compte creat per a tu a __siteName__",
"email-enrollAccount-text": "Hola __user__,\n\nPer començar a utilitzar el servei, segueix l'enllaç següent.\n\n__url__\n\nGràcies.", "email-enrollAccount-text": "Hola __user__,\n\nPer començar a utilitzar el servei, segueix l'enllaç següent.\n\n__url__\n\nGràcies.",
"email-fail": "Error enviant el correu", "email-fail": "Error enviant el correu",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Se suprimiran totes les llistes, fitxes, etiquetes i activitats i no podreu recuperar el contingut del tauler. No hi ha cap desfer.", "delete-board-confirm-popup": "Se suprimiran totes les llistes, fitxes, etiquetes i activitats i no podreu recuperar el contingut del tauler. No hi ha cap desfer.",
"boardDeletePopup-title": "Vols suprimir el tauler?", "boardDeletePopup-title": "Vols suprimir el tauler?",
"delete-board": "Suprimeix el tauler", "delete-board": "Suprimeix el tauler",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasques per al tauler __board__", "default-subtasks-board": "Subtasques per al tauler __board__",
"default": "Per defecte", "default": "Per defecte",
"defaultdefault": "Per defecte", "defaultdefault": "Per defecte",
@ -761,7 +777,7 @@
"subtask-settings": "Configuració de subtasques", "subtask-settings": "Configuració de subtasques",
"card-settings": "Configuració de fitxa", "card-settings": "Configuració de fitxa",
"minicard-settings": "Configuració de la minifitxa", "minicard-settings": "Configuració de la minifitxa",
"boardSubtaskSettingsPopup-title": "Configuració de les subtasques del tauler", "boardSubtaskSettingsPopup-title": "Configuració de subtasques",
"boardCardSettingsPopup-title": "Configuració de fitxa", "boardCardSettingsPopup-title": "Configuració de fitxa",
"boardMinicardSettingsPopup-title": "Configuració de la minifitxa", "boardMinicardSettingsPopup-title": "Configuració de la minifitxa",
"deposit-subtasks-board": "Diposita subtasques a aquest tauler:", "deposit-subtasks-board": "Diposita subtasques a aquest tauler:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "jo", "dueCardsViewChange-choice-me": "jo",
"dueCardsViewChange-choice-all": "Tots els usuaris", "dueCardsViewChange-choice-all": "Tots els usuaris",
"dueCardsViewChange-choice-all-description": "Mostra totes les fitxes incompletes amb una *data de venciment* de taulers per als quals l'usuari té permís.", "dueCardsViewChange-choice-all-description": "Mostra totes les fitxes incompletes amb una *data de venciment* de taulers per als quals l'usuari té permís.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Fitxes Trencades", "broken-cards": "Fitxes Trencades",
"board-title-not-found": "No s'ha trobat el tauler '%s'.", "board-title-not-found": "No s'ha trobat el tauler '%s'.",
"swimlane-title-not-found": "No s'ha trobat el carril '%s'.", "swimlane-title-not-found": "No s'ha trobat el carril '%s'.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Estat",
"migration-progress-details": "Detalls",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completat", "completed": "Completat",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "smazat komentář %s", "activity-deleteComment": "smazat komentář %s",
"activity-receivedDate": "editoval(a) datum přijetí na %s z %s", "activity-receivedDate": "editoval(a) datum přijetí na %s z %s",
"activity-startDate": "editoval(a) datum zahájení na %s z %s", "activity-startDate": "editoval(a) datum zahájení na %s z %s",
"allboards.starred": "Starred",
"allboards.templates": "Šablony",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "editoval(a) termín dokončení na %s z %s", "activity-dueDate": "editoval(a) termín dokončení na %s z %s",
"activity-endDate": "editoval(a) datum ukončení na %s z %s", "activity-endDate": "editoval(a) datum ukončení na %s z %s",
"add-attachment": "Přidat přílohu", "add-attachment": "Přidat přílohu",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Nadpis první karty\", \"description\":\"Popis první karty\"}, {\"title\":\"Nadpis druhé karty\",\"description\":\"Popis druhé karty\"},{\"title\":\"Nadpis poslední kary\",\"description\":\"Popis poslední karty\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Nadpis první karty\", \"description\":\"Popis první karty\"}, {\"title\":\"Nadpis druhé karty\",\"description\":\"Popis druhé karty\"},{\"title\":\"Nadpis poslední kary\",\"description\":\"Popis poslední karty\"} ]",
"create": "Vytvořit", "create": "Vytvořit",
"createBoardPopup-title": "Vytvořit tablo", "createBoardPopup-title": "Vytvořit tablo",
"createTemplateContainerPopup-title": "Přidat kontejner šablony",
"chooseBoardSourcePopup-title": "Importovat tablo", "chooseBoardSourcePopup-title": "Importovat tablo",
"createLabelPopup-title": "Vytvořit štítek", "createLabelPopup-title": "Vytvořit štítek",
"createCustomField": "Vytvořit pole", "createCustomField": "Vytvořit pole",
@ -357,9 +370,9 @@
"custom-fields": "Vlastní pole", "custom-fields": "Vlastní pole",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Zamítnout", "decline": "Zamítnout",
"default-avatar": "Výchozí avatar", "default-avatar": "Výchozí avatar",
"delete": "Smazat", "delete": "Smazat",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Změnit notifikace", "editNotificationPopup-title": "Změnit notifikace",
"editProfilePopup-title": "Upravit profil", "editProfilePopup-title": "Upravit profil",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "Byl vytvořen účet na __siteName__", "email-enrollAccount-subject": "Byl vytvořen účet na __siteName__",
"email-enrollAccount-text": "Ahoj __user__,\n\nMůžeš začít používat službu kliknutím na odkaz níže.\n\n__url__\n\nDěkujeme.", "email-enrollAccount-text": "Ahoj __user__,\n\nMůžeš začít používat službu kliknutím na odkaz níže.\n\n__url__\n\nDěkujeme.",
"email-fail": "Odeslání emailu selhalo", "email-fail": "Odeslání emailu selhalo",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Všechny sloupce, štítky a aktivity budou smazány a obsah tabla nebude možné obnovit. Toto nelze vrátit zpět.", "delete-board-confirm-popup": "Všechny sloupce, štítky a aktivity budou smazány a obsah tabla nebude možné obnovit. Toto nelze vrátit zpět.",
"boardDeletePopup-title": "Smazat tablo?", "boardDeletePopup-title": "Smazat tablo?",
"delete-board": "Smazat tablo", "delete-board": "Smazat tablo",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Podúkoly pro tablo __board__", "default-subtasks-board": "Podúkoly pro tablo __board__",
"default": "Výchozí", "default": "Výchozí",
"defaultdefault": "Výchozí", "defaultdefault": "Výchozí",
@ -761,7 +777,7 @@
"subtask-settings": "Nastavení podúkolů", "subtask-settings": "Nastavení podúkolů",
"card-settings": "Nastavení karet", "card-settings": "Nastavení karet",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů tabla", "boardSubtaskSettingsPopup-title": "Nastavení podúkolů",
"boardCardSettingsPopup-title": "Nastavení karet", "boardCardSettingsPopup-title": "Nastavení karet",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Vložit podúkoly do tohoto tabla", "deposit-subtasks-board": "Vložit podúkoly do tohoto tabla",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Moje", "dueCardsViewChange-choice-me": "Moje",
"dueCardsViewChange-choice-all": "Všechny", "dueCardsViewChange-choice-all": "Všechny",
"dueCardsViewChange-choice-all-description": "Zobrazí všechny nedokončené karty s *Termínem dokončení* z každého tabla, ke kterému má uživatel oprávnění.", "dueCardsViewChange-choice-all-description": "Zobrazí všechny nedokončené karty s *Termínem dokončení* z každého tabla, ke kterému má uživatel oprávnění.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Rozbité karty", "broken-cards": "Rozbité karty",
"board-title-not-found": "Tablo '%s' nenalezeno.", "board-title-not-found": "Tablo '%s' nenalezeno.",
"swimlane-title-not-found": "Swimlane '%s' nenalezena.", "swimlane-title-not-found": "Swimlane '%s' nenalezena.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Stav",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Dokončeno", "completed": "Dokončeno",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "smazat komentář %s", "activity-deleteComment": "smazat komentář %s",
"activity-receivedDate": "editoval(a) datum přijetí na %s z %s", "activity-receivedDate": "editoval(a) datum přijetí na %s z %s",
"activity-startDate": "editoval(a) datum zahájení na %s z %s", "activity-startDate": "editoval(a) datum zahájení na %s z %s",
"allboards.starred": "Starred",
"allboards.templates": "Šablony",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "editoval(a) termín dokončení na %s z %s", "activity-dueDate": "editoval(a) termín dokončení na %s z %s",
"activity-endDate": "editoval(a) datum ukončení na %s z %s", "activity-endDate": "editoval(a) datum ukončení na %s z %s",
"add-attachment": "Přidat přílohu", "add-attachment": "Přidat přílohu",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Nadpis první karty\", \"description\":\"Popis první karty\"}, {\"title\":\"Nadpis druhé karty\",\"description\":\"Popis druhé karty\"},{\"title\":\"Nadpis poslední kary\",\"description\":\"Popis poslední karty\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Nadpis první karty\", \"description\":\"Popis první karty\"}, {\"title\":\"Nadpis druhé karty\",\"description\":\"Popis druhé karty\"},{\"title\":\"Nadpis poslední kary\",\"description\":\"Popis poslední karty\"} ]",
"create": "Vytvořit", "create": "Vytvořit",
"createBoardPopup-title": "Vytvořit tablo", "createBoardPopup-title": "Vytvořit tablo",
"createTemplateContainerPopup-title": "Přidat kontejner šablony",
"chooseBoardSourcePopup-title": "Importovat tablo", "chooseBoardSourcePopup-title": "Importovat tablo",
"createLabelPopup-title": "Vytvořit štítek", "createLabelPopup-title": "Vytvořit štítek",
"createCustomField": "Vytvořit pole", "createCustomField": "Vytvořit pole",
@ -357,9 +370,9 @@
"custom-fields": "Vlastní pole", "custom-fields": "Vlastní pole",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Zamítnout", "decline": "Zamítnout",
"default-avatar": "Výchozí avatar", "default-avatar": "Výchozí avatar",
"delete": "Smazat", "delete": "Smazat",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Změnit notifikace", "editNotificationPopup-title": "Změnit notifikace",
"editProfilePopup-title": "Upravit profil", "editProfilePopup-title": "Upravit profil",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "Byl vytvořen účet na __siteName__", "email-enrollAccount-subject": "Byl vytvořen účet na __siteName__",
"email-enrollAccount-text": "Ahoj __user__,\n\nMůžeš začít používat službu kliknutím na odkaz níže.\n\n__url__\n\nDěkujeme.", "email-enrollAccount-text": "Ahoj __user__,\n\nMůžeš začít používat službu kliknutím na odkaz níže.\n\n__url__\n\nDěkujeme.",
"email-fail": "Odeslání emailu selhalo", "email-fail": "Odeslání emailu selhalo",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Všechny sloupce, štítky a aktivity budou smazány a obsah tabla nebude možné obnovit. Toto nelze vrátit zpět.", "delete-board-confirm-popup": "Všechny sloupce, štítky a aktivity budou smazány a obsah tabla nebude možné obnovit. Toto nelze vrátit zpět.",
"boardDeletePopup-title": "Smazat tablo?", "boardDeletePopup-title": "Smazat tablo?",
"delete-board": "Smazat tablo", "delete-board": "Smazat tablo",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Podúkoly pro tablo __board__", "default-subtasks-board": "Podúkoly pro tablo __board__",
"default": "Výchozí", "default": "Výchozí",
"defaultdefault": "Výchozí", "defaultdefault": "Výchozí",
@ -761,7 +777,7 @@
"subtask-settings": "Nastavení podúkolů", "subtask-settings": "Nastavení podúkolů",
"card-settings": "Nastavení karet", "card-settings": "Nastavení karet",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů tabla", "boardSubtaskSettingsPopup-title": "Nastavení podúkolů",
"boardCardSettingsPopup-title": "Nastavení karet", "boardCardSettingsPopup-title": "Nastavení karet",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Vložit podúkoly do tohoto tabla", "deposit-subtasks-board": "Vložit podúkoly do tohoto tabla",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Moje", "dueCardsViewChange-choice-me": "Moje",
"dueCardsViewChange-choice-all": "Všechny", "dueCardsViewChange-choice-all": "Všechny",
"dueCardsViewChange-choice-all-description": "Zobrazí všechny nedokončené karty s *Termínem dokončení* z každého tabla, ke kterému má uživatel oprávnění.", "dueCardsViewChange-choice-all-description": "Zobrazí všechny nedokončené karty s *Termínem dokončení* z každého tabla, ke kterému má uživatel oprávnění.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Rozbité karty", "broken-cards": "Rozbité karty",
"board-title-not-found": "Tablo '%s' nenalezeno.", "board-title-not-found": "Tablo '%s' nenalezeno.",
"swimlane-title-not-found": "Swimlane '%s' nenalezena.", "swimlane-title-not-found": "Swimlane '%s' nenalezena.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Stav",
"migration-progress-details": "Podrobnosti",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Dokončeno", "completed": "Dokončeno",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "slettede kommentar %s", "activity-deleteComment": "slettede kommentar %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Skabeloner",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Tilføj vedhæftning", "add-attachment": "Tilføj vedhæftning",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Opret", "create": "Opret",
"createBoardPopup-title": "Opret tavle", "createBoardPopup-title": "Opret tavle",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Importér tavle", "chooseBoardSourcePopup-title": "Importér tavle",
"createLabelPopup-title": "Opret etikette", "createLabelPopup-title": "Opret etikette",
"createCustomField": "Opret felt", "createCustomField": "Opret felt",
@ -357,9 +370,9 @@
"custom-fields": "Brugerdefinerede felter", "custom-fields": "Brugerdefinerede felter",
"date": "Dato", "date": "Dato",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Afslå", "decline": "Afslå",
"default-avatar": "Standard-avatar", "default-avatar": "Standard-avatar",
"delete": "Slet", "delete": "Slet",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Redigér notifikation", "editNotificationPopup-title": "Redigér notifikation",
"editProfilePopup-title": "Redigér profil", "editProfilePopup-title": "Redigér profil",
"email": "E-mail", "email": "E-mail",
"email-address": "Email Address",
"email-enrollAccount-subject": "Der er oprettet konto til dig på __siteName__", "email-enrollAccount-subject": "Der er oprettet konto til dig på __siteName__",
"email-enrollAccount-text": "Hej __user__,\n\nFor at begynde at benytte tjenesten, så klik linket nedenfor.\n\n__url__\n\nTak.", "email-enrollAccount-text": "Hej __user__,\n\nFor at begynde at benytte tjenesten, så klik linket nedenfor.\n\n__url__\n\nTak.",
"email-fail": "Afsendelse af e-mail mislykkedes", "email-fail": "Afsendelse af e-mail mislykkedes",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Alle lister, kort, etiketter og aktiviteter vil blive slettet og du får ikke mulighed for at genskabe tavlens indhold. Dette kan ikke fortrydes.", "delete-board-confirm-popup": "Alle lister, kort, etiketter og aktiviteter vil blive slettet og du får ikke mulighed for at genskabe tavlens indhold. Dette kan ikke fortrydes.",
"boardDeletePopup-title": "Slet tavle?", "boardDeletePopup-title": "Slet tavle?",
"delete-board": "Slet tavle", "delete-board": "Slet tavle",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Delopgaver for tavlen __board__", "default-subtasks-board": "Delopgaver for tavlen __board__",
"default": "Standard", "default": "Standard",
"defaultdefault": "Standard", "defaultdefault": "Standard",
@ -761,7 +777,7 @@
"subtask-settings": "Indstillinger for delopgaver", "subtask-settings": "Indstillinger for delopgaver",
"card-settings": "Indstillinger for kort", "card-settings": "Indstillinger for kort",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Indstillinger for delopgaver i tavle", "boardSubtaskSettingsPopup-title": "Indstillinger for delopgaver",
"boardCardSettingsPopup-title": "Indstillinger for kort", "boardCardSettingsPopup-title": "Indstillinger for kort",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Indsæt delopgaver på denne tavle:", "deposit-subtasks-board": "Indsæt delopgaver på denne tavle:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Fuldført", "completed": "Fuldført",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "löschte Kommentar %s", "activity-deleteComment": "löschte Kommentar %s",
"activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s", "activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s",
"activity-startDate": "hat Startdatum zu %s geändert auf %s", "activity-startDate": "hat Startdatum zu %s geändert auf %s",
"allboards.starred": "Starred",
"allboards.templates": "Vorlagen",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s", "activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s",
"activity-endDate": "hat Enddatum zu %s geändert auf %s", "activity-endDate": "hat Enddatum zu %s geändert auf %s",
"add-attachment": "Datei anhängen", "add-attachment": "Datei anhängen",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]",
"create": "Erstellen", "create": "Erstellen",
"createBoardPopup-title": "Board erstellen", "createBoardPopup-title": "Board erstellen",
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
"chooseBoardSourcePopup-title": "Board importieren", "chooseBoardSourcePopup-title": "Board importieren",
"createLabelPopup-title": "Label erstellen", "createLabelPopup-title": "Label erstellen",
"createCustomField": "Feld erstellen", "createCustomField": "Feld erstellen",
@ -357,9 +370,9 @@
"custom-fields": "Benutzerdefinierte Felder", "custom-fields": "Benutzerdefinierte Felder",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Ablehnen", "decline": "Ablehnen",
"default-avatar": "Standard Profilbild", "default-avatar": "Standard Profilbild",
"delete": "Löschen", "delete": "Löschen",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Benachrichtigung ändern", "editNotificationPopup-title": "Benachrichtigung ändern",
"editProfilePopup-title": "Profil ändern", "editProfilePopup-title": "Profil ändern",
"email": "E-Mail", "email": "E-Mail",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt", "email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt",
"email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.", "email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.",
"email-fail": "Senden der E-Mail fehlgeschlagen", "email-fail": "Senden der E-Mail fehlgeschlagen",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.", "delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.",
"boardDeletePopup-title": "Board löschen?", "boardDeletePopup-title": "Board löschen?",
"delete-board": "Board löschen", "delete-board": "Board löschen",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Teilaufgabe für __board__ Board", "default-subtasks-board": "Teilaufgabe für __board__ Board",
"default": "Standard", "default": "Standard",
"defaultdefault": "Standard", "defaultdefault": "Standard",
@ -761,7 +777,7 @@
"subtask-settings": "Einstellungen für Teilaufgaben", "subtask-settings": "Einstellungen für Teilaufgaben",
"card-settings": "Karten-Einstellungen", "card-settings": "Karten-Einstellungen",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben", "boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
"boardCardSettingsPopup-title": "Karten-Einstellungen", "boardCardSettingsPopup-title": "Karten-Einstellungen",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:", "deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Ich", "dueCardsViewChange-choice-me": "Ich",
"dueCardsViewChange-choice-all": "alle Benutzer", "dueCardsViewChange-choice-all": "alle Benutzer",
"dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.", "dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Fehlerhafte Karten", "broken-cards": "Fehlerhafte Karten",
"board-title-not-found": "Board „%s“ nicht gefunden.", "board-title-not-found": "Board „%s“ nicht gefunden.",
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.", "swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "abgeschlossen", "completed": "abgeschlossen",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "löschte Kommentar %s", "activity-deleteComment": "löschte Kommentar %s",
"activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s", "activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s",
"activity-startDate": "hat Startdatum zu %s geändert auf %s", "activity-startDate": "hat Startdatum zu %s geändert auf %s",
"allboards.starred": "Starred",
"allboards.templates": "Vorlagen",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s", "activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s",
"activity-endDate": "hat Enddatum zu %s geändert auf %s", "activity-endDate": "hat Enddatum zu %s geändert auf %s",
"add-attachment": "Datei anhängen", "add-attachment": "Datei anhängen",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]",
"create": "Erstellen", "create": "Erstellen",
"createBoardPopup-title": "Board erstellen", "createBoardPopup-title": "Board erstellen",
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
"chooseBoardSourcePopup-title": "Board importieren", "chooseBoardSourcePopup-title": "Board importieren",
"createLabelPopup-title": "Label erstellen", "createLabelPopup-title": "Label erstellen",
"createCustomField": "Feld erstellen", "createCustomField": "Feld erstellen",
@ -357,9 +370,9 @@
"custom-fields": "Benutzerdefinierte Felder", "custom-fields": "Benutzerdefinierte Felder",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Ablehnen", "decline": "Ablehnen",
"default-avatar": "Standard Profilbild", "default-avatar": "Standard Profilbild",
"delete": "Löschen", "delete": "Löschen",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Benachrichtigung ändern", "editNotificationPopup-title": "Benachrichtigung ändern",
"editProfilePopup-title": "Profil ändern", "editProfilePopup-title": "Profil ändern",
"email": "E-Mail", "email": "E-Mail",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt", "email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt",
"email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.", "email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.",
"email-fail": "Senden der E-Mail fehlgeschlagen", "email-fail": "Senden der E-Mail fehlgeschlagen",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.", "delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.",
"boardDeletePopup-title": "Board löschen?", "boardDeletePopup-title": "Board löschen?",
"delete-board": "Board löschen", "delete-board": "Board löschen",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Teilaufgabe für __board__ Board", "default-subtasks-board": "Teilaufgabe für __board__ Board",
"default": "Standard", "default": "Standard",
"defaultdefault": "Standard", "defaultdefault": "Standard",
@ -761,7 +777,7 @@
"subtask-settings": "Einstellungen für Teilaufgaben", "subtask-settings": "Einstellungen für Teilaufgaben",
"card-settings": "Karten-Einstellungen", "card-settings": "Karten-Einstellungen",
"minicard-settings": "Einstellungen für Minikarte", "minicard-settings": "Einstellungen für Minikarte",
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben", "boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
"boardCardSettingsPopup-title": "Karten-Einstellungen", "boardCardSettingsPopup-title": "Karten-Einstellungen",
"boardMinicardSettingsPopup-title": "Einstellungen für Minikarte", "boardMinicardSettingsPopup-title": "Einstellungen für Minikarte",
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:", "deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Ich", "dueCardsViewChange-choice-me": "Ich",
"dueCardsViewChange-choice-all": "alle Benutzer", "dueCardsViewChange-choice-all": "alle Benutzer",
"dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.", "dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Fehlerhafte Karten", "broken-cards": "Fehlerhafte Karten",
"board-title-not-found": "Board „%s“ nicht gefunden.", "board-title-not-found": "Board „%s“ nicht gefunden.",
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.", "swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "abgeschlossen", "completed": "abgeschlossen",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "löschte Kommentar %s", "activity-deleteComment": "löschte Kommentar %s",
"activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s", "activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s",
"activity-startDate": "hat Startdatum zu %s geändert auf %s", "activity-startDate": "hat Startdatum zu %s geändert auf %s",
"allboards.starred": "Starred",
"allboards.templates": "Vorlagen",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s", "activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s",
"activity-endDate": "hat Enddatum zu %s geändert auf %s", "activity-endDate": "hat Enddatum zu %s geändert auf %s",
"add-attachment": "Datei anhängen", "add-attachment": "Datei anhängen",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]",
"create": "Erstellen", "create": "Erstellen",
"createBoardPopup-title": "Board erstellen", "createBoardPopup-title": "Board erstellen",
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
"chooseBoardSourcePopup-title": "Board importieren", "chooseBoardSourcePopup-title": "Board importieren",
"createLabelPopup-title": "Label erstellen", "createLabelPopup-title": "Label erstellen",
"createCustomField": "Feld erstellen", "createCustomField": "Feld erstellen",
@ -357,9 +370,9 @@
"custom-fields": "Benutzerdefinierte Felder", "custom-fields": "Benutzerdefinierte Felder",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Ablehnen", "decline": "Ablehnen",
"default-avatar": "Standard Profilbild", "default-avatar": "Standard Profilbild",
"delete": "Löschen", "delete": "Löschen",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Benachrichtigung ändern", "editNotificationPopup-title": "Benachrichtigung ändern",
"editProfilePopup-title": "Profil ändern", "editProfilePopup-title": "Profil ändern",
"email": "E-Mail", "email": "E-Mail",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt", "email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt",
"email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.", "email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.",
"email-fail": "Senden der E-Mail fehlgeschlagen", "email-fail": "Senden der E-Mail fehlgeschlagen",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.", "delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.",
"boardDeletePopup-title": "Board löschen?", "boardDeletePopup-title": "Board löschen?",
"delete-board": "Board löschen", "delete-board": "Board löschen",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Teilaufgabe für __board__ Board", "default-subtasks-board": "Teilaufgabe für __board__ Board",
"default": "Standard", "default": "Standard",
"defaultdefault": "Standard", "defaultdefault": "Standard",
@ -761,7 +777,7 @@
"subtask-settings": "Einstellungen für Teilaufgaben", "subtask-settings": "Einstellungen für Teilaufgaben",
"card-settings": "Karten-Einstellungen", "card-settings": "Karten-Einstellungen",
"minicard-settings": "Minikarte-Einstellungen", "minicard-settings": "Minikarte-Einstellungen",
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben", "boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
"boardCardSettingsPopup-title": "Karten-Einstellungen", "boardCardSettingsPopup-title": "Karten-Einstellungen",
"boardMinicardSettingsPopup-title": "Minikarte-Einstellungen", "boardMinicardSettingsPopup-title": "Minikarte-Einstellungen",
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:", "deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Ich", "dueCardsViewChange-choice-me": "Ich",
"dueCardsViewChange-choice-all": "alle Benutzer", "dueCardsViewChange-choice-all": "alle Benutzer",
"dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.", "dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Fehlerhafte Karten", "broken-cards": "Fehlerhafte Karten",
"board-title-not-found": "Board „%s“ nicht gefunden.", "board-title-not-found": "Board „%s“ nicht gefunden.",
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.", "swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Abgeschlossen",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "abgeschlossen", "completed": "abgeschlossen",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "löschte Kommentar %s", "activity-deleteComment": "löschte Kommentar %s",
"activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s", "activity-receivedDate": "hat Empfangsdatum zu %s geändert auf %s",
"activity-startDate": "hat Startdatum zu %s geändert auf %s", "activity-startDate": "hat Startdatum zu %s geändert auf %s",
"allboards.starred": "Starred",
"allboards.templates": "Vorlagen",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s", "activity-dueDate": "hat Fälligkeitsdatum zu %s geändert auf %s",
"activity-endDate": "hat Enddatum zu %s geändert auf %s", "activity-endDate": "hat Enddatum zu %s geändert auf %s",
"add-attachment": "Datei anhängen", "add-attachment": "Datei anhängen",
@ -177,22 +189,22 @@
"boardChangeViewPopup-title": "Boardansicht", "boardChangeViewPopup-title": "Boardansicht",
"boards": "Boards", "boards": "Boards",
"board-view": "Boardansicht", "board-view": "Boardansicht",
"desktop-mode": "Desktop Mode", "desktop-mode": "Desktop-Modus",
"mobile-mode": "Mobile Mode", "mobile-mode": "Handy-Modus",
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode", "mobile-desktop-toggle": "Umschalten zwischen Mobil und Desktop Ansicht",
"zoom-in": "Vergrößern", "zoom-in": "Vergrößern",
"zoom-out": "Verkleinern", "zoom-out": "Verkleinern",
"click-to-change-zoom": "Click to change zoom level", "click-to-change-zoom": "Klicken um die Zoom Stufe zu ändern",
"zoom-level": "Zoom Level", "zoom-level": "Zoomstufe",
"enter-zoom-level": "Enter zoom level (50-300%):", "enter-zoom-level": "Eingabe Zoom Stufe (50-300%):",
"board-view-cal": "Kalender", "board-view-cal": "Kalender",
"board-view-swimlanes": "Swimlanes", "board-view-swimlanes": "Swimlanes",
"board-view-collapse": "Einklappen", "board-view-collapse": "Einklappen",
"board-view-gantt": "Gantt", "board-view-gantt": "Gantt",
"board-view-lists": "Listen", "board-view-lists": "Listen",
"bucket-example": "Like \"Bucket List\" for example", "bucket-example": "z.B. \"Löffelliste\"",
"calendar-previous-month-label": "Previous Month", "calendar-previous-month-label": "Vorheriger Monat",
"calendar-next-month-label": "Next Month", "calendar-next-month-label": "Nächster Monat",
"cancel": "Abbrechen", "cancel": "Abbrechen",
"card-archived": "Diese Karte wurde ins Archiv verschoben", "card-archived": "Diese Karte wurde ins Archiv verschoben",
"board-archived": "Dieses Board wurde ins Archiv verschoben.", "board-archived": "Dieses Board wurde ins Archiv verschoben.",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Titel der ersten Karte\", \"description\":\"Beschreibung der ersten Karte\"}, {\"title\":\"Titel der zweiten Karte\",\"description\":\"Beschreibung der zweiten Karte\"},{\"title\":\"Titel der letzten Karte\",\"description\":\"Beschreibung der letzten Karte\"} ]",
"create": "Erstellen", "create": "Erstellen",
"createBoardPopup-title": "Board erstellen", "createBoardPopup-title": "Board erstellen",
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
"chooseBoardSourcePopup-title": "Board importieren", "chooseBoardSourcePopup-title": "Board importieren",
"createLabelPopup-title": "Label erstellen", "createLabelPopup-title": "Label erstellen",
"createCustomField": "Feld erstellen", "createCustomField": "Feld erstellen",
@ -356,10 +369,10 @@
"custom-field-text": "Text", "custom-field-text": "Text",
"custom-fields": "Benutzerdefinierte Felder", "custom-fields": "Benutzerdefinierte Felder",
"date": "Datum", "date": "Datum",
"date-format": "Date Format", "date-format": "Datumsformat",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "JJJJ-MM-TT hh:mm",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "TT-MM-JJJJ",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-TT-JJJJ",
"decline": "Ablehnen", "decline": "Ablehnen",
"default-avatar": "Standard Profilbild", "default-avatar": "Standard Profilbild",
"delete": "Löschen", "delete": "Löschen",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Benachrichtigung ändern", "editNotificationPopup-title": "Benachrichtigung ändern",
"editProfilePopup-title": "Profil ändern", "editProfilePopup-title": "Profil ändern",
"email": "E-Mail", "email": "E-Mail",
"email-address": "E-Mail Adresse",
"email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt", "email-enrollAccount-subject": "Ihr Benutzerkonto auf __siteName__ wurde erstellt",
"email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.", "email-enrollAccount-text": "Hallo __user__,\n\num den Dienst nutzen zu können, klicken Sie bitte auf folgenden Link:\n\n__url__\n\nDanke.",
"email-fail": "Senden der E-Mail fehlgeschlagen", "email-fail": "Senden der E-Mail fehlgeschlagen",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.", "delete-board-confirm-popup": "Alle Listen, Karten, Labels und Akivitäten werden gelöscht und Sie können die Inhalte des Boards nicht wiederherstellen! Die Aktion kann nicht rückgängig gemacht werden.",
"boardDeletePopup-title": "Board löschen?", "boardDeletePopup-title": "Board löschen?",
"delete-board": "Board löschen", "delete-board": "Board löschen",
"delete-duplicate-lists": "Lösche doppelte Listen",
"delete-duplicate-lists-confirm": "Sicher? Es werden alle doppelten Listen gelöscht, die den gleichen Namen haben und keine Karten enthalten.",
"default-subtasks-board": "Teilaufgabe für __board__ Board", "default-subtasks-board": "Teilaufgabe für __board__ Board",
"default": "Standard", "default": "Standard",
"defaultdefault": "Standard", "defaultdefault": "Standard",
@ -761,7 +777,7 @@
"subtask-settings": "Einstellungen für Teilaufgaben", "subtask-settings": "Einstellungen für Teilaufgaben",
"card-settings": "Karten-Einstellungen", "card-settings": "Karten-Einstellungen",
"minicard-settings": "Minikarte-Einstellungen", "minicard-settings": "Minikarte-Einstellungen",
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben", "boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
"boardCardSettingsPopup-title": "Karten-Einstellungen", "boardCardSettingsPopup-title": "Karten-Einstellungen",
"boardMinicardSettingsPopup-title": "Minikarte-Einstellungen", "boardMinicardSettingsPopup-title": "Minikarte-Einstellungen",
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:", "deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Ich", "dueCardsViewChange-choice-me": "Ich",
"dueCardsViewChange-choice-all": "alle Benutzer", "dueCardsViewChange-choice-all": "alle Benutzer",
"dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.", "dueCardsViewChange-choice-all-description": "Zeigt alle unvollständigen Karten mit einem *Fälligkeits*-Datum auf Boards, für die der Benutzer Berechtigungen hat.",
"dueCards-noResults-title": "Keine fälligen Karten gefunden",
"dueCards-noResults-description": "Sie haben momentan keine Karten mit Fälligkeitsdaten.",
"broken-cards": "Fehlerhafte Karten", "broken-cards": "Fehlerhafte Karten",
"board-title-not-found": "Board „%s“ nicht gefunden.", "board-title-not-found": "Board „%s“ nicht gefunden.",
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.", "swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
@ -1290,14 +1308,14 @@
"accessibility-info-not-added-yet": "Es wurde noch keine Information zur Bedienungshilfe hinzugefügt", "accessibility-info-not-added-yet": "Es wurde noch keine Information zur Bedienungshilfe hinzugefügt",
"accessibility-title": "Bedienungshilfe Titel", "accessibility-title": "Bedienungshilfe Titel",
"accessibility-content": "Barrierefreier Eintrag", "accessibility-content": "Barrierefreier Eintrag",
"accounts-lockout-settings": "Brute Force Protection Settings", "accounts-lockout-settings": "Brute-Force-Schutz Einstellungen",
"accounts-lockout-info": "These settings control how login attempts are protected against brute force attacks.", "accounts-lockout-info": "Diese Einstellungen steuern, wie Anmeldeversuche gegen Brute-Force-Angriffe geschützt werden",
"accounts-lockout-known-users": "Settings for known users (correct username, wrong password)", "accounts-lockout-known-users": "Einstellungen für bekannte Benutzer (korrekter Benutzername, falsches Passwort)",
"accounts-lockout-unknown-users": "Settings for unknown users (non-existent username)", "accounts-lockout-unknown-users": "Einstellungen für unbekannte Benutzer (nicht existierender Benutzername)",
"accounts-lockout-failures-before": "Fehler vor einer Sperrung", "accounts-lockout-failures-before": "Fehler vor einer Sperrung",
"accounts-lockout-period": "Dauer der Sperrung (Sekunden)", "accounts-lockout-period": "Dauer der Sperrung (Sekunden)",
"accounts-lockout-failure-window": "Failure window (seconds)", "accounts-lockout-failure-window": "Fehlerfenster (Sekunden)",
"accounts-lockout-settings-updated": "Brute force protection settings have been updated", "accounts-lockout-settings-updated": "Die Brute-force-Schutz Einstellungen wurden aktualisiert",
"accounts-lockout-locked-users": "Gesperrte Benutzer", "accounts-lockout-locked-users": "Gesperrte Benutzer",
"accounts-lockout-locked-users-info": "Kürzlich gesperrte Benutzer aufgrund von zu vielen fehlerhaften Logins", "accounts-lockout-locked-users-info": "Kürzlich gesperrte Benutzer aufgrund von zu vielen fehlerhaften Logins",
"accounts-lockout-no-locked-users": "Es gibt aktuell keine gesperrten Benutzer", "accounts-lockout-no-locked-users": "Es gibt aktuell keine gesperrten Benutzer",
@ -1305,7 +1323,7 @@
"accounts-lockout-remaining-time": "Verbleibende Zeit", "accounts-lockout-remaining-time": "Verbleibende Zeit",
"accounts-lockout-user-unlocked": "Benutzer wurde erfolgreich entsperrt", "accounts-lockout-user-unlocked": "Benutzer wurde erfolgreich entsperrt",
"accounts-lockout-confirm-unlock": "Wollen Sie den Benutzer wirklich entsperren?", "accounts-lockout-confirm-unlock": "Wollen Sie den Benutzer wirklich entsperren?",
"accounts-lockout-confirm-unlock-all": "Are you sure you want to unlock all locked users?", "accounts-lockout-confirm-unlock-all": "Wollen Sie wirklich alle gesperrten Benutzer entsperren?",
"accounts-lockout-show-locked-users": "Zeige nur gesperrte Benutzer", "accounts-lockout-show-locked-users": "Zeige nur gesperrte Benutzer",
"accounts-lockout-user-locked": "Benutzer ist gesperrt", "accounts-lockout-user-locked": "Benutzer ist gesperrt",
"accounts-lockout-click-to-unlock": "Klicken Sie, um den Benutzer zu entsperren", "accounts-lockout-click-to-unlock": "Klicken Sie, um den Benutzer zu entsperren",
@ -1316,183 +1334,246 @@
"admin-people-filter-active": "Aktiv", "admin-people-filter-active": "Aktiv",
"admin-people-filter-inactive": "Nicht aktiv", "admin-people-filter-inactive": "Nicht aktiv",
"admin-people-active-status": "Aktiv Status", "admin-people-active-status": "Aktiv Status",
"admin-people-user-active": "User is active - click to deactivate", "admin-people-user-active": "Benutzer ist aktiv - zum Deaktivieren klicken",
"admin-people-user-inactive": "User is inactive - click to activate", "admin-people-user-inactive": "Benutzer ist inaktiv - zum Aktivieren klicken",
"accounts-lockout-all-users-unlocked": "All locked users have been unlocked", "accounts-lockout-all-users-unlocked": "Alle gesperrten Benutzer wurden entsperrt",
"accounts-lockout-unlock-all": "Alle entsperren", "accounts-lockout-unlock-all": "Alle entsperren",
"active-cron-jobs": "Active Scheduled Jobs", "active-cron-jobs": "Aktive geplante Aufgaben",
"add-cron-job": "Add Scheduled Job", "add-cron-job": "Geplante Aufgabe hinzufügen",
"add-cron-job-placeholder": "Add Scheduled Job functionality coming soon", "add-cron-job-placeholder": "Funktion „Geplante Aufgaben hinzufügen” in Kürze verfügbar",
"attachment-storage-configuration": "Attachment Storage Configuration", "attachment-storage-configuration": "Konfiguration des Anhangspeichers",
"attachments-path": "Attachments Path", "attachments-path": "Anhänge Pfad",
"attachments-path-description": "Path where attachment files are stored", "attachments-path-description": "Pfad unter dem die Anhänge gespeichert werden",
"avatars-path": "Avatars Path", "avatars-path": "Pfad zu den Avataren",
"avatars-path-description": "Path where avatar files are stored", "avatars-path-description": "Pfad unter dem die Avatardateien gespeichert werden",
"board-archive-failed": "Failed to schedule board archive", "board-archive-failed": "Planung der Brettarchivierung fehlgeschlagen ",
"board-archive-scheduled": "Board archive scheduled successfully", "board-archive-scheduled": "Brettarchivierung erfolgreich eingeplant",
"board-backup-failed": "Failed to schedule board backup", "board-backup-failed": "Planung der Brettsicherung fehlgeschlagen ",
"board-backup-scheduled": "Board backup scheduled successfully", "board-backup-scheduled": "Brettsicherung erfolgreich eingeplant",
"board-cleanup-failed": "Failed to schedule board cleanup", "board-cleanup-failed": "Planung des Brettaufräumens fehlgeschlagen",
"board-cleanup-scheduled": "Board cleanup scheduled successfully", "board-cleanup-scheduled": "Brettaufräumen erfolgreich eingeplant",
"board-operations": "Board Operations", "board-operations": "Brettoperationen",
"cron-jobs": "Scheduled Jobs", "cron-jobs": "Geplante Aufgaben",
"cron-migrations": "Geplante Migrationen", "cron-migrations": "Geplante Migrationen",
"cron-job-delete-confirm": "Are you sure you want to delete this scheduled job?", "cron-job-delete-confirm": "Sind Sie sicher, dass Sie diese geplante Aufgabe löschen wollen?",
"cron-job-delete-failed": "Failed to delete scheduled job", "cron-job-delete-failed": "Löschen der geplanten Aufgabe fehlgeschlagen",
"cron-job-deleted": "Scheduled job deleted successfully", "cron-job-deleted": "Geplante Aufgabe erfolgreich gelöscht",
"cron-job-pause-failed": "Failed to pause scheduled job", "cron-job-pause-failed": "Anhalten der geplanten Aufgabe fehlgeschlagen",
"cron-job-paused": "Scheduled job paused successfully", "cron-job-paused": "Geplante Aufgabe erfolgreich angehalten",
"filesystem-path-description": "Base path for file storage", "filesystem-path-description": "Basispfad des Dateispeichers",
"gridfs-enabled": "GridFS Enabled", "gridfs-enabled": "GridFS aktiviert",
"gridfs-enabled-description": "Use MongoDB GridFS for file storage", "gridfs-enabled-description": "Benutze MongoDB GridFS als Dateispeicher",
"migration-pause-failed": "Failed to pause migrations", "migration-pause-failed": "Unterbrechung der Migrationen fehlgeschlagen",
"migration-paused": "Migrations paused successfully", "migration-paused": "Migrationen erfolgreich unterbrochen",
"migration-progress": "Migration Progress", "migration-progress": "Migrationsfortschritt",
"migration-start-failed": "Failed to start migrations", "migration-start-failed": "Start der Migrationen fehlgeschlagen",
"migration-started": "Migrations started successfully", "migration-started": "Migrationen erfolgreich gestartet",
"migration-status": "Migration Status", "migration-status": "Migrationsstatus",
"migration-stop-confirm": "Are you sure you want to stop all migrations?", "migration-stop-confirm": "Sind Sie sicher, dass Sie alle Migrationen stoppen wollen?",
"migration-stop-failed": "Failed to stop migrations", "migration-stop-failed": "Stoppen der Migrationen fehlgeschlagen",
"migration-stopped": "Migrations stopped successfully", "migration-stopped": "Migrationen erfolgreich gestoppt",
"mongodb-gridfs-storage": "MongoDB GridFS Storage", "mongodb-gridfs-storage": "MongoDB GridFS Speicher",
"pause-all-migrations": "Pause All Migrations", "pause-all-migrations": "Alle Migrationen anhalten",
"s3-access-key": "S3 Access Key", "s3-access-key": "S3 Zugriffsschlüssel",
"s3-access-key-description": "AWS S3 access key for authentication", "s3-access-key-description": "AWS S3 Zugangsschlüssel zur Authentifizierung",
"s3-access-key-placeholder": "Enter S3 access key", "s3-access-key-placeholder": "S3 Zugriffsschlüssel eingeben",
"s3-bucket": "S3 Bucket", "s3-bucket": "S3 Bucket",
"s3-bucket-description": "S3 bucket name for storing files", "s3-bucket-description": "S3 Bucket Name um Dateien zu speichern",
"s3-connection-failed": "S3 connection failed", "s3-connection-failed": "S3 Verbindung fehlgeschlagen",
"s3-connection-success": "S3 connection successful", "s3-connection-success": "S3 Verbindung erfolgreich",
"s3-enabled": "S3 Enabled", "s3-enabled": "S3 aktiviert",
"s3-enabled-description": "Use AWS S3 or MinIO for file storage", "s3-enabled-description": "Benutze AWS S3 oder MiniIO als Dateispeicher",
"s3-endpoint": "S3 Endpoint", "s3-endpoint": "S3 Endpunkt",
"s3-endpoint-description": "S3 endpoint URL (e.g., s3.amazonaws.com or minio.example.com)", "s3-endpoint-description": "S3 Endpunkt URL (z.B., s3.amazonaws.com oder minio.example.com)",
"s3-minio-storage": "S3/MinIO Storage", "s3-minio-storage": "S3/MinIO Speicher",
"s3-port": "S3 Port", "s3-port": "S3 Port",
"s3-port-description": "S3 endpoint port number", "s3-port-description": "S3 Endpunkt Port Nummer",
"s3-region": "S3 Region", "s3-region": "S3 Region",
"s3-region-description": "AWS S3 region (e.g., us-east-1)", "s3-region-description": "AWS S3 Region (z.B., us-east-1)",
"s3-secret-key": "S3 Secret Key", "s3-secret-key": "S3 geheimer Schlüssel",
"s3-secret-key-description": "AWS S3 secret key for authentication", "s3-secret-key-description": "AWS S3 geheimer Schlüssel zur Authentifizierung",
"s3-secret-key-placeholder": "Enter S3 secret key", "s3-secret-key-placeholder": "S3 geheimen Schlüssel eingeben",
"s3-secret-key-required": "S3 secret key is required", "s3-secret-key-required": "S3 geheimer Schlüssel ist erforderlich",
"s3-settings-save-failed": "Failed to save S3 settings", "s3-settings-save-failed": "Speicherung der S3 Einstellungen fehlgeschlagen",
"s3-settings-saved": "S3 settings saved successfully", "s3-settings-saved": "S3 Einstellungen erfolgreich gespeichert",
"s3-ssl-enabled": "S3 SSL Enabled", "s3-ssl-enabled": "S3 SSL aktiviert",
"s3-ssl-enabled-description": "Use SSL/TLS for S3 connections", "s3-ssl-enabled-description": "Benutze SSL/TLS für S3 Verbindungen",
"save-s3-settings": "Save S3 Settings", "save-s3-settings": "S3 Einstellungen speichern",
"schedule-board-archive": "Schedule Board Archive", "schedule-board-archive": "Planung Brettarchiv",
"schedule-board-backup": "Schedule Board Backup", "schedule-board-backup": "Planung Brettsicherung",
"schedule-board-cleanup": "Schedule Board Cleanup", "schedule-board-cleanup": "Planung Brettsäuberung",
"scheduled-board-operations": "Scheduled Board Operations", "scheduled-board-operations": "Geplante Brettoperationen",
"start-all-migrations": "Start All Migrations", "start-all-migrations": "Starte alle Migrationen",
"stop-all-migrations": "Stop All Migrations", "stop-all-migrations": "Stoppe alle Migrationen",
"test-s3-connection": "Test S3 Connection", "test-s3-connection": "Teste S3 Verbindungen",
"writable-path": "Writable Path", "writable-path": "Beschreibbarer Pfad",
"writable-path-description": "Base directory path for file storage", "writable-path-description": "Basispfad des Dateispeichers",
"add-job": "Add Job", "add-job": "Aufgabe hinzufügen",
"attachment-migration": "Attachment Migration", "attachment-migration": "Anhangmigration",
"attachment-monitoring": "Attachment Monitoring", "attachment-monitoring": "Anhangüberwachung",
"attachment-settings": "Attachment Settings", "attachment-settings": "Anhangeinstellungen",
"attachment-storage-settings": "Storage Settings", "attachment-storage-settings": "Speichereinstellungen",
"automatic-migration": "Automatic Migration", "automatic-migration": "Automatische Migration",
"back-to-settings": "Back to Settings", "back-to-settings": "Zurück zu den Einstellungen",
"board-id": "Board ID", "board-id": "Brett ID",
"board-migration": "Board Migration", "board-migration": "Brettmigration",
"card-show-lists-on-minicard": "Show Lists on Minicard", "board-migrations": "Board Migrations",
"cleanup": "Cleanup", "card-show-lists-on-minicard": "Zeige Listen auf der Minikarte",
"cleanup-old-jobs": "Cleanup Old Jobs", "comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Vollständig",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Gesamtfortschritt",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Aufräumen",
"cleanup-old-jobs": "Alte Aufgaben aufräumen",
"completed": "abgeschlossen", "completed": "abgeschlossen",
"conversion-info-text": "This conversion is performed once per board and improves performance. You can continue using the board normally.", "conversion-info-text": "Diese Umstellung wird einmal pro Brett durchgeführt und verbessert die Performanz. Sie können das Brett normal verwenden.",
"converting-board": "Converting Board", "converting-board": "Brett umwandeln",
"converting-board-description": "Converting board structure for improved functionality. This may take a few moments.", "converting-board-description": "Umwandlung der Brettstruktur für verbesserte Funktionalität. Das kann einen Moment dauern.",
"cpu-cores": "CPU Cores", "cpu-cores": "CPU Cores",
"cpu-usage": "CPU Usage", "cpu-usage": "CPU Usage",
"current-action": "Current Action", "current-action": "Laufender Vorgang",
"database-migration": "Database Migration", "database-migration": "Datenbankmigration",
"database-migration-description": "Updating database structure for improved functionality and performance. This process may take several minutes.", "database-migration-description": "Update der Datenbankstruktur für eine Verbesserung der Funktionalität und der Performanz. Das kann ein paar Minuten dauern.",
"database-migrations": "Database Migrations", "database-migrations": "Datenbankmigration",
"days-old": "Days Old", "days-old": "Tage alt",
"duration": "Duration", "duration": "Dauer",
"errors": "Errors", "errors": "Fehler",
"estimated-time-remaining": "Estimated time remaining", "estimated-time-remaining": "Geschätzte Zeit übrig",
"every-1-day": "Every 1 day", "every-1-day": "Jeden Tag",
"every-1-hour": "Every 1 hour", "every-1-hour": "Jede Stunde",
"every-1-minute": "Every 1 minute", "every-1-minute": "Jede Minute",
"every-10-minutes": "Every 10 minutes", "every-10-minutes": "Alle 10 Minuten",
"every-30-minutes": "Every 30 minutes", "every-30-minutes": "Alle 30 Minuten",
"every-5-minutes": "Every 5 minutes", "every-5-minutes": "Alle 5 Minuten",
"every-6-hours": "Every 6 hours", "every-6-hours": "Alle 6 Stunden",
"export-monitoring": "Export Monitoring", "export-monitoring": "Exportüberwachung",
"filesystem-attachments": "Filesystem Attachments", "filesystem-attachments": "Dateisystemanhänge",
"filesystem-size": "Filesystem Size", "filesystem-size": "Dateisystem Größe",
"filesystem-storage": "Filesystem Storage", "filesystem-storage": "Dateisystem Speicher",
"force-board-scan": "Force Board Scan", "force-board-scan": "Erzwinge Brettscan",
"gridfs-attachments": "GridFS Attachments", "gridfs-attachments": "GridFS Anhänge",
"gridfs-size": "GridFS Size", "gridfs-size": "GridFS Größe",
"gridfs-storage": "GridFS", "gridfs-storage": "GridFS",
"hide-list-on-minicard": "Hide List on Minicard", "hide-list-on-minicard": "Verberge Liste auf der Minikarte",
"idle-migration": "Idle Migration", "idle-migration": "Untätige Migration",
"job-description": "Job Description", "job-description": "Aufgabenbeschreibung",
"job-details": "Job Details", "job-details": "Aufgabendetails",
"job-name": "Job Name", "job-name": "Aufgabenname",
"job-queue": "Job Queue", "job-queue": "Aufgabenwarteschlange",
"last-run": "Last Run", "last-run": "Letzte Ausführung",
"max-concurrent": "Max Concurrent", "max-concurrent": "Max. gleichzeitig",
"memory-usage": "Memory Usage", "memory-usage": "Speicherauslastung",
"migrate-all-to-filesystem": "Migrate All to Filesystem", "migrate-all-to-filesystem": "Migriere alles ins Dateisystem",
"migrate-all-to-gridfs": "Migrate All to GridFS", "migrate-all-to-gridfs": "Migriere alles ins GridFS",
"migrate-all-to-s3": "Migrate All to S3", "migrate-all-to-s3": "Migriere alles ins S3",
"migrated-attachments": "Migrated Attachments", "migrated-attachments": "Migrierte Anhänge",
"migration-batch-size": "Batch Size", "migration-batch-size": "Batchgröße",
"migration-batch-size-description": "Number of attachments to process in each batch (1-100)", "migration-batch-size-description": "Anzahl der zu bearbeitenden Anhänge pro Batch (1-100)",
"migration-cpu-threshold": "CPU Threshold (%)", "migration-cpu-threshold": "CPU Threshold (%)",
"migration-cpu-threshold-description": "Pause migration when CPU usage exceeds this percentage (10-90)", "migration-cpu-threshold-description": "Unterbreche Migration, wenn CPU Benutzung diesen Wert überschreitet (10-90%)",
"migration-delay-ms": "Delay (ms)", "migration-delay-ms": "Verzögerung (ms)",
"migration-delay-ms-description": "Delay between batches in milliseconds (100-10000)", "migration-delay-ms-description": "Verzögerung zwischen Batches in Millisekunden (100-10000)",
"migration-detector": "Migration Detector", "migration-detector": "Migrationdetektor",
"migration-info-text": "Database migrations are performed once and improve system performance. The process continues in the background even if you close your browser.", "migration-info-text": "Datenbankmigrationen werden einmal durchgeführt und verbessern die Systemperformanz. Dieser Vorgang läuft im Hintergrund weiter, auch wenn Sie den Browser schließen.",
"migration-log": "Migration Log", "migration-log": "Migration Log",
"migration-markers": "Migration Markers", "migration-markers": "Migrationsmarkierungen",
"migration-resume-failed": "Failed to resume migration", "migration-resume-failed": "Fortfahren der Migration misslungen",
"migration-resumed": "Migration resumed", "migration-resumed": "Migration fortgesetzt",
"migration-steps": "Migration Steps", "migration-steps": "Migrationsschritte",
"migration-warning-text": "Please do not close your browser during migration. The process will continue in the background but may take longer to complete.", "migration-warning-text": "Bitte schließen Sie nicht den Browser während der Migration. Der Vorgang wird zwar im Hintergrund fortgesetzt, braucht aber länger.",
"monitoring-export-failed": "Failed to export monitoring data", "monitoring-export-failed": "Export der Beobachtungsdaten misslungen",
"monitoring-refresh-failed": "Failed to refresh monitoring data", "monitoring-refresh-failed": "Neuladen der Beobachtungsdaten misslungen",
"next": "Next", "next": "Weiter",
"next-run": "Next Run", "next-run": "Nächster Lauf",
"of": "von", "of": "von",
"operation-type": "Operation Type", "operation-type": "Operationstyp",
"overall-progress": "Overall Progress", "overall-progress": "Gesamtfortschritt",
"page": "Page", "page": "Seite",
"pause-migration": "Pause Migration", "pause-migration": "Migration unterbrechen",
"previous": "Previous", "previous": "Zurück",
"refresh": "Refresh", "refresh": "Neuladen",
"refresh-monitoring": "Refresh Monitoring", "refresh-monitoring": "Beobachten neuladen",
"remaining-attachments": "Remaining Attachments", "remaining-attachments": "Verbleibende Anhänge",
"resume-migration": "Resume Migration", "resume-migration": "Migration fortsetzen",
"run-once": "Run once", "run-once": "Einmal ausführen",
"s3-attachments": "S3 Attachments", "s3-attachments": "S3 Anhänge",
"s3-size": "S3 Size", "s3-size": "S3 Größe",
"s3-storage": "S3", "s3-storage": "S3",
"scanning-status": "Scanning Status", "scanning-status": "Scanstatus",
"schedule": "Schedule", "schedule": "Zeitplanung",
"search-boards-or-operations": "Search boards or operations...", "search-boards-or-operations": "Durchsuche Bretter oder Vorgänge",
"show-list-on-minicard": "Show List on Minicard", "show-list-on-minicard": "Zeige Liste auf der Minikarte",
"showing": "Showing", "showing": "Gezeigt",
"start-test-operation": "Start Test Operation", "start-test-operation": "Starte Testvorgang",
"start-time": "Start Time", "start-time": "Startzeit",
"step-progress": "Step Progress", "step-progress": "Durchschreite Fortschritt",
"stop-migration": "Stop Migration", "stop-migration": "Stoppe Migration",
"storage-distribution": "Storage Distribution", "storage-distribution": "Speicherverteilung",
"system-resources": "System Resources", "system-resources": "Systemressourcen",
"total-attachments": "Total Attachments", "total-attachments": "Gesamte Anhänge",
"total-operations": "Total Operations", "total-operations": "Gesamte Vorgänge",
"total-size": "Total Size", "total-size": "Gesamte Größe",
"unmigrated-boards": "Unmigrated Boards", "unmigrated-boards": "Nicht migrierte Bretter",
"weight": "Weight", "weight": "Gewicht",
"idle": "Idle", "idle": "Untätig",
"complete": "Complete", "complete": "Vollständig",
"cron": "Cron" "cron": "Cron"
} }

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "διεγράφη το σχόλιο %s", "activity-deleteComment": "διεγράφη το σχόλιο %s",
"activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %s από %s", "activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %s από %s",
"activity-startDate": "η ημερομηνία έναρξης άλλαξε σε %s από %s", "activity-startDate": "η ημερομηνία έναρξης άλλαξε σε %s από %s",
"allboards.starred": "Starred",
"allboards.templates": "Πρότυπα",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "υπέστη επεξεργασία η τιμή της προθεσμίας σε %s από %s", "activity-dueDate": "υπέστη επεξεργασία η τιμή της προθεσμίας σε %s από %s",
"activity-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s", "activity-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s",
"add-attachment": "Προσθήκη Συνημμένου", "add-attachment": "Προσθήκη Συνημμένου",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]",
"create": "Δημιουργία", "create": "Δημιουργία",
"createBoardPopup-title": "Δημιουργία Πίνακα", "createBoardPopup-title": "Δημιουργία Πίνακα",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Εισαγωγή πίνακα", "chooseBoardSourcePopup-title": "Εισαγωγή πίνακα",
"createLabelPopup-title": "Δημιουργία Ετικέτας", "createLabelPopup-title": "Δημιουργία Ετικέτας",
"createCustomField": "Δημιουργία Πεδίου", "createCustomField": "Δημιουργία Πεδίου",
@ -357,9 +370,9 @@
"custom-fields": "Προσαρμοσμένα Πεδία", "custom-fields": "Προσαρμοσμένα Πεδία",
"date": "Ημερομηνία", "date": "Ημερομηνία",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Απόρριψη", "decline": "Απόρριψη",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Διαγραφή", "delete": "Διαγραφή",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Επεξεργασία Ειδοποίησης", "editNotificationPopup-title": "Επεξεργασία Ειδοποίησης",
"editProfilePopup-title": "Επεξεργασία Προφίλ", "editProfilePopup-title": "Επεξεργασία Προφίλ",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__", "email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__",
"email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.", "email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.",
"email-fail": "Η αποστολή του email απέτυχε", "email-fail": "Η αποστολή του email απέτυχε",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Διαγραφή Πίνακα;", "boardDeletePopup-title": "Διαγραφή Πίνακα;",
"delete-board": "Διαγραφή Πίνακα", "delete-board": "Διαγραφή Πίνακα",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Προεπιλογή", "default": "Προεπιλογή",
"defaultdefault": "Προεπιλογή", "defaultdefault": "Προεπιλογή",
@ -761,7 +777,7 @@
"subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)", "subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)",
"card-settings": "Ρυθμίσεις Κάρτας", "card-settings": "Ρυθμίσεις Κάρτας",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Ρυθμίσεις υποεργασιών (subtasks)",
"boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας", "boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "διεγράφη το σχόλιο %s", "activity-deleteComment": "διεγράφη το σχόλιο %s",
"activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %s από %s", "activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %s από %s",
"activity-startDate": "η ημερομηνία έναρξης άλλαξε σε %s από %s", "activity-startDate": "η ημερομηνία έναρξης άλλαξε σε %s από %s",
"allboards.starred": "Starred",
"allboards.templates": "Πρότυπα",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "υπέστη επεξεργασία η τιμή της προθεσμίας σε %s από %s", "activity-dueDate": "υπέστη επεξεργασία η τιμή της προθεσμίας σε %s από %s",
"activity-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s", "activity-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s",
"add-attachment": "Προσθήκη Συνημμένου", "add-attachment": "Προσθήκη Συνημμένου",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]",
"create": "Δημιουργία", "create": "Δημιουργία",
"createBoardPopup-title": "Δημιουργία Πίνακα", "createBoardPopup-title": "Δημιουργία Πίνακα",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Εισαγωγή πίνακα", "chooseBoardSourcePopup-title": "Εισαγωγή πίνακα",
"createLabelPopup-title": "Δημιουργία Ετικέτας", "createLabelPopup-title": "Δημιουργία Ετικέτας",
"createCustomField": "Δημιουργία Πεδίου", "createCustomField": "Δημιουργία Πεδίου",
@ -357,9 +370,9 @@
"custom-fields": "Προσαρμοσμένα Πεδία", "custom-fields": "Προσαρμοσμένα Πεδία",
"date": "Ημερομηνία", "date": "Ημερομηνία",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Απόρριψη", "decline": "Απόρριψη",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Διαγραφή", "delete": "Διαγραφή",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Επεξεργασία Ειδοποίησης", "editNotificationPopup-title": "Επεξεργασία Ειδοποίησης",
"editProfilePopup-title": "Επεξεργασία Προφίλ", "editProfilePopup-title": "Επεξεργασία Προφίλ",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__", "email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__",
"email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.", "email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.",
"email-fail": "Η αποστολή του email απέτυχε", "email-fail": "Η αποστολή του email απέτυχε",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Διαγραφή Πίνακα;", "boardDeletePopup-title": "Διαγραφή Πίνακα;",
"delete-board": "Διαγραφή Πίνακα", "delete-board": "Διαγραφή Πίνακα",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Προεπιλογή", "default": "Προεπιλογή",
"defaultdefault": "Προεπιλογή", "defaultdefault": "Προεπιλογή",
@ -761,7 +777,7 @@
"subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)", "subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)",
"card-settings": "Ρυθμίσεις Κάρτας", "card-settings": "Ρυθμίσεις Κάρτας",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Ρυθμίσεις υποεργασιών (subtasks)",
"boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας", "boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

View file

@ -78,6 +78,18 @@
"activity-deleteComment": "deleted comment %s", "activity-deleteComment": "deleted comment %s",
"activity-receivedDate": "edited received date to %s of %s", "activity-receivedDate": "edited received date to %s of %s",
"activity-startDate": "edited start date to %s of %s", "activity-startDate": "edited start date to %s of %s",
"allboards.starred": "Starred",
"allboards.templates": "Templates",
"allboards.remaining": "Remaining",
"allboards.workspaces": "Workspaces",
"allboards.add-workspace": "Add Workspace",
"allboards.add-workspace-prompt": "Workspace name",
"allboards.add-subworkspace": "Add Subworkspace",
"allboards.add-subworkspace-prompt": "Subworkspace name",
"allboards.edit-workspace": "Edit workspace",
"allboards.edit-workspace-name": "Workspace name",
"allboards.edit-workspace-icon": "Workspace icon (markdown)",
"multi-selection-active": "Click checkboxes to select boards",
"activity-dueDate": "edited due date to %s of %s", "activity-dueDate": "edited due date to %s of %s",
"activity-endDate": "edited end date to %s of %s", "activity-endDate": "edited end date to %s of %s",
"add-attachment": "Add Attachment", "add-attachment": "Add Attachment",
@ -337,6 +349,7 @@
"copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]", "copyManyCardsPopup-format": "[ {\"title\": \"First card title\", \"description\":\"First card description\"}, {\"title\":\"Second card title\",\"description\":\"Second card description\"},{\"title\":\"Last card title\",\"description\":\"Last card description\"} ]",
"create": "Create", "create": "Create",
"createBoardPopup-title": "Create Board", "createBoardPopup-title": "Create Board",
"createTemplateContainerPopup-title": "Add Template Container",
"chooseBoardSourcePopup-title": "Import board", "chooseBoardSourcePopup-title": "Import board",
"createLabelPopup-title": "Create Label", "createLabelPopup-title": "Create Label",
"createCustomField": "Create Field", "createCustomField": "Create Field",
@ -357,9 +370,9 @@
"custom-fields": "Custom Fields", "custom-fields": "Custom Fields",
"date": "Date", "date": "Date",
"date-format": "Date Format", "date-format": "Date Format",
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM", "date-format-yyyy-mm-dd": "YYYY-MM-DD",
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM", "date-format-dd-mm-yyyy": "DD-MM-YYYY",
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM", "date-format-mm-dd-yyyy": "MM-DD-YYYY",
"decline": "Decline", "decline": "Decline",
"default-avatar": "Default avatar", "default-avatar": "Default avatar",
"delete": "Delete", "delete": "Delete",
@ -385,6 +398,7 @@
"editNotificationPopup-title": "Edit Notification", "editNotificationPopup-title": "Edit Notification",
"editProfilePopup-title": "Edit Profile", "editProfilePopup-title": "Edit Profile",
"email": "Email", "email": "Email",
"email-address": "Email Address",
"email-enrollAccount-subject": "An account created for you on __siteName__", "email-enrollAccount-subject": "An account created for you on __siteName__",
"email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.", "email-enrollAccount-text": "Hello __user__,\n\nTo start using the service, simply click the link below.\n\n__url__\n\nThanks.",
"email-fail": "Sending email failed", "email-fail": "Sending email failed",
@ -754,6 +768,8 @@
"delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.", "delete-board-confirm-popup": "All lists, cards, labels, and activities will be deleted and you won't be able to recover the board contents. There is no undo.",
"boardDeletePopup-title": "Delete Board?", "boardDeletePopup-title": "Delete Board?",
"delete-board": "Delete Board", "delete-board": "Delete Board",
"delete-duplicate-lists": "Delete Duplicate Lists",
"delete-duplicate-lists-confirm": "Are you sure? This will delete all duplicate lists that have the same name and contain no cards.",
"default-subtasks-board": "Subtasks for __board__ board", "default-subtasks-board": "Subtasks for __board__ board",
"default": "Default", "default": "Default",
"defaultdefault": "Default", "defaultdefault": "Default",
@ -761,7 +777,7 @@
"subtask-settings": "Subtasks Settings", "subtask-settings": "Subtasks Settings",
"card-settings": "Card Settings", "card-settings": "Card Settings",
"minicard-settings": "Minicard Settings", "minicard-settings": "Minicard Settings",
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings", "boardSubtaskSettingsPopup-title": "Subtasks Settings",
"boardCardSettingsPopup-title": "Card Settings", "boardCardSettingsPopup-title": "Card Settings",
"boardMinicardSettingsPopup-title": "Minicard Settings", "boardMinicardSettingsPopup-title": "Minicard Settings",
"deposit-subtasks-board": "Deposit subtasks to this board:", "deposit-subtasks-board": "Deposit subtasks to this board:",
@ -1015,6 +1031,8 @@
"dueCardsViewChange-choice-me": "Me", "dueCardsViewChange-choice-me": "Me",
"dueCardsViewChange-choice-all": "All Users", "dueCardsViewChange-choice-all": "All Users",
"dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.", "dueCardsViewChange-choice-all-description": "Shows all incomplete cards with a *Due* date from boards for which the user has permission.",
"dueCards-noResults-title": "No Due Cards Found",
"dueCards-noResults-description": "You don't have any cards with due dates at the moment.",
"broken-cards": "Broken Cards", "broken-cards": "Broken Cards",
"board-title-not-found": "Board '%s' not found.", "board-title-not-found": "Board '%s' not found.",
"swimlane-title-not-found": "Swimlane '%s' not found.", "swimlane-title-not-found": "Swimlane '%s' not found.",
@ -1399,7 +1417,70 @@
"back-to-settings": "Back to Settings", "back-to-settings": "Back to Settings",
"board-id": "Board ID", "board-id": "Board ID",
"board-migration": "Board Migration", "board-migration": "Board Migration",
"board-migrations": "Board Migrations",
"card-show-lists-on-minicard": "Show Lists on Minicard", "card-show-lists-on-minicard": "Show Lists on Minicard",
"comprehensive-board-migration": "Comprehensive Board Migration",
"comprehensive-board-migration-description": "Performs comprehensive checks and fixes for board data integrity, including list ordering, card positions, and swimlane structure.",
"delete-duplicate-empty-lists-migration": "Delete Duplicate Empty Lists",
"delete-duplicate-empty-lists-migration-description": "Safely deletes empty duplicate lists. Only removes lists that have no cards AND have another list with the same title that contains cards.",
"lost-cards": "Lost Cards",
"lost-cards-list": "Restored Items",
"restore-lost-cards-migration": "Restore Lost Cards",
"restore-lost-cards-migration-description": "Finds and restores cards and lists with missing swimlaneId or listId. Creates a 'Lost Cards' swimlane to make all lost items visible again.",
"restore-all-archived-migration": "Restore All Archived",
"restore-all-archived-migration-description": "Restores all archived swimlanes, lists, and cards. Automatically fixes any missing swimlaneId or listId to make items visible.",
"fix-missing-lists-migration": "Fix Missing Lists",
"fix-missing-lists-migration-description": "Detects and repairs missing or corrupted lists in the board structure.",
"fix-avatar-urls-migration": "Fix Avatar URLs",
"fix-avatar-urls-migration-description": "Updates avatar URLs for board members to use the correct storage backend and fixes broken avatar references.",
"fix-all-file-urls-migration": "Fix All File URLs",
"fix-all-file-urls-migration-description": "Updates all file attachment URLs on this board to use the correct storage backend and fixes broken file references.",
"migration-needed": "Migration Needed",
"migration-complete": "Complete",
"migration-running": "Running...",
"migration-successful": "Migration completed successfully",
"migration-failed": "Migration failed",
"migrations": "Migrations",
"migrations-admin-only": "Only board administrators can run migrations",
"migrations-description": "Run data integrity checks and repairs for this board. Each migration can be executed individually.",
"no-issues-found": "No issues found",
"run-migration": "Run Migration",
"run-comprehensive-migration-confirm": "This will perform a comprehensive migration to check and fix board data integrity. This may take a few moments. Continue?",
"run-delete-duplicate-empty-lists-migration-confirm": "This will first convert any shared lists to per-swimlane lists, then delete empty lists that have a duplicate list with the same title containing cards. Only truly redundant empty lists will be removed. Continue?",
"run-restore-lost-cards-migration-confirm": "This will create a 'Lost Cards' swimlane and restore all cards and lists with missing swimlaneId or listId. This only affects non-archived items. Continue?",
"run-restore-all-archived-migration-confirm": "This will restore ALL archived swimlanes, lists, and cards, making them visible again. Any items with missing IDs will be automatically fixed. This cannot be easily undone. Continue?",
"run-fix-missing-lists-migration-confirm": "This will detect and repair missing or corrupted lists in the board structure. Continue?",
"run-fix-avatar-urls-migration-confirm": "This will update avatar URLs for board members to use the correct storage backend. Continue?",
"run-fix-all-file-urls-migration-confirm": "This will update all file attachment URLs on this board to use the correct storage backend. Continue?",
"restore-lost-cards-nothing-to-restore": "No lost swimlanes, lists, or cards to restore",
"migration-progress-title": "Board Migration in Progress",
"migration-progress-overall": "Overall Progress",
"migration-progress-current-step": "Current Step",
"migration-progress-status": "Status",
"migration-progress-details": "Details",
"migration-progress-note": "Please wait while we migrate your board to the latest structure...",
"step-analyze-board-structure": "Analyze Board Structure",
"step-fix-orphaned-cards": "Fix Orphaned Cards",
"step-convert-shared-lists": "Convert Shared Lists",
"step-ensure-per-swimlane-lists": "Ensure Per-Swimlane Lists",
"step-validate-migration": "Validate Migration",
"step-fix-avatar-urls": "Fix Avatar URLs",
"step-fix-attachment-urls": "Fix Attachment URLs",
"step-analyze-lists": "Analyze Lists",
"step-create-missing-lists": "Create Missing Lists",
"step-update-cards": "Update Cards",
"step-finalize": "Finalize",
"step-delete-duplicate-empty-lists": "Delete Duplicate Empty Lists",
"step-ensure-lost-cards-swimlane": "Ensure Lost Cards Swimlane",
"step-restore-lists": "Restore Lists",
"step-restore-cards": "Restore Cards",
"step-restore-swimlanes": "Restore Swimlanes",
"step-fix-missing-ids": "Fix Missing IDs",
"step-scan-users": "Checking board member avatars",
"step-scan-files": "Checking board file attachments",
"step-fix-file-urls": "Fixing file URLs",
"cleanup": "Cleanup", "cleanup": "Cleanup",
"cleanup-old-jobs": "Cleanup Old Jobs", "cleanup-old-jobs": "Cleanup Old Jobs",
"completed": "Completed", "completed": "Completed",

Some files were not shown because too many files have changed in this diff Show more