mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 07:20:12 +01:00
Compare commits
136 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0ce8e8b74d | ||
|
|
4ea53af76e | ||
|
|
016f17d663 | ||
|
|
07f69950a7 | ||
|
|
cec625607d | ||
|
|
a290c7b34b | ||
|
|
5b77ac1b44 | ||
|
|
41c635afb5 | ||
|
|
adbf729cb2 | ||
|
|
88ea716d63 | ||
|
|
003a07ebce | ||
|
|
d3c237bc66 | ||
|
|
bac0fa81fc | ||
|
|
a42915614a | ||
|
|
5ff9bf331f | ||
|
|
36d7b0f8a7 | ||
|
|
67c8a98f20 | ||
|
|
a81a603031 | ||
|
|
e30ce78053 | ||
|
|
3d70de94c6 | ||
|
|
70975c2944 | ||
|
|
960e2126b4 | ||
|
|
3db1305e58 | ||
|
|
f16780b5e3 | ||
|
|
37a3065f3c | ||
|
|
7ff1649d89 | ||
|
|
a39ae31b45 | ||
|
|
6302a48221 | ||
|
|
c277bee9d2 | ||
|
|
c5f5ce126d | ||
|
|
0004ae716b | ||
|
|
7f53dfac3c | ||
|
|
18003900c2 | ||
|
|
fe104791b5 | ||
|
|
6244657ca5 | ||
|
|
46866dac85 | ||
|
|
c829c073cf | ||
|
|
0772ca4036 | ||
|
|
581733d605 | ||
|
|
b02af27ac3 | ||
|
|
20af0a2ef5 | ||
|
|
c58ab5b07d | ||
|
|
e5e711c938 | ||
|
|
42594abe4e | ||
|
|
0afbdc95b4 | ||
|
|
16a74bb748 | ||
|
|
8711b476be | ||
|
|
df9fba4765 | ||
|
|
7d27139aa9 | ||
|
|
e4638d5fbc | ||
|
|
bc5854dd29 | ||
|
|
ba49d4d140 | ||
|
|
71b7dcffb5 | ||
|
|
7713e613b4 | ||
|
|
91a0aa7387 | ||
|
|
fbd6b920ef | ||
|
|
1b25d1d572 | ||
|
|
e93e72234c | ||
|
|
15d9b0ae3a | ||
|
|
550d87ac6c | ||
|
|
f8e576e890 | ||
|
|
fb8ef4d978 | ||
|
|
5127e87898 | ||
|
|
3f2d4444e4 | ||
|
|
9c7badb0eb | ||
|
|
9d9f77a731 | ||
|
|
c400ce74b1 | ||
|
|
c2e20ee4a3 | ||
|
|
ccd9034339 | ||
|
|
0a1a075f31 | ||
|
|
4aaeec9515 | ||
|
|
ea310d7508 | ||
|
|
0a2e6a0c38 | ||
|
|
f26d582018 | ||
|
|
e9a727301d | ||
|
|
d64d2f9c42 | ||
|
|
5c0d122e84 | ||
|
|
5079c853a7 | ||
|
|
b039ba12a2 | ||
|
|
3323ac6ac1 | ||
|
|
3204311ac1 | ||
|
|
0fc2ad97cd | ||
|
|
30620d0ca4 | ||
|
|
bccc22c5fe | ||
|
|
ecf2418347 | ||
|
|
0c99cb3103 | ||
|
|
034dc08269 | ||
|
|
d1a51b42f6 | ||
|
|
92bfbb2d0c | ||
|
|
91b846e2cd | ||
|
|
7fe7fb4c15 | ||
|
|
0cebd8aa4d | ||
|
|
8662c96d1c | ||
|
|
0cbc9402f3 | ||
|
|
940df02456 | ||
|
|
b4b598f542 | ||
|
|
ef19c35b5a | ||
|
|
fc98120269 | ||
|
|
b8a3d6deaf | ||
|
|
45537ede87 | ||
|
|
29a9c5bc7b | ||
|
|
7ca81285b1 | ||
|
|
49a865cdbf | ||
|
|
a0c30c35ed | ||
|
|
de20424885 | ||
|
|
f7e09ae89c | ||
|
|
c6d4600683 | ||
|
|
bd1837ee36 | ||
|
|
544b24ceb1 | ||
|
|
0825374183 | ||
|
|
b053fb8e61 | ||
|
|
ae11e80bde | ||
|
|
8e296231ba | ||
|
|
49891eff36 | ||
|
|
58df525b49 | ||
|
|
1761f43afa | ||
|
|
37d7d938c5 | ||
|
|
b7ca2310b2 | ||
|
|
c562b3969a | ||
|
|
d1d553e8d7 | ||
|
|
b6e7b258e0 | ||
|
|
c7bbe47221 | ||
|
|
347fa9e5cd | ||
|
|
07ce151508 | ||
|
|
665c9b5e52 | ||
|
|
9399a0c545 | ||
|
|
a540b12895 | ||
|
|
e29d9dcd17 | ||
|
|
1aa0d84977 | ||
|
|
7f31d7c812 | ||
|
|
4987a95d8e | ||
|
|
ef7771febb | ||
|
|
12cba0e148 | ||
|
|
c3a4052227 | ||
|
|
82f048ccef | ||
|
|
7a585a3dfb |
247 changed files with 23046 additions and 3624 deletions
1
.github/FUNDING.yml
vendored
1
.github/FUNDING.yml
vendored
|
|
@ -1,3 +1,4 @@
|
|||
# These are supported funding model platforms
|
||||
|
||||
github: wekan
|
||||
custom: ['https://wekan.fi/commercial-support/']
|
||||
|
|
|
|||
2
.github/workflows/depsreview.yaml
vendored
2
.github/workflows/depsreview.yaml
vendored
|
|
@ -9,6 +9,6 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v4
|
||||
|
|
|
|||
4
.github/workflows/docker-publish.yml
vendored
4
.github/workflows/docker-publish.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
|||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# Login against a Docker registry except on PR
|
||||
# https://github.com/docker/login-action
|
||||
|
|
@ -48,7 +48,7 @@ jobs:
|
|||
# https://github.com/docker/metadata-action
|
||||
- name: Extract Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@c1e51972afc2121e065aed6d45c65596fe445f3f
|
||||
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051
|
||||
with:
|
||||
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
|
||||
|
||||
|
|
|
|||
2
.github/workflows/dockerimage.yml
vendored
2
.github/workflows/dockerimage.yml
vendored
|
|
@ -15,6 +15,6 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
- uses: actions/checkout@v6
|
||||
- name: Build the Docker image
|
||||
run: docker build . --file Dockerfile --tag wekan:$(date +%s)
|
||||
|
|
|
|||
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
|
@ -15,7 +15,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
|
|
|
|||
20
.github/workflows/test_suite.yml
vendored
20
.github/workflows/test_suite.yml
vendored
|
|
@ -18,7 +18,7 @@ jobs:
|
|||
# runs-on: ubuntu-latest
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v5
|
||||
# uses: actions/checkout@v6
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
|
|
@ -42,7 +42,7 @@ jobs:
|
|||
# needs: [lintcode]
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v5
|
||||
# uses: actions/checkout@v6
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
|
|
@ -65,7 +65,7 @@ jobs:
|
|||
# needs: [lintcode,lintstyle]
|
||||
# steps:
|
||||
# - name: checkout
|
||||
# uses: actions/checkout@v5
|
||||
# uses: actions/checkout@v6
|
||||
#
|
||||
# - name: setup node
|
||||
# uses: actions/setup-node@v1
|
||||
|
|
@ -90,12 +90,12 @@ jobs:
|
|||
|
||||
# CHECKOUTS
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
# CACHING
|
||||
- name: Install Meteor
|
||||
id: cache-meteor-install
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.meteor
|
||||
key: v1-meteor-${{ hashFiles('.meteor/versions') }}
|
||||
|
|
@ -104,7 +104,7 @@ jobs:
|
|||
|
||||
- name: Cache NPM dependencies
|
||||
id: cache-meteor-npm
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: ~/.npm
|
||||
key: v1-npm-${{ hashFiles('package-lock.json') }}
|
||||
|
|
@ -113,7 +113,7 @@ jobs:
|
|||
|
||||
- name: Cache Meteor build
|
||||
id: cache-meteor-build
|
||||
uses: actions/cache@v4
|
||||
uses: actions/cache@v5
|
||||
with:
|
||||
path: |
|
||||
.meteor/local/resolver-result-cache.json
|
||||
|
|
@ -136,7 +136,7 @@ jobs:
|
|||
run: sh ./test-wekan.sh -cv
|
||||
|
||||
- name: Upload coverage
|
||||
uses: actions/upload-artifact@v4
|
||||
uses: actions/upload-artifact@v6
|
||||
with:
|
||||
name: coverage-folder
|
||||
path: .coverage/
|
||||
|
|
@ -147,10 +147,10 @@ jobs:
|
|||
needs: [tests]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v5
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Download coverage
|
||||
uses: actions/download-artifact@v5
|
||||
uses: actions/download-artifact@v7
|
||||
with:
|
||||
name: coverage-folder
|
||||
path: .coverage/
|
||||
|
|
|
|||
162
CHANGELOG.md
162
CHANGELOG.md
|
|
@ -22,6 +22,168 @@ 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.
|
||||
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
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
||||
- [Fix Admin Panel / People editing and layout](https://github.com/wekan/wekan/commit/7a585a3dfb080af51f88669ea5928f715779cee4).
|
||||
Thanks to xet7.
|
||||
- [Fix upgrade to 8.08 duplicates lists](https://github.com/wekan/wekan/commit/c3a405222782a4a91eb8725faaa8309f0926dcc4).
|
||||
Thanks to xet7.
|
||||
|
||||
Thanks to above GitHub users for their contributions and translators for their translations.
|
||||
|
||||
# v8.08 2025-10-21 WeKan ® release
|
||||
|
||||
This release fixes the following bugs:
|
||||
|
|
|
|||
|
|
@ -249,9 +249,9 @@ cd /home/wekan/app
|
|||
# Remove legacy webbroser bundle, so that Wekan works also at Android Firefox, iOS Safari, etc.
|
||||
#rm -rf /home/wekan/app_build/bundle/programs/web.browser.legacy
|
||||
#mv /home/wekan/app_build/bundle /build
|
||||
wget "https://github.com/wekan/wekan/releases/download/v8.08/wekan-8.08-amd64.zip"
|
||||
unzip wekan-8.08-amd64.zip
|
||||
rm wekan-8.08-amd64.zip
|
||||
wget "https://github.com/wekan/wekan/releases/download/v8.17/wekan-8.17-amd64.zip"
|
||||
unzip wekan-8.17-amd64.zip
|
||||
rm wekan-8.17-amd64.zip
|
||||
mv /home/wekan/app/bundle /build
|
||||
|
||||
# Put back the original tar
|
||||
|
|
|
|||
87
SECURITY.md
87
SECURITY.md
|
|
@ -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
|
||||
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.
|
||||
## Responsible Security Disclosure
|
||||
|
||||
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?
|
||||
|
||||
|
|
@ -26,7 +34,7 @@ CWSS (optional): %cwss
|
|||
|
||||
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
|
||||
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?
|
||||
|
||||
|
|
@ -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
|
||||
- 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.
|
||||
- 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
|
||||
|
||||
|
|
@ -172,6 +175,57 @@ Meteor.startup(() => {
|
|||
- https://github.com/wekan/wekan/blob/main/client/components/cards/attachments.js#L303-L312
|
||||
- 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
|
||||
|
||||
- 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.
|
||||
|
||||
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
|
||||
|
||||
## 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).
|
||||
We welcome all fixes to improve security by email to security@wekan.fi
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
|
||||
appVersion: "v8.08.0"
|
||||
appVersion: "v8.17.0"
|
||||
files:
|
||||
userUploads:
|
||||
- README.md
|
||||
|
|
|
|||
|
|
@ -15,3 +15,50 @@ import '/client/components/migrationProgress';
|
|||
|
||||
// Import cron settings
|
||||
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();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -269,57 +269,71 @@
|
|||
}
|
||||
/* Mobile view styles - applied when isMiniScreen is true (iPhone, etc.) */
|
||||
.board-wrapper.mobile-view {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.board-wrapper.mobile-view .board-canvas {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.board-wrapper.mobile-view .board-canvas.mobile-view .swimlane {
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: flex;
|
||||
display: block !important;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 800px),
|
||||
screen and (max-device-width: 932px) and (-webkit-min-device-pixel-ratio: 3) {
|
||||
.board-wrapper {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas {
|
||||
width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
left: 0 !important;
|
||||
right: 0 !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.board-wrapper .board-canvas .swimlane {
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: flex;
|
||||
display: block !important;
|
||||
flex-direction: column;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
overflow-x: hidden;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
}
|
||||
}
|
||||
.calendar-event-green {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import dragscroll from '@wekanteam/dragscroll';
|
|||
import { boardConverter } from '/client/lib/boardConverter';
|
||||
import { migrationManager } from '/client/lib/migrationManager';
|
||||
import { attachmentMigrationManager } from '/client/lib/attachmentMigrationManager';
|
||||
import { migrationProgressManager } from '/client/components/migrationProgress';
|
||||
import Swimlanes from '/models/swimlanes';
|
||||
import Lists from '/models/lists';
|
||||
|
||||
|
|
@ -17,6 +18,8 @@ BlazeComponent.extendComponent({
|
|||
this.isConverting = new ReactiveVar(false);
|
||||
this.isMigrating = new ReactiveVar(false);
|
||||
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:
|
||||
// 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);
|
||||
|
||||
Tracker.nonreactive(() => {
|
||||
Tracker.autorun(() => {
|
||||
if (handle.ready()) {
|
||||
// Use a separate autorun for subscription ready state to avoid reactive loops
|
||||
this.subscriptionReadyAutorun = Tracker.autorun(() => {
|
||||
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)
|
||||
this.ensureDefaultSwimlane(currentBoardId);
|
||||
// Check if board needs conversion
|
||||
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) {
|
||||
// Only create swimlane once per board
|
||||
if (this._swimlaneCreated.has(boardId)) {
|
||||
|
|
@ -56,10 +71,17 @@ BlazeComponent.extendComponent({
|
|||
const swimlanes = board.swimlanes();
|
||||
|
||||
if (swimlanes.length === 0) {
|
||||
const swimlaneId = Swimlanes.insert({
|
||||
title: 'Default',
|
||||
boardId: boardId,
|
||||
});
|
||||
// Check if any swimlane exists in the database to avoid race conditions
|
||||
const existingSwimlanes = ReactiveCache.getSwimlanes({ 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);
|
||||
} else {
|
||||
this._swimlaneCreated.add(boardId);
|
||||
|
|
@ -77,49 +99,10 @@ BlazeComponent.extendComponent({
|
|||
return;
|
||||
}
|
||||
|
||||
// Check if board needs migration based on migration version
|
||||
const needsMigration = !board.migrationVersion || board.migrationVersion < 1;
|
||||
|
||||
if (needsMigration) {
|
||||
// Start background migration for old boards
|
||||
this.isMigrating.set(true);
|
||||
await this.startBackgroundMigration(boardId);
|
||||
this.isMigrating.set(false);
|
||||
}
|
||||
// Automatic migration disabled - migrations must be run manually from sidebar
|
||||
// Board admins can run migrations from the sidebar Migrations menu
|
||||
this.isBoardReady.set(true);
|
||||
|
||||
// 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) {
|
||||
console.error('Error during board conversion check:', error);
|
||||
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) {
|
||||
try {
|
||||
// Start background migration using the cron system
|
||||
|
|
@ -177,7 +290,7 @@ BlazeComponent.extendComponent({
|
|||
console.log(`Board ${boardId} has no shared lists to convert`);
|
||||
}
|
||||
// Mark as processed even if no shared lists
|
||||
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } });
|
||||
Boards.update(boardId, { $set: { hasSharedListsConverted: true } });
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -197,38 +310,59 @@ BlazeComponent.extendComponent({
|
|||
});
|
||||
|
||||
if (!existingList) {
|
||||
// Create a new list in this swimlane
|
||||
const newListData = {
|
||||
title: sharedList.title,
|
||||
// Double-check to avoid race conditions
|
||||
const doubleCheckList = ReactiveCache.getList({
|
||||
boardId: boardId,
|
||||
swimlaneId: swimlane._id,
|
||||
sort: sharedList.sort || 0,
|
||||
archived: sharedList.archived || false,
|
||||
createdAt: new Date(),
|
||||
modifiedAt: new Date()
|
||||
};
|
||||
title: sharedList.title
|
||||
});
|
||||
|
||||
// Copy other properties if they exist
|
||||
if (sharedList.color) newListData.color = sharedList.color;
|
||||
if (sharedList.wipLimit) newListData.wipLimit = sharedList.wipLimit;
|
||||
if (sharedList.wipLimitEnabled) newListData.wipLimitEnabled = sharedList.wipLimitEnabled;
|
||||
if (sharedList.wipLimitSoft) newListData.wipLimitSoft = sharedList.wipLimitSoft;
|
||||
if (!doubleCheckList) {
|
||||
// Create a new list in this swimlane
|
||||
const newListData = {
|
||||
title: sharedList.title,
|
||||
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 (sharedList.wipLimit) newListData.wipLimit = sharedList.wipLimit;
|
||||
if (sharedList.wipLimitEnabled) newListData.wipLimitEnabled = sharedList.wipLimitEnabled;
|
||||
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 {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`List "${sharedList.title}" already exists in swimlane ${swimlane.title || swimlane._id}, skipping`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Archive or remove the original shared list
|
||||
Lists.update(sharedList._id, {
|
||||
$set: {
|
||||
archived: true,
|
||||
modifiedAt: new Date()
|
||||
}
|
||||
});
|
||||
// Remove the original shared list completely
|
||||
Lists.remove(sharedList._id);
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Removed shared list "${sharedList.title}"`);
|
||||
}
|
||||
}
|
||||
|
||||
// Mark board as processed
|
||||
Meteor.call('boards.update', boardId, { $set: { hasSharedListsConverted: true } });
|
||||
Boards.update(boardId, { $set: { hasSharedListsConverted: true } });
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(`Successfully converted ${sharedLists.length} shared lists to per-swimlane lists for board ${boardId}`);
|
||||
|
|
@ -286,7 +420,9 @@ BlazeComponent.extendComponent({
|
|||
});
|
||||
|
||||
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) {
|
||||
|
|
@ -294,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) {
|
||||
try {
|
||||
// Check if board has already been migrated
|
||||
|
|
@ -359,39 +544,50 @@ BlazeComponent.extendComponent({
|
|||
this._isDragging = false;
|
||||
// Used to set the overlay
|
||||
this.mouseHasEnterCardDetails = false;
|
||||
this._sortFieldsFixed = new Set(); // Track which boards have had sort fields fixed
|
||||
|
||||
// fix swimlanes sort field if there are null values
|
||||
const currentBoardData = Utils.getCurrentBoard();
|
||||
if (currentBoardData && Swimlanes) {
|
||||
const nullSortSwimlanes = currentBoardData.nullSortSwimlanes();
|
||||
if (nullSortSwimlanes.length > 0) {
|
||||
const swimlanes = currentBoardData.swimlanes();
|
||||
let count = 0;
|
||||
swimlanes.forEach(s => {
|
||||
Swimlanes.update(s._id, {
|
||||
$set: {
|
||||
sort: count,
|
||||
},
|
||||
const boardId = currentBoardData._id;
|
||||
// Only fix sort fields once per board to prevent reactive loops
|
||||
if (!this._sortFieldsFixed.has(`swimlanes-${boardId}`)) {
|
||||
const nullSortSwimlanes = currentBoardData.nullSortSwimlanes();
|
||||
if (nullSortSwimlanes.length > 0) {
|
||||
const swimlanes = currentBoardData.swimlanes();
|
||||
let count = 0;
|
||||
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
|
||||
if (currentBoardData && Lists) {
|
||||
const nullSortLists = currentBoardData.nullSortLists();
|
||||
if (nullSortLists.length > 0) {
|
||||
const lists = currentBoardData.lists();
|
||||
let count = 0;
|
||||
lists.forEach(l => {
|
||||
Lists.update(l._id, {
|
||||
$set: {
|
||||
sort: count,
|
||||
},
|
||||
const boardId = currentBoardData._id;
|
||||
// Only fix sort fields once per board to prevent reactive loops
|
||||
if (!this._sortFieldsFixed.has(`lists-${boardId}`)) {
|
||||
const nullSortLists = currentBoardData.nullSortLists();
|
||||
if (nullSortLists.length > 0) {
|
||||
const lists = currentBoardData.lists();
|
||||
let count = 0;
|
||||
lists.forEach(l => {
|
||||
Lists.update(l._id, {
|
||||
$set: {
|
||||
sort: count,
|
||||
},
|
||||
});
|
||||
count += 1;
|
||||
});
|
||||
count += 1;
|
||||
});
|
||||
}
|
||||
this._sortFieldsFixed.add(`lists-${boardId}`);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1175,9 +1371,13 @@ BlazeComponent.extendComponent({
|
|||
const firstSwimlane = currentBoard.swimlanes()[0];
|
||||
Meteor.call('createCardWithDueDate', currentBoard._id, firstList._id, myTitle, startDate.toDate(), firstSwimlane._id, function(error, result) {
|
||||
if (error) {
|
||||
console.log(error);
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log(error);
|
||||
}
|
||||
} else {
|
||||
console.log("Card Created", result);
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log("Card Created", result);
|
||||
}
|
||||
}
|
||||
});
|
||||
closeModal();
|
||||
|
|
|
|||
|
|
@ -505,73 +505,73 @@
|
|||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
}
|
||||
.mobile-mode .swimlane {
|
||||
display: block !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane .swimlane-header {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 1rem 0 !important;
|
||||
padding: 1rem !important;
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
}
|
||||
.mobile-mode .swimlane .swimlane-header {
|
||||
display: block !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
margin: 0 0 1rem 0 !important;
|
||||
padding: 1rem !important;
|
||||
font-size: clamp(18px, 2.5vw, 32px) !important;
|
||||
font-weight: bold !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
}
|
||||
|
||||
.mobile-mode .swimlane .lists {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
.mobile-mode .swimlane .lists {
|
||||
display: block !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
flex-direction: column !important;
|
||||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list {
|
||||
display: block !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
flex-basis: auto !important;
|
||||
flex-grow: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
bottom: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
.mobile-mode .list {
|
||||
display: block !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
margin: 0 0 2rem 0 !important;
|
||||
padding: 0 !important;
|
||||
float: none !important;
|
||||
clear: both !important;
|
||||
border-left: none !important;
|
||||
border-right: none !important;
|
||||
border-top: none !important;
|
||||
border-bottom: 2px solid #ccc !important;
|
||||
flex: none !important;
|
||||
flex-basis: auto !important;
|
||||
flex-grow: 0 !important;
|
||||
flex-shrink: 0 !important;
|
||||
position: static !important;
|
||||
left: auto !important;
|
||||
right: auto !important;
|
||||
top: auto !important;
|
||||
bottom: auto !important;
|
||||
transform: none !important;
|
||||
}
|
||||
|
||||
.mobile-mode .list:first-child {
|
||||
margin-left: 0 !important;
|
||||
|
|
@ -667,9 +667,9 @@
|
|||
flex-wrap: nowrap !important;
|
||||
align-items: stretch !important;
|
||||
justify-content: flex-start !important;
|
||||
width: 100% !important;
|
||||
max-width: 100% !important;
|
||||
min-width: 100% !important;
|
||||
width: 100vw !important;
|
||||
max-width: 100vw !important;
|
||||
min-width: 100vw !important;
|
||||
overflow-x: hidden !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.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(
|
||||
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
|
||||
title="{{_ currentBoard.permission}}")
|
||||
|
|
@ -38,6 +31,13 @@ template(name="boardHeaderBar")
|
|||
if $eq watchLevel "muted"
|
||||
| 🔕
|
||||
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}}")
|
||||
| {{sortCardsIcon}}
|
||||
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.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(
|
||||
class="{{#if currentUser.isBoardAdmin}}js-change-visibility{{else}}is-disabled{{/if}}"
|
||||
title="{{_ currentBoard.permission}}")
|
||||
|
|
@ -78,6 +74,11 @@ template(name="boardHeaderBar")
|
|||
| 🔔
|
||||
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}}")
|
||||
| {{sortCardsIcon}}
|
||||
if isSortActive
|
||||
|
|
@ -266,6 +267,36 @@ template(name="createBoardPopup")
|
|||
| /
|
||||
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")
|
||||
// h2
|
||||
// | {{_ 'list-sort-by'}}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,10 @@ BlazeComponent.extendComponent({
|
|||
{
|
||||
'click .js-edit-board-title': Popup.open('boardChangeTitle'),
|
||||
'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-change-visibility': Popup.open('boardChangeVisibility'),
|
||||
|
|
@ -82,18 +85,26 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
'click .js-toggle-board-view': Popup.open('boardChangeView'),
|
||||
'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
|
||||
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();
|
||||
} 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
|
||||
if (typeof Blaze !== 'undefined' && Blaze._globalHelpers && Blaze._globalHelpers.Sidebar) {
|
||||
const sidebar = Blaze._globalHelpers.Sidebar();
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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());
|
||||
|
||||
} else {
|
||||
|
|
@ -301,6 +321,15 @@ const CreateBoard = BlazeComponent.extendComponent({
|
|||
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());
|
||||
}
|
||||
},
|
||||
|
|
@ -322,6 +351,13 @@ const CreateBoard = BlazeComponent.extendComponent({
|
|||
},
|
||||
}).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 {
|
||||
onSubmit(event) {
|
||||
super.onSubmit(event);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,273 @@
|
|||
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 {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
|
@ -106,23 +373,35 @@
|
|||
.board-list li.starred .is-star-active,
|
||||
.board-list li.starred .is-not-star-active {
|
||||
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 {
|
||||
overflow: hidden;
|
||||
background-color: #999;
|
||||
background-color: inherit; /* Inherit board color from parent li.js-board */
|
||||
color: #f6f6f6;
|
||||
min-height: 100px;
|
||||
font-size: 16px;
|
||||
line-height: 22px;
|
||||
border-radius: 3px;
|
||||
border-radius: 0; /* No border-radius - parent .js-board has it */
|
||||
display: block;
|
||||
font-weight: 700;
|
||||
padding: 8px;
|
||||
margin: 8px;
|
||||
padding: 36px 8px 32px 8px; /* Top padding for drag handle, bottom for checkbox */
|
||||
margin: 0; /* No margin - moved to parent .js-board */
|
||||
position: relative;
|
||||
text-decoration: none;
|
||||
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 {
|
||||
border: 4px solid #fff;
|
||||
}
|
||||
|
|
@ -150,13 +429,20 @@
|
|||
.board-list .js-add-board .label {
|
||||
font-weight: normal;
|
||||
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 {
|
||||
background-color: #939393;
|
||||
.board-list .js-add-board .label:hover {
|
||||
background-color: #808080; /* Even darker on hover */
|
||||
}
|
||||
.board-list .is-star-active,
|
||||
.board-list .is-not-star-active {
|
||||
bottom: 0;
|
||||
top: 0;
|
||||
font-size: 14px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
|
|
@ -164,7 +450,6 @@
|
|||
padding: 9px 9px;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transition-duration: 0.15s;
|
||||
transition-property: color, font-size, background;
|
||||
}
|
||||
|
|
@ -238,6 +523,95 @@
|
|||
.board-list li:hover a .is-not-star-active {
|
||||
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 {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
|
|
@ -739,9 +1113,62 @@
|
|||
#resetBtn {
|
||||
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 {
|
||||
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 {
|
||||
padding: 6px 0 6px 8px;
|
||||
width: 100%;
|
||||
|
|
|
|||
|
|
@ -2,151 +2,160 @@ template(name="boardList")
|
|||
.wrapper
|
||||
.board-list-header
|
||||
|
||||
ul.AllBoardTeamsOrgs
|
||||
li.AllBoardTeams
|
||||
if userHasTeams
|
||||
select.js-AllBoardTeams#jsAllBoardTeams("multiple")
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each teamsDatas
|
||||
option(value="{{teamId}}") {{_ teamDisplayName}}
|
||||
.boards-layout
|
||||
// Left menu
|
||||
.boards-left-menu
|
||||
ul.menu
|
||||
li(class="menu-item {{#if isSelectedMenu 'starred'}}active{{/if}}")
|
||||
a.js-select-menu(data-type="starred")
|
||||
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
|
||||
if userHasOrgs
|
||||
select.js-AllBoardOrgs#jsAllBoardOrgs("multiple")
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each orgsDatas
|
||||
option(value="{{orgId}}") {{orgDisplayName}}
|
||||
// Existing filter by orgs/teams (kept)
|
||||
ul.AllBoardTeamsOrgs
|
||||
li.AllBoardTeams
|
||||
if userHasTeams
|
||||
select.js-AllBoardTeams#jsAllBoardTeams("multiple")
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each teamsDatas
|
||||
option(value="{{teamId}}") {{_ teamDisplayName}}
|
||||
|
||||
//li.AllBoardTemplates
|
||||
// if userHasTemplates
|
||||
// select.js-AllBoardTemplates#jsAllBoardTemplates("multiple")
|
||||
// option(value="-1") {{_ 'templates'}} :
|
||||
// each templatesDatas
|
||||
// option(value="{{templateId}}") {{_ templateDisplayName}}
|
||||
li.AllBoardOrgs
|
||||
if userHasOrgs
|
||||
select.js-AllBoardOrgs#jsAllBoardOrgs("multiple")
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each orgsDatas
|
||||
option(value="{{orgId}}") {{orgDisplayName}}
|
||||
|
||||
li.AllBoardBtns
|
||||
div.AllBoardButtonsContainer
|
||||
if userHasOrgsOrTeams
|
||||
i.fa.fa-filter
|
||||
input#filterBtn(type="button" value="{{_ 'filter'}}")
|
||||
input#resetBtn(type="button" value="{{_ 'filter-clear'}}")
|
||||
li.AllBoardBtns
|
||||
div.AllBoardButtonsContainer
|
||||
if userHasOrgsOrTeams
|
||||
span 🔍
|
||||
input#filterBtn(type="button" value="{{_ 'filter'}}")
|
||||
button#resetBtn.filter-reset-btn
|
||||
span.reset-icon ❌
|
||||
span {{_ 'filter-clear'}}
|
||||
|
||||
ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
li.js-add-board
|
||||
a.board-list-item.label(title="{{_ 'add-board'}}")
|
||||
| {{_ 'add-board'}}
|
||||
each boards
|
||||
li(class="{{_id}}" class="{{#if isStarred}}starred{{/if}}" class=colorClass).js-board
|
||||
if isInvited
|
||||
.board-list-item
|
||||
span.details
|
||||
span.board-list-item-name= title
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
p.board-list-item-desc {{_ 'just-invited'}}
|
||||
button.js-accept-invite.primary {{_ 'accept'}}
|
||||
button.js-decline-invite {{_ 'decline'}}
|
||||
else
|
||||
if $eq type "template-container"
|
||||
a.js-open-board.template-container.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'template-container'}}")
|
||||
+viewer
|
||||
= title
|
||||
i.fa.js-star-board(
|
||||
class="fa-star{{#if isStarred}} is-star-active{{else}}-o{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
p.board-list-item-desc
|
||||
+viewer
|
||||
= description
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
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'}}")
|
||||
// Right boards grid
|
||||
.boards-right-grid
|
||||
.boards-path-header
|
||||
.path-left
|
||||
span.path-icon {{currentMenuPath.icon}}
|
||||
span.path-text {{currentMenuPath.text}}
|
||||
if BoardMultiSelection.isActive
|
||||
span.multiselection-hint 📌 {{_ 'multi-selection-active'}}
|
||||
.path-right
|
||||
if canModifyBoards
|
||||
if hasBoardsSelected
|
||||
button.js-archive-selected-boards.board-header-btn
|
||||
span 📦
|
||||
span {{_ 'archive-board'}}
|
||||
button.js-duplicate-selected-boards.board-header-btn
|
||||
span 📋
|
||||
span {{_ 'duplicate-board'}}
|
||||
a.board-header-btn.js-multiselection-activate(
|
||||
title="{{#if BoardMultiSelection.isActive}}{{_ 'multi-selection-on'}}{{else}}{{_ 'multi-selection'}}{{/if}}"
|
||||
class="{{#if BoardMultiSelection.isActive}}emphasis{{/if}}")
|
||||
| ☑️
|
||||
if BoardMultiSelection.isActive
|
||||
a.board-header-btn-close.js-multiselection-reset(title="{{_ 'filter-clear'}}")
|
||||
| ✖
|
||||
ul.board-list.clearfix.js-boards(class="{{#if isMiniScreen}}mobile-view{{/if}} {{#if BoardMultiSelection.isActive}}is-multiselection-active{{/if}}")
|
||||
li.js-add-board
|
||||
if isSelectedMenu 'templates'
|
||||
a.board-list-item.label(title="{{_ 'add-template-container'}}")
|
||||
| ➕ {{_ 'add-template-container'}}
|
||||
else
|
||||
a.js-open-board.board-list-item(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}")
|
||||
+viewer
|
||||
= title
|
||||
unless currentSetting.hideBoardMemberList
|
||||
if allowsBoardMemberList
|
||||
.minicard-members
|
||||
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 }}
|
||||
a.js-star-board(
|
||||
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
| {{#if isStarred}}⭐{{else}}☆{{/if}}
|
||||
p.board-list-item-desc
|
||||
+viewer
|
||||
= description
|
||||
if hasSpentTimeCards
|
||||
i.fa.js-has-spenttime-cards(
|
||||
class="fa-circle{{#if hasOvertimeCards}} has-overtime-card-active{{else}} no-overtime-card-active{{/if}}"
|
||||
title="{{#if hasOvertimeCards}}{{_ 'has-overtime-cards'}}{{else}}{{_ 'has-spenttime-cards'}}{{/if}}")
|
||||
i.fa.board-handle(
|
||||
class="fa-arrows"
|
||||
title="{{_ 'drag-board'}}")
|
||||
if isSandstorm
|
||||
a.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
| 📋
|
||||
a.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
| 📦
|
||||
else if isAdministrable
|
||||
a.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
| 📋
|
||||
a.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
| 📦
|
||||
else if currentUser.isAdmin
|
||||
a.js-clone-board(
|
||||
class="fa-clone"
|
||||
title="{{_ 'duplicate-board'}}")
|
||||
| 📋
|
||||
a.js-archive-board(
|
||||
class="fa-archive"
|
||||
title="{{_ 'archive-board'}}")
|
||||
| 📦
|
||||
a.board-list-item.label(title="{{_ 'add-board'}}")
|
||||
| ➕ {{_ 'add-board'}}
|
||||
each boards
|
||||
li.js-board(class="{{_id}} {{#if isStarred}}starred{{/if}} {{colorClass}} {{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}", draggable="true")
|
||||
if isInvited
|
||||
.board-list-item
|
||||
if BoardMultiSelection.isActive
|
||||
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
|
||||
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
|
||||
span.details
|
||||
span.board-list-item-name= title
|
||||
span.js-star-board(
|
||||
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
| {{#if isStarred}}⭐{{else}}☆{{/if}}
|
||||
p.board-list-item-desc {{_ 'just-invited'}}
|
||||
button.js-accept-invite.primary {{_ 'accept'}}
|
||||
button.js-decline-invite {{_ 'decline'}}
|
||||
else
|
||||
if $eq type "template-container"
|
||||
.template-container.board-list-item
|
||||
if BoardMultiSelection.isActive
|
||||
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
|
||||
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
|
||||
span.board-handle(title="{{_ 'drag-board'}}") ↕️
|
||||
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'template-container'}}")
|
||||
+viewer
|
||||
= title
|
||||
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}}")
|
||||
| ⏱️
|
||||
span.js-star-board(
|
||||
class="{{#if isStarred}}is-star-active{{else}}is-not-star-active{{/if}}"
|
||||
title="{{_ 'star-board-title'}}")
|
||||
| {{#if isStarred}}⭐{{else}}☆{{/if}}
|
||||
else
|
||||
.board-list-item
|
||||
if BoardMultiSelection.isActive
|
||||
.materialCheckBox.multi-selection-checkbox.js-toggle-board-multi-selection(
|
||||
class="{{#if BoardMultiSelection.isSelected _id}}is-checked{{/if}}")
|
||||
span.board-handle(title="{{_ 'drag-board'}}") ↕️
|
||||
a.js-open-board(href="{{pathFor 'board' id=_id slug=slug}}")
|
||||
span.details
|
||||
span.board-list-item-name(title="{{_ 'board-drag-drop-reorder-or-click-open'}}")
|
||||
+viewer
|
||||
= title
|
||||
unless currentSetting.hideBoardMemberList
|
||||
if allowsBoardMemberList
|
||||
.minicard-members
|
||||
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")
|
||||
h1 {{_ title }}
|
||||
|
|
@ -157,3 +166,25 @@ template(name="boardListHeaderBar")
|
|||
// a.board-header-btn(href="{{pathFor 'board' id=templatesBoardId slug=templatesBoardSlug}}")
|
||||
// i.fa.fa-clone
|
||||
// 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)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,9 @@ Template.boardList.helpers({
|
|||
return Utils.isMiniScreen() && Session.get('currentBoard'); */
|
||||
return true;
|
||||
},
|
||||
BoardMultiSelection() {
|
||||
return BoardMultiSelection;
|
||||
},
|
||||
})
|
||||
|
||||
Template.boardListHeaderBar.events({
|
||||
|
|
@ -45,6 +48,9 @@ BlazeComponent.extendComponent({
|
|||
onCreated() {
|
||||
Meteor.subscribe('setting');
|
||||
Meteor.subscribe('tableVisibilityModeSettings');
|
||||
this.selectedMenu = new ReactiveVar('starred');
|
||||
this.selectedWorkspaceIdVar = new ReactiveVar(null);
|
||||
this.workspacesTreeVar = new ReactiveVar([]);
|
||||
let currUser = ReactiveCache.getCurrentUser();
|
||||
let userLanguage;
|
||||
if (currUser && currUser.profile) {
|
||||
|
|
@ -53,9 +59,72 @@ BlazeComponent.extendComponent({
|
|||
if (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() {
|
||||
// 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 $boards = this.$('.js-boards');
|
||||
|
|
@ -73,27 +142,20 @@ BlazeComponent.extendComponent({
|
|||
EscapeActions.executeUpTo('popup-close');
|
||||
},
|
||||
stop(evt, ui) {
|
||||
// To attribute the new index number, we need to get the DOM element
|
||||
// of the previous and the following card -- if any.
|
||||
const prevBoardDom = ui.item.prev('.js-board').get(0);
|
||||
const nextBoardBom = ui.item.next('.js-board').get(0);
|
||||
const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardBom, 1);
|
||||
const nextBoardDom = ui.item.next('.js-board').get(0);
|
||||
const sortIndex = Utils.calculateIndex(prevBoardDom, nextBoardDom, 1);
|
||||
|
||||
const boardDomElement = ui.item.get(0);
|
||||
const board = Blaze.getData(boardDomElement);
|
||||
// Normally the jquery-ui sortable library moves the dragged DOM element
|
||||
// to its new position, which disrupts Blaze reactive updates mechanism
|
||||
// (especially when we move the last card of a list, or when multiple
|
||||
// users move some cards at the same time). To prevent these UX glitches
|
||||
// we ask sortable to gracefully cancel the move, and to put back the
|
||||
// DOM in its initial state. The card move is then handled reactively by
|
||||
// Blaze with the below query.
|
||||
$boards.sortable('cancel');
|
||||
board.move(sortIndex.base);
|
||||
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(() => {
|
||||
if (Utils.isTouchScreenOrShowDesktopDragHandles()) {
|
||||
$boards.sortable({
|
||||
|
|
@ -101,6 +163,7 @@ BlazeComponent.extendComponent({
|
|||
});
|
||||
}
|
||||
});
|
||||
*/
|
||||
},
|
||||
userHasTeams() {
|
||||
if (ReactiveCache.getCurrentUser()?.teams?.length > 0)
|
||||
|
|
@ -132,6 +195,41 @@ BlazeComponent.extendComponent({
|
|||
const ret = this.userHasOrgs() || this.userHasTeams();
|
||||
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() {
|
||||
let query = {
|
||||
// { type: 'board' },
|
||||
|
|
@ -184,10 +282,33 @@ BlazeComponent.extendComponent({
|
|||
};
|
||||
}
|
||||
|
||||
const ret = ReactiveCache.getBoards(query, {
|
||||
sort: { sort: 1 /* boards default sorting */ },
|
||||
});
|
||||
return ret;
|
||||
const boards = ReactiveCache.getBoards(query, {});
|
||||
const currentUser = ReactiveCache.getCurrentUser();
|
||||
let list = boards;
|
||||
// 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) {
|
||||
/* Bug Board icons random dance https://github.com/wekan/wekan/issues/4214
|
||||
|
|
@ -235,11 +356,65 @@ BlazeComponent.extendComponent({
|
|||
events() {
|
||||
return [
|
||||
{
|
||||
'click .js-add-board': Popup.open('createBoard'),
|
||||
'click .js-star-board'(evt) {
|
||||
const boardId = this.currentData()._id;
|
||||
ReactiveCache.getCurrentUser().toggleBoardStar(boardId);
|
||||
'click .js-select-menu'(evt) {
|
||||
const type = evt.currentTarget.getAttribute('data-type');
|
||||
this.selectedWorkspaceIdVar.set(null);
|
||||
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();
|
||||
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) {
|
||||
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) {
|
||||
let allBoards = document.getElementsByClassName("js-board");
|
||||
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');
|
||||
|
|
|
|||
|
|
@ -8,39 +8,72 @@
|
|||
.card-date.is-active {
|
||||
background-color: #b3b3b3;
|
||||
}
|
||||
.card-date.current,
|
||||
.card-date.almost-due,
|
||||
.card-date.due,
|
||||
.card-date.long-overdue {
|
||||
/* Date status colors - red = overdue, amber = due soon, no shade = not due */
|
||||
.card-date.overdue {
|
||||
background-color: #ff4444; /* Red for overdue */
|
||||
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 {
|
||||
background-color: #5ba639;
|
||||
background-color: #5ba639; /* Green for current/active */
|
||||
color: #fff;
|
||||
}
|
||||
.card-date.current:hover,
|
||||
.card-date.current.is-active {
|
||||
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.almost-due.is-active {
|
||||
background-color: #bc9f07;
|
||||
.card-date.completed:hover,
|
||||
.card-date.completed.is-active {
|
||||
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.due.is-active {
|
||||
background-color: #c73200;
|
||||
.card-date.completed-early:hover,
|
||||
.card-date.completed-early.is-active {
|
||||
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.long-overdue.is-active {
|
||||
background-color: #fd3e24;
|
||||
.card-date.completed-late:hover,
|
||||
.card-date.completed-late.is-active {
|
||||
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 */
|
||||
|
|
|
|||
|
|
@ -97,6 +97,12 @@ template(name="minicardCustomFieldDate")
|
|||
template(name="editCardReceivedDatePopup")
|
||||
form.edit-card-received-date
|
||||
.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
|
||||
a.js-clear-date {{_ 'clear'}}
|
||||
.datepicker-actions
|
||||
|
|
@ -106,6 +112,11 @@ template(name="editCardReceivedDatePopup")
|
|||
template(name="editCardStartDatePopup")
|
||||
form.edit-card-start-date
|
||||
.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
|
||||
a.js-clear-date {{_ 'clear'}}
|
||||
.datepicker-actions
|
||||
|
|
@ -115,6 +126,11 @@ template(name="editCardStartDatePopup")
|
|||
template(name="editCardDueDatePopup")
|
||||
form.edit-card-due-date
|
||||
.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
|
||||
a.js-clear-date {{_ 'clear'}}
|
||||
.datepicker-actions
|
||||
|
|
@ -124,6 +140,11 @@ template(name="editCardDueDatePopup")
|
|||
template(name="editCardEndDatePopup")
|
||||
form.edit-card-end-date
|
||||
.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
|
||||
a.js-clear-date {{_ 'clear'}}
|
||||
.datepicker-actions
|
||||
|
|
|
|||
|
|
@ -50,6 +50,17 @@ import {
|
|||
onRendered() {
|
||||
super.onRendered();
|
||||
// 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) {
|
||||
|
|
@ -157,14 +168,18 @@ class CardReceivedDate extends CardDate {
|
|||
const endAt = this.data().getEnd();
|
||||
const startAt = this.data().getStart();
|
||||
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 (
|
||||
(startAt && isAfter(theDate, startAt)) ||
|
||||
(endAt && isAfter(theDate, endAt)) ||
|
||||
(dueAt && isAfter(theDate, dueAt))
|
||||
)
|
||||
classes += 'long-overdue';
|
||||
else classes += 'current';
|
||||
) {
|
||||
classes += 'overdue';
|
||||
} else {
|
||||
classes += 'not-due';
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
|
|
@ -193,16 +208,22 @@ class CardStartDate extends CardDate {
|
|||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'start-date' + ' ';
|
||||
let classes = 'start-date ';
|
||||
const dueAt = this.data().getDue();
|
||||
const endAt = this.data().getEnd();
|
||||
const theDate = this.date.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)))
|
||||
classes += 'long-overdue';
|
||||
else if (isAfter(theDate, now)) classes += '';
|
||||
else classes += 'current';
|
||||
|
||||
// Start date logic: if start date is after due or end dates, it's overdue
|
||||
if ((endAt && isAfter(theDate, endAt)) || (dueAt && isAfter(theDate, dueAt))) {
|
||||
classes += 'overdue';
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
|
@ -231,17 +252,35 @@ class CardDueDate extends CardDate {
|
|||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'due-date' + ' ';
|
||||
let classes = 'due-date ';
|
||||
const endAt = this.data().getEnd();
|
||||
const theDate = this.date.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 is an end date, don't need to flag the due date
|
||||
else if (endAt) classes += '';
|
||||
else if (diff(now, theDate, 'days') >= 2) classes += 'long-overdue';
|
||||
else if (diff(now, theDate, 'minute') >= 0) classes += 'due';
|
||||
else if (diff(now, theDate, 'days') >= -1) classes += 'almost-due';
|
||||
|
||||
// If there's an end date and it's before the due date, task is completed early
|
||||
if (endAt && isBefore(endAt, theDate)) {
|
||||
classes += 'completed-early';
|
||||
}
|
||||
// If there's an end date, don't show due date status since task is completed
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
@ -270,12 +309,23 @@ class CardEndDate extends CardDate {
|
|||
}
|
||||
|
||||
classes() {
|
||||
let classes = 'end-date' + ' ';
|
||||
let classes = 'end-date ';
|
||||
const dueAt = this.data().getDue();
|
||||
const theDate = this.date.get();
|
||||
if (!dueAt) classes += '';
|
||||
else if (isBefore(theDate, dueAt)) classes += 'current';
|
||||
else if (isAfter(theDate, dueAt)) classes += 'due';
|
||||
|
||||
if (!dueAt) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ template(name="cardDetails")
|
|||
if currentBoard.allowsMembers
|
||||
.card-details-item.card-details-item-members
|
||||
h3.card-details-item-title
|
||||
| 👤s
|
||||
| 👥
|
||||
| {{_ 'members'}}
|
||||
each userId in getMembers
|
||||
+userAvatar(userId=userId cardId=_id)
|
||||
|
|
@ -242,7 +242,7 @@ template(name="cardDetails")
|
|||
if currentBoard.allowsAssignedBy
|
||||
.card-details-item.card-details-item-name
|
||||
h3.card-details-item-title
|
||||
| 👤-plus
|
||||
| ✍️
|
||||
| {{_ 'assigned-by'}}
|
||||
if canModifyCard
|
||||
unless currentUser.isWorker
|
||||
|
|
|
|||
|
|
@ -430,56 +430,57 @@ BlazeComponent.extendComponent({
|
|||
) {
|
||||
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) {
|
||||
let newState = null;
|
||||
if ($(e.target).hasClass('js-poker-vote-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')) {
|
||||
newState = 'two';
|
||||
this.data().setPoker(Meteor.userId(), newState);
|
||||
Meteor.call('cards.pokerVote', this.data()._id, newState);
|
||||
}
|
||||
if ($(e.target).hasClass('js-poker-vote-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')) {
|
||||
newState = 'five';
|
||||
this.data().setPoker(Meteor.userId(), newState);
|
||||
Meteor.call('cards.pokerVote', this.data()._id, newState);
|
||||
}
|
||||
if ($(e.target).hasClass('js-poker-vote-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')) {
|
||||
newState = 'thirteen';
|
||||
this.data().setPoker(Meteor.userId(), newState);
|
||||
Meteor.call('cards.pokerVote', this.data()._id, newState);
|
||||
}
|
||||
if ($(e.target).hasClass('js-poker-vote-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')) {
|
||||
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')) {
|
||||
newState = 'oneHundred';
|
||||
this.data().setPoker(Meteor.userId(), newState);
|
||||
Meteor.call('cards.pokerVote', this.data()._id, newState);
|
||||
}
|
||||
if ($(e.target).hasClass('js-poker-vote-unsure')) {
|
||||
newState = 'unsure';
|
||||
this.data().setPoker(Meteor.userId(), newState);
|
||||
Meteor.call('cards.pokerVote', this.data()._id, newState);
|
||||
}
|
||||
},
|
||||
'click .js-poker-finish'(e) {
|
||||
if ($(e.target).hasClass('js-poker-finish')) {
|
||||
e.preventDefault();
|
||||
const now = formatDateTime(new Date());
|
||||
this.data().setPokerEnd(now);
|
||||
const now = new Date();
|
||||
Meteor.call('cards.setPokerEnd', this.data()._id, now);
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -487,9 +488,9 @@ BlazeComponent.extendComponent({
|
|||
if ($(e.target).hasClass('js-poker-replay')) {
|
||||
e.preventDefault();
|
||||
this.currentCard = this.currentData();
|
||||
this.currentCard.replayPoker();
|
||||
this.data().unsetPokerEnd();
|
||||
this.data().unsetPokerEstimation();
|
||||
Meteor.call('cards.replayPoker', this.currentCard._id);
|
||||
Meteor.call('cards.unsetPokerEnd', this.currentCard._id);
|
||||
Meteor.call('cards.unsetPokerEstimation', this.currentCard._id);
|
||||
}
|
||||
},
|
||||
'click .js-poker-estimation'(event) {
|
||||
|
|
@ -500,9 +501,9 @@ BlazeComponent.extendComponent({
|
|||
this.find('#pokerEstimation').value = '';
|
||||
|
||||
if (ruleTitle) {
|
||||
this.data().setPokerEstimation(parseInt(ruleTitle, 10));
|
||||
Meteor.call('cards.setPokerEstimation', this.data()._id, parseInt(ruleTitle, 10));
|
||||
} else {
|
||||
this.data().setPokerEstimation('');
|
||||
Meteor.call('cards.unsetPokerEstimation', this.data()._id);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
@ -1105,20 +1106,15 @@ BlazeComponent.extendComponent({
|
|||
'is-checked',
|
||||
);
|
||||
const endString = this.currentCard.getVoteEnd();
|
||||
|
||||
this.currentCard.setVoteQuestion(
|
||||
voteQuestion,
|
||||
publicVote,
|
||||
allowNonBoardMembers,
|
||||
);
|
||||
Meteor.call('cards.setVoteQuestion', this.currentCard._id, voteQuestion, publicVote, allowNonBoardMembers);
|
||||
if (endString) {
|
||||
this.currentCard.setVoteEnd(endString);
|
||||
Meteor.call('cards.setVoteEnd', this.currentCard._id, endString);
|
||||
}
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-remove-vote': Popup.afterConfirm('deleteVote', () => {
|
||||
event.preventDefault();
|
||||
this.currentCard.unsetVote();
|
||||
Meteor.call('cards.unsetVote', this.currentCard._id);
|
||||
Popup.back();
|
||||
}),
|
||||
'click a.js-toggle-vote-public'(event) {
|
||||
|
|
@ -1317,10 +1313,10 @@ BlazeComponent.extendComponent({
|
|||
];
|
||||
}
|
||||
_storeDate(newDate) {
|
||||
this.card.setVoteEnd(newDate);
|
||||
Meteor.call('cards.setVoteEnd', this.card._id, newDate);
|
||||
}
|
||||
_deleteDate() {
|
||||
this.card.unsetVoteEnd();
|
||||
Meteor.call('cards.unsetVoteEnd', this.card._id);
|
||||
}
|
||||
}.register('editVoteEndDatePopup'));
|
||||
|
||||
|
|
@ -1342,17 +1338,14 @@ BlazeComponent.extendComponent({
|
|||
);
|
||||
const endString = this.currentCard.getPokerEnd();
|
||||
|
||||
this.currentCard.setPokerQuestion(
|
||||
pokerQuestion,
|
||||
allowNonBoardMembers,
|
||||
);
|
||||
Meteor.call('cards.setPokerQuestion', this.currentCard._id, pokerQuestion, allowNonBoardMembers);
|
||||
if (endString) {
|
||||
this.currentCard.setPokerEnd(endString);
|
||||
Meteor.call('cards.setPokerEnd', this.currentCard._id, new Date(endString));
|
||||
}
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-remove-poker': Popup.afterConfirm('deletePoker', (event) => {
|
||||
this.currentCard.unsetPoker();
|
||||
Meteor.call('cards.unsetPoker', this.currentCard._id);
|
||||
Popup.back();
|
||||
}),
|
||||
'click a.js-toggle-poker-allow-non-members'(event) {
|
||||
|
|
@ -1573,10 +1566,10 @@ BlazeComponent.extendComponent({
|
|||
];
|
||||
}
|
||||
_storeDate(newDate) {
|
||||
this.card.setPokerEnd(newDate);
|
||||
Meteor.call('cards.setPokerEnd', this.card._id, newDate);
|
||||
}
|
||||
_deleteDate() {
|
||||
this.card.unsetPokerEnd();
|
||||
Meteor.call('cards.unsetPokerEnd', this.card._id);
|
||||
}
|
||||
}.register('editPokerEndDatePopup'));
|
||||
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ textarea.js-edit-checklist-item {
|
|||
padding-top: 3px;
|
||||
float: left;
|
||||
}
|
||||
.checklist-title span.fa.checklist-handle.fa-arrows::before {
|
||||
content: "↕️" !important;
|
||||
font-family: inherit !important;
|
||||
}
|
||||
#card-details-overlay {
|
||||
top: 0;
|
||||
bottom: -600px;
|
||||
|
|
@ -148,6 +152,10 @@ textarea.js-edit-checklist-item {
|
|||
padding-top: 2px;
|
||||
padding-right: 10px;
|
||||
}
|
||||
.checklist-item span.fa.checklistitem-handle.fa-arrows::before {
|
||||
content: "↕️" !important;
|
||||
font-family: inherit !important;
|
||||
}
|
||||
.js-delete-checklist-item,
|
||||
.js-convert-checklist-item-to-card {
|
||||
margin: 0 0 0.5em 1.33em;
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ template(name="addChecklistItemForm")
|
|||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-submit-add-checklist-item-form(type="submit") {{_ 'save'}}
|
||||
a.js-close-inlined-form(title="{{_ 'close-add-checklist-item'}}")
|
||||
| ❌
|
||||
if showNewlineBecomesNewChecklistItem
|
||||
.material-toggle-switch(title="{{_ 'newlineBecomesNewChecklistItem'}}")
|
||||
input.toggle-switch(type="checkbox" id="toggleNewlineBecomesNewChecklistItem")
|
||||
|
|
@ -91,6 +92,7 @@ template(name="editChecklistItemForm")
|
|||
.edit-controls.clearfix
|
||||
button.primary.confirm.js-submit-edit-checklist-item-form(type="submit") {{_ 'save'}}
|
||||
a.js-close-inlined-form(title="{{_ 'close-edit-checklist-item'}}")
|
||||
| ❌
|
||||
span(title=createdAt) {{ moment createdAt }}
|
||||
if canModifyCard
|
||||
a.js-delete-checklist-item {{_ "delete"}}...
|
||||
|
|
|
|||
|
|
@ -229,6 +229,74 @@
|
|||
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 */
|
||||
.minicard .card-date i.fa {
|
||||
margin-right: 0.3vw;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ template(name="minicard")
|
|||
class="{{#if colorClass}}minicard-{{colorClass}}{{/if}}")
|
||||
if canModifyCard
|
||||
a.minicard-details-menu-with-handle.js-open-minicard-details-menu(title="{{_ 'cardDetailsActionsPopup-title'}}") ☰
|
||||
if canMoveCard
|
||||
.handle
|
||||
| ↕️
|
||||
.dates
|
||||
|
|
@ -141,7 +142,7 @@ template(name="minicard")
|
|||
if canModifyCard
|
||||
if 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
|
||||
//span.badge-comment.badge-text
|
||||
|
|
@ -149,36 +150,36 @@ template(name="minicard")
|
|||
if getDescription
|
||||
unless currentBoard.allowsDescriptionTextOnMinicard
|
||||
.badge.badge-state-image-only(title=getDescription)
|
||||
span.badge-icon | 📝
|
||||
span.badge-icon 📝
|
||||
if 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-icon(class="{{#if $eq voteState false}}text-red{{/if}}") | 👎
|
||||
span.badge-icon(class="{{#if $eq voteState false}}text-red{{/if}}") 👎
|
||||
span.badge-text {{ voteCountNegative }}
|
||||
if 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
|
||||
span.badge-text {{ getPokerEstimation }}
|
||||
if attachments.length
|
||||
if currentBoard.allowsBadgeAttachmentOnMinicard
|
||||
.badge
|
||||
span.badge-icon | 📎
|
||||
span.badge-icon 📎
|
||||
span.badge-text= attachments.length
|
||||
if checklists.length
|
||||
.badge(class="{{#if checklistFinished}}is-finished{{/if}}")
|
||||
span.badge-icon | ☑️
|
||||
span.badge-icon ☑️
|
||||
span.badge-text.check-list-text {{checklistFinishedCount}}/{{checklistItemCount}}
|
||||
if allSubtasks.count
|
||||
.badge
|
||||
span.badge-icon | 🌐
|
||||
span.badge-icon 🌐
|
||||
span.badge-text.check-list-text {{subtasksFinishedCount}}/{{allSubtasksCount}}
|
||||
//{{subtasksFinishedCount}}/{{subtasksCount}} does not work because when a subtaks is archived, the count goes down
|
||||
if currentBoard.allowsCardSortingByNumber
|
||||
if currentBoard.allowsCardSortingByNumberOnMinicard
|
||||
.badge
|
||||
span.badge-icon | 🔢
|
||||
span.badge-icon 🔢
|
||||
span.badge-text.check-list-sort {{ sort }}
|
||||
if currentBoard.allowsDescriptionTextOnMinicard
|
||||
if getDescription
|
||||
|
|
|
|||
|
|
@ -56,17 +56,17 @@ template(name="importMapMembersAddPopup")
|
|||
p
|
||||
| {{_ 'import-user-select'}}
|
||||
.js-map-member
|
||||
+EasySearch.Input(index=searchIndex)
|
||||
input.js-search-member-input(type="text" placeholder="{{_ 'search-users'}}")
|
||||
ul.pop-over-list
|
||||
+EasySearch.Each(index=searchIndex)
|
||||
each searchResults
|
||||
li.item.js-member-item
|
||||
a.name.js-select-import(title="{{profile.fullname}} ({{username}})" data-id="{{__originalId}}")
|
||||
+userAvatar(userId=__originalId)
|
||||
a.name.js-select-import(title="{{profile.fullname}} ({{username}})" data-id="{{_id}}")
|
||||
+userAvatar(userId=_id)
|
||||
span.full-name
|
||||
= profile.fullname
|
||||
| (<span class="username">{{username}}</span>)
|
||||
+EasySearch.IfSearching(index=searchIndex)
|
||||
if searching.get
|
||||
+spinner
|
||||
+EasySearch.IfNoResults(index=searchIndex)
|
||||
if noResults.get
|
||||
.manage-member-section
|
||||
p.quiet {{_ 'no-results'}}
|
||||
|
|
|
|||
|
|
@ -311,6 +311,73 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
}).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({
|
||||
searchIndex: () => UserSearchIndex,
|
||||
searchResults() {
|
||||
return importMemberPopupState.searchResults.get();
|
||||
},
|
||||
searching() {
|
||||
return importMemberPopupState.searching;
|
||||
},
|
||||
noResults() {
|
||||
return importMemberPopupState.noResults;
|
||||
}
|
||||
})
|
||||
|
|
|
|||
|
|
@ -378,9 +378,6 @@ body.list-resizing-active * {
|
|||
position: relative;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.list-header .list-rotated {
|
||||
|
||||
}
|
||||
.list-header .list-header-watch-icon {
|
||||
padding-left: 10px;
|
||||
|
|
@ -644,17 +641,22 @@ body.list-resizing-active * {
|
|||
.mini-list.mobile-view {
|
||||
flex: 0 0 60px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list.mobile-view {
|
||||
display: contents;
|
||||
display: block !important;
|
||||
flex-basis: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.list.mobile-view:first-child {
|
||||
margin-left: 0px;
|
||||
|
|
@ -662,9 +664,11 @@ body.list-resizing-active * {
|
|||
.list.mobile-view.ui-sortable-helper {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list.mobile-view.ui-sortable-helper .list-header.ui-sortable-handle {
|
||||
cursor: grabbing;
|
||||
|
|
@ -672,14 +676,17 @@ body.list-resizing-active * {
|
|||
.list.mobile-view.placeholder {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list.mobile-view .list-body {
|
||||
padding: 15px 19px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
}
|
||||
.list.mobile-view .list-header {
|
||||
/*Updated padding values for mobile devices, this should fix text grouping issue*/
|
||||
|
|
@ -688,8 +695,9 @@ body.list-resizing-active * {
|
|||
min-height: 30px;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
/* Force grid layout for iPhone */
|
||||
display: grid !important;
|
||||
grid-template-columns: 30px 1fr auto auto !important;
|
||||
|
|
@ -770,17 +778,22 @@ body.list-resizing-active * {
|
|||
.mini-list {
|
||||
flex: 0 0 60px;
|
||||
height: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list {
|
||||
display: contents;
|
||||
display: block !important;
|
||||
flex-basis: auto;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
}
|
||||
.list:first-child {
|
||||
margin-left: 0px;
|
||||
|
|
@ -788,9 +801,11 @@ body.list-resizing-active * {
|
|||
.list.ui-sortable-helper {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list.ui-sortable-helper .list-header.ui-sortable-handle {
|
||||
cursor: grabbing;
|
||||
|
|
@ -798,14 +813,17 @@ body.list-resizing-active * {
|
|||
.list.placeholder {
|
||||
flex: 0 0 60px;
|
||||
height: 60px;
|
||||
width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
border-left: 0px !important;
|
||||
border-bottom: 1px solid #ccc;
|
||||
display: block !important;
|
||||
}
|
||||
.list-body {
|
||||
padding: 15px 19px;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
}
|
||||
.list-header {
|
||||
/*Updated padding values for mobile devices, this should fix text grouping issue*/
|
||||
|
|
@ -814,8 +832,9 @@ body.list-resizing-active * {
|
|||
min-height: 30px;
|
||||
margin-top: 10px;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-width: 100%;
|
||||
width: 100vw;
|
||||
max-width: 100vw;
|
||||
min-width: 100vw;
|
||||
}
|
||||
.list-header .list-header-left-icon {
|
||||
padding: 7px;
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@ template(name="listHeader")
|
|||
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰
|
||||
else
|
||||
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
|
||||
if isWatching
|
||||
i.list-header-watch-icon | 👁️
|
||||
|
|
@ -72,7 +73,8 @@ template(name="listHeader")
|
|||
a.js-open-list-menu(title="{{_ 'listActionPopup-title'}}") ☰
|
||||
if currentUser.isBoardMember
|
||||
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")
|
||||
.list-composer
|
||||
|
|
|
|||
|
|
@ -32,7 +32,16 @@ template(name="dueCards")
|
|||
span.global-search-error-messages
|
||||
= msg
|
||||
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")
|
||||
if currentUser
|
||||
|
|
|
|||
|
|
@ -1,13 +1,6 @@
|
|||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import { CardSearchPagedComponent } from '../../lib/cardSearch';
|
||||
import {
|
||||
OPERATOR_HAS,
|
||||
OPERATOR_SORT,
|
||||
OPERATOR_USER,
|
||||
ORDER_ASCENDING,
|
||||
PREDICATE_DUE_AT,
|
||||
} from '../../../config/search-const';
|
||||
import { QueryParams } from '../../../config/query-classes';
|
||||
import { BlazeComponent } from 'meteor/peerlibrary:blaze-components';
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
|
||||
// const subManager = new SubsManager();
|
||||
|
||||
|
|
@ -31,6 +24,47 @@ Template.dueCards.helpers({
|
|||
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({
|
||||
|
|
@ -55,71 +89,50 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
}).register('dueCardsViewChangePopup');
|
||||
|
||||
class DueCardsComponent extends CardSearchPagedComponent {
|
||||
class DueCardsComponent extends BlazeComponent {
|
||||
onCreated() {
|
||||
super.onCreated();
|
||||
|
||||
// Add a small delay to ensure ReactiveCache is ready
|
||||
this.searchRetryCount = 0;
|
||||
this.maxRetries = 3;
|
||||
this._cachedCards = null;
|
||||
this._cachedTimestamp = null;
|
||||
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
|
||||
Meteor.setTimeout(() => {
|
||||
this.performSearch();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
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...');
|
||||
// Subscribe to the optimized due cards publication
|
||||
this.autorun(() => {
|
||||
const allUsers = this.dueCardsView() === 'all';
|
||||
if (this.subscriptionHandle) {
|
||||
this.subscriptionHandle.stop();
|
||||
}
|
||||
Meteor.setTimeout(() => {
|
||||
this.performSearch();
|
||||
}, 1000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('User authenticated:', currentUser.username);
|
||||
}
|
||||
|
||||
const queryParams = new QueryParams();
|
||||
queryParams.addPredicate(OPERATOR_HAS, {
|
||||
field: PREDICATE_DUE_AT,
|
||||
exists: true,
|
||||
});
|
||||
// queryParams[OPERATOR_LIMIT] = 5;
|
||||
queryParams.addPredicate(OPERATOR_SORT, {
|
||||
name: PREDICATE_DUE_AT,
|
||||
order: ORDER_ASCENDING,
|
||||
this.subscriptionHandle = Meteor.subscribe('dueCards', allUsers);
|
||||
|
||||
// Update loading state based on subscription
|
||||
this.autorun(() => {
|
||||
if (this.subscriptionHandle && this.subscriptionHandle.ready()) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('dueCards: subscription ready, loading data...');
|
||||
}
|
||||
this.isLoading.set(false);
|
||||
const cards = this.dueCardsList();
|
||||
this.hasResults.set(cards && cards.length > 0);
|
||||
} else {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('dueCards: subscription not ready, showing loading...');
|
||||
}
|
||||
this.isLoading.set(true);
|
||||
this.hasResults.set(false);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Note: User filtering is handled server-side based on board membership
|
||||
// The OPERATOR_USER filter is too restrictive as it only shows cards where
|
||||
// the user is assigned or a member of the card, not the board
|
||||
// if (Utils && Utils.dueCardsView && Utils.dueCardsView() !== 'all') {
|
||||
// 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'));
|
||||
onDestroyed() {
|
||||
super.onDestroyed();
|
||||
if (this.subscriptionHandle) {
|
||||
this.subscriptionHandle.stop();
|
||||
}
|
||||
|
||||
this.runGlobalSearch(queryParams);
|
||||
}
|
||||
|
||||
dueCardsView() {
|
||||
|
|
@ -132,29 +145,106 @@ class DueCardsComponent extends CardSearchPagedComponent {
|
|||
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() {
|
||||
const results = this.getResults();
|
||||
console.log('results:', results);
|
||||
const cards = [];
|
||||
if (results) {
|
||||
results.forEach(card => {
|
||||
cards.push(card);
|
||||
// Check if subscription is ready
|
||||
if (!this.subscriptionHandle || !this.subscriptionHandle.ready()) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('dueCards client: subscription not ready');
|
||||
}
|
||||
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) => {
|
||||
const x = a.dueAt === null ? new Date('2100-12-31') : a.dueAt;
|
||||
const y = b.dueAt === null ? new Date('2100-12-31') : b.dueAt;
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('dueCards client: filtered to', filteredCards.length, 'cards');
|
||||
}
|
||||
|
||||
if (x > y) return 1;
|
||||
else if (x < y) return -1;
|
||||
// Cache the results for 5 seconds to avoid re-filtering on every render
|
||||
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
|
||||
console.log('cards:', cards);
|
||||
return cards;
|
||||
return filteredCards;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -83,10 +83,6 @@ template(name="header")
|
|||
i.mobile-icon(class="{{#if mobileMode}}active{{/if}}") 📱
|
||||
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
|
||||
|
||||
|
|
|
|||
|
|
@ -93,6 +93,29 @@
|
|||
max-height: inherit;
|
||||
}
|
||||
|
||||
/* Admin edit popups: use full height */
|
||||
.pop-over[data-popup="editUser"],
|
||||
.pop-over[data-popup="editOrg"],
|
||||
.pop-over[data-popup="editTeam"] {
|
||||
height: calc(100vh - 20px) !important;
|
||||
max-height: calc(100vh - 20px) !important;
|
||||
}
|
||||
|
||||
.pop-over[data-popup="editUser"] .content-wrapper,
|
||||
.pop-over[data-popup="editOrg"] .content-wrapper,
|
||||
.pop-over[data-popup="editTeam"] .content-wrapper {
|
||||
max-height: calc(100vh - 80px) !important; /* Subtract header height */
|
||||
height: calc(100vh - 80px) !important;
|
||||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
.pop-over[data-popup="editUser"] .content-container,
|
||||
.pop-over[data-popup="editOrg"] .content-container,
|
||||
.pop-over[data-popup="editTeam"] .content-container {
|
||||
max-height: calc(100vh - 80px) !important; /* Subtract header height */
|
||||
height: calc(100vh - 80px) !important;
|
||||
}
|
||||
|
||||
/* Ensure language popup list can scroll properly */
|
||||
.pop-over .pop-over-list {
|
||||
max-height: none;
|
||||
|
|
@ -270,6 +293,8 @@
|
|||
overflow-y: auto !important;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.pop-over[data-popup="editCardReceivedDatePopup"] .edit-date button,
|
||||
.pop-over[data-popup="editCardStartDatePopup"] .edit-date button,
|
||||
.pop-over[data-popup="editCardDueDatePopup"] .edit-date button,
|
||||
|
|
@ -364,9 +389,6 @@
|
|||
margin: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
.pop-over .quiet {
|
||||
/* padding: 6px 6px 4px;*/
|
||||
}
|
||||
.pop-over.search-over {
|
||||
background: #f0f0f0;
|
||||
min-height: 14vh;
|
||||
|
|
|
|||
|
|
@ -1,38 +1,33 @@
|
|||
/* Migration Progress Styles */
|
||||
.migration-overlay {
|
||||
.migration-progress-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
z-index: 10000;
|
||||
display: none;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: rgba(0, 0, 0, 0.7);
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow-y: auto;
|
||||
backdrop-filter: blur(2px);
|
||||
}
|
||||
|
||||
.migration-overlay.active {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.migration-modal {
|
||||
.migration-progress-modal {
|
||||
background: white;
|
||||
border-radius: 12px;
|
||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.4);
|
||||
max-width: 800px;
|
||||
width: 95%;
|
||||
max-height: 90vh;
|
||||
border-radius: 8px;
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
max-width: 500px;
|
||||
width: 90%;
|
||||
max-height: 80vh;
|
||||
overflow: hidden;
|
||||
animation: slideInScale 0.4s ease-out;
|
||||
margin: 20px;
|
||||
animation: migrationModalSlideIn 0.3s ease-out;
|
||||
}
|
||||
|
||||
@keyframes slideInScale {
|
||||
@keyframes migrationModalSlideIn {
|
||||
from {
|
||||
opacity: 0;
|
||||
transform: translateY(-30px) scale(0.95);
|
||||
transform: translateY(-20px) scale(0.95);
|
||||
}
|
||||
to {
|
||||
opacity: 1;
|
||||
|
|
@ -40,333 +35,235 @@
|
|||
}
|
||||
}
|
||||
|
||||
.migration-header {
|
||||
padding: 24px 32px 20px;
|
||||
border-bottom: 2px solid #e0e0e0;
|
||||
text-align: center;
|
||||
.migration-progress-header {
|
||||
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
|
||||
color: white;
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.migration-header h3 {
|
||||
margin: 0 0 8px 0;
|
||||
font-size: 24px;
|
||||
.migration-progress-title {
|
||||
margin: 0;
|
||||
font-size: 18px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.migration-header h3 i {
|
||||
margin-right: 12px;
|
||||
color: #FFD700;
|
||||
}
|
||||
|
||||
.migration-header p {
|
||||
margin: 0;
|
||||
.migration-progress-close {
|
||||
cursor: pointer;
|
||||
font-size: 16px;
|
||||
opacity: 0.9;
|
||||
opacity: 0.8;
|
||||
transition: opacity 0.2s ease;
|
||||
}
|
||||
|
||||
.migration-content {
|
||||
padding: 24px 32px;
|
||||
max-height: 60vh;
|
||||
overflow-y: auto;
|
||||
.migration-progress-close:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.migration-overview {
|
||||
margin-bottom: 32px;
|
||||
padding: 20px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 8px;
|
||||
border-left: 4px solid #667eea;
|
||||
.migration-progress-content {
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.overall-progress {
|
||||
margin-bottom: 20px;
|
||||
.migration-progress-overall {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 12px;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 6px;
|
||||
overflow: hidden;
|
||||
.migration-progress-overall-label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
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%;
|
||||
background: linear-gradient(90deg, #667eea, #764ba2);
|
||||
border-radius: 6px;
|
||||
border-radius: 10px;
|
||||
transition: width 0.3s ease;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.progress-fill::after {
|
||||
.migration-progress-overall-fill::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
rgba(255, 255, 255, 0.4),
|
||||
transparent
|
||||
);
|
||||
animation: shimmer 2s infinite;
|
||||
background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent);
|
||||
animation: migrationProgressShimmer 2s infinite;
|
||||
}
|
||||
|
||||
@keyframes shimmer {
|
||||
0% {
|
||||
transform: translateX(-100%);
|
||||
}
|
||||
100% {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
@keyframes migrationProgressShimmer {
|
||||
0% { transform: translateX(-100%); }
|
||||
100% { transform: translateX(100%); }
|
||||
}
|
||||
|
||||
.progress-text {
|
||||
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 {
|
||||
.migration-progress-overall-percentage {
|
||||
text-align: right;
|
||||
min-width: 40px;
|
||||
}
|
||||
|
||||
.step-progress .progress-text {
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.step-progress-bar {
|
||||
width: 100%;
|
||||
height: 4px;
|
||||
background-color: #e0e0e0;
|
||||
border-radius: 2px;
|
||||
overflow: hidden;
|
||||
margin-top: 8px;
|
||||
.migration-progress-current-step {
|
||||
margin-bottom: 25px;
|
||||
}
|
||||
|
||||
.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%;
|
||||
background: linear-gradient(90deg, #667eea, #764ba2);
|
||||
border-radius: 2px;
|
||||
border-radius: 8px;
|
||||
transition: width 0.3s ease;
|
||||
}
|
||||
|
||||
.migration-status {
|
||||
text-align: center;
|
||||
color: #333;
|
||||
font-size: 16px;
|
||||
background-color: #e3f2fd;
|
||||
padding: 12px 16px;
|
||||
.migration-progress-step-percentage {
|
||||
text-align: right;
|
||||
font-size: 12px;
|
||||
color: #666;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.migration-progress-status {
|
||||
margin-bottom: 20px;
|
||||
padding: 15px;
|
||||
background: #f8f9fa;
|
||||
border-radius: 6px;
|
||||
border: 1px solid #bbdefb;
|
||||
margin-bottom: 16px;
|
||||
border-left: 4px solid #007bff;
|
||||
}
|
||||
|
||||
.migration-status i {
|
||||
margin-right: 8px;
|
||||
color: #2196f3;
|
||||
.migration-progress-status-label {
|
||||
font-weight: 600;
|
||||
color: #333;
|
||||
margin-bottom: 5px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.migration-footer {
|
||||
padding: 16px 32px 24px;
|
||||
border-top: 1px solid #e0e0e0;
|
||||
background-color: #f8f9fa;
|
||||
.migration-progress-status-text {
|
||||
color: #555;
|
||||
font-size: 14px;
|
||||
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;
|
||||
color: #666;
|
||||
font-size: 13px;
|
||||
line-height: 1.4;
|
||||
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;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
/* Responsive design */
|
||||
@media (max-width: 768px) {
|
||||
.migration-modal {
|
||||
width: 98%;
|
||||
margin: 10px;
|
||||
@media (max-width: 600px) {
|
||||
.migration-progress-modal {
|
||||
width: 95%;
|
||||
margin: 20px;
|
||||
}
|
||||
|
||||
.migration-header,
|
||||
.migration-content,
|
||||
.migration-footer {
|
||||
padding-left: 16px;
|
||||
padding-right: 16px;
|
||||
.migration-progress-content {
|
||||
padding: 20px;
|
||||
}
|
||||
|
||||
.migration-header h3 {
|
||||
font-size: 20px;
|
||||
.migration-progress-header {
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
.step-header {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
}
|
||||
|
||||
.step-progress {
|
||||
text-align: left;
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.steps-list {
|
||||
max-height: 200px;
|
||||
.migration-progress-title {
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
/* 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;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +1,43 @@
|
|||
template(name="migrationProgress")
|
||||
.migration-overlay(class="{{#if isMigrating}}active{{/if}}")
|
||||
.migration-modal
|
||||
.migration-header
|
||||
h3
|
||||
| 🗄️
|
||||
| {{_ 'database-migration'}}
|
||||
p {{_ 'database-migration-description'}}
|
||||
|
||||
.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}}
|
||||
if isMigrating
|
||||
.migration-progress-overlay
|
||||
.migration-progress-modal
|
||||
.migration-progress-header
|
||||
h3.migration-progress-title
|
||||
| 🔄 Board Migration in Progress
|
||||
.migration-progress-close.js-close-migration-progress
|
||||
| ❌
|
||||
|
||||
.migration-steps
|
||||
h4 {{_ 'migration-steps'}}
|
||||
.steps-list
|
||||
each migrationSteps
|
||||
.migration-step(class="{{#if completed}}completed{{/if}}" class="{{#if isCurrentStep}}current{{/if}}")
|
||||
.step-header
|
||||
.step-icon
|
||||
if completed
|
||||
| ✅
|
||||
else if isCurrentStep
|
||||
| ⚙️
|
||||
else
|
||||
| ⭕
|
||||
.step-info
|
||||
.step-name {{name}}
|
||||
.step-description {{description}}
|
||||
.step-progress
|
||||
if completed
|
||||
.progress-text 100%
|
||||
else if isCurrentStep
|
||||
.progress-text {{progress}}%
|
||||
else
|
||||
.progress-text 0%
|
||||
if isCurrentStep
|
||||
.step-progress-bar
|
||||
.progress-fill(style="width: {{progress}}%")
|
||||
.migration-progress-content
|
||||
.migration-progress-overall
|
||||
.migration-progress-overall-label
|
||||
| Overall Progress: {{currentStep}} of {{totalSteps}} steps
|
||||
.migration-progress-overall-bar
|
||||
.migration-progress-overall-fill(style="{{progressBarStyle}}")
|
||||
.migration-progress-overall-percentage
|
||||
| {{overallProgress}}%
|
||||
|
||||
.migration-progress-current-step
|
||||
.migration-progress-step-label
|
||||
| Current Step: {{stepNameFormatted}}
|
||||
.migration-progress-step-bar
|
||||
.migration-progress-step-fill(style="{{stepProgressBarStyle}}")
|
||||
.migration-progress-step-percentage
|
||||
| {{stepProgress}}%
|
||||
|
||||
.migration-progress-status
|
||||
.migration-progress-status-label
|
||||
| Status:
|
||||
.migration-progress-status-text
|
||||
| {{stepStatus}}
|
||||
|
||||
if stepDetailsFormatted
|
||||
.migration-progress-details
|
||||
.migration-progress-details-label
|
||||
| Details:
|
||||
.migration-progress-details-text
|
||||
| {{stepDetailsFormatted}}
|
||||
|
||||
.migration-status
|
||||
| ℹ️
|
||||
| {{migrationStatus}}
|
||||
|
||||
.migration-footer
|
||||
.migration-info
|
||||
| 💡
|
||||
| {{_ 'migration-info-text'}}
|
||||
.migration-warning
|
||||
| ⚠️
|
||||
| {{_ 'migration-warning-text'}}
|
||||
.migration-progress-footer
|
||||
.migration-progress-note
|
||||
| Please wait while we migrate your board to the latest structure...
|
||||
|
|
@ -1,54 +1,212 @@
|
|||
import { Template } from 'meteor/templating';
|
||||
import {
|
||||
migrationManager,
|
||||
isMigrating,
|
||||
migrationProgress,
|
||||
migrationStatus,
|
||||
migrationCurrentStep,
|
||||
migrationEstimatedTime,
|
||||
migrationSteps
|
||||
} from '/client/lib/migrationManager';
|
||||
/**
|
||||
* Migration Progress Component
|
||||
* Displays detailed progress for comprehensive board migration
|
||||
*/
|
||||
|
||||
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({
|
||||
isMigrating() {
|
||||
return isMigrating.get();
|
||||
},
|
||||
|
||||
migrationProgress() {
|
||||
|
||||
overallProgress() {
|
||||
return migrationProgress.get();
|
||||
},
|
||||
|
||||
migrationStatus() {
|
||||
|
||||
overallStatus() {
|
||||
return migrationStatus.get();
|
||||
},
|
||||
|
||||
migrationCurrentStep() {
|
||||
|
||||
currentStep() {
|
||||
return migrationCurrentStep.get();
|
||||
},
|
||||
|
||||
migrationEstimatedTime() {
|
||||
return migrationEstimatedTime.get();
|
||||
|
||||
totalSteps() {
|
||||
return migrationTotalSteps.get();
|
||||
},
|
||||
|
||||
migrationSteps() {
|
||||
const steps = migrationSteps.get();
|
||||
const currentStep = migrationCurrentStep.get();
|
||||
|
||||
stepName() {
|
||||
return migrationStepName.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 => ({
|
||||
...step,
|
||||
isCurrentStep: step.name === currentStep
|
||||
}));
|
||||
// Convert snake_case to Title Case
|
||||
return stepName
|
||||
.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() {
|
||||
// Subscribe to migration state changes
|
||||
this.autorun(() => {
|
||||
isMigrating.get();
|
||||
migrationProgress.get();
|
||||
migrationStatus.get();
|
||||
migrationCurrentStep.get();
|
||||
migrationEstimatedTime.get();
|
||||
migrationSteps.get();
|
||||
});
|
||||
});
|
||||
// Template events
|
||||
Template.migrationProgress.events({
|
||||
'click .js-close-migration-progress'() {
|
||||
migrationProgressManager.clearProgress();
|
||||
}
|
||||
});
|
||||
|
|
@ -71,6 +71,13 @@ table tr:nth-child(even) {
|
|||
left: 0 !important;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
/* Make checkbox column fit content */
|
||||
table th:first-child,
|
||||
table td:first-child {
|
||||
width: auto;
|
||||
min-width: auto;
|
||||
}
|
||||
#divAddOrRemoveTeam {
|
||||
background: #008000;
|
||||
display: none;
|
||||
|
|
@ -141,7 +148,7 @@ table tr:nth-child(even) {
|
|||
}
|
||||
|
||||
.account-active-status {
|
||||
width: 20px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
@ -170,7 +177,7 @@ table tr:nth-child(even) {
|
|||
}
|
||||
|
||||
.account-status {
|
||||
width: 20px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ template(name="people")
|
|||
option(value="locked") {{_ 'admin-people-filter-locked'}}
|
||||
option(value="active") {{_ 'admin-people-filter-active'}}
|
||||
option(value="inactive") {{_ 'admin-people-filter-inactive'}}
|
||||
option(value="admin") Admin
|
||||
button#unlockAllUsers.unlock-all-btn
|
||||
| 🔓
|
||||
| {{_ 'accounts-lockout-unlock-all'}}
|
||||
|
|
@ -57,7 +58,7 @@ template(name="people")
|
|||
| {{_ 'add'}} / {{_ 'delete'}} {{_ 'teams'}}
|
||||
else if lockedUsersSetting.get
|
||||
span
|
||||
| 🔒.text-red
|
||||
span.text-red 🔒
|
||||
unless isMiniScreen
|
||||
| {{_ 'accounts-lockout-locked-users'}}
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ template(name="people")
|
|||
| {{_ 'people'}}
|
||||
li
|
||||
a.js-locked-users-menu(data-id="locked-users-setting")
|
||||
| 🔒.text-red
|
||||
span.text-red 🔒
|
||||
| {{_ 'accounts-lockout-locked-users'}}
|
||||
.main-body
|
||||
if loading.get
|
||||
|
|
@ -100,7 +101,6 @@ template(name="orgGeneral")
|
|||
th {{_ 'displayName'}}
|
||||
th {{_ 'description'}}
|
||||
th {{_ 'shortName'}}
|
||||
th {{_ 'autoAddUsersWithDomainName'}}
|
||||
th {{_ 'website'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
|
|
@ -140,16 +140,9 @@ template(name="peopleGeneral")
|
|||
th {{_ 'admin-people-active-status'}}
|
||||
th {{_ 'username'}}
|
||||
th {{_ 'fullname'}}
|
||||
th {{_ 'initials'}}
|
||||
th {{_ 'admin'}}
|
||||
th {{_ 'email'}}
|
||||
th {{_ 'verified'}}
|
||||
th {{_ 'createdAt'}}
|
||||
th {{_ 'active'}}
|
||||
th {{_ 'authentication-method'}}
|
||||
th {{_ 'import-usernames'}}
|
||||
th {{_ 'organizations'}}
|
||||
th {{_ 'teams'}}
|
||||
th
|
||||
+newUserRow
|
||||
tbody
|
||||
|
|
@ -190,10 +183,6 @@ template(name="orgRow")
|
|||
td {{ orgData.orgShortName }}
|
||||
else
|
||||
td <s>{{ orgData.orgShortName }}</s>
|
||||
if orgData.orgIsActive
|
||||
td {{ orgData.orgAutoAddUsersWithDomainName }}
|
||||
else
|
||||
td <s>{{ orgData.orgAutoAddUsersWithDomainName }}</s>
|
||||
if orgData.orgIsActive
|
||||
td {{ orgData.orgWebsite }}
|
||||
else
|
||||
|
|
@ -258,14 +247,14 @@ template(name="peopleRow")
|
|||
input.selectUserChkBox(type="checkbox", id="{{userData._id}}")
|
||||
td.account-status
|
||||
if isUserLocked
|
||||
| 🔒.text-red.js-toggle-lock-status(data-user-id=userData._id, data-is-locked="true", title="{{_ 'accounts-lockout-click-to-unlock'}}")
|
||||
span.text-red.js-toggle-lock-status(data-user-id=userData._id, data-is-locked="true", title="{{_ 'accounts-lockout-click-to-unlock'}}") 🔒
|
||||
else
|
||||
| 🔓.text-green.js-toggle-lock-status(data-user-id=userData._id, data-is-locked="false", title="{{_ 'accounts-lockout-user-unlocked'}}")
|
||||
span.text-green.js-toggle-lock-status(data-user-id=userData._id, data-is-locked="false", title="{{_ 'accounts-lockout-user-unlocked'}}") 🔓
|
||||
td.account-active-status
|
||||
if userData.loginDisabled
|
||||
| 🚫.text-red.js-toggle-active-status(data-user-id=userData._id, data-is-active="false", title="{{_ 'admin-people-user-inactive'}}")
|
||||
span.text-red.js-toggle-active-status(data-user-id=userData._id, data-is-active="false", title="{{_ 'admin-people-user-inactive'}}") 🚫
|
||||
else
|
||||
| ✅.text-green.js-toggle-active-status(data-user-id=userData._id, data-is-active="true", title="{{_ 'admin-people-user-active'}}")
|
||||
span.text-green.js-toggle-active-status(data-user-id=userData._id, data-is-active="true", title="{{_ 'admin-people-user-active'}}") ✅
|
||||
if userData.loginDisabled
|
||||
td.username <s>{{ userData.username }}</s>
|
||||
else if isUserLocked
|
||||
|
|
@ -276,10 +265,6 @@ template(name="peopleRow")
|
|||
td <s>{{ userData.profile.fullname }}</s>
|
||||
else
|
||||
td {{ userData.profile.fullname }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.profile.initials }}</s>
|
||||
else
|
||||
td {{ userData.profile.initials }}
|
||||
if userData.loginDisabled
|
||||
td
|
||||
if userData.isAdmin
|
||||
|
|
@ -296,43 +281,10 @@ template(name="peopleRow")
|
|||
td <s>{{ userData.emails.[0].address }}</s>
|
||||
else
|
||||
td {{ userData.emails.[0].address }}
|
||||
if userData.loginDisabled
|
||||
td
|
||||
if userData.emails.[0].verified
|
||||
| <s>{{_ 'yes'}}</s>
|
||||
else
|
||||
| <s>{{_ 'no'}}</s>
|
||||
else
|
||||
td
|
||||
if userData.emails.[0].verified
|
||||
| {{_ 'yes'}}
|
||||
else
|
||||
| {{_ 'no'}}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ moment userData.createdAt 'LLL' }}</s>
|
||||
else
|
||||
td {{ moment userData.createdAt 'LLL' }}
|
||||
td
|
||||
if userData.loginDisabled
|
||||
| {{_ 'no'}}
|
||||
else
|
||||
| {{_ 'yes'}}
|
||||
if userData.loginDisabled
|
||||
td <s>{{_ userData.authenticationMethod }}</s>
|
||||
else
|
||||
td {{_ userData.authenticationMethod }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.importUsernamesString }}</s>
|
||||
else
|
||||
td {{ userData.importUsernamesString }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.orgsUserBelongs }}</s>
|
||||
else
|
||||
td {{ userData.orgsUserBelongs }}
|
||||
if userData.loginDisabled
|
||||
td <s>{{ userData.teamsUserBelongs }}</s>
|
||||
else
|
||||
td {{ userData.teamsUserBelongs }}
|
||||
td
|
||||
a.edit-user
|
||||
| ✏️
|
||||
|
|
@ -448,8 +400,8 @@ template(name="editUserPopup")
|
|||
option(value="{{value}}") {{_ value}}
|
||||
label
|
||||
| {{_ 'organizations'}}
|
||||
| ➕#addUserOrg
|
||||
| ➖#removeUserOrg
|
||||
span#addUserOrg ➕
|
||||
span#removeUserOrg ➖
|
||||
select.js-orgs#jsOrgs
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each value in orgsDatas
|
||||
|
|
@ -458,8 +410,8 @@ template(name="editUserPopup")
|
|||
input#jsUserOrgIdsInPut.js-userOrgIds.hide(type="hidden" value=user.orgIdsUserBelongs)
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
| ➕#addUserTeam
|
||||
| ➖#removeUserTeam
|
||||
span#addUserTeam ➕
|
||||
span#removeUserTeam ➖
|
||||
select.js-teams#jsTeams
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each value in teamsDatas
|
||||
|
|
@ -591,8 +543,8 @@ template(name="newUserPopup")
|
|||
option(value="{{value}}") {{_ value}}
|
||||
label
|
||||
| {{_ 'organizations'}}
|
||||
| ➕#addUserOrgNewUser
|
||||
| ➖#removeUserOrgNewUser
|
||||
span#addUserOrgNewUser ➕
|
||||
span#removeUserOrgNewUser ➖
|
||||
select.js-orgsNewUser#jsOrgsNewUser
|
||||
option(value="-1") {{_ 'organizations'}} :
|
||||
each value in orgsDatas
|
||||
|
|
@ -601,8 +553,8 @@ template(name="newUserPopup")
|
|||
input#jsUserOrgIdsInPutNewUser.js-userOrgIdsNewUser.hide(type="text" value=user.orgIdsUserBelongs)
|
||||
label
|
||||
| {{_ 'teams'}}
|
||||
| ➕#addUserTeamNewUser
|
||||
| ➖#removeUserTeamNewUser
|
||||
span#addUserTeamNewUser ➕
|
||||
span#removeUserTeamNewUser ➖
|
||||
select.js-teamsNewUser#jsTeamsNewUser
|
||||
option(value="-1") {{_ 'teams'}} :
|
||||
each value in teamsDatas
|
||||
|
|
|
|||
|
|
@ -172,6 +172,10 @@ BlazeComponent.extendComponent({
|
|||
// Show only inactive users (loginDisabled is true)
|
||||
query['loginDisabled'] = true;
|
||||
break;
|
||||
case 'admin':
|
||||
// Show only admin users (isAdmin is true)
|
||||
query['isAdmin'] = true;
|
||||
break;
|
||||
case 'all':
|
||||
default:
|
||||
// Show all users, no additional filter
|
||||
|
|
|
|||
|
|
@ -48,6 +48,59 @@
|
|||
display: flex;
|
||||
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 {
|
||||
display: flex;
|
||||
height: 30px;
|
||||
|
|
|
|||
|
|
@ -34,32 +34,26 @@ template(name='homeSidebar')
|
|||
hr
|
||||
ul#cards.label-text-hidden
|
||||
a.flex.js-toggle-minicard-label-text(title="{{_ 'hide-minicard-label-text'}}")
|
||||
span {{#if hiddenMinicardLabelText}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'hide-minicard-label-text'}}
|
||||
b
|
||||
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
|
||||
if currentUser
|
||||
ul#cards.vertical-scrollbars-toggle
|
||||
a.flex.js-vertical-scrollbars-toggle(title="{{_ 'enable-vertical-scrollbars'}}")
|
||||
span {{#if isVerticalScrollbars}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'enable-vertical-scrollbars'}}
|
||||
b
|
||||
.materialCheckBox(class="{{#if isVerticalScrollbars}}is-checked{{/if}}")
|
||||
ul#cards.show-week-of-year-toggle
|
||||
a.flex.js-show-week-of-year-toggle(title="{{_ 'show-week-of-year'}}")
|
||||
span {{#if isShowWeekOfYear}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'show-week-of-year'}}
|
||||
b
|
||||
.materialCheckBox(class="{{#if isShowWeekOfYear}}is-checked{{/if}}")
|
||||
hr
|
||||
unless currentUser.isNoComments
|
||||
h3.activity-title
|
||||
| 💬
|
||||
| {{_ 'activities'}}
|
||||
|
||||
.material-toggle-switch(title="{{_ 'show-activities'}}")
|
||||
if showActivities
|
||||
input.toggle-switch(type="checkbox" id="toggleShowActivitiesBoard" checked="checked")
|
||||
else
|
||||
input.toggle-switch(type="checkbox" id="toggleShowActivitiesBoard")
|
||||
label.toggle-label(for="toggleShowActivitiesBoard")
|
||||
a.flex.js-toggle-show-activities(title="{{_ 'show-activities'}}")
|
||||
span {{#if showActivities}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'show-activities'}}
|
||||
+activities(mode="board")
|
||||
|
||||
template(name="membersWidget")
|
||||
|
|
@ -185,165 +179,282 @@ template(name="boardInfoOnMyBoardsPopup")
|
|||
unless currentSetting.hideCardCounterList
|
||||
div.check-div
|
||||
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
|
||||
| 🚪
|
||||
| {{_ 'show-card-counter-per-list'}}
|
||||
unless currentSetting.hideBoardMemberList
|
||||
div.check-div
|
||||
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
|
||||
| ⏳
|
||||
| {{_ 'show-board_members-avatar'}}
|
||||
|
||||
template(name="boardCardSettingsPopup")
|
||||
form.board-card-settings
|
||||
h3 {{_ 'show-on-card'}}, {{_ 'show-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-receiveddate(class="{{#if allowsReceivedDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsReceivedDate}}is-checked{{/if}}")
|
||||
.card-settings-grid
|
||||
.card-settings-column
|
||||
h4 {{_ 'show-on-card'}}
|
||||
.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
|
||||
| 🚪
|
||||
| {{_ 'card-received'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-startdate(class="{{#if allowsStartDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsStartDate}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-startdate(title="{{_ 'card-start'}}" class="{{#if allowsStartDate}}is-checked{{/if}}")
|
||||
span {{#if allowsStartDate}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| ⏳
|
||||
| {{_ 'card-start'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-duedate(class="{{#if allowsDueDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDueDate}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-duedate(title="{{_ 'card-due'}}" class="{{#if allowsDueDate}}is-checked{{/if}}")
|
||||
span {{#if allowsDueDate}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 🚪
|
||||
| {{_ 'card-due'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-enddate(class="{{#if allowsEndDate}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsEndDate}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-enddate(title="{{_ 'card-end'}}" class="{{#if allowsEndDate}}is-checked{{/if}}")
|
||||
span {{#if allowsEndDate}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| ⏰
|
||||
| {{_ 'card-end'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-members(class="{{#if allowsMembers}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsMembers}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-members(title="{{_ 'members'}}" class="{{#if allowsMembers}}is-checked{{/if}}")
|
||||
span {{#if allowsMembers}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 👥
|
||||
| {{_ 'members'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-creator(class="{{#if allowsCreator}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCreator}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 👤
|
||||
| {{_ 'creator'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-creator-on-minicard(class="{{#if allowsCreatorOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCreatorOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 👤
|
||||
| {{_ 'creator-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-assignee(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-assignee(title="{{_ 'assignee'}}" class="{{#if allowsAssignee}}is-checked{{/if}}")
|
||||
span {{#if allowsAssignee}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 👤
|
||||
| {{_ 'assignee'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-assigned-by(class="{{#if allowsAssignedBy}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAssignedBy}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
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
|
||||
| 🛒
|
||||
| {{_ 'assigned-by'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-requested-by(class="{{#if allowsRequestedBy}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsRequestedBy}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
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
|
||||
| 👤➕
|
||||
| {{_ 'requested-by'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-sorting-by-number(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCardSortingByNumber}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 🔢
|
||||
| {{_ 'card-sorting-by-number'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-sorting-by-number-on-minicard(class="{{#if allowsCardSortingByNumberOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCardSortingByNumberOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 🔢
|
||||
| {{_ 'card-sorting-by-number-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-show-lists(class="{{#if allowsShowLists}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsShowLists}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 📋
|
||||
| {{_ 'card-show-lists'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-labels(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-labels(title="{{_ 'labels'}}" class="{{#if allowsLabels}}is-checked{{/if}}")
|
||||
span {{#if allowsLabels}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 🏷️
|
||||
| {{_ 'labels'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-show-lists-on-minicard(class="{{#if allowsShowListsOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsShowListsOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 📋
|
||||
| {{_ 'card-show-lists-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-card-number(class="{{#if allowsCardNumber}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCardNumber}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
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
|
||||
| #️⃣
|
||||
| {{_ 'card'}}
|
||||
| {{_ 'number'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-title(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionTitle}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
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
|
||||
| 📝
|
||||
| {{_ 'description'}}
|
||||
| {{_ 'title'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-text(class="{{#if allowsDescriptionText}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionText}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
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
|
||||
| 📝
|
||||
| {{_ 'description'}}
|
||||
| {{_ 'custom-field-text'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-description-text-on-minicard(class="{{#if allowsDescriptionTextOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsDescriptionTextOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 📝
|
||||
| {{_ 'description-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-checklists(class="{{#if allowsChecklists}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsChecklists}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-checklists(title="{{_ 'checklists'}}" class="{{#if allowsChecklists}}is-checked{{/if}}")
|
||||
span {{#if allowsChecklists}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| ✅
|
||||
| {{_ 'checklists'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-subtasks(title="{{_ 'subtasks'}}" class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
span {{#if allowsSubtasks}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 🌐
|
||||
| {{_ 'subtasks'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-attachments(class="{{#if allowsAttachments}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsAttachments}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.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
|
||||
a.flex.js-field-has-attachments(title="{{_ 'attachments'}}" class="{{#if allowsAttachments}}is-checked{{/if}}")
|
||||
span {{#if allowsAttachments}}✅{{else}}⬜{{/if}}
|
||||
.card-settings-column
|
||||
span
|
||||
| 📎
|
||||
| {{_ 'attachments'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-badge-attachment-on-minicard(class="{{#if allowsBadgeAttachmentOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsBadgeAttachmentOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 📎
|
||||
| {{_ 'badge-attachment-on-minicard'}}
|
||||
div.check-div
|
||||
a.flex.js-field-has-cover-attachment-on-minicard(class="{{#if allowsCoverAttachmentOnMinicard}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsCoverAttachmentOnMinicard}}is-checked{{/if}}")
|
||||
.card-settings-row
|
||||
.card-settings-column
|
||||
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
|
||||
| 📖
|
||||
| 🖼️
|
||||
|
|
@ -364,27 +475,27 @@ template(name="boardCardSettingsPopup")
|
|||
template(name="boardSubtaskSettingsPopup")
|
||||
form.board-subtask-settings
|
||||
h3 {{_ 'show-parent-in-minicard'}}
|
||||
a#prefix-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-full-path'}}is-checked{{/if}}")
|
||||
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}}")
|
||||
span {{#if $eq presentParentTask 'prefix-with-full-path'}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'prefix-with-full-path'}}
|
||||
a#prefix-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if $eq presentParentTask 'prefix-with-parent'}}is-checked{{/if}}")
|
||||
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}}")
|
||||
span {{#if $eq presentParentTask 'prefix-with-parent'}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'prefix-with-parent'}}
|
||||
a#subtext-with-full-path.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-full-path'}}is-checked{{/if}}")
|
||||
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}}")
|
||||
span {{#if $eq presentParentTask 'subtext-with-full-path'}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'subtext-with-full-path'}}
|
||||
a#subtext-with-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if $eq presentParentTask 'subtext-with-parent'}}is-checked{{/if}}")
|
||||
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}}")
|
||||
span {{#if $eq presentParentTask 'subtext-with-parent'}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'subtext-with-parent'}}
|
||||
a#no-parent.flex.js-field-show-parent-in-minicard(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
|
||||
a#no-parent.flex.js-field-show-parent-in-minicard(title="{{_ 'no-parent'}}" class="{{#if $eq presentParentTask 'no-parent'}}is-checked{{/if}}")
|
||||
span {{#if $eq presentParentTask 'no-parent'}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'no-parent'}}
|
||||
div
|
||||
hr
|
||||
|
||||
div.check-div
|
||||
a.flex.js-field-has-subtasks(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
.materialCheckBox(class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
a.flex.js-field-has-subtasks(title="{{_ 'show-subtasks-field'}}" class="{{#if allowsSubtasks}}is-checked{{/if}}")
|
||||
span {{#if allowsSubtasks}}✅{{else}}⬜{{/if}}
|
||||
span {{_ 'show-subtasks-field'}}
|
||||
|
||||
label
|
||||
|
|
@ -426,13 +537,18 @@ template(name="archiveBoardPopup")
|
|||
| 📦
|
||||
| {{_ 'archive'}}
|
||||
|
||||
template(name="deleteDuplicateListsPopup")
|
||||
p {{_ 'delete-duplicate-lists-confirm'}}
|
||||
button.js-confirm.negate.full(type="submit")
|
||||
| 🗑️
|
||||
| {{_ 'delete'}}
|
||||
|
||||
template(name="outgoingWebhooksPopup")
|
||||
each integrations
|
||||
form.integration-form
|
||||
a.flex
|
||||
span {{#unless enabled}}✅{{else}}⬜{{/unless}}
|
||||
span {{_ 'disable-webhook'}}
|
||||
b
|
||||
.materialCheckBox(class="{{#unless enabled}}is-checked{{/unless}}")
|
||||
input.js-outgoing-webhooks-title(placeholder="{{_ 'webhook-title'}}" type="text" name="title" value=title)
|
||||
input.js-outgoing-webhooks-url(type="text" name="url" value=url)
|
||||
input.js-outgoing-webhooks-token(placeholder="{{_ 'webhook-token' }}" type="text" value=token name="token")
|
||||
|
|
@ -471,6 +587,10 @@ template(name="boardMenuPopup")
|
|||
| 📦
|
||||
| {{_ 'archived-items'}}
|
||||
if currentUser.isBoardAdmin
|
||||
li
|
||||
a.js-open-migrations
|
||||
| 🔧
|
||||
| {{_ 'migrations'}}
|
||||
li
|
||||
a.js-change-board-color
|
||||
| 🎨
|
||||
|
|
@ -511,6 +631,10 @@ template(name="boardMenuPopup")
|
|||
if currentUser.isBoardAdmin
|
||||
hr
|
||||
ul.pop-over-list
|
||||
// li
|
||||
// a.js-delete-duplicate-lists
|
||||
// | 🗑️
|
||||
// | {{_ 'delete-duplicate-lists'}}
|
||||
li
|
||||
a.js-archive-board
|
||||
| ➡️📦
|
||||
|
|
@ -631,7 +755,7 @@ template(name="removeBoardTeamPopup")
|
|||
|
||||
template(name="addMemberPopup")
|
||||
.js-search-member
|
||||
+EasySearch.Input(index=searchIndex)
|
||||
input.js-search-member-input(type="text" placeholder="{{_ 'email-address'}}")
|
||||
|
||||
if loading.get
|
||||
+spinner
|
||||
|
|
@ -639,25 +763,38 @@ template(name="addMemberPopup")
|
|||
.warning {{_ error.get}}
|
||||
else
|
||||
ul.pop-over-list
|
||||
+EasySearch.Each(index=searchIndex)
|
||||
each searchResults
|
||||
li.item.js-member-item(class="{{#if isBoardMember}}disabled{{/if}}")
|
||||
a.name.js-select-member(title="{{profile.fullname}} ({{username}})")
|
||||
+userAvatar(userId=__originalId)
|
||||
+userAvatar(userId=_id)
|
||||
span.full-name
|
||||
= profile.fullname
|
||||
| (<span class="username">{{username}}</span>)
|
||||
if isBoardMember
|
||||
.quiet ({{_ 'joined'}})
|
||||
|
||||
+EasySearch.IfSearching(index=searchIndex)
|
||||
if searching.get
|
||||
+spinner
|
||||
|
||||
+EasySearch.IfNoResults(index=searchIndex)
|
||||
if noResults.get
|
||||
.manage-member-section
|
||||
p.quiet {{_ 'no-results'}}
|
||||
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")
|
||||
ul.pop-over-list
|
||||
li
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ const viewTitles = {
|
|||
multiselection: 'multi-selection',
|
||||
customFields: 'custom-fields',
|
||||
archives: 'archives',
|
||||
migrations: 'migrations',
|
||||
};
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
|
|
@ -195,7 +196,7 @@ BlazeComponent.extendComponent({
|
|||
events() {
|
||||
return [
|
||||
{
|
||||
'click #toggleShowActivitiesBoard'() {
|
||||
'click .js-toggle-show-activities'() {
|
||||
Utils.getCurrentBoard().toggleShowActivities();
|
||||
},
|
||||
},
|
||||
|
|
@ -271,10 +272,53 @@ Template.boardMenuPopup.events({
|
|||
Sidebar.setView('archives');
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-open-migrations'() {
|
||||
Sidebar.setView('migrations');
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-change-board-color': Popup.open('boardChangeColor'),
|
||||
'click .js-change-background-image': Popup.open('boardChangeBackgroundImage'),
|
||||
'click .js-board-info-on-my-boards': Popup.open('boardInfoOnMyBoards'),
|
||||
'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() {
|
||||
const currentBoard = Utils.getCurrentBoard();
|
||||
currentBoard.archive();
|
||||
|
|
@ -822,7 +866,11 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
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() {
|
||||
|
|
@ -874,7 +922,11 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
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) {
|
||||
result = 'no-parent';
|
||||
}
|
||||
|
|
@ -886,19 +938,11 @@ BlazeComponent.extendComponent({
|
|||
{
|
||||
'click .js-field-has-subtasks'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
|
||||
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
|
||||
$(`.js-field-has-subtasks ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
$('.js-field-has-subtasks').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsSubtasks;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsSubtasks: newValue } });
|
||||
$('.js-field-deposit-board').prop(
|
||||
'disabled',
|
||||
!this.currentBoard.allowsSubtasks,
|
||||
!newValue,
|
||||
);
|
||||
},
|
||||
'change .js-field-deposit-board'(evt) {
|
||||
|
|
@ -914,28 +958,13 @@ BlazeComponent.extendComponent({
|
|||
evt.preventDefault();
|
||||
},
|
||||
'click .js-field-show-parent-in-minicard'(evt) {
|
||||
const value =
|
||||
evt.target.id ||
|
||||
$(evt.target).parent()[0].id ||
|
||||
$(evt.target)
|
||||
.parent()[0]
|
||||
.parent()[0].id;
|
||||
const options = [
|
||||
'prefix-with-full-path',
|
||||
'prefix-with-parent',
|
||||
'subtext-with-full-path',
|
||||
'subtext-with-parent',
|
||||
'no-parent',
|
||||
];
|
||||
options.forEach(function(element) {
|
||||
if (element !== value) {
|
||||
$(`#${element} ${MCB}`).toggleClass(CKCLS, false);
|
||||
$(`#${element}`).toggleClass(CKCLS, false);
|
||||
}
|
||||
});
|
||||
$(`#${value} ${MCB}`).toggleClass(CKCLS, true);
|
||||
$(`#${value}`).toggleClass(CKCLS, true);
|
||||
this.currentBoard.setPresentParentTask(value);
|
||||
// Get the ID from the anchor element, not the span
|
||||
const anchorElement = $(evt.target).closest('.js-field-show-parent-in-minicard')[0];
|
||||
const value = anchorElement ? anchorElement.id : null;
|
||||
|
||||
if (value) {
|
||||
Boards.update(this.currentBoard._id, { $set: { presentParentTask: value } });
|
||||
}
|
||||
evt.preventDefault();
|
||||
},
|
||||
},
|
||||
|
|
@ -949,115 +978,168 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
allowsReceivedDate() {
|
||||
return this.currentBoard.allowsReceivedDate;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsReceivedDate : false;
|
||||
},
|
||||
|
||||
allowsStartDate() {
|
||||
return this.currentBoard.allowsStartDate;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsStartDate : false;
|
||||
},
|
||||
|
||||
allowsDueDate() {
|
||||
return this.currentBoard.allowsDueDate;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsDueDate : false;
|
||||
},
|
||||
|
||||
allowsEndDate() {
|
||||
return this.currentBoard.allowsEndDate;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsEndDate : false;
|
||||
},
|
||||
|
||||
allowsSubtasks() {
|
||||
return this.currentBoard.allowsSubtasks;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsSubtasks : false;
|
||||
},
|
||||
|
||||
allowsCreator() {
|
||||
return this.currentBoard.allowsCreator ?? false;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? (currentBoard.allowsCreator ?? false) : false;
|
||||
},
|
||||
|
||||
allowsCreatorOnMinicard() {
|
||||
return this.currentBoard.allowsCreatorOnMinicard ?? false;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? (currentBoard.allowsCreatorOnMinicard ?? false) : false;
|
||||
},
|
||||
|
||||
allowsMembers() {
|
||||
return this.currentBoard.allowsMembers;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsMembers : false;
|
||||
},
|
||||
|
||||
allowsAssignee() {
|
||||
return this.currentBoard.allowsAssignee;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsAssignee : false;
|
||||
},
|
||||
|
||||
allowsAssignedBy() {
|
||||
return this.currentBoard.allowsAssignedBy;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsAssignedBy : false;
|
||||
},
|
||||
|
||||
allowsRequestedBy() {
|
||||
return this.currentBoard.allowsRequestedBy;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsRequestedBy : false;
|
||||
},
|
||||
|
||||
allowsCardSortingByNumber() {
|
||||
return this.currentBoard.allowsCardSortingByNumber;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsCardSortingByNumber : false;
|
||||
},
|
||||
|
||||
allowsShowLists() {
|
||||
return this.currentBoard.allowsShowLists;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsShowLists : false;
|
||||
},
|
||||
|
||||
|
||||
allowsLabels() {
|
||||
return this.currentBoard.allowsLabels;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsLabels : false;
|
||||
},
|
||||
|
||||
allowsShowListsOnMinicard() {
|
||||
return this.currentBoard.allowsShowListsOnMinicard;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsShowListsOnMinicard : false;
|
||||
},
|
||||
|
||||
allowsChecklists() {
|
||||
return this.currentBoard.allowsChecklists;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsChecklists : false;
|
||||
},
|
||||
|
||||
allowsAttachments() {
|
||||
return this.currentBoard.allowsAttachments;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsAttachments : false;
|
||||
},
|
||||
|
||||
allowsComments() {
|
||||
return this.currentBoard.allowsComments;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsComments : false;
|
||||
},
|
||||
|
||||
allowsCardNumber() {
|
||||
return this.currentBoard.allowsCardNumber;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsCardNumber : false;
|
||||
},
|
||||
|
||||
allowsDescriptionTitle() {
|
||||
return this.currentBoard.allowsDescriptionTitle;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsDescriptionTitle : false;
|
||||
},
|
||||
|
||||
allowsDescriptionText() {
|
||||
return this.currentBoard.allowsDescriptionText;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsDescriptionText : false;
|
||||
},
|
||||
|
||||
isBoardSelected() {
|
||||
return this.currentBoard.dateSettingsDefaultBoardID;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.dateSettingsDefaultBoardID : false;
|
||||
},
|
||||
|
||||
isNullBoardSelected() {
|
||||
return (
|
||||
this.currentBoard.dateSettingsDefaultBoardId === null ||
|
||||
this.currentBoard.dateSettingsDefaultBoardId === undefined
|
||||
);
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? (
|
||||
currentBoard.dateSettingsDefaultBoardId === null ||
|
||||
currentBoard.dateSettingsDefaultBoardId === undefined
|
||||
) : true;
|
||||
},
|
||||
|
||||
allowsDescriptionTextOnMinicard() {
|
||||
return this.currentBoard.allowsDescriptionTextOnMinicard;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsDescriptionTextOnMinicard : false;
|
||||
},
|
||||
|
||||
allowsCoverAttachmentOnMinicard() {
|
||||
return this.currentBoard.allowsCoverAttachmentOnMinicard;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsCoverAttachmentOnMinicard : false;
|
||||
},
|
||||
|
||||
allowsBadgeAttachmentOnMinicard() {
|
||||
return this.currentBoard.allowsBadgeAttachmentOnMinicard;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsBadgeAttachmentOnMinicard : false;
|
||||
},
|
||||
|
||||
allowsCardSortingByNumberOnMinicard() {
|
||||
return this.currentBoard.allowsCardSortingByNumberOnMinicard;
|
||||
const boardId = Session.get('currentBoard');
|
||||
const currentBoard = ReactiveCache.getBoard(boardId);
|
||||
return currentBoard ? currentBoard.allowsCardSortingByNumberOnMinicard : false;
|
||||
},
|
||||
|
||||
boards() {
|
||||
|
|
@ -1100,203 +1182,73 @@ BlazeComponent.extendComponent({
|
|||
{
|
||||
'click .js-field-has-receiveddate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsReceivedDate = !this.currentBoard
|
||||
.allowsReceivedDate;
|
||||
this.currentBoard.setAllowsReceivedDate(
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
$(`.js-field-has-receiveddate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
$('.js-field-has-receiveddate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsReceivedDate,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsReceivedDate;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsReceivedDate: newValue } });
|
||||
},
|
||||
'click .js-field-has-startdate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsStartDate = !this.currentBoard
|
||||
.allowsStartDate;
|
||||
this.currentBoard.setAllowsStartDate(
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
$(`.js-field-has-startdate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
$('.js-field-has-startdate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsStartDate,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsStartDate;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsStartDate: newValue } });
|
||||
},
|
||||
'click .js-field-has-enddate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsEndDate = !this.currentBoard.allowsEndDate;
|
||||
this.currentBoard.setAllowsEndDate(this.currentBoard.allowsEndDate);
|
||||
$(`.js-field-has-enddate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsEndDate,
|
||||
);
|
||||
$('.js-field-has-enddate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsEndDate,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsEndDate;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsEndDate: newValue } });
|
||||
},
|
||||
'click .js-field-has-duedate'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsDueDate = !this.currentBoard.allowsDueDate;
|
||||
this.currentBoard.setAllowsDueDate(this.currentBoard.allowsDueDate);
|
||||
$(`.js-field-has-duedate ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDueDate,
|
||||
);
|
||||
$('.js-field-has-duedate').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsDueDate,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsDueDate;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsDueDate: newValue } });
|
||||
},
|
||||
'click .js-field-has-subtasks'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsSubtasks = !this.currentBoard.allowsSubtasks;
|
||||
this.currentBoard.setAllowsSubtasks(this.currentBoard.allowsSubtasks);
|
||||
$(`.js-field-has-subtasks ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
$('.js-field-has-subtasks').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsSubtasks,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsSubtasks;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsSubtasks: newValue } });
|
||||
},
|
||||
'click .js-field-has-creator'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCreator = !this.currentBoard.allowsCreator;
|
||||
this.currentBoard.setAllowsCreator(this.currentBoard.allowsCreator);
|
||||
$(`.js-field-has-creator ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreator,
|
||||
);
|
||||
$('.js-field-has-creator').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreator,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsCreator;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsCreator: newValue } });
|
||||
},
|
||||
'click .js-field-has-creator-on-minicard'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCreatorOnMinicard = !this.currentBoard.allowsCreatorOnMinicard;
|
||||
this.currentBoard.setAllowsCreatorOnMinicard(this.currentBoard.allowsCreatorOnMinicard);
|
||||
$(`.js-field-has-creator-on-minicard ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreatorOnMinicard,
|
||||
);
|
||||
$('.js-field-has-creator-on-minicard').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsCreatorOnMinicard,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsCreatorOnMinicard;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsCreatorOnMinicard: newValue } });
|
||||
},
|
||||
'click .js-field-has-members'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsMembers = !this.currentBoard.allowsMembers;
|
||||
this.currentBoard.setAllowsMembers(this.currentBoard.allowsMembers);
|
||||
$(`.js-field-has-members ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsMembers,
|
||||
);
|
||||
$('.js-field-has-members').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsMembers,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsMembers;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsMembers: newValue } });
|
||||
},
|
||||
'click .js-field-has-assignee'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsAssignee = !this.currentBoard.allowsAssignee;
|
||||
this.currentBoard.setAllowsAssignee(this.currentBoard.allowsAssignee);
|
||||
$(`.js-field-has-assignee ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignee,
|
||||
);
|
||||
$('.js-field-has-assignee').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignee,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsAssignee;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsAssignee: newValue } });
|
||||
},
|
||||
'click .js-field-has-assigned-by'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsAssignedBy = !this.currentBoard
|
||||
.allowsAssignedBy;
|
||||
this.currentBoard.setAllowsAssignedBy(
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
$(`.js-field-has-assigned-by ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
$('.js-field-has-assigned-by').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsAssignedBy,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsAssignedBy;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsAssignedBy: newValue } });
|
||||
},
|
||||
'click .js-field-has-requested-by'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsRequestedBy = !this.currentBoard
|
||||
.allowsRequestedBy;
|
||||
this.currentBoard.setAllowsRequestedBy(
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
$(`.js-field-has-requested-by ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
$('.js-field-has-requested-by').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsRequestedBy,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsRequestedBy;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsRequestedBy: newValue } });
|
||||
},
|
||||
'click .js-field-has-card-sorting-by-number'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsCardSortingByNumber = !this.currentBoard
|
||||
.allowsCardSortingByNumber;
|
||||
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,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsCardSortingByNumber;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsCardSortingByNumber: newValue } });
|
||||
},
|
||||
'click .js-field-has-card-show-lists'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsShowLists = !this.currentBoard
|
||||
.allowsShowLists;
|
||||
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,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsShowLists;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsShowLists: newValue } });
|
||||
},
|
||||
'click .js-field-has-labels'(evt) {
|
||||
evt.preventDefault();
|
||||
this.currentBoard.allowsLabels = !this.currentBoard.allowsLabels;
|
||||
this.currentBoard.setAllowsLabels(this.currentBoard.allowsLabels);
|
||||
$(`.js-field-has-labels ${MCB}`).toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsLabels,
|
||||
);
|
||||
$('.js-field-has-labels').toggleClass(
|
||||
CKCLS,
|
||||
this.currentBoard.allowsLabels,
|
||||
);
|
||||
const newValue = !this.currentBoard.allowsLabels;
|
||||
Boards.update(this.currentBoard._id, { $set: { allowsLabels: newValue } });
|
||||
},
|
||||
'click .js-field-has-card-show-lists-on-minicard'(evt) {
|
||||
evt.preventDefault();
|
||||
|
|
@ -1492,19 +1444,27 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
}).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({
|
||||
onCreated() {
|
||||
this.error = new ReactiveVar('');
|
||||
this.loading = new ReactiveVar(false);
|
||||
// Use Session variables
|
||||
this.searchTimeout = null;
|
||||
},
|
||||
|
||||
onRendered() {
|
||||
this.find('.js-search-member input').focus();
|
||||
this.find('.js-search-member-input').focus();
|
||||
this.setLoading(false);
|
||||
},
|
||||
|
||||
isBoardMember() {
|
||||
const userId = this.currentData().__originalId;
|
||||
const userId = this.currentData()._id;
|
||||
const user = ReactiveCache.getUser(userId);
|
||||
return user && user.isBoardMember();
|
||||
},
|
||||
|
|
@ -1514,15 +1474,35 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
Session.set('addMemberPopup.error', error);
|
||||
},
|
||||
|
||||
setLoading(w) {
|
||||
this.loading.set(w);
|
||||
Session.set('addMemberPopup.loading', w);
|
||||
},
|
||||
|
||||
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) {
|
||||
|
|
@ -1540,18 +1520,30 @@ BlazeComponent.extendComponent({
|
|||
events() {
|
||||
return [
|
||||
{
|
||||
'keyup input'() {
|
||||
'keyup .js-search-member-input'(event) {
|
||||
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'() {
|
||||
const userId = this.currentData().__originalId;
|
||||
const userId = this.currentData()._id;
|
||||
const currentBoard = Utils.getCurrentBoard();
|
||||
if (!currentBoard.hasMember(userId)) {
|
||||
this.inviteUser(userId);
|
||||
}
|
||||
},
|
||||
'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)) {
|
||||
this.inviteUser(idNameEmail);
|
||||
} else this.setError('email-invalid');
|
||||
|
|
@ -1562,7 +1554,35 @@ BlazeComponent.extendComponent({
|
|||
}).register('addMemberPopup');
|
||||
|
||||
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({
|
||||
|
|
|
|||
|
|
@ -95,3 +95,7 @@ template(name="createCustomFieldPopup")
|
|||
template(name="deleteCustomFieldPopup")
|
||||
p {{_ "custom-field-delete-pop"}}
|
||||
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")
|
||||
|
|
|
|||
109
client/components/sidebar/sidebarMigrations.jade
Normal file
109
client/components/sidebar/sidebarMigrations.jade
Normal 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'}}
|
||||
341
client/components/sidebar/sidebarMigrations.js
Normal file
341
client/components/sidebar/sidebarMigrations.js
Normal 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');
|
||||
|
|
@ -25,25 +25,26 @@ template(name="swimlaneFixedHeader")
|
|||
.swimlane-header-menu
|
||||
if currentUser
|
||||
unless currentUser.isCommentOnly
|
||||
a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}")
|
||||
| ➕
|
||||
a.js-open-swimlane-menu(title="{{_ 'swimlaneActionPopup-title'}}")
|
||||
| ☰
|
||||
//// TODO: Collapse Swimlane: make button working, etc.
|
||||
//unless collapsed
|
||||
// a.js-collapse-swimlane(title="{{_ 'collapse'}}")
|
||||
// i.fa.fa-arrow-down.swimlane-header-collapse-down
|
||||
// ⬆️.swimlane-header-collapse-up
|
||||
//if collapsed
|
||||
// a.js-collapse-swimlane(title="{{_ 'uncollapse'}}")
|
||||
// ⬆️.swimlane-header-collapse-up
|
||||
// i.fa.fa-arrow-down.swimlane-header-collapse-down
|
||||
unless isTouchScreen
|
||||
a.swimlane-header-handle.handle.js-swimlane-header-handle
|
||||
| ↕️
|
||||
if isTouchScreen
|
||||
a.swimlane-header-miniscreen-handle.handle.js-swimlane-header-handle
|
||||
| ↕️
|
||||
unless currentUser.isWorker
|
||||
a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}")
|
||||
| ➕
|
||||
a.js-open-swimlane-menu(title="{{_ 'swimlaneActionPopup-title'}}")
|
||||
| ☰
|
||||
//// TODO: Collapse Swimlane: make button working, etc.
|
||||
//unless collapsed
|
||||
// a.js-collapse-swimlane(title="{{_ 'collapse'}}")
|
||||
// i.fa.fa-arrow-down.swimlane-header-collapse-down
|
||||
// ⬆️.swimlane-header-collapse-up
|
||||
//if collapsed
|
||||
// a.js-collapse-swimlane(title="{{_ 'uncollapse'}}")
|
||||
// ⬆️.swimlane-header-collapse-up
|
||||
// i.fa.fa-arrow-down.swimlane-header-collapse-down
|
||||
unless isTouchScreen
|
||||
a.swimlane-header-handle.handle.js-swimlane-header-handle
|
||||
| ↕️
|
||||
if isTouchScreen
|
||||
a.swimlane-header-miniscreen-handle.handle.js-swimlane-header-handle
|
||||
| ↕️
|
||||
|
||||
template(name="editSwimlaneTitleForm")
|
||||
.list-composer
|
||||
|
|
|
|||
|
|
@ -178,6 +178,11 @@ BlazeComponent.extendComponent({
|
|||
events() {
|
||||
return [
|
||||
{
|
||||
'submit form'(event) {
|
||||
event.preventDefault();
|
||||
this.currentSwimlane.setColor(this.currentColor.get());
|
||||
Popup.back();
|
||||
},
|
||||
'click .js-palette-color'() {
|
||||
this.currentColor.set(this.currentData().color);
|
||||
},
|
||||
|
|
|
|||
|
|
@ -112,7 +112,7 @@
|
|||
padding: 7px;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
left: 87vw;
|
||||
right: 10px;
|
||||
font-size: 24px;
|
||||
cursor: move;
|
||||
z-index: 15;
|
||||
|
|
|
|||
|
|
@ -228,10 +228,8 @@ function initSortable(boardComponent, $listsDom) {
|
|||
|
||||
// Don't cancel the sortable when moving to a different swimlane
|
||||
// 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 {
|
||||
Lists.update(list._id, {
|
||||
|
|
@ -682,6 +680,11 @@ Template.swimlane.helpers({
|
|||
canSeeAddList() {
|
||||
return ReactiveCache.getCurrentUser().isBoardAdmin();
|
||||
},
|
||||
|
||||
lists() {
|
||||
// Return per-swimlane lists for this swimlane
|
||||
return this.myLists();
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize sortable on DOM elements
|
||||
|
|
@ -722,6 +725,89 @@ setTimeout(() => {
|
|||
}
|
||||
},
|
||||
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 {
|
||||
const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]);
|
||||
|
|
@ -731,6 +817,18 @@ setTimeout(() => {
|
|||
} catch (e) {
|
||||
// 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) {
|
||||
// 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 {
|
||||
const boardComponent = BlazeComponent.getComponentForElement(ui.item[0]);
|
||||
|
|
@ -778,6 +959,18 @@ setTimeout(() => {
|
|||
} catch (e) {
|
||||
// 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');
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
template(name="userAvatar")
|
||||
a.member(class="js-{{#if assignee}}assignee{{else}}member{{/if}}" title="{{userData.profile.fullname}} ({{userData.username}}) {{_ memberType}}")
|
||||
if userData.profile.avatarUrl
|
||||
img.avatar.avatar-image(src="{{userData.profile.avatarUrl}}")
|
||||
img.avatar.avatar-image(src="{{avatarUrl}}")
|
||||
else
|
||||
+userAvatarInitials(userId=userData._id)
|
||||
|
||||
|
|
@ -87,7 +87,7 @@ template(name="changeAvatarPopup")
|
|||
each uploadedAvatars
|
||||
li: a.js-select-avatar
|
||||
.member
|
||||
img.avatar.avatar-image(src="{{link}}?auth=false&brokenIsFine=true")
|
||||
img.avatar.avatar-image(src="{{link}}")
|
||||
| {{_ 'uploaded-avatar'}}
|
||||
if isSelected
|
||||
| ✅
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
const user = ReactiveCache.getUser(this.userId);
|
||||
return user && user.isBoardAdmin() ? 'admin' : 'normal';
|
||||
|
|
@ -179,7 +194,7 @@ BlazeComponent.extendComponent({
|
|||
isSelected() {
|
||||
const userProfile = ReactiveCache.getCurrentUser().profile;
|
||||
const avatarUrl = userProfile && userProfile.avatarUrl;
|
||||
const currentAvatarUrl = `${this.currentData().link()}?auth=false&brokenIsFine=true`;
|
||||
const currentAvatarUrl = this.currentData().link();
|
||||
return avatarUrl === currentAvatarUrl;
|
||||
},
|
||||
|
||||
|
|
@ -220,7 +235,7 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
},
|
||||
'click .js-select-avatar'() {
|
||||
const avatarUrl = `${this.currentData().link()}?auth=false&brokenIsFine=true`;
|
||||
const avatarUrl = this.currentData().link();
|
||||
this.setAvatar(avatarUrl);
|
||||
},
|
||||
'click .js-select-initials'() {
|
||||
|
|
|
|||
|
|
@ -12,11 +12,6 @@ template(name="headerUserBar")
|
|||
|
||||
template(name="memberMenuPopup")
|
||||
ul.pop-over-list
|
||||
// Bookmarks at the very top
|
||||
li
|
||||
a.js-open-bookmarks
|
||||
| 🔖
|
||||
| {{_ 'bookmarks'}}
|
||||
with currentUser
|
||||
li
|
||||
a.js-my-cards(href="{{pathFor 'my-cards'}}")
|
||||
|
|
@ -32,6 +27,7 @@ template(name="memberMenuPopup")
|
|||
| {{_ 'globalSearch-title'}}
|
||||
li
|
||||
a(href="{{pathFor 'home'}}")
|
||||
| 🏠
|
||||
| 🏠
|
||||
| {{_ 'all-boards'}}
|
||||
li
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ Blaze.registerHelper('canModifyCard', () =>
|
|||
Utils.canModifyCard(),
|
||||
);
|
||||
|
||||
Blaze.registerHelper('canMoveCard', () =>
|
||||
Utils.canMoveCard(),
|
||||
);
|
||||
|
||||
Blaze.registerHelper('canModifyBoard', () =>
|
||||
Utils.canModifyBoard(),
|
||||
);
|
||||
|
|
|
|||
73
client/lib/boardMultiSelection.js
Normal file
73
client/lib/boardMultiSelection.js
Normal 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);
|
||||
},
|
||||
};
|
||||
|
|
@ -179,11 +179,16 @@ export class CardSearchPagedComponent extends BlazeComponent {
|
|||
console.log('getResults - no sessionData or no cards array, trying direct card search');
|
||||
}
|
||||
// Fallback: try to get cards directly from the client-side collection
|
||||
// Use a more efficient query with limit and sort
|
||||
const selector = {
|
||||
type: 'cardType-card',
|
||||
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') {
|
||||
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) {
|
||||
allCards.forEach(card => {
|
||||
if (card && card._id) {
|
||||
if (process.env.DEBUG === 'true') {
|
||||
console.log('getResults - direct card:', card._id, card.title);
|
||||
}
|
||||
cards.push(card);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,32 +1,27 @@
|
|||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
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
|
||||
function adjustedTimeFormat() {
|
||||
return 'HH:mm';
|
||||
// Helper to check if a date is valid
|
||||
function isValidDate(date) {
|
||||
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 {
|
||||
template() {
|
||||
|
|
@ -76,10 +71,10 @@ export class DatePicker extends BlazeComponent {
|
|||
return '';
|
||||
}
|
||||
dateFormat() {
|
||||
return 'L';
|
||||
return 'YYYY-MM-DD';
|
||||
}
|
||||
timeFormat() {
|
||||
return 'LT';
|
||||
return 'HH:mm';
|
||||
}
|
||||
|
||||
events() {
|
||||
|
|
@ -89,7 +84,8 @@ export class DatePicker extends BlazeComponent {
|
|||
// Native HTML date input validation
|
||||
const dateValue = this.find('#date').value;
|
||||
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)) {
|
||||
this.error.set('');
|
||||
} else {
|
||||
|
|
@ -101,7 +97,8 @@ export class DatePicker extends BlazeComponent {
|
|||
// Native HTML time input validation
|
||||
const timeValue = this.find('#time').value;
|
||||
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)) {
|
||||
this.error.set('');
|
||||
} else {
|
||||
|
|
@ -121,7 +118,9 @@ export class DatePicker extends BlazeComponent {
|
|||
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)) {
|
||||
this.error.set('invalid');
|
||||
|
|
|
|||
94
client/lib/fixDuplicateLists.js
Normal file
94
client/lib/fixDuplicateLists.js
Normal 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;
|
||||
}
|
||||
|
||||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -218,6 +218,22 @@ window.Popup = new (class {
|
|||
const viewportHeight = $(window).height();
|
||||
const popupWidth = Math.min(380, viewportWidth * 0.55) + 15; // Add 15px for margin
|
||||
|
||||
// Check if this is an admin panel edit popup
|
||||
const isAdminEditPopup = $element.hasClass('edit-user') ||
|
||||
$element.hasClass('edit-org') ||
|
||||
$element.hasClass('edit-team');
|
||||
|
||||
if (isAdminEditPopup) {
|
||||
// Center the popup horizontally and use full height
|
||||
const centeredLeft = (viewportWidth - popupWidth) / 2;
|
||||
|
||||
return {
|
||||
left: Math.max(10, centeredLeft), // Ensure popup doesn't go off screen
|
||||
top: 10, // Start from top with small margin
|
||||
maxHeight: viewportHeight - 20, // Use full height minus small margins
|
||||
};
|
||||
}
|
||||
|
||||
// Calculate available height for popup
|
||||
const popupTop = offset.top + $element.outerHeight();
|
||||
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@ import DOMPurify from 'dompurify';
|
|||
export function getSecureDOMPurifyConfig() {
|
||||
return {
|
||||
// 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
|
||||
ALLOWED_ATTR: ['href', 'title', 'alt', 'src', 'width', 'height', 'target', 'rel'],
|
||||
// Allow safe protocols for links
|
||||
|
|
@ -44,7 +44,7 @@ export function getSecureDOMPurifyConfig() {
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
// Additional check for base64 encoded SVG with script tags
|
||||
if (src.startsWith('data:image/svg+xml;base64,')) {
|
||||
try {
|
||||
|
|
|
|||
|
|
@ -214,6 +214,15 @@ Utils = {
|
|||
);
|
||||
return ret;
|
||||
},
|
||||
canMoveCard() {
|
||||
const currentUser = ReactiveCache.getCurrentUser();
|
||||
const ret = (
|
||||
currentUser &&
|
||||
currentUser.isBoardMember() &&
|
||||
!currentUser.isCommentOnly()
|
||||
);
|
||||
return ret;
|
||||
},
|
||||
canModifyBoard() {
|
||||
const currentUser = ReactiveCache.getCurrentUser();
|
||||
const ret = (
|
||||
|
|
@ -231,9 +240,21 @@ Utils = {
|
|||
window.location.reload();
|
||||
},
|
||||
setBoardView(view) {
|
||||
currentUser = ReactiveCache.getCurrentUser();
|
||||
const currentUser = ReactiveCache.getCurrentUser();
|
||||
|
||||
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') {
|
||||
window.localStorage.setItem('boardView', 'board-view-swimlanes'); //true
|
||||
Utils.reload();
|
||||
|
|
|
|||
103
docs/Platforms/FOSS/Snap/Snap-build.md
Normal file
103
docs/Platforms/FOSS/Snap/Snap-build.md
Normal 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`
|
||||
|
|
@ -10,7 +10,7 @@ This is without container (without Docker or Snap).
|
|||
|
||||
Right click and download files 1-4:
|
||||
|
||||
1. [wekan-8.08-amd64-windows.zip](https://github.com/wekan/wekan/releases/download/v8.08/wekan-8.08-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)
|
||||
|
||||
|
|
@ -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.
|
||||
|
||||
7. Unzip `wekan-8.08-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)
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "تعليق محذوف %s",
|
||||
"activity-receivedDate": "edited received 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-endDate": "edited end date to %s of %s",
|
||||
"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\"} ]",
|
||||
"create": "إنشاء",
|
||||
"createBoardPopup-title": "إنشاء لوحة",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "استيراد لوحة",
|
||||
"createLabelPopup-title": "إنشاء علامة",
|
||||
"createCustomField": "انشاء حقل",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "تاريخ",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "صورة شخصية افتراضية",
|
||||
"delete": "حذف",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "تصحيح الإشعار",
|
||||
"editProfilePopup-title": "تعديل الملف الشخصي",
|
||||
"email": "البريد الإلكتروني",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "انا",
|
||||
"dueCardsViewChange-choice-all": "كل المستخدمين",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "изтрит коментар %s",
|
||||
"activity-receivedDate": "edited received 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-endDate": "edited end date to %s of %s",
|
||||
"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\"} ]",
|
||||
"create": "Създай",
|
||||
"createBoardPopup-title": "Създай Табло",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Импортирай Табло",
|
||||
"createLabelPopup-title": "Създай Табло",
|
||||
"createCustomField": "Създай Поле",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Собствени полета",
|
||||
"date": "Дата",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Отказ",
|
||||
"default-avatar": "Основен аватар",
|
||||
"delete": "Изтрий",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Промени известията",
|
||||
"editProfilePopup-title": "Промяна на профила",
|
||||
"email": "Имейл",
|
||||
"email-address": "Email Address",
|
||||
"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-fail": "Неуспешно изпращане на имейла",
|
||||
|
|
@ -754,6 +768,8 @@
|
|||
"delete-board-confirm-popup": "Всички списъци, карти, имена и действия ще бъдат изтрити и няма да можете да възстановите съдържанието на дъската. Няма връщане назад.",
|
||||
"boardDeletePopup-title": "Изтриване на Таблото?",
|
||||
"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": "по подразбиране",
|
||||
"defaultdefault": "по подразбиране",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Настройки на Подзадачите",
|
||||
"card-settings": "Настройки на Карта",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Настройки за Подзадачите за това Табло",
|
||||
"boardSubtaskSettingsPopup-title": "Настройки на Подзадачите",
|
||||
"boardCardSettingsPopup-title": "Настройки на Карта",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Вложете под-задачи към тази дъска:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Завършено",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Krouiñ",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Diverkañ",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "Ha esborrar el comentari %s",
|
||||
"activity-receivedDate": "editat la data de recepció 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-endDate": "data de finalització editada a %s de %s",
|
||||
"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\"} ]",
|
||||
"create": "Crea",
|
||||
"createBoardPopup-title": "Crea tauler",
|
||||
"createTemplateContainerPopup-title": "Afegeix un Contenidor de plantilles",
|
||||
"chooseBoardSourcePopup-title": "Importa tauler",
|
||||
"createLabelPopup-title": "Crea etiqueta",
|
||||
"createCustomField": "Crear campament",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Camps Personalitzats",
|
||||
"date": "Dades",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Declina",
|
||||
"default-avatar": "Avatar per defecte",
|
||||
"delete": "Esborra",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edita la notificació",
|
||||
"editProfilePopup-title": "Edita el teu Perfil",
|
||||
"email": "Correu electrònic",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "Vols suprimir 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": "Per defecte",
|
||||
"defaultdefault": "Per defecte",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Configuració de subtasques",
|
||||
"card-settings": "Configuració de fitxa",
|
||||
"minicard-settings": "Configuració de la minifitxa",
|
||||
"boardSubtaskSettingsPopup-title": "Configuració de les subtasques del tauler",
|
||||
"boardSubtaskSettingsPopup-title": "Configuració de subtasques",
|
||||
"boardCardSettingsPopup-title": "Configuració de fitxa",
|
||||
"boardMinicardSettingsPopup-title": "Configuració de la minifitxa",
|
||||
"deposit-subtasks-board": "Diposita subtasques a aquest tauler:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "jo",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "No s'ha trobat el tauler '%s'.",
|
||||
"swimlane-title-not-found": "No s'ha trobat el carril '%s'.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completat",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "smazat komentář %s",
|
||||
"activity-receivedDate": "editoval(a) datum přijetí 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-endDate": "editoval(a) datum ukončení na %s z %s",
|
||||
"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\"} ]",
|
||||
"create": "Vytvořit",
|
||||
"createBoardPopup-title": "Vytvořit tablo",
|
||||
"createTemplateContainerPopup-title": "Přidat kontejner šablony",
|
||||
"chooseBoardSourcePopup-title": "Importovat tablo",
|
||||
"createLabelPopup-title": "Vytvořit štítek",
|
||||
"createCustomField": "Vytvořit pole",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Vlastní pole",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Zamítnout",
|
||||
"default-avatar": "Výchozí avatar",
|
||||
"delete": "Smazat",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Změnit notifikace",
|
||||
"editProfilePopup-title": "Upravit profil",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Výchozí",
|
||||
"defaultdefault": "Výchozí",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Nastavení podúkolů",
|
||||
"card-settings": "Nastavení karet",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů tabla",
|
||||
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů",
|
||||
"boardCardSettingsPopup-title": "Nastavení karet",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Vložit podúkoly do tohoto tabla",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Moje",
|
||||
"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í.",
|
||||
"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",
|
||||
"board-title-not-found": "Tablo '%s' nenalezeno.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' nenalezena.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Dokončeno",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "smazat komentář %s",
|
||||
"activity-receivedDate": "editoval(a) datum přijetí 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-endDate": "editoval(a) datum ukončení na %s z %s",
|
||||
"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\"} ]",
|
||||
"create": "Vytvořit",
|
||||
"createBoardPopup-title": "Vytvořit tablo",
|
||||
"createTemplateContainerPopup-title": "Přidat kontejner šablony",
|
||||
"chooseBoardSourcePopup-title": "Importovat tablo",
|
||||
"createLabelPopup-title": "Vytvořit štítek",
|
||||
"createCustomField": "Vytvořit pole",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Vlastní pole",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Zamítnout",
|
||||
"default-avatar": "Výchozí avatar",
|
||||
"delete": "Smazat",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Změnit notifikace",
|
||||
"editProfilePopup-title": "Upravit profil",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Výchozí",
|
||||
"defaultdefault": "Výchozí",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Nastavení podúkolů",
|
||||
"card-settings": "Nastavení karet",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů tabla",
|
||||
"boardSubtaskSettingsPopup-title": "Nastavení podúkolů",
|
||||
"boardCardSettingsPopup-title": "Nastavení karet",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Vložit podúkoly do tohoto tabla",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Moje",
|
||||
"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í.",
|
||||
"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",
|
||||
"board-title-not-found": "Tablo '%s' nenalezeno.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' nenalezena.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Dokončeno",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "slettede kommentar %s",
|
||||
"activity-receivedDate": "edited received 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-endDate": "edited end date to %s of %s",
|
||||
"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\"} ]",
|
||||
"create": "Opret",
|
||||
"createBoardPopup-title": "Opret tavle",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Importér tavle",
|
||||
"createLabelPopup-title": "Opret etikette",
|
||||
"createCustomField": "Opret felt",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Brugerdefinerede felter",
|
||||
"date": "Dato",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Afslå",
|
||||
"default-avatar": "Standard-avatar",
|
||||
"delete": "Slet",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Redigér notifikation",
|
||||
"editProfilePopup-title": "Redigér profil",
|
||||
"email": "E-mail",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Standard",
|
||||
"defaultdefault": "Standard",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Indstillinger for delopgaver",
|
||||
"card-settings": "Indstillinger for kort",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Indstillinger for delopgaver i tavle",
|
||||
"boardSubtaskSettingsPopup-title": "Indstillinger for delopgaver",
|
||||
"boardCardSettingsPopup-title": "Indstillinger for kort",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Indsæt delopgaver på denne tavle:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Fuldført",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "löschte Kommentar %s",
|
||||
"activity-receivedDate": "hat Empfangsdatum 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-endDate": "hat Enddatum zu %s geändert auf %s",
|
||||
"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\"} ]",
|
||||
"create": "Erstellen",
|
||||
"createBoardPopup-title": "Board erstellen",
|
||||
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
|
||||
"chooseBoardSourcePopup-title": "Board importieren",
|
||||
"createLabelPopup-title": "Label erstellen",
|
||||
"createCustomField": "Feld erstellen",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Benutzerdefinierte Felder",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Ablehnen",
|
||||
"default-avatar": "Standard Profilbild",
|
||||
"delete": "Löschen",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Benachrichtigung ändern",
|
||||
"editProfilePopup-title": "Profil ändern",
|
||||
"email": "E-Mail",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Standard",
|
||||
"defaultdefault": "Standard",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Einstellungen für Teilaufgaben",
|
||||
"card-settings": "Karten-Einstellungen",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben",
|
||||
"boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
|
||||
"boardCardSettingsPopup-title": "Karten-Einstellungen",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Ich",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board „%s“ nicht gefunden.",
|
||||
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "abgeschlossen",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "löschte Kommentar %s",
|
||||
"activity-receivedDate": "hat Empfangsdatum 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-endDate": "hat Enddatum zu %s geändert auf %s",
|
||||
"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\"} ]",
|
||||
"create": "Erstellen",
|
||||
"createBoardPopup-title": "Board erstellen",
|
||||
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
|
||||
"chooseBoardSourcePopup-title": "Board importieren",
|
||||
"createLabelPopup-title": "Label erstellen",
|
||||
"createCustomField": "Feld erstellen",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Benutzerdefinierte Felder",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Ablehnen",
|
||||
"default-avatar": "Standard Profilbild",
|
||||
"delete": "Löschen",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Benachrichtigung ändern",
|
||||
"editProfilePopup-title": "Profil ändern",
|
||||
"email": "E-Mail",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Standard",
|
||||
"defaultdefault": "Standard",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Einstellungen für Teilaufgaben",
|
||||
"card-settings": "Karten-Einstellungen",
|
||||
"minicard-settings": "Einstellungen für Minikarte",
|
||||
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben",
|
||||
"boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
|
||||
"boardCardSettingsPopup-title": "Karten-Einstellungen",
|
||||
"boardMinicardSettingsPopup-title": "Einstellungen für Minikarte",
|
||||
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Ich",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board „%s“ nicht gefunden.",
|
||||
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "abgeschlossen",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "löschte Kommentar %s",
|
||||
"activity-receivedDate": "hat Empfangsdatum 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-endDate": "hat Enddatum zu %s geändert auf %s",
|
||||
"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\"} ]",
|
||||
"create": "Erstellen",
|
||||
"createBoardPopup-title": "Board erstellen",
|
||||
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
|
||||
"chooseBoardSourcePopup-title": "Board importieren",
|
||||
"createLabelPopup-title": "Label erstellen",
|
||||
"createCustomField": "Feld erstellen",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Benutzerdefinierte Felder",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Ablehnen",
|
||||
"default-avatar": "Standard Profilbild",
|
||||
"delete": "Löschen",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Benachrichtigung ändern",
|
||||
"editProfilePopup-title": "Profil ändern",
|
||||
"email": "E-Mail",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Standard",
|
||||
"defaultdefault": "Standard",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Einstellungen für Teilaufgaben",
|
||||
"card-settings": "Karten-Einstellungen",
|
||||
"minicard-settings": "Minikarte-Einstellungen",
|
||||
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben",
|
||||
"boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
|
||||
"boardCardSettingsPopup-title": "Karten-Einstellungen",
|
||||
"boardMinicardSettingsPopup-title": "Minikarte-Einstellungen",
|
||||
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Ich",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board „%s“ nicht gefunden.",
|
||||
"swimlane-title-not-found": "Swimlane „%s“ nicht gefunden.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "abgeschlossen",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "löschte Kommentar %s",
|
||||
"activity-receivedDate": "hat Empfangsdatum 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-endDate": "hat Enddatum zu %s geändert auf %s",
|
||||
"add-attachment": "Datei anhängen",
|
||||
|
|
@ -177,22 +189,22 @@
|
|||
"boardChangeViewPopup-title": "Boardansicht",
|
||||
"boards": "Boards",
|
||||
"board-view": "Boardansicht",
|
||||
"desktop-mode": "Desktop Mode",
|
||||
"mobile-mode": "Mobile Mode",
|
||||
"mobile-desktop-toggle": "Toggle between Mobile and Desktop Mode",
|
||||
"desktop-mode": "Desktop-Modus",
|
||||
"mobile-mode": "Handy-Modus",
|
||||
"mobile-desktop-toggle": "Umschalten zwischen Mobil und Desktop Ansicht",
|
||||
"zoom-in": "Vergrößern",
|
||||
"zoom-out": "Verkleinern",
|
||||
"click-to-change-zoom": "Click to change zoom level",
|
||||
"zoom-level": "Zoom Level",
|
||||
"enter-zoom-level": "Enter zoom level (50-300%):",
|
||||
"click-to-change-zoom": "Klicken um die Zoom Stufe zu ändern",
|
||||
"zoom-level": "Zoomstufe",
|
||||
"enter-zoom-level": "Eingabe Zoom Stufe (50-300%):",
|
||||
"board-view-cal": "Kalender",
|
||||
"board-view-swimlanes": "Swimlanes",
|
||||
"board-view-collapse": "Einklappen",
|
||||
"board-view-gantt": "Gantt",
|
||||
"board-view-lists": "Listen",
|
||||
"bucket-example": "Like \"Bucket List\" for example",
|
||||
"calendar-previous-month-label": "Previous Month",
|
||||
"calendar-next-month-label": "Next Month",
|
||||
"bucket-example": "z.B. \"Löffelliste\"",
|
||||
"calendar-previous-month-label": "Vorheriger Monat",
|
||||
"calendar-next-month-label": "Nächster Monat",
|
||||
"cancel": "Abbrechen",
|
||||
"card-archived": "Diese Karte 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\"} ]",
|
||||
"create": "Erstellen",
|
||||
"createBoardPopup-title": "Board erstellen",
|
||||
"createTemplateContainerPopup-title": "Vorlagen-Container hinzufügen",
|
||||
"chooseBoardSourcePopup-title": "Board importieren",
|
||||
"createLabelPopup-title": "Label erstellen",
|
||||
"createCustomField": "Feld erstellen",
|
||||
|
|
@ -356,10 +369,10 @@
|
|||
"custom-field-text": "Text",
|
||||
"custom-fields": "Benutzerdefinierte Felder",
|
||||
"date": "Datum",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format": "Datumsformat",
|
||||
"date-format-yyyy-mm-dd": "JJJJ-MM-TT hh:mm",
|
||||
"date-format-dd-mm-yyyy": "TT-MM-JJJJ",
|
||||
"date-format-mm-dd-yyyy": "MM-TT-JJJJ",
|
||||
"decline": "Ablehnen",
|
||||
"default-avatar": "Standard Profilbild",
|
||||
"delete": "Löschen",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Benachrichtigung ändern",
|
||||
"editProfilePopup-title": "Profil ändern",
|
||||
"email": "E-Mail",
|
||||
"email-address": "E-Mail Adresse",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Standard",
|
||||
"defaultdefault": "Standard",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Einstellungen für Teilaufgaben",
|
||||
"card-settings": "Karten-Einstellungen",
|
||||
"minicard-settings": "Minikarte-Einstellungen",
|
||||
"boardSubtaskSettingsPopup-title": "Boardeinstellungen für Teilaufgaben",
|
||||
"boardSubtaskSettingsPopup-title": "Einstellungen für Teilaufgaben",
|
||||
"boardCardSettingsPopup-title": "Karten-Einstellungen",
|
||||
"boardMinicardSettingsPopup-title": "Minikarte-Einstellungen",
|
||||
"deposit-subtasks-board": "Teilaufgaben in diesem Board ablegen:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Ich",
|
||||
"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.",
|
||||
"dueCards-noResults-title": "Keine fälligen Karten gefunden",
|
||||
"dueCards-noResults-description": "Sie haben momentan keine Karten mit Fälligkeitsdaten.",
|
||||
"broken-cards": "Fehlerhafte Karten",
|
||||
"board-title-not-found": "Board „%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-title": "Bedienungshilfe Titel",
|
||||
"accessibility-content": "Barrierefreier Eintrag",
|
||||
"accounts-lockout-settings": "Brute Force Protection Settings",
|
||||
"accounts-lockout-info": "These settings control how login attempts are protected against brute force attacks.",
|
||||
"accounts-lockout-known-users": "Settings for known users (correct username, wrong password)",
|
||||
"accounts-lockout-unknown-users": "Settings for unknown users (non-existent username)",
|
||||
"accounts-lockout-settings": "Brute-Force-Schutz Einstellungen",
|
||||
"accounts-lockout-info": "Diese Einstellungen steuern, wie Anmeldeversuche gegen Brute-Force-Angriffe geschützt werden",
|
||||
"accounts-lockout-known-users": "Einstellungen für bekannte Benutzer (korrekter Benutzername, falsches Passwort)",
|
||||
"accounts-lockout-unknown-users": "Einstellungen für unbekannte Benutzer (nicht existierender Benutzername)",
|
||||
"accounts-lockout-failures-before": "Fehler vor einer Sperrung",
|
||||
"accounts-lockout-period": "Dauer der Sperrung (Sekunden)",
|
||||
"accounts-lockout-failure-window": "Failure window (seconds)",
|
||||
"accounts-lockout-settings-updated": "Brute force protection settings have been updated",
|
||||
"accounts-lockout-failure-window": "Fehlerfenster (Sekunden)",
|
||||
"accounts-lockout-settings-updated": "Die Brute-force-Schutz Einstellungen wurden aktualisiert",
|
||||
"accounts-lockout-locked-users": "Gesperrte Benutzer",
|
||||
"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",
|
||||
|
|
@ -1305,7 +1323,7 @@
|
|||
"accounts-lockout-remaining-time": "Verbleibende Zeit",
|
||||
"accounts-lockout-user-unlocked": "Benutzer wurde erfolgreich entsperrt",
|
||||
"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-user-locked": "Benutzer ist gesperrt",
|
||||
"accounts-lockout-click-to-unlock": "Klicken Sie, um den Benutzer zu entsperren",
|
||||
|
|
@ -1316,183 +1334,246 @@
|
|||
"admin-people-filter-active": "Aktiv",
|
||||
"admin-people-filter-inactive": "Nicht aktiv",
|
||||
"admin-people-active-status": "Aktiv Status",
|
||||
"admin-people-user-active": "User is active - click to deactivate",
|
||||
"admin-people-user-inactive": "User is inactive - click to activate",
|
||||
"accounts-lockout-all-users-unlocked": "All locked users have been unlocked",
|
||||
"admin-people-user-active": "Benutzer ist aktiv - zum Deaktivieren klicken",
|
||||
"admin-people-user-inactive": "Benutzer ist inaktiv - zum Aktivieren klicken",
|
||||
"accounts-lockout-all-users-unlocked": "Alle gesperrten Benutzer wurden entsperrt",
|
||||
"accounts-lockout-unlock-all": "Alle entsperren",
|
||||
"active-cron-jobs": "Active Scheduled Jobs",
|
||||
"add-cron-job": "Add Scheduled Job",
|
||||
"add-cron-job-placeholder": "Add Scheduled Job functionality coming soon",
|
||||
"attachment-storage-configuration": "Attachment Storage Configuration",
|
||||
"attachments-path": "Attachments Path",
|
||||
"attachments-path-description": "Path where attachment files are stored",
|
||||
"avatars-path": "Avatars Path",
|
||||
"avatars-path-description": "Path where avatar files are stored",
|
||||
"board-archive-failed": "Failed to schedule board archive",
|
||||
"board-archive-scheduled": "Board archive scheduled successfully",
|
||||
"board-backup-failed": "Failed to schedule board backup",
|
||||
"board-backup-scheduled": "Board backup scheduled successfully",
|
||||
"board-cleanup-failed": "Failed to schedule board cleanup",
|
||||
"board-cleanup-scheduled": "Board cleanup scheduled successfully",
|
||||
"board-operations": "Board Operations",
|
||||
"cron-jobs": "Scheduled Jobs",
|
||||
"active-cron-jobs": "Aktive geplante Aufgaben",
|
||||
"add-cron-job": "Geplante Aufgabe hinzufügen",
|
||||
"add-cron-job-placeholder": "Funktion „Geplante Aufgaben hinzufügen” in Kürze verfügbar",
|
||||
"attachment-storage-configuration": "Konfiguration des Anhangspeichers",
|
||||
"attachments-path": "Anhänge Pfad",
|
||||
"attachments-path-description": "Pfad unter dem die Anhänge gespeichert werden",
|
||||
"avatars-path": "Pfad zu den Avataren",
|
||||
"avatars-path-description": "Pfad unter dem die Avatardateien gespeichert werden",
|
||||
"board-archive-failed": "Planung der Brettarchivierung fehlgeschlagen ",
|
||||
"board-archive-scheduled": "Brettarchivierung erfolgreich eingeplant",
|
||||
"board-backup-failed": "Planung der Brettsicherung fehlgeschlagen ",
|
||||
"board-backup-scheduled": "Brettsicherung erfolgreich eingeplant",
|
||||
"board-cleanup-failed": "Planung des Brettaufräumens fehlgeschlagen",
|
||||
"board-cleanup-scheduled": "Brettaufräumen erfolgreich eingeplant",
|
||||
"board-operations": "Brettoperationen",
|
||||
"cron-jobs": "Geplante Aufgaben",
|
||||
"cron-migrations": "Geplante Migrationen",
|
||||
"cron-job-delete-confirm": "Are you sure you want to delete this scheduled job?",
|
||||
"cron-job-delete-failed": "Failed to delete scheduled job",
|
||||
"cron-job-deleted": "Scheduled job deleted successfully",
|
||||
"cron-job-pause-failed": "Failed to pause scheduled job",
|
||||
"cron-job-paused": "Scheduled job paused successfully",
|
||||
"filesystem-path-description": "Base path for file storage",
|
||||
"gridfs-enabled": "GridFS Enabled",
|
||||
"gridfs-enabled-description": "Use MongoDB GridFS for file storage",
|
||||
"migration-pause-failed": "Failed to pause migrations",
|
||||
"migration-paused": "Migrations paused successfully",
|
||||
"migration-progress": "Migration Progress",
|
||||
"migration-start-failed": "Failed to start migrations",
|
||||
"migration-started": "Migrations started successfully",
|
||||
"migration-status": "Migration Status",
|
||||
"migration-stop-confirm": "Are you sure you want to stop all migrations?",
|
||||
"migration-stop-failed": "Failed to stop migrations",
|
||||
"migration-stopped": "Migrations stopped successfully",
|
||||
"mongodb-gridfs-storage": "MongoDB GridFS Storage",
|
||||
"pause-all-migrations": "Pause All Migrations",
|
||||
"s3-access-key": "S3 Access Key",
|
||||
"s3-access-key-description": "AWS S3 access key for authentication",
|
||||
"s3-access-key-placeholder": "Enter S3 access key",
|
||||
"cron-job-delete-confirm": "Sind Sie sicher, dass Sie diese geplante Aufgabe löschen wollen?",
|
||||
"cron-job-delete-failed": "Löschen der geplanten Aufgabe fehlgeschlagen",
|
||||
"cron-job-deleted": "Geplante Aufgabe erfolgreich gelöscht",
|
||||
"cron-job-pause-failed": "Anhalten der geplanten Aufgabe fehlgeschlagen",
|
||||
"cron-job-paused": "Geplante Aufgabe erfolgreich angehalten",
|
||||
"filesystem-path-description": "Basispfad des Dateispeichers",
|
||||
"gridfs-enabled": "GridFS aktiviert",
|
||||
"gridfs-enabled-description": "Benutze MongoDB GridFS als Dateispeicher",
|
||||
"migration-pause-failed": "Unterbrechung der Migrationen fehlgeschlagen",
|
||||
"migration-paused": "Migrationen erfolgreich unterbrochen",
|
||||
"migration-progress": "Migrationsfortschritt",
|
||||
"migration-start-failed": "Start der Migrationen fehlgeschlagen",
|
||||
"migration-started": "Migrationen erfolgreich gestartet",
|
||||
"migration-status": "Migrationsstatus",
|
||||
"migration-stop-confirm": "Sind Sie sicher, dass Sie alle Migrationen stoppen wollen?",
|
||||
"migration-stop-failed": "Stoppen der Migrationen fehlgeschlagen",
|
||||
"migration-stopped": "Migrationen erfolgreich gestoppt",
|
||||
"mongodb-gridfs-storage": "MongoDB GridFS Speicher",
|
||||
"pause-all-migrations": "Alle Migrationen anhalten",
|
||||
"s3-access-key": "S3 Zugriffsschlüssel",
|
||||
"s3-access-key-description": "AWS S3 Zugangsschlüssel zur Authentifizierung",
|
||||
"s3-access-key-placeholder": "S3 Zugriffsschlüssel eingeben",
|
||||
"s3-bucket": "S3 Bucket",
|
||||
"s3-bucket-description": "S3 bucket name for storing files",
|
||||
"s3-connection-failed": "S3 connection failed",
|
||||
"s3-connection-success": "S3 connection successful",
|
||||
"s3-enabled": "S3 Enabled",
|
||||
"s3-enabled-description": "Use AWS S3 or MinIO for file storage",
|
||||
"s3-endpoint": "S3 Endpoint",
|
||||
"s3-endpoint-description": "S3 endpoint URL (e.g., s3.amazonaws.com or minio.example.com)",
|
||||
"s3-minio-storage": "S3/MinIO Storage",
|
||||
"s3-bucket-description": "S3 Bucket Name um Dateien zu speichern",
|
||||
"s3-connection-failed": "S3 Verbindung fehlgeschlagen",
|
||||
"s3-connection-success": "S3 Verbindung erfolgreich",
|
||||
"s3-enabled": "S3 aktiviert",
|
||||
"s3-enabled-description": "Benutze AWS S3 oder MiniIO als Dateispeicher",
|
||||
"s3-endpoint": "S3 Endpunkt",
|
||||
"s3-endpoint-description": "S3 Endpunkt URL (z.B., s3.amazonaws.com oder minio.example.com)",
|
||||
"s3-minio-storage": "S3/MinIO Speicher",
|
||||
"s3-port": "S3 Port",
|
||||
"s3-port-description": "S3 endpoint port number",
|
||||
"s3-port-description": "S3 Endpunkt Port Nummer",
|
||||
"s3-region": "S3 Region",
|
||||
"s3-region-description": "AWS S3 region (e.g., us-east-1)",
|
||||
"s3-secret-key": "S3 Secret Key",
|
||||
"s3-secret-key-description": "AWS S3 secret key for authentication",
|
||||
"s3-secret-key-placeholder": "Enter S3 secret key",
|
||||
"s3-secret-key-required": "S3 secret key is required",
|
||||
"s3-settings-save-failed": "Failed to save S3 settings",
|
||||
"s3-settings-saved": "S3 settings saved successfully",
|
||||
"s3-ssl-enabled": "S3 SSL Enabled",
|
||||
"s3-ssl-enabled-description": "Use SSL/TLS for S3 connections",
|
||||
"save-s3-settings": "Save S3 Settings",
|
||||
"schedule-board-archive": "Schedule Board Archive",
|
||||
"schedule-board-backup": "Schedule Board Backup",
|
||||
"schedule-board-cleanup": "Schedule Board Cleanup",
|
||||
"scheduled-board-operations": "Scheduled Board Operations",
|
||||
"start-all-migrations": "Start All Migrations",
|
||||
"stop-all-migrations": "Stop All Migrations",
|
||||
"test-s3-connection": "Test S3 Connection",
|
||||
"writable-path": "Writable Path",
|
||||
"writable-path-description": "Base directory path for file storage",
|
||||
"add-job": "Add Job",
|
||||
"attachment-migration": "Attachment Migration",
|
||||
"attachment-monitoring": "Attachment Monitoring",
|
||||
"attachment-settings": "Attachment Settings",
|
||||
"attachment-storage-settings": "Storage Settings",
|
||||
"automatic-migration": "Automatic Migration",
|
||||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"card-show-lists-on-minicard": "Show Lists on Minicard",
|
||||
"cleanup": "Cleanup",
|
||||
"cleanup-old-jobs": "Cleanup Old Jobs",
|
||||
"s3-region-description": "AWS S3 Region (z.B., us-east-1)",
|
||||
"s3-secret-key": "S3 geheimer Schlüssel",
|
||||
"s3-secret-key-description": "AWS S3 geheimer Schlüssel zur Authentifizierung",
|
||||
"s3-secret-key-placeholder": "S3 geheimen Schlüssel eingeben",
|
||||
"s3-secret-key-required": "S3 geheimer Schlüssel ist erforderlich",
|
||||
"s3-settings-save-failed": "Speicherung der S3 Einstellungen fehlgeschlagen",
|
||||
"s3-settings-saved": "S3 Einstellungen erfolgreich gespeichert",
|
||||
"s3-ssl-enabled": "S3 SSL aktiviert",
|
||||
"s3-ssl-enabled-description": "Benutze SSL/TLS für S3 Verbindungen",
|
||||
"save-s3-settings": "S3 Einstellungen speichern",
|
||||
"schedule-board-archive": "Planung Brettarchiv",
|
||||
"schedule-board-backup": "Planung Brettsicherung",
|
||||
"schedule-board-cleanup": "Planung Brettsäuberung",
|
||||
"scheduled-board-operations": "Geplante Brettoperationen",
|
||||
"start-all-migrations": "Starte alle Migrationen",
|
||||
"stop-all-migrations": "Stoppe alle Migrationen",
|
||||
"test-s3-connection": "Teste S3 Verbindungen",
|
||||
"writable-path": "Beschreibbarer Pfad",
|
||||
"writable-path-description": "Basispfad des Dateispeichers",
|
||||
"add-job": "Aufgabe hinzufügen",
|
||||
"attachment-migration": "Anhangmigration",
|
||||
"attachment-monitoring": "Anhangüberwachung",
|
||||
"attachment-settings": "Anhangeinstellungen",
|
||||
"attachment-storage-settings": "Speichereinstellungen",
|
||||
"automatic-migration": "Automatische Migration",
|
||||
"back-to-settings": "Zurück zu den Einstellungen",
|
||||
"board-id": "Brett ID",
|
||||
"board-migration": "Brettmigration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"card-show-lists-on-minicard": "Zeige Listen auf der Minikarte",
|
||||
"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",
|
||||
"conversion-info-text": "This conversion is performed once per board and improves performance. You can continue using the board normally.",
|
||||
"converting-board": "Converting Board",
|
||||
"converting-board-description": "Converting board structure for improved functionality. This may take a few moments.",
|
||||
"conversion-info-text": "Diese Umstellung wird einmal pro Brett durchgeführt und verbessert die Performanz. Sie können das Brett normal verwenden.",
|
||||
"converting-board": "Brett umwandeln",
|
||||
"converting-board-description": "Umwandlung der Brettstruktur für verbesserte Funktionalität. Das kann einen Moment dauern.",
|
||||
"cpu-cores": "CPU Cores",
|
||||
"cpu-usage": "CPU Usage",
|
||||
"current-action": "Current Action",
|
||||
"database-migration": "Database Migration",
|
||||
"database-migration-description": "Updating database structure for improved functionality and performance. This process may take several minutes.",
|
||||
"database-migrations": "Database Migrations",
|
||||
"days-old": "Days Old",
|
||||
"duration": "Duration",
|
||||
"errors": "Errors",
|
||||
"estimated-time-remaining": "Estimated time remaining",
|
||||
"every-1-day": "Every 1 day",
|
||||
"every-1-hour": "Every 1 hour",
|
||||
"every-1-minute": "Every 1 minute",
|
||||
"every-10-minutes": "Every 10 minutes",
|
||||
"every-30-minutes": "Every 30 minutes",
|
||||
"every-5-minutes": "Every 5 minutes",
|
||||
"every-6-hours": "Every 6 hours",
|
||||
"export-monitoring": "Export Monitoring",
|
||||
"filesystem-attachments": "Filesystem Attachments",
|
||||
"filesystem-size": "Filesystem Size",
|
||||
"filesystem-storage": "Filesystem Storage",
|
||||
"force-board-scan": "Force Board Scan",
|
||||
"gridfs-attachments": "GridFS Attachments",
|
||||
"gridfs-size": "GridFS Size",
|
||||
"current-action": "Laufender Vorgang",
|
||||
"database-migration": "Datenbankmigration",
|
||||
"database-migration-description": "Update der Datenbankstruktur für eine Verbesserung der Funktionalität und der Performanz. Das kann ein paar Minuten dauern.",
|
||||
"database-migrations": "Datenbankmigration",
|
||||
"days-old": "Tage alt",
|
||||
"duration": "Dauer",
|
||||
"errors": "Fehler",
|
||||
"estimated-time-remaining": "Geschätzte Zeit übrig",
|
||||
"every-1-day": "Jeden Tag",
|
||||
"every-1-hour": "Jede Stunde",
|
||||
"every-1-minute": "Jede Minute",
|
||||
"every-10-minutes": "Alle 10 Minuten",
|
||||
"every-30-minutes": "Alle 30 Minuten",
|
||||
"every-5-minutes": "Alle 5 Minuten",
|
||||
"every-6-hours": "Alle 6 Stunden",
|
||||
"export-monitoring": "Exportüberwachung",
|
||||
"filesystem-attachments": "Dateisystemanhänge",
|
||||
"filesystem-size": "Dateisystem Größe",
|
||||
"filesystem-storage": "Dateisystem Speicher",
|
||||
"force-board-scan": "Erzwinge Brettscan",
|
||||
"gridfs-attachments": "GridFS Anhänge",
|
||||
"gridfs-size": "GridFS Größe",
|
||||
"gridfs-storage": "GridFS",
|
||||
"hide-list-on-minicard": "Hide List on Minicard",
|
||||
"idle-migration": "Idle Migration",
|
||||
"job-description": "Job Description",
|
||||
"job-details": "Job Details",
|
||||
"job-name": "Job Name",
|
||||
"job-queue": "Job Queue",
|
||||
"last-run": "Last Run",
|
||||
"max-concurrent": "Max Concurrent",
|
||||
"memory-usage": "Memory Usage",
|
||||
"migrate-all-to-filesystem": "Migrate All to Filesystem",
|
||||
"migrate-all-to-gridfs": "Migrate All to GridFS",
|
||||
"migrate-all-to-s3": "Migrate All to S3",
|
||||
"migrated-attachments": "Migrated Attachments",
|
||||
"migration-batch-size": "Batch Size",
|
||||
"migration-batch-size-description": "Number of attachments to process in each batch (1-100)",
|
||||
"hide-list-on-minicard": "Verberge Liste auf der Minikarte",
|
||||
"idle-migration": "Untätige Migration",
|
||||
"job-description": "Aufgabenbeschreibung",
|
||||
"job-details": "Aufgabendetails",
|
||||
"job-name": "Aufgabenname",
|
||||
"job-queue": "Aufgabenwarteschlange",
|
||||
"last-run": "Letzte Ausführung",
|
||||
"max-concurrent": "Max. gleichzeitig",
|
||||
"memory-usage": "Speicherauslastung",
|
||||
"migrate-all-to-filesystem": "Migriere alles ins Dateisystem",
|
||||
"migrate-all-to-gridfs": "Migriere alles ins GridFS",
|
||||
"migrate-all-to-s3": "Migriere alles ins S3",
|
||||
"migrated-attachments": "Migrierte Anhänge",
|
||||
"migration-batch-size": "Batchgröße",
|
||||
"migration-batch-size-description": "Anzahl der zu bearbeitenden Anhänge pro Batch (1-100)",
|
||||
"migration-cpu-threshold": "CPU Threshold (%)",
|
||||
"migration-cpu-threshold-description": "Pause migration when CPU usage exceeds this percentage (10-90)",
|
||||
"migration-delay-ms": "Delay (ms)",
|
||||
"migration-delay-ms-description": "Delay between batches in milliseconds (100-10000)",
|
||||
"migration-detector": "Migration Detector",
|
||||
"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-cpu-threshold-description": "Unterbreche Migration, wenn CPU Benutzung diesen Wert überschreitet (10-90%)",
|
||||
"migration-delay-ms": "Verzögerung (ms)",
|
||||
"migration-delay-ms-description": "Verzögerung zwischen Batches in Millisekunden (100-10000)",
|
||||
"migration-detector": "Migrationdetektor",
|
||||
"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-markers": "Migration Markers",
|
||||
"migration-resume-failed": "Failed to resume migration",
|
||||
"migration-resumed": "Migration resumed",
|
||||
"migration-steps": "Migration Steps",
|
||||
"migration-warning-text": "Please do not close your browser during migration. The process will continue in the background but may take longer to complete.",
|
||||
"monitoring-export-failed": "Failed to export monitoring data",
|
||||
"monitoring-refresh-failed": "Failed to refresh monitoring data",
|
||||
"next": "Next",
|
||||
"next-run": "Next Run",
|
||||
"migration-markers": "Migrationsmarkierungen",
|
||||
"migration-resume-failed": "Fortfahren der Migration misslungen",
|
||||
"migration-resumed": "Migration fortgesetzt",
|
||||
"migration-steps": "Migrationsschritte",
|
||||
"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": "Export der Beobachtungsdaten misslungen",
|
||||
"monitoring-refresh-failed": "Neuladen der Beobachtungsdaten misslungen",
|
||||
"next": "Weiter",
|
||||
"next-run": "Nächster Lauf",
|
||||
"of": "von",
|
||||
"operation-type": "Operation Type",
|
||||
"overall-progress": "Overall Progress",
|
||||
"page": "Page",
|
||||
"pause-migration": "Pause Migration",
|
||||
"previous": "Previous",
|
||||
"refresh": "Refresh",
|
||||
"refresh-monitoring": "Refresh Monitoring",
|
||||
"remaining-attachments": "Remaining Attachments",
|
||||
"resume-migration": "Resume Migration",
|
||||
"run-once": "Run once",
|
||||
"s3-attachments": "S3 Attachments",
|
||||
"s3-size": "S3 Size",
|
||||
"operation-type": "Operationstyp",
|
||||
"overall-progress": "Gesamtfortschritt",
|
||||
"page": "Seite",
|
||||
"pause-migration": "Migration unterbrechen",
|
||||
"previous": "Zurück",
|
||||
"refresh": "Neuladen",
|
||||
"refresh-monitoring": "Beobachten neuladen",
|
||||
"remaining-attachments": "Verbleibende Anhänge",
|
||||
"resume-migration": "Migration fortsetzen",
|
||||
"run-once": "Einmal ausführen",
|
||||
"s3-attachments": "S3 Anhänge",
|
||||
"s3-size": "S3 Größe",
|
||||
"s3-storage": "S3",
|
||||
"scanning-status": "Scanning Status",
|
||||
"schedule": "Schedule",
|
||||
"search-boards-or-operations": "Search boards or operations...",
|
||||
"show-list-on-minicard": "Show List on Minicard",
|
||||
"showing": "Showing",
|
||||
"start-test-operation": "Start Test Operation",
|
||||
"start-time": "Start Time",
|
||||
"step-progress": "Step Progress",
|
||||
"stop-migration": "Stop Migration",
|
||||
"storage-distribution": "Storage Distribution",
|
||||
"system-resources": "System Resources",
|
||||
"total-attachments": "Total Attachments",
|
||||
"total-operations": "Total Operations",
|
||||
"total-size": "Total Size",
|
||||
"unmigrated-boards": "Unmigrated Boards",
|
||||
"weight": "Weight",
|
||||
"idle": "Idle",
|
||||
"complete": "Complete",
|
||||
"scanning-status": "Scanstatus",
|
||||
"schedule": "Zeitplanung",
|
||||
"search-boards-or-operations": "Durchsuche Bretter oder Vorgänge",
|
||||
"show-list-on-minicard": "Zeige Liste auf der Minikarte",
|
||||
"showing": "Gezeigt",
|
||||
"start-test-operation": "Starte Testvorgang",
|
||||
"start-time": "Startzeit",
|
||||
"step-progress": "Durchschreite Fortschritt",
|
||||
"stop-migration": "Stoppe Migration",
|
||||
"storage-distribution": "Speicherverteilung",
|
||||
"system-resources": "Systemressourcen",
|
||||
"total-attachments": "Gesamte Anhänge",
|
||||
"total-operations": "Gesamte Vorgänge",
|
||||
"total-size": "Gesamte Größe",
|
||||
"unmigrated-boards": "Nicht migrierte Bretter",
|
||||
"weight": "Gewicht",
|
||||
"idle": "Untätig",
|
||||
"complete": "Vollständig",
|
||||
"cron": "Cron"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "διεγράφη το σχόλιο %s",
|
||||
"activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %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-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s",
|
||||
"add-attachment": "Προσθήκη Συνημμένου",
|
||||
|
|
@ -337,6 +349,7 @@
|
|||
"copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]",
|
||||
"create": "Δημιουργία",
|
||||
"createBoardPopup-title": "Δημιουργία Πίνακα",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Εισαγωγή πίνακα",
|
||||
"createLabelPopup-title": "Δημιουργία Ετικέτας",
|
||||
"createCustomField": "Δημιουργία Πεδίου",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Προσαρμοσμένα Πεδία",
|
||||
"date": "Ημερομηνία",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Απόρριψη",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Διαγραφή",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Επεξεργασία Ειδοποίησης",
|
||||
"editProfilePopup-title": "Επεξεργασία Προφίλ",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__",
|
||||
"email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.",
|
||||
"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.",
|
||||
"boardDeletePopup-title": "Διαγραφή Πίνακα;",
|
||||
"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": "Προεπιλογή",
|
||||
"defaultdefault": "Προεπιλογή",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)",
|
||||
"card-settings": "Ρυθμίσεις Κάρτας",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Ρυθμίσεις υποεργασιών (subtasks)",
|
||||
"boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "διεγράφη το σχόλιο %s",
|
||||
"activity-receivedDate": "η ημερομηνία λήψης άλλαξε σε %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-endDate": "η ημερομηνία λήξης άλλαξε σε %s από %s",
|
||||
"add-attachment": "Προσθήκη Συνημμένου",
|
||||
|
|
@ -337,6 +349,7 @@
|
|||
"copyManyCardsPopup-format": "[ {\"title\": \"Τίτλος πρώτης κάρτας\", \"description\":\"Περιγραφή πρώτης κάρτας\"}, {\"title\":\"Τίτλος δεύτερης κάρτας\",\"description\":\"Περιγραφή δεύτερης κάρτας\"},{\"title\":\"Τίτλος τελευταίας κάρτας\",\"description\":\"Περιγραφή τελευταίας κάρτας\"} ]",
|
||||
"create": "Δημιουργία",
|
||||
"createBoardPopup-title": "Δημιουργία Πίνακα",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Εισαγωγή πίνακα",
|
||||
"createLabelPopup-title": "Δημιουργία Ετικέτας",
|
||||
"createCustomField": "Δημιουργία Πεδίου",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Προσαρμοσμένα Πεδία",
|
||||
"date": "Ημερομηνία",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Απόρριψη",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Διαγραφή",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Επεξεργασία Ειδοποίησης",
|
||||
"editProfilePopup-title": "Επεξεργασία Προφίλ",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"email-enrollAccount-subject": "Ένας λογαριασμός δημιουργήθηκε για εσάς στο __siteName__",
|
||||
"email-enrollAccount-text": "Χαίρετε __user__,\n\nΓια να ξεκινήσετε να χρησιμοποιείτε αυτή την υπηρεσία, απλώς κάνετε κλικ στον παρακάτω σύνδεσμο.\n\n__url__\n\nΕυχαριστούμε.",
|
||||
"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.",
|
||||
"boardDeletePopup-title": "Διαγραφή Πίνακα;",
|
||||
"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": "Προεπιλογή",
|
||||
"defaultdefault": "Προεπιλογή",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Ρυθμίσεις υποεργασιών (subtasks)",
|
||||
"card-settings": "Ρυθμίσεις Κάρτας",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Ρυθμίσεις υποεργασιών (subtasks)",
|
||||
"boardCardSettingsPopup-title": "Ρυθμίσεις Κάρτας",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
|
|
@ -78,6 +78,18 @@
|
|||
"activity-deleteComment": "deleted comment %s",
|
||||
"activity-receivedDate": "edited received 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-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\"} ]",
|
||||
"create": "Create",
|
||||
"createBoardPopup-title": "Create Board",
|
||||
"createTemplateContainerPopup-title": "Add Template Container",
|
||||
"chooseBoardSourcePopup-title": "Import board",
|
||||
"createLabelPopup-title": "Create Label",
|
||||
"createCustomField": "Create Field",
|
||||
|
|
@ -357,9 +370,9 @@
|
|||
"custom-fields": "Custom Fields",
|
||||
"date": "Date",
|
||||
"date-format": "Date Format",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD HH:MM",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY HH:MM",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY HH:MM",
|
||||
"date-format-yyyy-mm-dd": "YYYY-MM-DD",
|
||||
"date-format-dd-mm-yyyy": "DD-MM-YYYY",
|
||||
"date-format-mm-dd-yyyy": "MM-DD-YYYY",
|
||||
"decline": "Decline",
|
||||
"default-avatar": "Default avatar",
|
||||
"delete": "Delete",
|
||||
|
|
@ -385,6 +398,7 @@
|
|||
"editNotificationPopup-title": "Edit Notification",
|
||||
"editProfilePopup-title": "Edit Profile",
|
||||
"email": "Email",
|
||||
"email-address": "Email Address",
|
||||
"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-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.",
|
||||
"boardDeletePopup-title": "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": "Default",
|
||||
"defaultdefault": "Default",
|
||||
|
|
@ -761,7 +777,7 @@
|
|||
"subtask-settings": "Subtasks Settings",
|
||||
"card-settings": "Card Settings",
|
||||
"minicard-settings": "Minicard Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Board Subtasks Settings",
|
||||
"boardSubtaskSettingsPopup-title": "Subtasks Settings",
|
||||
"boardCardSettingsPopup-title": "Card Settings",
|
||||
"boardMinicardSettingsPopup-title": "Minicard Settings",
|
||||
"deposit-subtasks-board": "Deposit subtasks to this board:",
|
||||
|
|
@ -1015,6 +1031,8 @@
|
|||
"dueCardsViewChange-choice-me": "Me",
|
||||
"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.",
|
||||
"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",
|
||||
"board-title-not-found": "Board '%s' not found.",
|
||||
"swimlane-title-not-found": "Swimlane '%s' not found.",
|
||||
|
|
@ -1399,7 +1417,70 @@
|
|||
"back-to-settings": "Back to Settings",
|
||||
"board-id": "Board ID",
|
||||
"board-migration": "Board Migration",
|
||||
"board-migrations": "Board Migrations",
|
||||
"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-old-jobs": "Cleanup Old Jobs",
|
||||
"completed": "Completed",
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue