Compare commits
15 Commits
feat/113-c
...
fix/kan-15
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31c9a36502 | ||
|
|
0f92ac0d9b | ||
|
|
eb0ca9c738 | ||
|
|
3233c35836 | ||
|
|
ba2fd7f695 | ||
|
|
c7f7531b11 | ||
|
|
4f57fc45a7 | ||
|
|
ea92dcd2ed | ||
|
|
d51600aba8 | ||
|
|
c3ed2e5e7f | ||
|
|
13b10471ec | ||
|
|
80d1c5f805 | ||
|
|
8079345546 | ||
|
|
4a67afdd3a | ||
|
|
d555546782 |
@@ -3,6 +3,8 @@
|
||||
# Required environment variables
|
||||
NEXT_PUBLIC_BASE_URL= # e.g. https://kan.bn
|
||||
BETTER_AUTH_SECRET= # Random 32+ char string (can gen with: openssl rand -base64 24 | tr -dc 'a-zA-Z0-9' | head -c 32)
|
||||
|
||||
# Fill if you want to use an external database
|
||||
POSTGRES_URL= # e.g. postgresql://kan:your_password@your_host:5432/kan
|
||||
|
||||
# Only required if deploying from compose
|
||||
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -50,3 +50,6 @@ docker-compose.override.yml
|
||||
# runtime env
|
||||
__ENV.js
|
||||
i18n.cache
|
||||
|
||||
# pgdata
|
||||
/apps/web/pgdata
|
||||
|
||||
64
README.md
64
README.md
@@ -138,36 +138,40 @@ pnpm dev
|
||||
|
||||
## Environment Variables 🔐
|
||||
|
||||
| Variable | Description | Required | Example |
|
||||
| -------------------------------- | -------------------------------------------------------- | ------------------ | --------------------------------------------- |
|
||||
| `POSTGRES_URL` | PostgreSQL connection URL | Yes | `postgres://user:pass@localhost:5432/db` |
|
||||
| `EMAIL_FROM` | Sender email address | For Email | `"Kan <hello@mail.kan.bn>"` |
|
||||
| `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` |
|
||||
| `SMTP_PORT` | SMTP server port | For Email | `465` |
|
||||
| `SMTP_USER` | SMTP username/email | No | `resend` |
|
||||
| `SMTP_PASSWORD` | SMTP password/token | No | `re_xxxx` |
|
||||
| `SMTP_SECURE` | Use secure SMTP connection (defaults to true if not set) | For Email | `true` |
|
||||
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
|
||||
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
|
||||
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
|
||||
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | For Google login | `xxx.apps.googleusercontent.com` |
|
||||
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | For Google login | `xxx` |
|
||||
| `DISCORD_CLIENT_ID` | Discord OAuth client ID | For Discord login | `xxx` |
|
||||
| `DISCORD_CLIENT_SECRET` | Discord OAuth client secret | For Discord login | `xxx` |
|
||||
| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | For GitHub login | `xxx` |
|
||||
| `GITHUB_CLIENT_SECRET` | GitHub OAuth client secret | For GitHub login | `xxx` |
|
||||
| `TRELLO_APP_API_KEY` | Trello app API key | For Trello import | `xxx` |
|
||||
| `TRELLO_APP_API_SECRET` | Trello app API secret | For Trello import | `xxx` |
|
||||
| `S3_REGION` | S3 storage region | For file uploads | `WEUR` |
|
||||
| `S3_ENDPOINT` | S3 endpoint URL | For file uploads | `https://xxx.r2.cloudflarestorage.com` |
|
||||
| `S3_ACCESS_KEY_ID` | S3 access key | For file uploads | `xxx` |
|
||||
| `S3_SECRET_ACCESS_KEY` | S3 secret key | For file uploads | `xxx` |
|
||||
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
|
||||
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
|
||||
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
|
||||
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
|
||||
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
|
||||
| `NEXT_PUBLIC_DISABLE_SIGN_UP` | Disable sign up | For authentication | `false` |
|
||||
| Variable | Description | Required | Example |
|
||||
| ----------------------------------------- | -------------------------------------------------------- | ------------------------ | ----------------------------------------------------------- |
|
||||
| `POSTGRES_URL` | PostgreSQL connection URL | To use external database | `postgres://user:pass@localhost:5432/db` |
|
||||
| `EMAIL_FROM` | Sender email address | For Email | `"Kan <hello@mail.kan.bn>"` |
|
||||
| `SMTP_HOST` | SMTP server hostname | For Email | `smtp.resend.com` |
|
||||
| `SMTP_PORT` | SMTP server port | For Email | `465` |
|
||||
| `SMTP_USER` | SMTP username/email | No | `resend` |
|
||||
| `SMTP_PASSWORD` | SMTP password/token | No | `re_xxxx` |
|
||||
| `SMTP_SECURE` | Use secure SMTP connection (defaults to true if not set) | For Email | `true` |
|
||||
| `NEXT_PUBLIC_BASE_URL` | Base URL of your installation | Yes | `http://localhost:3000` |
|
||||
| `BETTER_AUTH_SECRET` | Auth encryption secret | Yes | Random 32+ char string |
|
||||
| `BETTER_AUTH_TRUSTED_ORIGINS` | Allowed callback origins | No | `http://localhost:3000,http://localhost:3001` |
|
||||
| `GOOGLE_CLIENT_ID` | Google OAuth client ID | For Google login | `xxx.apps.googleusercontent.com` |
|
||||
| `GOOGLE_CLIENT_SECRET` | Google OAuth client secret | For Google login | `xxx` |
|
||||
| `DISCORD_CLIENT_ID` | Discord OAuth client ID | For Discord login | `xxx` |
|
||||
| `DISCORD_CLIENT_SECRET` | Discord OAuth client secret | For Discord login | `xxx` |
|
||||
| `GITHUB_CLIENT_ID` | GitHub OAuth client ID | For GitHub login | `xxx` |
|
||||
| `GITHUB_CLIENT_SECRET` | GitHub OAuth client secret | For GitHub login | `xxx` |
|
||||
| `OIDC_CLIENT_ID` | Generic OIDC client ID | For OIDC login | `xxx` |
|
||||
| `OIDC_CLIENT_SECRET` | Generic OIDC client secret | For OIDC login | `xxx` |
|
||||
| `OIDC_DISCOVERY_URL` | OIDC discovery URL | For OIDC login | `https://auth.example.com/.well-known/openid-configuration` |
|
||||
| `TRELLO_APP_API_KEY` | Trello app API key | For Trello import | `xxx` |
|
||||
| `TRELLO_APP_API_SECRET` | Trello app API secret | For Trello import | `xxx` |
|
||||
| `S3_REGION` | S3 storage region | For file uploads | `WEUR` |
|
||||
| `S3_ENDPOINT` | S3 endpoint URL | For file uploads | `https://xxx.r2.cloudflarestorage.com` |
|
||||
| `S3_ACCESS_KEY_ID` | S3 access key | For file uploads | `xxx` |
|
||||
| `S3_SECRET_ACCESS_KEY` | S3 secret key | For file uploads | `xxx` |
|
||||
| `S3_FORCE_PATH_STYLE` | Use path-style URLs for S3 | For file uploads | `true` |
|
||||
| `NEXT_PUBLIC_STORAGE_URL` | Storage service URL | For file uploads | `https://storage.kanbn.com` |
|
||||
| `NEXT_PUBLIC_STORAGE_DOMAIN` | Storage domain name | For file uploads | `kanbn.com` |
|
||||
| `NEXT_PUBLIC_AVATAR_BUCKET_NAME` | S3 bucket name for avatars | For file uploads | `avatars` |
|
||||
| `NEXT_PUBLIC_ALLOW_CREDENTIALS` | Allow email & password login | For authentication | `true` |
|
||||
| `NEXT_PUBLIC_DISABLE_SIGN_UP` | Disable sign up | For authentication | `false` |
|
||||
| `NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY` | Hide “Powered by kan.bn” on public boards (self-host) | For white labelling | `true` |
|
||||
|
||||
See `.env.example` for a complete list of supported environment variables.
|
||||
|
||||
|
||||
@@ -81,5 +81,4 @@ ARG PORT=3000
|
||||
ENV PORT=${PORT}
|
||||
EXPOSE ${PORT}
|
||||
|
||||
CMD ["sh", "-c", "cd /app && pnpm db:migrate && cd /app/apps/web && pnpm start"]
|
||||
|
||||
CMD ["sh", "-c", "if [ -n \"$POSTGRES_URL\" ]; then cd /app && pnpm db:migrate && cd /app/apps/web; fi && pnpm start"]
|
||||
|
||||
@@ -13,17 +13,25 @@ checksums:
|
||||
Activity%20logs/singular: 8b1f0bb96a905646ecfad1cfdfa42168
|
||||
Add%20a%20card/singular: 9d80becc4fe65a74e0004e4fd290735d
|
||||
Add%20a%20comment.../singular: c28cfccc0cc69a2a2487e37eb9988028
|
||||
Add%20description...%20(type%20'%2F'%20to%20open%20commands)/singular: df99ea599521682e9ad0a90716955dc6
|
||||
Add%20an%20item.../singular: f8e7993980420698700b07f56b3a38af
|
||||
Add%20checklist/singular: 05d73200b56cfea75fb3a0f94c9bfb74
|
||||
Add%20description...%20(type%20'%2F'%20to%20open%20commands%20or%20'%40'%20to%20mention)/singular: c6eb35a796dd7ac0e3dbc66244b71248
|
||||
Add%20details.../singular: 2f42547fd5d199f173aa7a88c8a9b19a
|
||||
Add%20label/singular: 0be732d46df263265935fda342097a08
|
||||
Add%20member/singular: 11979625770516ca287e929381778e02
|
||||
added%20a%20checklist/singular: 44304f4a5ef3a46378eea243b5d2df79
|
||||
added%20a%20checklist%20item/singular: 20bc0330dba5a9ec978e04bec174365a
|
||||
added%20a%20label%20to%20the%20card/singular: 04c5e4ee9b7b7e77ef089d2ac473d235
|
||||
added%20a%20member%20to%20the%20card/singular: 95495e770062e2fd590333d56e6308d2
|
||||
added%20label%20%3C0%3E%7Blabel%7D%3C%2F0%3E/singular: 1caba6b6bca4c6fa1ab173d241059dc2
|
||||
added%20checklist%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: fb6a852c50c1629f47c6f155fc93fdee
|
||||
added%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: bdd202da20b1fffbec21792c5453f90c
|
||||
added%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: b32be052b3d57de0c9120fa7f9fc86ee
|
||||
Admin%20roles/singular: 32a5d78073b9bb9a246773afba8831df
|
||||
All%20seats%20are%20free%20during%20the%20beta%20until%20Sept%201st!/singular: 015cec3899cf99e37c3cf231d432e31d
|
||||
All%20systems%20operational/singular: ee943a4046b09e6334cceeea9fda2bfc
|
||||
Already%20have%20an%20account%3F%20%3C0%3E%3C1%3ESign%20in%3C%2F1%3E%3C%2F0%3E/singular: 2959fd276248208b65cb27ed46b20135
|
||||
An%20error%20occurred%20while%20disconnecting%20your%20Trello%20account./singular: 0aa3973b860c1faf8d9123aebf567e40
|
||||
An%20unexpected%20error%20occurred.%20Please%20try%20again%20later./singular: 1b5749b0cca6a62d75a577bee6804074
|
||||
API%20keys/singular: 07f3620a30e08136f0b072c9af8d1eef
|
||||
API%20Reference/singular: 7dcc877064bfdf889ec55dbc9e06a242
|
||||
Applicants/singular: 4babd8331a1441e91087f855f43e57f8
|
||||
@@ -31,10 +39,11 @@ checksums:
|
||||
Are%20you%20sure%20want%20to%20remove%20%7BentityLabel%7D%3F/singular: f9b67026c5ef86ac4d5944380d571961
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20the%20workspace%20%7B0%7D%3F/singular: 27ba2854202dd77c51e78c64e5c93946
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20this%20card%3F/singular: 131a5a7cccca7be8b32c987d9fa0b0c0
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20this%20checklist%3F/singular: 7c0f540603474b1a30462dda087fd2f0
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20this%20comment%3F/singular: 55fe6f1b52b71b91b2a079cfda3cc7fe
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20this%20label%3F/singular: 037fbaf1d04356937e6afb574714f51f
|
||||
Are%20you%20sure%20you%20want%20to%20delete%20your%20account%3F/singular: 428b74d781063224c3e63980e1094ec3
|
||||
assigned%20%3C0%3E%7BmemberName%7D%3C%2F0%3E%20to%20the%20card/singular: 4fb1c419a78a0f010a3e5790801551fc
|
||||
assigned%20%3C0%3E%7B0%7D%3C%2F0%3E%20to%20the%20card/singular: 9df6d89fa83706123dedd8cba2243d04
|
||||
Awaiting%20Customer/singular: 122c108794f321c10e05a08f09b11457
|
||||
Backlog/singular: 35919fd5b10ad212839a75e72829fe4e
|
||||
Basic%20Kanban/singular: e46ebc406749486f3907436970d4d6c7
|
||||
@@ -59,8 +68,10 @@ checksums:
|
||||
Cancel/singular: 2e2a849c2223911717de8caa2c71bade
|
||||
Card%20not%20found/singular: 91509e2f92b0b3b11330b6983139fdbf
|
||||
Card%20title/singular: 7c34f59f4005e6cb3a6ff546ea0b96e3
|
||||
Change%20Password/singular: a552fc5c4189ebc3e2e6018edda7d18f
|
||||
Change%20the%20language%20of%20the%20app./singular: fb20db145e28ed44aba89c146ded7bfc
|
||||
Check%20your%20inbox/singular: e9a430fcd298def74212238df0f680d6
|
||||
Checklist%20name/singular: 5eb5de823f7ca5a4d97bb41e6a3f675a
|
||||
Clear%20filters/singular: 8f40ab5af527e4b190da94e7b6221379
|
||||
Click%20on%20the%20link%20we've%20sent%20to%20%7BmagicLinkRecipient%7D%20to%20sign%20in./singular: 210b6ff8727f976182ec3f29ea3c7667
|
||||
Code%20Review/singular: a2da6c2339301e7c3ddf068c4ff9f7e8
|
||||
@@ -70,7 +81,10 @@ checksums:
|
||||
Company/singular: 9e36d11fa82d1bd4563eef2abc4fcfba
|
||||
Complete/singular: d3e36d723de0cfdea51c5b4171d30b4d
|
||||
Complete%20control%20and%20ownership%3A/singular: 0d8b682ba873272217425ccfc96aa9cd
|
||||
completed%20a%20checklist%20item/singular: 757b04c6c80cc927e1c597c0ad4fda33
|
||||
completed%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 71ec18acf051fc909a48a07ca3578673
|
||||
Confirm%20URL%20change/singular: e14b4ce081d1ef6194b37e1814e97b39
|
||||
Confirm%20your%20new%20password/singular: a0d2935d7b63f8dd19d7c0de47524416
|
||||
Connect%20Trello/singular: 4440a0b9e387ef7136e3958e7a089213
|
||||
Connect%20your%20favorite%20tools%20to%20streamline%20your%20workflow./singular: 033c5dcdb059ccb634aef7fe63f2f45d
|
||||
Connect%20your%20Trello%20account%20to%20import%20boards./singular: 84a510a7485f43e43f2191bd161171d7
|
||||
@@ -83,6 +97,7 @@ checksums:
|
||||
Create%20another/singular: 2de8a82a416eb78c0462aa36278edc9a
|
||||
Create%20board/singular: 155b62818bfab0e34f0089e1b34a32f3
|
||||
Create%20card/singular: 32792935dd5837a9433909b04021c22b
|
||||
Create%20checklist/singular: 5cbca15a7004558c4e6d381f83a34da2
|
||||
Create%20label/singular: c64e8180fa956f005edc1fd9b8e65abb
|
||||
Create%20list/singular: 858c3d514aa95765ec82114393199144
|
||||
Create%20new%20board/singular: cbb87b1f4cc46b336ad9510c9f19407c
|
||||
@@ -92,6 +107,7 @@ checksums:
|
||||
Create%20workspace/singular: 2e6718e79964ea5ce22d76c2189c77ca
|
||||
created%20the%20card/singular: 605475f5aaeb4dbccbf7c4eb9107b43d
|
||||
Critical/singular: eb327cd411b50aee954f8d1d215d003a
|
||||
Current%20password%20is%20required/singular: 72536bca9598680027f2be8ce80ac280
|
||||
Custom%20domain/singular: b09e7a9c187b7163b4a6cfc78042fe42
|
||||
Custom%20URLs%20are%20a%20premium%20feature.%20You'll%20be%20directed%20to%20upgrade%20your%20account./singular: b52e4f6122cf739c9551d29beb89b25e
|
||||
Customer%20Support/singular: 50e3c77e22e41061ca85ea2f02625a2e
|
||||
@@ -103,6 +119,10 @@ checksums:
|
||||
Delete%20comment/singular: a3dae0c9ddbc73677aad9812e3dffd69
|
||||
Delete%20list/singular: b694f58e4c973d8797a78e746b550b1f
|
||||
Delete%20workspace/singular: 9017c821209528d9b20d40a488854cdf
|
||||
deleted%20a%20checklist/singular: c54f922dc6c238c9141c700cb3180baf
|
||||
deleted%20a%20checklist%20item/singular: 2b7a861600102ac5c271dd25c1df261a
|
||||
deleted%20checklist%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 60f9107197e756487d3f95a1083846b5
|
||||
deleted%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 8b7e270f612f9e91bda7f5cfb853d843
|
||||
Design/singular: 991b75727b6784c1a063a7462b76186d
|
||||
Disconnect%20Trello/singular: a2dd737d133887d34504728c7e7f05e3
|
||||
Discuss%20and%20collaborate%20on%20cards./singular: f2e87816709f602130831ead50bba457
|
||||
@@ -124,9 +144,13 @@ checksums:
|
||||
email/singular: f31eb214738e037d58e26149797739df
|
||||
Email/singular: e7f34943a0c2fb849db1839ff6ef5cb5
|
||||
Enhancement/singular: 785fe23c0eef0a5b60b5b2a88151de31
|
||||
Enter%20your%20current%20password/singular: bfceabde4c0b6f2cb439015b76549651
|
||||
Enter%20your%20current%20password%20and%20choose%20a%20new%20secure%20password./singular: 9bb88155b18e98ea799c0e939d16af64
|
||||
Enter%20your%20email%20address/singular: 9bc008365ebe3e404e241c8ca876f56e
|
||||
Enter%20your%20name/singular: cd95fbdd0533f2c2e8edf9d9bd9aa8df
|
||||
Enter%20your%20new%20password/singular: c67251e3002b68bc20a7cf5de23e43ac
|
||||
Enter%20your%20password/singular: ea4fdd034522dead21bae0c0abb52eae
|
||||
Error%20Changing%20Password/singular: ebecb5c1b72ba4b063117241f5ba4f2d
|
||||
Error%20deleting%20account/singular: d42965a9bc9e5ec4ed57890268924643
|
||||
Error%20deleting%20label/singular: 94387e3a45ec768ae7715701ae00136e
|
||||
Error%20deleting%20workspace/singular: 0aec9bd8170bc84f5ea5c9a47c52ed26
|
||||
@@ -211,20 +235,25 @@ checksums:
|
||||
Long-term/singular: 51cb6f0b112250c5a091ca5f0866904b
|
||||
Low%20Priority/singular: 509b5cb7c1e8a185e0aa6d38c64c90e8
|
||||
magic%20link/singular: db9d17a5bd98bba8aa0d8068c68579f3
|
||||
marked%20a%20checklist%20item%20as%20incomplete/singular: 35d0822f65971b97774b962561b02649
|
||||
marked%20checklist%20item%20%3C0%3E%7B0%7D%3C%2F0%3E%20as%20incomplete/singular: 4c38799ff25321ea25017bf4cd8e2e4f
|
||||
Medium%20Priority/singular: 1f527cd6d1ed602930bcaa303f503b51
|
||||
Members/singular: 0932e80cba1e3e0a7f52bb67ff31da32
|
||||
Members%20%7C%20%7B0%7D/singular: a29e3e9f1076acd178c417d047584e88
|
||||
Monthly/singular: 818f1192e32bb855597f930d3e78806e
|
||||
moved%20the%20card%20from%20%3C0%3E%7BfromList%7D%3C%2F0%3E%20to%3C1%3E%7BtoList%7D%3C%2F1%3E/singular: c2d0d72ad97510344b51154ef15060e0
|
||||
moved%20the%20card%20from%20%3C0%3E%7B0%7D%3C%2F0%3E%20to%3C1%3E%7B1%7D%3C%2F1%3E/singular: 11edf0427766c26db541d46379dc3c16
|
||||
moved%20the%20card%20to%20another%20list/singular: 2e8c41bfafb42fa299ce56e4300205ff
|
||||
Name/singular: 9368b5a047572b6051f334af5aa76819
|
||||
Need%20help%3F/singular: 04e7322f2d3ffb2d73ff2f64b71637c8
|
||||
New/singular: 126d036fae5fb6b629728ecb97e6195b
|
||||
New%20board/singular: 63f4e979e29a7fc2f5c09ff91fa75966
|
||||
New%20card/singular: a33f6219a756127f91c2523cfe845a19
|
||||
New%20checklist/singular: 58252b71e9693ae0f4d2d0b72108a569
|
||||
New%20import/singular: e8fddfe15dd170277df919e5d37efd47
|
||||
New%20label/singular: 890040da52a88c16c249a4ac78980f81
|
||||
New%20list/singular: 146c2e642b11056a0b07ed65733e4178
|
||||
New%20password%20is%20required/singular: f88427a4cca058631199a4384cb5622e
|
||||
New%20password%20must%20be%20different%20from%20current%20password/singular: db33013fcc6c40995cf8a37deb3d5667
|
||||
New%20Ticket/singular: 665ff16ec736cba20e8a1b3beb3baa09
|
||||
New%20workspace/singular: 8eecf05b4ce29aa880adfed2e11476af
|
||||
Newsletter/singular: dcfb9666301924431ac8ae88e5b6f9d7
|
||||
@@ -241,11 +270,15 @@ checksums:
|
||||
Organize%20and%20find%20cards%20quickly%20with%20powerful%20filtering%20tools./singular: 1b9898c4b21e9dff413b4f76dc59db56
|
||||
Own%20your%20data/singular: cc2178dac4bdf6b07f030cfc2a7510e6
|
||||
Part-time/singular: 213d63da450f35dabb3ab0e35e29feed
|
||||
Password%20Changed/singular: 1fcebe9ddb46f722a57f195efddc695d
|
||||
Password%20must%20be%20at%20least%208%20characters/singular: 4c30501d085eaccea47af34212bb26a7
|
||||
Passwords%20do%20not%20match/singular: 37ca1f4e0afc9a0b8e9617f767103c92
|
||||
Payment%20frequency/singular: 63ded0e4ffb462ca8bd33d38e4691d86
|
||||
Pending/singular: 030a6f3395d5d4efddd3cc67d6009039
|
||||
per%20user%2Fmonth/singular: 72af182c1ba6df6732640f4d8a78d360
|
||||
Personal%20Project/singular: d7820b1bf4efecc61ed89234567aaa9c
|
||||
Planning/singular: 353f58c75248275fe091740607501610
|
||||
Please%20confirm%20your%20new%20password/singular: 43d0307b9307238cc6c199cfa66caff2
|
||||
Please%20enter%20a%20valid%20email%20address/singular: 8de4bc8832b11b380bc4cbcedc16e48b
|
||||
Please%20enter%20a%20valid%20name/singular: f2d741f1b5cae722e35cb5206786f932
|
||||
Please%20enter%20a%20valid%20password/singular: 4b32c17e19b79bcbf0bb092c06ba310f
|
||||
@@ -268,7 +301,10 @@ checksums:
|
||||
Remove%20member/singular: 1d77c2ca3768e486fd1fb5df30cb60d9
|
||||
removed%20a%20label%20from%20the%20card/singular: f83ec18850a2a8a3f8242a740a04df06
|
||||
removed%20a%20member%20from%20the%20card/singular: 0bd7561bb79358fde3d595c3e60a315a
|
||||
removed%20label%20%3C0%3E%7Blabel%7D%3C%2F0%3E/singular: 1e7ebc1866136352bdc3cd90afc083f0
|
||||
removed%20label%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 7e0936b15831e65754588b8512f62fcb
|
||||
renamed%20a%20checklist/singular: 4d208de1857740e63469007c5b8b491a
|
||||
renamed%20checklist%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: e95d119ef65b0af6c0a96bef182be671
|
||||
renamed%20checklist%20item%20to%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: 50f55f71f9245890afee434d7adc2140
|
||||
Research/singular: 3368e9638d1619babd6df9fad592274f
|
||||
Resolution/singular: 6d8bd9e1bd7dae5ae38c93061d32990e
|
||||
Resources/singular: ec7fb05ed963bb6781a35782b3475502
|
||||
@@ -307,6 +343,7 @@ checksums:
|
||||
Templates/singular: 8ed62f56c81fa96c0f3182acb331bf63
|
||||
Terms%20of%20service/singular: 0b8a8b23aff021a6cde79613fdb39c28
|
||||
Thank%20you%20for%20your%20feedback!/singular: 07edd8c50685a52c0969d711df26d768
|
||||
The%20current%20password%20you%20entered%20is%20incorrect./singular: 67a76bf346ab4b48563269e9d941a64a
|
||||
The%20main%20difference%20between%20Kan%20and%20Trello%20is%20that%20Kan%20is%20open%20source%2C%20allowing%20anyone%20to%20view%2C%20modify%2C%20and%20contribute%20to%20our%20code.%20Our%20cloud%20offering%20also%20offers%20no%20restrictions%20on%20features%20for%20individual%20use%2C%20whereas%20Trello%20locks%20basic%20features%20such%20as%20the%20number%20of%20boards%20you%20can%20create%20behind%20a%20paywall./singular: db6e22cc955c5fbe547feedeb48f8719
|
||||
The%20open%20source%20%3C0%2F%3E%20alternative%20to%20Trello/singular: 692cb2e8a8e610953c996826beed45a2
|
||||
The%20visibility%20of%20your%20board%20has%20been%20set%20to%20%7B0%7D./singular: 970e17a115f7374e60e0a8ded425db8f
|
||||
@@ -324,22 +361,28 @@ checksums:
|
||||
Trello%20disconnected/singular: 54b24a3e6c9a7eedd8c8d1060ab1175d
|
||||
Trello%20imports/singular: 6827eca403faa8f89891d17827e72af9
|
||||
Triaging/singular: 1d40799fcae53a8a27688fdae2a48dee
|
||||
Unable%20to%20add%20checklist%20item/singular: 4c4c3eaaf10b348b39ae97eb5dc455df
|
||||
Unable%20to%20add%20comment/singular: 49bb435880817434698f31a6069564d6
|
||||
Unable%20to%20create%20card/singular: 90112ea12ec6fa42097a6e022ae048a4
|
||||
Unable%20to%20create%20checklist/singular: 94eed122e42e0951cd08b9ec62f5eeb6
|
||||
Unable%20to%20create%20list/singular: 7fbbf8314f8d08a4123c7daef09fed05
|
||||
Unable%20to%20create%20workspace/singular: c1c949477e121d73ed6683eddf9cd874
|
||||
Unable%20to%20delete%20card/singular: 50ff06aa1265fe464f776aba33f1bef9
|
||||
Unable%20to%20delete%20checklist/singular: d7067e2c009f4919f0cca77df3c228ee
|
||||
Unable%20to%20delete%20checklist%20item/singular: a74144593b625e4d8d7ecf734462c60d
|
||||
Unable%20to%20delete%20comment/singular: 550198b2c87f06726a843c79c1026ed9
|
||||
Unable%20to%20remove%20member/singular: 39025a0c53818438829603d213baef06
|
||||
Unable%20to%20send%20feedback/singular: 656c93265d7e2bef1245b17d85f85ae5
|
||||
Unable%20to%20update%20board%20URL/singular: 080746884059142358b58d9a44ff7d93
|
||||
Unable%20to%20update%20board%20visibility/singular: a76a21d561b8943e9276e027a1e3f70d
|
||||
Unable%20to%20update%20card/singular: eca6002e57af8ec97324eae64e3b5731
|
||||
Unable%20to%20update%20checklist/singular: 44c10f49f448909ceca481ed9b4b07e7
|
||||
Unable%20to%20update%20checklist%20item/singular: 5c86b3523531c30d58856e3ecde0cb55
|
||||
Unable%20to%20update%20comment/singular: 05e798ed6b0f3fee41f3e8832eb699ea
|
||||
Unable%20to%20update%20labels/singular: dca2bdc3dcf74bc9d95e05156039a291
|
||||
Unable%20to%20update%20list/singular: 14aa802f91b9b4c05236c8c75afb33da
|
||||
Unable%20to%20update%20members/singular: 9a851a6b0c75ee16d25cf2ff4b67b255
|
||||
unassigned%20%3C0%3E%7BmemberName%7D%3C%2F0%3E%20from%20the%20card/singular: 105d4eeb32044126b8dde243bad11d56
|
||||
unassigned%20%3C0%3E%7B0%7D%3C%2F0%3E%20from%20the%20card/singular: b683cc07092348c1e75dba40b1262b85
|
||||
unassigned%20themselves%20from%20the%20card/singular: 27c6f293c562af6a44348d7f00036d30
|
||||
Unlimited%20activity%20log/singular: 8c993de94cda0deac19ba14ecafce6a5
|
||||
Unlimited%20boards/singular: cb4fd858137ce825c2f1904d142d8042
|
||||
@@ -349,9 +392,10 @@ checksums:
|
||||
Unlimited%20lists/singular: 5c418701b27b9acbc5dd199719007362
|
||||
Update/singular: 079fc039262fd31b10532929685c2d1b
|
||||
Update%20label/singular: 97880b503dfe956941c5f23025a1c102
|
||||
updated%20a%20checklist%20item/singular: 198e1d1d503f4b69b752dd84d0cc0e9d
|
||||
updated%20the%20description/singular: 70fd604b6dc957a75be90ea77572d76d
|
||||
updated%20the%20title/singular: 98cf8f12923ec1a58e767e3a40863b21
|
||||
updated%20the%20title%20to%20%3C0%3E%7BtoTitle%7D%3C%2F0%3E/singular: 70cdf681ec2b6ef8e14397bc1f93f945
|
||||
updated%20the%20title%20to%20%3C0%3E%7B0%7D%3C%2F0%3E/singular: aca196d729401d8adc5c8ca9d558840e
|
||||
Upgrade/singular: 63c3b52882e0d779859307d672c178c2
|
||||
Urgent/singular: e79afcd4398e52e10e7e8243a7eecabe
|
||||
URL%20can%20only%20contain%20letters%2C%20numbers%2C%20and%20hyphens/singular: 875d37d2d920f98ef60a314eda8a5d9a
|
||||
@@ -391,6 +435,7 @@ checksums:
|
||||
Writing/singular: 4f5f3ee3320c252921f80c42653c5d49
|
||||
Yearly/singular: 87f43e016c19cb25860f456549a2f431
|
||||
Yes%2C%20we%20offer%20an%20forever%20free%20plan%20for%20individual%20use.%20No%20restrictions%2C%20no%20paywalls%2C%20no%20limits./singular: 963cee303d0ff13c1719f4575e774fe3
|
||||
You%20are%20about%20to%20change%20your%20password./singular: df4783d593505766d78c5bc08d3d48ac
|
||||
You%20can%20get%20a%20custom%20workspace%20URL%2C%20like%20%3C0%3Ekan.bn%2Fkan%3C%2F0%3E%2C%20by%20going%20into%20your%20%3C1%3Eworkspace%20settings%3C%2F1%3E%20and%20purchasing%20a%20pro%20workspace%20subscription.%20All%20subscriptions%20help%20fund%20the%20development%20of%20the%20project!/singular: 41dd145ef56f539e12dc064a9807c660
|
||||
You%20can%20invite%20team%20members%20by%20clicking%20the%20%22Invite%22%20button%20in%20the%20top%20right%20corner%20of%20the%20%3C0%3Emembers%20page%3C%2F0%3E%20and%20entering%20their%20email%20address.%20They%20will%20receive%20an%20email%20with%20a%20link%20to%20join%20the%20workspace./singular: 47e125eb9b4c11cab5a2f4b3ab08e883
|
||||
You%20can%20self-host%20by%20following%20the%20instructions%20in%20our%20%3C0%3Erepo%3C%2F0%3E./singular: a6152a41b2d8f64d5a657e5b8bc808a9
|
||||
@@ -399,6 +444,7 @@ checksums:
|
||||
Your%20account%20has%20been%20deleted./singular: 8c8d944e07388c5877effdb2c2803dcf
|
||||
Your%20boards%20have%20been%20imported./singular: 403972e7a25afc2415762c1c2b1ec868
|
||||
Your%20display%20name%20has%20been%20updated./singular: 15e5fff36c554c16ec5214427fae1bf4
|
||||
Your%20password%20has%20been%20changed./singular: 8f730f68d52b7efa727aa0784282ebcb
|
||||
Your%20profile%20image%20has%20been%20updated./singular: 099e1780348cd7bf617721344371a430
|
||||
Your%20Trello%20account%20has%20been%20disconnected./singular: 126aeeb73f7e4cad338056e4c933f39b
|
||||
Your%20Trello%20account%20is%20connected./singular: 0499d193001fce2fbec445ae034ce512
|
||||
|
||||
@@ -31,12 +31,12 @@ const config = {
|
||||
|
||||
images: {
|
||||
remotePatterns: [
|
||||
|
||||
{
|
||||
protocol: "https",
|
||||
hostname: process.env.S3_FORCE_PATH_STYLE === "true"
|
||||
? `${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`
|
||||
: `*.${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`,
|
||||
hostname:
|
||||
env("S3_FORCE_PATH_STYLE") === "true"
|
||||
? `${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`
|
||||
: `*.${env("NEXT_PUBLIC_STORAGE_DOMAIN")}`,
|
||||
},
|
||||
{
|
||||
protocol: "http",
|
||||
@@ -54,4 +54,16 @@ const config = {
|
||||
},
|
||||
};
|
||||
|
||||
// Only allow external images when OIDC is configured (for OIDC provider avatars)
|
||||
if (
|
||||
env("OIDC_CLIENT_ID") &&
|
||||
env("OIDC_CLIENT_SECRET") &&
|
||||
env("OIDC_DISCOVERY_URL")
|
||||
) {
|
||||
config.images?.remotePatterns?.push({
|
||||
protocol: "https",
|
||||
hostname: "**",
|
||||
});
|
||||
}
|
||||
|
||||
export default config;
|
||||
|
||||
@@ -33,6 +33,7 @@
|
||||
"@tailwindcss/typography": "^0.5.16",
|
||||
"@tanstack/react-query": "catalog:",
|
||||
"@tiptap/extension-link": "^2.22.2",
|
||||
"@tiptap/extension-mention": "^3.0.9",
|
||||
"@tiptap/extension-placeholder": "^2.14.0",
|
||||
"@tiptap/pm": "^2.14.0",
|
||||
"@tiptap/react": "^2.14.0",
|
||||
@@ -48,6 +49,7 @@
|
||||
"next": "^15.3.4",
|
||||
"next-logger": "^5.0.1",
|
||||
"next-runtime-env": "^1.7.2",
|
||||
"next-themes": "^0.4.6",
|
||||
"nextjs-cors": "^2.2.0",
|
||||
"pino": "^9.6.0",
|
||||
"posthog-js": "^1.254.0",
|
||||
|
||||
@@ -4,7 +4,7 @@ import { t } from "@lingui/core/macro";
|
||||
import { Trans } from "@lingui/react/macro";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { env } from "next-runtime-env";
|
||||
import { useState } from "react";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import {
|
||||
FaApple,
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
FaGoogle,
|
||||
FaLinkedin,
|
||||
FaMicrosoft,
|
||||
FaOpenid,
|
||||
FaReddit,
|
||||
FaSpotify,
|
||||
FaTiktok,
|
||||
@@ -33,6 +34,8 @@ import Button from "~/components/Button";
|
||||
import Input from "~/components/Input";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
|
||||
type AuthProvider = SocialProvider | "oidc";
|
||||
|
||||
interface FormValues {
|
||||
name?: string;
|
||||
email: string;
|
||||
@@ -141,16 +144,28 @@ const availableSocialProviders = {
|
||||
name: "Zoom",
|
||||
icon: SiZoom,
|
||||
},
|
||||
oidc: {
|
||||
id: "oidc",
|
||||
name: "OIDC",
|
||||
icon: FaOpenid,
|
||||
},
|
||||
};
|
||||
|
||||
export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
const [isLoginWithProviderPending, setIsLoginWithProviderPending] =
|
||||
useState<null | SocialProvider>(null);
|
||||
const isCredentialsEnabled =
|
||||
env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true";
|
||||
useState<null | AuthProvider>(null);
|
||||
const [isCredentialsEnabled, setIsCredentialsEnabled] = useState(false);
|
||||
const [isLoginWithEmailPending, setIsLoginWithEmailPending] = useState(false);
|
||||
const [loginError, setLoginError] = useState<string | null>(null);
|
||||
const { showPopup } = usePopup();
|
||||
const oidcProviderName = "OIDC";
|
||||
|
||||
// Safely get environment variables on client side to avoid hydration mismatch
|
||||
useEffect(() => {
|
||||
const credentialsAllowed =
|
||||
env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true";
|
||||
setIsCredentialsEnabled(credentialsAllowed);
|
||||
}, []);
|
||||
|
||||
const {
|
||||
register,
|
||||
@@ -226,13 +241,26 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
setIsLoginWithEmailPending(false);
|
||||
};
|
||||
|
||||
const handleLoginWithProvider = async (provider: SocialProvider) => {
|
||||
const handleLoginWithProvider = async (provider: AuthProvider) => {
|
||||
setIsLoginWithProviderPending(provider);
|
||||
setLoginError(null);
|
||||
const { error } = await authClient.signIn.social({
|
||||
provider,
|
||||
callbackURL: "/boards",
|
||||
});
|
||||
|
||||
let error;
|
||||
if (provider === "oidc") {
|
||||
// Use oauth2 signin for OIDC provider
|
||||
const result = await authClient.signIn.oauth2({
|
||||
providerId: "oidc",
|
||||
callbackURL: "/boards",
|
||||
});
|
||||
error = result.error;
|
||||
} else {
|
||||
// Use social signin for traditional social providers
|
||||
const result = await authClient.signIn.social({
|
||||
provider,
|
||||
callbackURL: "/boards",
|
||||
});
|
||||
error = result.error;
|
||||
}
|
||||
|
||||
setIsLoginWithProviderPending(null);
|
||||
|
||||
@@ -260,13 +288,16 @@ export function Auth({ setIsMagicLinkSent, isSignUp }: AuthProps) {
|
||||
return (
|
||||
<Button
|
||||
key={key}
|
||||
onClick={() => handleLoginWithProvider(key as SocialProvider)}
|
||||
onClick={() => handleLoginWithProvider(key as AuthProvider)}
|
||||
isLoading={isLoginWithProviderPending === key}
|
||||
iconLeft={<provider.icon />}
|
||||
fullWidth
|
||||
size="lg"
|
||||
>
|
||||
<Trans>Continue with {provider.name}</Trans>
|
||||
<Trans>
|
||||
Continue with{" "}
|
||||
{key === "oidc" ? oidcProviderName : provider.name}
|
||||
</Trans>
|
||||
</Button>
|
||||
);
|
||||
})}
|
||||
|
||||
@@ -5,7 +5,7 @@ import LoadingSpinner from "./LoadingSpinner";
|
||||
|
||||
interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
variant?: "primary" | "secondary" | "danger" | "ghost";
|
||||
size?: "sm" | "md" | "lg";
|
||||
size?: "xs" | "sm" | "md" | "lg";
|
||||
isLoading?: boolean;
|
||||
iconLeft?: React.ReactNode;
|
||||
iconRight?: React.ReactNode;
|
||||
@@ -28,6 +28,7 @@ const Button = ({
|
||||
}: ButtonProps) => {
|
||||
const classes = twMerge(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-2 text-sm font-semibold text-light-50 shadow-sm focus-visible:outline-none",
|
||||
size === "xs" && "text-xs px-2 py-1",
|
||||
size === "sm" && "text-xs",
|
||||
size === "lg" && "py-[0.65rem]",
|
||||
fullWidth && "w-full",
|
||||
|
||||
@@ -55,51 +55,59 @@ export default function CheckboxDropdown({
|
||||
|
||||
const renderMenuItems = (items: Item[], groupKey: string | null) => (
|
||||
<>
|
||||
{items.map((item) => (
|
||||
<Menu.Item key={item.key}>
|
||||
<div
|
||||
className="group flex items-center rounded-[5px] p-2 hover:bg-light-200 dark:hover:bg-dark-300"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelect(groupKey, { key: item.key, value: item.value });
|
||||
}}
|
||||
>
|
||||
<input
|
||||
id={item.key}
|
||||
name={item.key}
|
||||
type="checkbox"
|
||||
className="h-[14px] w-[14px] rounded bg-transparent"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onChange={() =>
|
||||
handleSelect(groupKey, { key: item.key, value: item.value })
|
||||
}
|
||||
checked={item.selected}
|
||||
/>
|
||||
{item.leftIcon && (
|
||||
<span className="ml-3 flex items-center">{item.leftIcon}</span>
|
||||
)}
|
||||
<label
|
||||
htmlFor={item.key}
|
||||
className="ml-3 text-[12px] text-dark-900"
|
||||
{items.length > 0 ? (
|
||||
items.map((item) => (
|
||||
<Menu.Item key={item.key}>
|
||||
<div
|
||||
className="group flex items-center rounded-[5px] p-2 hover:bg-light-200 dark:hover:bg-dark-300"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
handleSelect(groupKey, { key: item.key, value: item.value });
|
||||
}}
|
||||
>
|
||||
{item.value}
|
||||
</label>
|
||||
{handleEdit && (
|
||||
<button
|
||||
type="button"
|
||||
className="invisible ml-auto group-hover:visible"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleEdit(item.key);
|
||||
}}
|
||||
<input
|
||||
id={item.key}
|
||||
name={item.key}
|
||||
type="checkbox"
|
||||
className="h-[14px] w-[14px] rounded bg-transparent"
|
||||
onClick={(event) => event.stopPropagation()}
|
||||
onChange={() =>
|
||||
handleSelect(groupKey, { key: item.key, value: item.value })
|
||||
}
|
||||
checked={item.selected}
|
||||
/>
|
||||
{item.leftIcon && (
|
||||
<span className="ml-3 flex items-center">{item.leftIcon}</span>
|
||||
)}
|
||||
<label
|
||||
htmlFor={item.key}
|
||||
className="ml-3 text-[12px] text-dark-900"
|
||||
>
|
||||
<HiEllipsisHorizontal size={20} className="text-dark-900" />
|
||||
</button>
|
||||
)}
|
||||
{item.value}
|
||||
</label>
|
||||
{handleEdit && (
|
||||
<button
|
||||
type="button"
|
||||
className="invisible ml-auto group-hover:visible"
|
||||
onClick={(event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
handleEdit(item.key);
|
||||
}}
|
||||
>
|
||||
<HiEllipsisHorizontal size={20} className="text-dark-900" />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
</Menu.Item>
|
||||
))
|
||||
) : (
|
||||
!handleCreate && (
|
||||
<div className="flex items-center p-2 text-[12px] text-dark-900">
|
||||
No items
|
||||
</div>
|
||||
</Menu.Item>
|
||||
))}
|
||||
)
|
||||
)}
|
||||
{handleCreate && (
|
||||
<button
|
||||
type="button"
|
||||
|
||||
58
apps/web/src/components/CircularProgress.tsx
Normal file
58
apps/web/src/components/CircularProgress.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
interface CircularProgressProps {
|
||||
progress: number; // 0-100
|
||||
size?: "sm" | "md" | "lg";
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const CircularProgress = ({
|
||||
progress,
|
||||
size = "md",
|
||||
className,
|
||||
}: CircularProgressProps) => {
|
||||
const radius = 40;
|
||||
const circumference = 2 * Math.PI * radius;
|
||||
const strokeDashoffset = circumference - (progress / 100) * circumference;
|
||||
|
||||
return (
|
||||
<div className={twMerge("relative", className)}>
|
||||
<svg
|
||||
className={twMerge(
|
||||
"-rotate-90 transform",
|
||||
size === "sm" && "h-4 w-4",
|
||||
size === "md" && "h-5 w-5",
|
||||
size === "lg" && "h-8 w-8",
|
||||
)}
|
||||
viewBox="0 0 100 100"
|
||||
>
|
||||
<circle
|
||||
cx="50"
|
||||
cy="50"
|
||||
r={radius}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="14"
|
||||
className="text-light-300 dark:text-dark-400"
|
||||
/>
|
||||
<circle
|
||||
cx="50"
|
||||
cy="50"
|
||||
r={radius}
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="14"
|
||||
strokeDasharray={circumference}
|
||||
strokeDashoffset={strokeDashoffset}
|
||||
strokeLinecap="round"
|
||||
className={twMerge(
|
||||
"transition-all duration-300 ease-in-out",
|
||||
progress === 100 ? "text-green-500" : "text-blue-500",
|
||||
)}
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default CircularProgress;
|
||||
@@ -10,7 +10,7 @@ import { authClient } from "@kan/auth/client";
|
||||
|
||||
import { useClickOutside } from "~/hooks/useClickOutside";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
import { WorkspaceProvider } from "~/providers/workspace";
|
||||
import FeedbackModal from "./FeedbackModal";
|
||||
import Modal from "./modal";
|
||||
@@ -41,7 +41,7 @@ export default function Dashboard({
|
||||
rightPanel,
|
||||
hasRightPanel = false,
|
||||
}: DashboardProps) {
|
||||
const theme = useTheme();
|
||||
const { theme } = useTheme();
|
||||
const { modalContentType } = useModal();
|
||||
|
||||
const { data: session, isPending: sessionLoading } = authClient.useSession();
|
||||
@@ -90,7 +90,7 @@ export default function Dashboard({
|
||||
}
|
||||
});
|
||||
|
||||
const isDarkMode = theme.activeTheme === "dark";
|
||||
const isDarkMode = theme === "dark";
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -12,11 +12,14 @@ export function DeleteLabelConfirmation({
|
||||
labelPublicId: string;
|
||||
refetch: () => void;
|
||||
}) {
|
||||
const { closeModal } = useModal();
|
||||
const { closeModal, closeModals } = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const deleteLabelMutation = api.label.delete.useMutation({
|
||||
onSuccess: () => refetch(),
|
||||
onSuccess: () => {
|
||||
refetch();
|
||||
closeModals(2);
|
||||
},
|
||||
onError: () =>
|
||||
showPopup({
|
||||
header: t`Error deleting label`,
|
||||
@@ -26,7 +29,6 @@ export function DeleteLabelConfirmation({
|
||||
});
|
||||
|
||||
const handleDeleteLabel = () => {
|
||||
closeModal();
|
||||
deleteLabelMutation.mutate({
|
||||
labelPublicId,
|
||||
});
|
||||
|
||||
@@ -15,10 +15,15 @@ import {
|
||||
ReactRenderer,
|
||||
useEditor,
|
||||
} from "@tiptap/react";
|
||||
import { useEffect } from "react";
|
||||
import StarterKit from "@tiptap/starter-kit";
|
||||
import Suggestion from "@tiptap/suggestion";
|
||||
import { forwardRef, useImperativeHandle, useRef, useState } from "react";
|
||||
import {
|
||||
forwardRef,
|
||||
useEffect,
|
||||
useImperativeHandle,
|
||||
useRef,
|
||||
useState,
|
||||
} from "react";
|
||||
import {
|
||||
HiH1,
|
||||
HiH2,
|
||||
@@ -34,6 +39,9 @@ import {
|
||||
} from "react-icons/hi2";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
import tippy from "tippy.js";
|
||||
import Mention from "@tiptap/extension-mention";
|
||||
import Avatar from "./Avatar";
|
||||
import { getAvatarUrl } from "~/utils/helpers";
|
||||
|
||||
declare module "@tiptap/core" {
|
||||
interface Commands<ReturnType> {
|
||||
@@ -69,6 +77,16 @@ export interface RenderSuggestionsProps {
|
||||
command: (item: SlashCommandItem) => void;
|
||||
}
|
||||
|
||||
export type WorkspaceMember = {
|
||||
publicId: string;
|
||||
user: {
|
||||
id: string;
|
||||
name: string | null;
|
||||
image: string | null;
|
||||
} | null;
|
||||
email: string;
|
||||
};
|
||||
|
||||
const CommandsList = forwardRef<
|
||||
{ onKeyDown: (props: SuggestionKeyDownProps) => boolean },
|
||||
{
|
||||
@@ -182,6 +200,125 @@ const RenderSuggestions = () => {
|
||||
};
|
||||
};
|
||||
|
||||
type MentionItem = { id: string; label: string; image: string | null };
|
||||
|
||||
const MentionList = forwardRef<
|
||||
{ onKeyDown: (props: SuggestionKeyDownProps) => boolean },
|
||||
{
|
||||
items: MentionItem[];
|
||||
command: (item: MentionItem) => void;
|
||||
}
|
||||
>(({ items, command }, ref) => {
|
||||
const [selectedIndex, setSelectedIndex] = useState(0);
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
onKeyDown: ({ event }: SuggestionKeyDownProps) => {
|
||||
if (event.key === "ArrowUp") {
|
||||
setSelectedIndex((selectedIndex + items.length - 1) % items.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === "ArrowDown") {
|
||||
setSelectedIndex((selectedIndex + 1) % items.length);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (event.key === "Enter") {
|
||||
const item = items[selectedIndex];
|
||||
if (item) {
|
||||
command(item);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
}));
|
||||
|
||||
return (
|
||||
<div className="w-56 rounded-md border-[1px] border-light-200 bg-light-50 shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-dark-500 dark:bg-dark-200">
|
||||
<div className="max-h-[350px] overflow-y-auto p-1 scrollbar-thin scrollbar-thumb-light-200 dark:scrollbar-thumb-dark-300">
|
||||
{items.length > 0 ? items.map((item, index) => (
|
||||
<button
|
||||
key={item.id}
|
||||
onClick={() => command(item)}
|
||||
className={twMerge(
|
||||
"group flex w-full items-center rounded-[5px] p-2 hover:bg-light-200 dark:hover:bg-dark-300",
|
||||
index === selectedIndex && "bg-light-200 dark:bg-dark-300",
|
||||
)}
|
||||
>
|
||||
<Avatar
|
||||
size="xs"
|
||||
name={item.label}
|
||||
imageUrl={
|
||||
item.image ? getAvatarUrl(item.image) : undefined
|
||||
}
|
||||
email={item.label}
|
||||
/>
|
||||
<span className="ml-3 text-[12px] font-medium text-dark-900 dark:text-dark-1000">
|
||||
{item.label}
|
||||
</span>
|
||||
</button>
|
||||
)) : (
|
||||
<div className="flex items-center justify-start p-2">
|
||||
<span className="text-dark-900 text-[12px] dark:text-dark-1000">No results</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
MentionList.displayName = "MentionList";
|
||||
|
||||
const renderMentionSuggestions = () => {
|
||||
let reactRenderer: ReactRenderer;
|
||||
let popup: TippyInstance[];
|
||||
|
||||
return {
|
||||
onStart: (props: any) => {
|
||||
reactRenderer = new ReactRenderer(MentionList, {
|
||||
props,
|
||||
editor: props.editor,
|
||||
});
|
||||
|
||||
if (!props.clientRect) return;
|
||||
|
||||
popup = tippy("body", {
|
||||
getReferenceClientRect: props.clientRect,
|
||||
appendTo: () => document.body,
|
||||
content: reactRenderer.element,
|
||||
showOnCreate: true,
|
||||
interactive: true,
|
||||
trigger: "manual",
|
||||
placement: "bottom-start",
|
||||
});
|
||||
},
|
||||
onUpdate(props: any) {
|
||||
reactRenderer.updateProps(props);
|
||||
if (!props.clientRect) return;
|
||||
popup[0]?.setProps({ getReferenceClientRect: props.clientRect });
|
||||
},
|
||||
onKeyDown(props: SuggestionKeyDownProps) {
|
||||
if (props.event.key === "Escape") {
|
||||
popup[0]?.hide();
|
||||
return true;
|
||||
}
|
||||
return (
|
||||
(
|
||||
reactRenderer.ref as {
|
||||
onKeyDown?: (props: SuggestionKeyDownProps) => boolean;
|
||||
}
|
||||
).onKeyDown?.(props) ?? false
|
||||
);
|
||||
},
|
||||
onExit() {
|
||||
popup[0]?.destroy();
|
||||
reactRenderer.destroy();
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
const SlashCommands = Extension.create<SlashCommandsOptions>({
|
||||
name: "slash-commands",
|
||||
addOptions() {
|
||||
@@ -285,11 +422,13 @@ export default function Editor({
|
||||
onChange,
|
||||
onBlur,
|
||||
readOnly = false,
|
||||
workspaceMembers,
|
||||
}: {
|
||||
content: string | null;
|
||||
onChange?: (value: string) => void;
|
||||
onBlur?: () => void;
|
||||
readOnly?: boolean;
|
||||
workspaceMembers: WorkspaceMember[];
|
||||
}) {
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
@@ -300,7 +439,7 @@ export default function Editor({
|
||||
Placeholder.configure({
|
||||
placeholder: readOnly
|
||||
? ""
|
||||
: t`Add description... (type '/' to open commands)`,
|
||||
: t`Add description... (type '/' to open commands or '@' to mention)`,
|
||||
}),
|
||||
Link.configure({
|
||||
openOnClick: true,
|
||||
@@ -321,6 +460,38 @@ export default function Editor({
|
||||
char: "/",
|
||||
},
|
||||
}),
|
||||
Mention.configure({
|
||||
HTMLAttributes: {
|
||||
class: 'mention',
|
||||
},
|
||||
suggestion: {
|
||||
char: "@",
|
||||
items: ({ query }: { query: string }) => {
|
||||
const all: MentionItem[] = workspaceMembers.map((member: WorkspaceMember) => ({
|
||||
id: member.publicId,
|
||||
label: member?.user?.name ?? member.email,
|
||||
image: member?.user?.image ?? null,
|
||||
}));
|
||||
const q = query.toLowerCase();
|
||||
return all.filter((u) => u.label.toLowerCase().includes(q));
|
||||
},
|
||||
command: ({ editor, range, props }: any) => {
|
||||
const mentionHTML = `<span data-type="mention" data-id="${props.id}" data-label="${props.label}">@${props.label}</span> `;
|
||||
|
||||
editor
|
||||
.chain()
|
||||
.focus()
|
||||
.deleteRange(range)
|
||||
.insertContent(mentionHTML)
|
||||
.focus()
|
||||
.run();
|
||||
},
|
||||
render: renderMentionSuggestions,
|
||||
},
|
||||
renderText({ options, node }) {
|
||||
return `${options.suggestion.char}${node.attrs.label ?? node.attrs.id}`;
|
||||
},
|
||||
}),
|
||||
],
|
||||
content,
|
||||
onUpdate: ({ editor }) => onChange?.(editor.getHTML()),
|
||||
@@ -369,11 +540,19 @@ export default function Editor({
|
||||
.tiptap p {
|
||||
margin: 0 0 1rem 0 !important;
|
||||
}
|
||||
.tiptap .mention {
|
||||
background-color: rgba(59, 130, 246, 0.1);
|
||||
border-radius: 0.25rem;
|
||||
padding: 0.125rem 0.25rem;
|
||||
color: rgb(59, 130, 246);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
`}</style>
|
||||
{!readOnly && editor && <EditorBubbleMenu editor={editor} />}
|
||||
<EditorContent
|
||||
editor={editor}
|
||||
className="prose dark:prose-invert prose-sm max-w-none overflow-y-auto [&_blockquote]:!text-xs [&_h1]:!text-lg [&_h2]:!text-base [&_h3]:!text-sm [&_ol]:!text-xs [&_p.is-empty::before]:text-light-900 [&_p.is-empty::before]:dark:text-dark-800 [&_p]:!text-sm [&_p]:text-black [&_p]:dark:text-white [&_ul]:!text-xs"
|
||||
className="prose dark:prose-invert prose-sm max-w-none overflow-y-auto [&_blockquote]:!text-xs [&_h1]:!text-lg [&_h2]:!text-base [&_h3]:!text-sm [&_ol]:!text-xs [&_p.is-empty::before]:text-light-900 [&_p.is-empty::before]:dark:text-dark-800 [&_p]:!text-sm [&_p]:text-light-950 [&_p]:dark:text-dark-950 [&_ul]:!text-xs"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -32,7 +32,7 @@ export function LabelForm({
|
||||
refetch: () => void;
|
||||
isEdit?: boolean;
|
||||
}) {
|
||||
const { closeModal, entityId, openModal } = useModal();
|
||||
const { closeModal, entityId, openModal, setModalState } = useModal();
|
||||
|
||||
const label = api.label.byPublicId.useQuery(
|
||||
{
|
||||
@@ -57,12 +57,13 @@ export function LabelForm({
|
||||
const isCreateAnotherEnabled = watch("isCreateAnotherEnabled");
|
||||
|
||||
const createLabel = api.label.create.useMutation({
|
||||
onSuccess: () => {
|
||||
onSuccess: (newLabel) => {
|
||||
const currentColourIndex = colours.findIndex(
|
||||
(c) => c.code === watch("colour").code,
|
||||
);
|
||||
try {
|
||||
refetch();
|
||||
setModalState("NEW_LABEL_CREATED", newLabel.publicId);
|
||||
if (!isCreateAnotherEnabled) {
|
||||
closeModal();
|
||||
} else {
|
||||
@@ -220,6 +221,7 @@ export function LabelForm({
|
||||
<div className="space-x-2">
|
||||
{isEdit && (
|
||||
<Button
|
||||
type="button"
|
||||
variant="secondary"
|
||||
onClick={() => openModal("DELETE_LABEL", entityId)}
|
||||
>
|
||||
|
||||
@@ -31,6 +31,7 @@ export function NewWorkspaceForm() {
|
||||
description: values.description,
|
||||
slug: values.slug,
|
||||
plan: values.plan,
|
||||
role: "admin",
|
||||
});
|
||||
closeModal();
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ import settingsIconLight from "~/assets/settings-light.json";
|
||||
import ReactiveButton from "~/components/ReactiveButton";
|
||||
import UserMenu from "~/components/UserMenu";
|
||||
import WorkspaceMenu from "~/components/WorkspaceMenu";
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
interface SideNavigationProps {
|
||||
user: UserType;
|
||||
@@ -59,9 +59,9 @@ export default function SideNavigation({
|
||||
|
||||
const { pathname } = router;
|
||||
|
||||
const { activeTheme } = useTheme();
|
||||
const { theme, resolvedTheme } = useTheme();
|
||||
|
||||
const isDarkMode = activeTheme === "dark";
|
||||
const isDarkMode = resolvedTheme === "dark";
|
||||
|
||||
const navigation = [
|
||||
{
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
import { CgDarkMode } from "react-icons/cg";
|
||||
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
|
||||
const ThemeToggle = () => {
|
||||
const { themePreference, switchTheme } = useTheme();
|
||||
const { theme, setTheme } = useTheme();
|
||||
|
||||
const toggleTheme = () => {
|
||||
switchTheme(themePreference === "light" ? "dark" : "light");
|
||||
setTheme(theme === "light" ? "dark" : "light");
|
||||
};
|
||||
|
||||
return (
|
||||
<button
|
||||
onClick={toggleTheme}
|
||||
className="rounded p-1.5 transition-all hover:bg-light-200 dark:hover:bg-dark-100"
|
||||
aria-label={`Switch to ${themePreference === "light" ? "dark" : "light"} theme`}
|
||||
aria-label={`Switch to ${theme === "light" ? "dark" : "light"} theme`}
|
||||
>
|
||||
<CgDarkMode
|
||||
className={`h-4 w-4 text-light-900 transition-transform duration-200 dark:text-dark-900 ${
|
||||
themePreference === "dark" ? "rotate-180" : "rotate-0"
|
||||
theme === "dark" ? "rotate-180" : "rotate-0"
|
||||
}`}
|
||||
/>
|
||||
</button>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { authClient } from "@kan/auth/client";
|
||||
|
||||
import { useIsMobile } from "~/hooks/useMediaQuery";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
import { getAvatarUrl } from "~/utils/helpers";
|
||||
|
||||
interface UserMenuProps {
|
||||
@@ -29,7 +29,7 @@ export default function UserMenu({
|
||||
onCloseSideNav,
|
||||
}: UserMenuProps) {
|
||||
const router = useRouter();
|
||||
const { themePreference, switchTheme } = useTheme();
|
||||
const { theme, setTheme } = useTheme();
|
||||
const { openModal } = useModal();
|
||||
const isMobile = useIsMobile();
|
||||
|
||||
@@ -127,12 +127,12 @@ export default function UserMenu({
|
||||
</div>
|
||||
<Menu.Item>
|
||||
<button
|
||||
onClick={() => switchTheme("system")}
|
||||
onClick={() => setTheme("system")}
|
||||
className="flex w-full items-center rounded-[5px] px-3 py-2 text-left text-xs hover:bg-light-200 dark:hover:bg-dark-400"
|
||||
>
|
||||
<span
|
||||
className={twMerge(
|
||||
themePreference === "system" ? "visible" : "invisible",
|
||||
theme === "system" ? "visible" : "invisible",
|
||||
"mr-4 h-[6px] w-[6px] rounded-full bg-light-900 dark:bg-dark-900",
|
||||
)}
|
||||
/>
|
||||
@@ -141,12 +141,12 @@ export default function UserMenu({
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<button
|
||||
onClick={() => switchTheme("dark")}
|
||||
onClick={() => setTheme("dark")}
|
||||
className="flex w-full items-center rounded-[5px] px-3 py-2 text-left text-xs hover:bg-light-200 dark:hover:bg-dark-400"
|
||||
>
|
||||
<span
|
||||
className={twMerge(
|
||||
themePreference === "dark" ? "visible" : "invisible",
|
||||
theme === "dark" ? "visible" : "invisible",
|
||||
"mr-4 h-[6px] w-[6px] rounded-full bg-light-900 dark:bg-dark-900",
|
||||
)}
|
||||
/>
|
||||
@@ -155,12 +155,12 @@ export default function UserMenu({
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
<button
|
||||
onClick={() => switchTheme("light")}
|
||||
onClick={() => setTheme("light")}
|
||||
className="flex w-full items-center rounded-[5px] px-3 py-2 text-left text-xs hover:bg-light-200 dark:hover:bg-dark-400"
|
||||
>
|
||||
<span
|
||||
className={twMerge(
|
||||
themePreference === "light" ? "visible" : "invisible",
|
||||
theme === "light" ? "visible" : "invisible",
|
||||
"mr-4 h-[6px] w-[6px] rounded-full bg-light-900 dark:bg-dark-900",
|
||||
)}
|
||||
/>
|
||||
|
||||
@@ -24,7 +24,7 @@ export const env = createEnv({
|
||||
s.split(",").every((l) => z.string().url().safeParse(l).success),
|
||||
)
|
||||
.optional(),
|
||||
POSTGRES_URL: z.string().url(),
|
||||
POSTGRES_URL: z.string().url().optional().or(z.literal("")),
|
||||
TRELLO_APP_API_KEY: z.string().optional(),
|
||||
TRELLO_APP_SECRET: z.string().optional(),
|
||||
STRIPE_SECRET_KEY: z.string().optional(),
|
||||
@@ -51,6 +51,10 @@ export const env = createEnv({
|
||||
VK_CLIENT_SECRET: z.string().optional(),
|
||||
LINKEDIN_CLIENT_ID: z.string().optional(),
|
||||
LINKEDIN_CLIENT_SECRET: z.string().optional(),
|
||||
// Generic OIDC Provider
|
||||
OIDC_CLIENT_ID: z.string().optional(),
|
||||
OIDC_CLIENT_SECRET: z.string().optional(),
|
||||
OIDC_DISCOVERY_URL: z.string().optional(),
|
||||
REDDIT_CLIENT_ID: z.string().optional(),
|
||||
REDDIT_CLIENT_SECRET: z.string().optional(),
|
||||
ROBLOX_CLIENT_ID: z.string().optional(),
|
||||
@@ -101,6 +105,13 @@ export const env = createEnv({
|
||||
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
|
||||
)
|
||||
.optional(),
|
||||
NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY: z
|
||||
.string()
|
||||
.transform((s) => (s === "" ? undefined : s))
|
||||
.refine(
|
||||
(s) => !s || s.toLowerCase() === "true" || s.toLowerCase() === "false",
|
||||
)
|
||||
.optional(),
|
||||
},
|
||||
/**
|
||||
* Destructure all variables from `process.env` to make sure they aren't tree-shaken away.
|
||||
@@ -119,6 +130,8 @@ export const env = createEnv({
|
||||
NEXT_PUBLIC_DISABLE_SIGN_UP: process.env.NEXT_PUBLIC_DISABLE_SIGN_UP,
|
||||
NEXT_PUBLIC_USE_STANDALONE_OUTPUT:
|
||||
process.env.NEXT_PUBLIC_USE_STANDALONE_OUTPUT,
|
||||
NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY:
|
||||
process.env.NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY,
|
||||
},
|
||||
skipValidation:
|
||||
!!process.env.CI || process.env.npm_lifecycle_event === "lint",
|
||||
|
||||
@@ -23,12 +23,12 @@ msgstr ", oder besuche unsere"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} Labels"
|
||||
|
||||
@@ -48,8 +48,8 @@ msgstr "Eine leistungsstarke, flexible Kanban-App, die dir hilft, Arbeit zu orga
|
||||
msgid "Account deleted"
|
||||
msgstr "Konto gelöscht"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Aktivität"
|
||||
|
||||
@@ -66,9 +66,21 @@ msgstr "Karte hinzufügen"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Kommentar hinzufügen..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Element hinzufügen..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Checkliste hinzufügen"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Beschreibung hinzufügen... (tippe '/' um Befehle zu öffnen oder '@' um jemanden zu erwähnen)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Details hinzufügen..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -80,17 +92,36 @@ msgstr "Label hinzufügen"
|
||||
msgid "Add member"
|
||||
msgstr "Mitglied hinzufügen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "hat eine Checkliste hinzugefügt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "hat ein Checklistenelement hinzugefügt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "hat ein Label zur Karte hinzugefügt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "hat ein Mitglied zur Karte hinzugefügt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "hat Label <0>{label}</0> hinzugefügt"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "hat Checkliste <0>{0}</0> hinzugefügt"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "hat Checklistenelement <0>{0}</0> hinzugefügt"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "hat Label <0>{0}</0> hinzugefügt"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -108,11 +139,15 @@ msgstr "Alle Systeme funktionieren"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "Du hast bereits ein Konto? <0><1>Anmelden</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "Beim Trennen deines Trello-Kontos ist ein Fehler aufgetreten."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "Ein unerwarteter Fehler ist aufgetreten. Bitte versuchen Sie es später erneut."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "API-Schlüssel"
|
||||
|
||||
@@ -141,11 +176,15 @@ msgstr "Bist du sicher, dass du den Workspace {0} löschen möchtest?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "Bist du sicher, dass du diese Karte löschen möchtest?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "Sind Sie sicher, dass Sie diese Checkliste löschen möchten?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "Bist du sicher, dass du diesen Kommentar löschen möchtest?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "Sind Sie sicher, dass Sie dieses Label löschen möchten?"
|
||||
|
||||
@@ -153,9 +192,10 @@ msgstr "Sind Sie sicher, dass Sie dieses Label löschen möchten?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "Bist du sicher, dass du dein Konto löschen möchtest?"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "hat <0>{memberName}</0> der Karte zugewiesen"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "hat <0>{0}</0> der Karte zugewiesen"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -169,12 +209,12 @@ msgstr "Backlog"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Einfaches Kanban"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Abrechnung"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Abrechnungsportal"
|
||||
|
||||
@@ -182,7 +222,7 @@ msgstr "Abrechnungsportal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blogbeitrag"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Board"
|
||||
|
||||
@@ -195,7 +235,7 @@ msgid "Board name is required"
|
||||
msgstr "Boardname ist erforderlich"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Board nicht gefunden"
|
||||
|
||||
@@ -248,23 +288,32 @@ msgstr "Fehlerbericht"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Abbrechen"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Karte nicht gefunden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Kartentitel"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Passwort ändern"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Ändere die Sprache der App."
|
||||
|
||||
@@ -273,6 +322,10 @@ msgstr "Ändere die Sprache der App."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Überprüfe deinen Posteingang"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Checklistenname"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Filter löschen"
|
||||
@@ -310,11 +363,24 @@ msgstr "Abgeschlossen"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Vollständige Kontrolle und Eigentum:"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "hat ein Checklistenelement abgeschlossen"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "hat Checklistenelement <0>{0}</0> abgeschlossen"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "URL-Änderung bestätigen"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Bestätigen Sie Ihr neues Passwort"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Trello verbinden"
|
||||
@@ -323,7 +389,7 @@ msgstr "Trello verbinden"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Verbinde deine Lieblingstools, um deinen Arbeitsablauf zu optimieren."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Verbinde dein Trello-Konto, um Boards zu importieren."
|
||||
|
||||
@@ -353,8 +419,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Kontrolliere, wer deine Boards ansehen und bearbeiten kann."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Weitere erstellen"
|
||||
|
||||
@@ -362,11 +428,15 @@ msgstr "Weitere erstellen"
|
||||
msgid "Create board"
|
||||
msgstr "Board erstellen"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Karte erstellen"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Checkliste erstellen"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Label erstellen"
|
||||
|
||||
@@ -383,11 +453,11 @@ msgid "Create new key"
|
||||
msgstr "Neuen Schlüssel erstellen"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Neues Label erstellen"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Neue Liste erstellen"
|
||||
|
||||
@@ -396,7 +466,7 @@ msgstr "Neue Liste erstellen"
|
||||
msgid "Create workspace"
|
||||
msgstr "Arbeitsbereich erstellen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "hat die Karte erstellt"
|
||||
|
||||
@@ -404,6 +474,10 @@ msgstr "hat die Karte erstellt"
|
||||
msgid "Critical"
|
||||
msgstr "Kritisch"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "Aktuelles Passwort ist erforderlich"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Benutzerdefinierte Domain"
|
||||
@@ -421,14 +495,15 @@ msgid "Dark"
|
||||
msgstr "Dunkel"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Löschen"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Konto löschen"
|
||||
@@ -437,7 +512,7 @@ msgstr "Konto löschen"
|
||||
msgid "Delete board"
|
||||
msgstr "Board löschen"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Karte löschen"
|
||||
|
||||
@@ -449,17 +524,35 @@ msgstr "Kommentar löschen"
|
||||
msgid "Delete list"
|
||||
msgstr "Liste löschen"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Workspace löschen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "hat eine Checkliste gelöscht"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "hat ein Checklistenelement gelöscht"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "hat Checkliste <0>{0}</0> gelöscht"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "hat Checklistenelement <0>{0}</0> gelöscht"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Design"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Trello trennen"
|
||||
|
||||
@@ -467,7 +560,7 @@ msgstr "Trello trennen"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Diskutiere und arbeite gemeinsam an Karten."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Anzeigename"
|
||||
|
||||
@@ -521,7 +614,7 @@ msgstr "Board-URL bearbeiten"
|
||||
msgid "Edit comment"
|
||||
msgstr "Kommentar bearbeiten"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Label bearbeiten"
|
||||
|
||||
@@ -545,6 +638,14 @@ msgstr "E-Mail"
|
||||
msgid "Enhancement"
|
||||
msgstr "Verbesserung"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Geben Sie Ihr aktuelles Passwort ein"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Geben Sie Ihr aktuelles Passwort ein und wählen Sie ein neues sicheres Passwort."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Gib deine E-Mail-Adresse ein"
|
||||
@@ -553,15 +654,23 @@ msgstr "Gib deine E-Mail-Adresse ein"
|
||||
msgid "Enter your name"
|
||||
msgstr "Gib deinen Namen ein"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Geben Sie Ihr neues Passwort ein"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Gib dein Passwort ein"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Fehler beim Ändern des Passworts"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Fehler beim Löschen des Kontos"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Fehler beim Löschen des Labels"
|
||||
|
||||
@@ -569,7 +678,7 @@ msgstr "Fehler beim Löschen des Labels"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Fehler beim Löschen des Arbeitsbereichs"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Fehler beim Trennen von Trello"
|
||||
|
||||
@@ -692,7 +801,7 @@ msgstr "Loslegen"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Beginne, indem du ein neues Board erstellst"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Beginne mit dem Erstellen einer neuen Liste"
|
||||
|
||||
@@ -849,8 +958,8 @@ msgstr "Kanban neu gedacht"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Beachten Sie, dass diese Aktion nicht rückgängig gemacht werden kann."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
@@ -859,7 +968,7 @@ msgstr "Labels"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Labels & Filter"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Sprache"
|
||||
|
||||
@@ -883,7 +992,7 @@ msgstr "Hell"
|
||||
msgid "Link copied"
|
||||
msgstr "Link kopiert"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "Liste"
|
||||
|
||||
@@ -911,13 +1020,22 @@ msgstr "Niedrige Priorität"
|
||||
msgid "magic link"
|
||||
msgstr "Magic Link"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "hat ein Checklistenelement als unvollständig markiert"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "hat Checklistenelement <0>{0}</0> als unvollständig markiert"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Mittlere Priorität"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -932,16 +1050,18 @@ msgstr "Mitglieder | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Monatlich"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "hat die Karte von <0>{fromList}</0> nach <1>{toList}</1> verschoben"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "hat die Karte von <0>{0}</0> nach <1>{1}</1> verschoben"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "hat die Karte in eine andere Liste verschoben"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -957,23 +1077,35 @@ msgstr "Neu"
|
||||
msgid "New board"
|
||||
msgstr "Neues Board"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "Neue Karte"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "Neue Checkliste"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "Neuer Import"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "Neues Label"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "Neue Liste"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "Neues Passwort ist erforderlich"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "Neues Passwort muss sich vom aktuellen Passwort unterscheiden"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "Neues Ticket"
|
||||
@@ -1002,7 +1134,7 @@ msgstr "Keine Boards gefunden"
|
||||
msgid "No credit card required"
|
||||
msgstr "Keine Kreditkarte erforderlich"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "Keine Listen"
|
||||
|
||||
@@ -1014,11 +1146,11 @@ msgstr "Angebot"
|
||||
msgid "Onboarding"
|
||||
msgstr "Einarbeitung"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Sobald Sie Ihr Konto löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Sobald Sie Ihren Arbeitsbereich löschen, gibt es kein Zurück mehr. Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
|
||||
@@ -1038,6 +1170,18 @@ msgstr "Besitze deine Daten"
|
||||
msgid "Part-time"
|
||||
msgstr "Teilzeit"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Passwort geändert"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "Passwort muss mindestens 8 Zeichen lang sein"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passwörter stimmen nicht überein"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Zahlungshäufigkeit"
|
||||
@@ -1059,6 +1203,10 @@ msgstr "Persönliches Projekt"
|
||||
msgid "Planning"
|
||||
msgstr "Planung"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Bitte bestätigen Sie Ihr neues Passwort"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Bitte gib eine gültige E-Mail-Adresse ein"
|
||||
@@ -1085,24 +1233,30 @@ msgstr "Bitte wähle eine Datei zum Hochladen aus."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Bitte versuche es später noch einmal oder kontaktiere den Kundensupport."
|
||||
|
||||
@@ -1128,7 +1282,7 @@ msgstr "Privat"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Profilbild aktualisiert"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Profilbild"
|
||||
|
||||
@@ -1168,17 +1322,32 @@ msgstr "Entfernen"
|
||||
msgid "Remove member"
|
||||
msgstr "Mitglied entfernen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "hat ein Label von der Karte entfernt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "hat ein Mitglied von der Karte entfernt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "hat Label <0>{label}</0> entfernt"
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "hat Label <0>{0}</0> entfernt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "hat eine Checkliste umbenannt"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "hat Checkliste <0>{0}</0> umbenannt"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "hat Checklistenelement in <0>{0}</0> umbenannt"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1241,7 +1410,7 @@ msgstr "Selbst hosten"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Selbst hosten mit Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "hat sich selbst die Karte zugewiesen"
|
||||
|
||||
@@ -1253,13 +1422,13 @@ msgstr "Feedback senden"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Einstellungen"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Einstellungen | {0}"
|
||||
|
||||
@@ -1338,6 +1507,10 @@ msgstr "Nutzungsbedingungen"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "Vielen Dank für dein Feedback!"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "Das eingegebene aktuelle Passwort ist falsch."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "Der hauptunterschied zwischen Kan und Trello ist, dass Kan open source ist und jedem ermöglicht, unseren code einzusehen, zu ändern und dazu beizutragen. Unser cloud-angebot bietet außerdem keine einschränkungen bei funktionen für die individuelle nutzung, während Trello grundlegende funktionen wie die anzahl der boards, die du erstellen kannst, hinter einer paywall versteckt."
|
||||
@@ -1360,8 +1533,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "Sie werden keinen Zugriff mehr auf diesen Workspace haben."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "Diese Aktion kann nicht rückgängig gemacht werden."
|
||||
|
||||
@@ -1398,7 +1572,7 @@ msgstr "Menü umschalten"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Verfolge alle kartenänderungen mit detaillierter aktivitätshistorie."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello getrennt"
|
||||
|
||||
@@ -1410,14 +1584,22 @@ msgstr "Trello-importe"
|
||||
msgid "Triaging"
|
||||
msgstr "Priorisierung"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "Checklistenelement kann nicht hinzugefügt werden"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Kommentar konnte nicht hinzugefügt werden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "Karte konnte nicht erstellt werden"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Checkliste kann nicht erstellt werden"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "Liste konnte nicht erstellt werden"
|
||||
@@ -1430,6 +1612,14 @@ msgstr "Workspace konnte nicht erstellt werden"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Karte konnte nicht gelöscht werden"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "Checkliste kann nicht gelöscht werden"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "Checklistenelement kann nicht gelöscht werden"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "Kommentar konnte nicht gelöscht werden"
|
||||
@@ -1450,11 +1640,19 @@ msgstr "Board-URL kann nicht aktualisiert werden"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Board-Sichtbarkeit konnte nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "Karte konnte nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "Checkliste kann nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "Checklistenelement kann nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "Kommentar konnte nicht aktualisiert werden"
|
||||
@@ -1464,7 +1662,7 @@ msgid "Unable to update labels"
|
||||
msgstr "Labels konnten nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "Liste konnte nicht aktualisiert werden"
|
||||
|
||||
@@ -1472,11 +1670,12 @@ msgstr "Liste konnte nicht aktualisiert werden"
|
||||
msgid "Unable to update members"
|
||||
msgstr "Mitglieder konnten nicht aktualisiert werden"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "<0>{memberName}</0> von der Karte entfernt"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "hat <0>{0}</0> von der Karte entfernt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "hat sich selbst von der Karte entfernt"
|
||||
|
||||
@@ -1512,21 +1711,26 @@ msgstr "Unbegrenzte listen"
|
||||
msgid "Update"
|
||||
msgstr "Aktualisieren"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Label aktualisieren"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "hat ein Checklistenelement aktualisiert"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "hat die Beschreibung aktualisiert"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "hat den Titel aktualisiert"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "hat den Titel zu <0>{toTitle}</0> aktualisiert"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "hat den Titel in <0>{0}</0> geändert"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1565,11 +1769,11 @@ msgstr "Benutzer ist bereits Mitglied dieses Arbeitsbereichs"
|
||||
msgid "Video"
|
||||
msgstr "Video"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "API-Schlüssel anzeigen und verwalten."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "Verwalte deine Abrechnung und dein Abonnement."
|
||||
|
||||
@@ -1621,7 +1825,7 @@ msgstr "Als Trello 2011 auf den markt kam, beeindruckte es alle mit seiner sorgf
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "Warum ein open source Trello entwickeln?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Arbeitsbereich"
|
||||
|
||||
@@ -1629,7 +1833,7 @@ msgstr "Arbeitsbereich"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Workspace gelöscht"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Workspace-Beschreibung"
|
||||
|
||||
@@ -1650,7 +1854,7 @@ msgstr "Workspace-Beschreibung aktualisiert"
|
||||
msgid "Workspace members"
|
||||
msgstr "Workspace-mitglieder"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Name des Workspaces"
|
||||
@@ -1671,7 +1875,7 @@ msgstr "Workspace-Name aktualisiert"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Workspace-Slug aktualisiert"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "Workspace-URL"
|
||||
|
||||
@@ -1687,6 +1891,10 @@ msgstr "Jährlich"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Ja, wir bieten einen dauerhaft kostenlosen plan für die individuelle nutzung an. Keine einschränkungen, keine paywalls, keine limits."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "Sie sind dabei, Ihr Passwort zu ändern."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "Du kannst eine benutzerdefinierte workspace-URL, wie <0>kan.bn/kan</0>, erhalten, indem du in deine <1>workspace-einstellungen</1> gehst und ein pro-workspace-abonnement kaufst. Alle abonnements helfen, die entwicklung des projekts zu finanzieren!"
|
||||
@@ -1719,15 +1927,19 @@ msgstr "Deine Boards wurden importiert."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Dein Anzeigename wurde aktualisiert."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Ihr Passwort wurde geändert."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "Dein Profilbild wurde aktualisiert."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Dein Trello-Konto wurde getrennt."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Dein Trello-Konto ist verbunden."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,12 +23,12 @@ msgstr ", or see our"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} labels"
|
||||
|
||||
@@ -60,8 +60,8 @@ msgstr "A powerful, flexible kanban app that helps you organise work, track prog
|
||||
msgid "Account deleted"
|
||||
msgstr "Account deleted"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Activity"
|
||||
|
||||
@@ -78,9 +78,25 @@ msgstr "Add a card"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Add a comment..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Add description... (type '/' to open commands)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Add an item..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Add checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Add description... (type '/' to open commands or '@' to mention)"
|
||||
|
||||
#: src/components/Editor.tsx:308
|
||||
#~ msgid "Add description... (type '/' to open commands)"
|
||||
#~ msgstr "Add description... (type '/' to open commands)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Add details..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -92,17 +108,40 @@ msgstr "Add label"
|
||||
msgid "Add member"
|
||||
msgstr "Add member"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "added a checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "added a checklist item"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "added a label to the card"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "added a member to the card"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "added checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "added checklist item <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "added label <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "added label <0>{label}</0>"
|
||||
#~ msgid "added label <0>{label}</0>"
|
||||
#~ msgstr "added label <0>{label}</0>"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -120,11 +159,15 @@ msgstr "All systems operational"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "Already have an account? <0><1>Sign in</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "An error occurred while disconnecting your Trello account."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "An unexpected error occurred. Please try again later."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "API keys"
|
||||
|
||||
@@ -157,11 +200,15 @@ msgstr "Are you sure you want to delete the workspace {0}?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "Are you sure you want to delete this card?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "Are you sure you want to delete this checklist?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "Are you sure you want to delete this comment?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "Are you sure you want to delete this label?"
|
||||
|
||||
@@ -169,9 +216,14 @@ msgstr "Are you sure you want to delete this label?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "Are you sure you want to delete your account?"
|
||||
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "assigned <0>{0}</0> to the card"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "assigned <0>{memberName}</0> to the card"
|
||||
#~ msgid "assigned <0>{memberName}</0> to the card"
|
||||
#~ msgstr "assigned <0>{memberName}</0> to the card"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -189,12 +241,12 @@ msgstr "Backlog"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Basic Kanban"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Billing"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Billing portal"
|
||||
|
||||
@@ -202,7 +254,7 @@ msgstr "Billing portal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blog Post"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Board"
|
||||
|
||||
@@ -219,7 +271,7 @@ msgid "Board name is required"
|
||||
msgstr "Board name is required"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Board not found"
|
||||
|
||||
@@ -276,23 +328,32 @@ msgstr "Bug Report"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Cancel"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Card not found"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Card title"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Change Password"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Change the language of the app."
|
||||
|
||||
@@ -301,6 +362,10 @@ msgstr "Change the language of the app."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Check your inbox"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Checklist name"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Clear filters"
|
||||
@@ -338,11 +403,24 @@ msgstr "Complete"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Complete control and ownership:"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "completed a checklist item"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "completed checklist item <0>{0}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "Confirm URL change"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirm your new password"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Connect Trello"
|
||||
@@ -351,7 +429,7 @@ msgstr "Connect Trello"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Connect your favorite tools to streamline your workflow."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Connect your Trello account to import boards."
|
||||
|
||||
@@ -381,8 +459,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Control who can view and edit your boards."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Create another"
|
||||
|
||||
@@ -398,11 +476,15 @@ msgstr "Create another"
|
||||
msgid "Create board"
|
||||
msgstr "Create board"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Create card"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Create checklist"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Create label"
|
||||
|
||||
@@ -419,11 +501,11 @@ msgid "Create new key"
|
||||
msgstr "Create new key"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Create new label"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Create new list"
|
||||
|
||||
@@ -432,7 +514,7 @@ msgstr "Create new list"
|
||||
msgid "Create workspace"
|
||||
msgstr "Create workspace"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "created the card"
|
||||
|
||||
@@ -440,6 +522,10 @@ msgstr "created the card"
|
||||
msgid "Critical"
|
||||
msgstr "Critical"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "Current password is required"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Custom domain"
|
||||
@@ -457,14 +543,15 @@ msgid "Dark"
|
||||
msgstr "Dark"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Delete"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Delete account"
|
||||
@@ -473,7 +560,7 @@ msgstr "Delete account"
|
||||
msgid "Delete board"
|
||||
msgstr "Delete board"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Delete card"
|
||||
|
||||
@@ -485,17 +572,35 @@ msgstr "Delete comment"
|
||||
msgid "Delete list"
|
||||
msgstr "Delete list"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Delete workspace"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "deleted a checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "deleted a checklist item"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "deleted checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "deleted checklist item <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Design"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Disconnect Trello"
|
||||
|
||||
@@ -503,7 +608,7 @@ msgstr "Disconnect Trello"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Discuss and collaborate on cards."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Display name"
|
||||
|
||||
@@ -557,7 +662,7 @@ msgstr "Edit board URL"
|
||||
msgid "Edit comment"
|
||||
msgstr "Edit comment"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Edit label"
|
||||
|
||||
@@ -581,6 +686,14 @@ msgstr "Email"
|
||||
msgid "Enhancement"
|
||||
msgstr "Enhancement"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Enter your current password"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Enter your current password and choose a new secure password."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Enter your email address"
|
||||
@@ -589,15 +702,23 @@ msgstr "Enter your email address"
|
||||
msgid "Enter your name"
|
||||
msgstr "Enter your name"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Enter your new password"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Enter your password"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Error Changing Password"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Error deleting account"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Error deleting label"
|
||||
|
||||
@@ -605,7 +726,7 @@ msgstr "Error deleting label"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Error deleting workspace"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Error disconnecting Trello"
|
||||
|
||||
@@ -729,7 +850,7 @@ msgstr "Get Started"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Get started by creating a new board"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Get started by creating a new list"
|
||||
|
||||
@@ -890,8 +1011,8 @@ msgstr "Kanban reimagined"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Keep in mind that this action is irreversible."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
@@ -900,7 +1021,7 @@ msgstr "Labels"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Labels & Filters"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Language"
|
||||
|
||||
@@ -924,7 +1045,7 @@ msgstr "Light"
|
||||
msgid "Link copied"
|
||||
msgstr "Link copied"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "List"
|
||||
|
||||
@@ -952,13 +1073,22 @@ msgstr "Low Priority"
|
||||
msgid "magic link"
|
||||
msgstr "magic link"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "marked a checklist item as incomplete"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "marked checklist item <0>{0}</0> as incomplete"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Medium Priority"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -973,16 +1103,22 @@ msgstr "Members | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Monthly"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
#~ msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
#~ msgstr "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "moved the card to another list"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -998,23 +1134,35 @@ msgstr "New"
|
||||
msgid "New board"
|
||||
msgstr "New board"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "New card"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "New checklist"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "New import"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "New label"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "New list"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "New password is required"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "New password must be different from current password"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "New Ticket"
|
||||
@@ -1047,7 +1195,7 @@ msgstr "No boards found"
|
||||
msgid "No credit card required"
|
||||
msgstr "No credit card required"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "No lists"
|
||||
|
||||
@@ -1059,11 +1207,11 @@ msgstr "Offer"
|
||||
msgid "Onboarding"
|
||||
msgstr "Onboarding"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
|
||||
@@ -1083,6 +1231,18 @@ msgstr "Own your data"
|
||||
msgid "Part-time"
|
||||
msgstr "Part-time"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Password Changed"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "Password must be at least 8 characters"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Passwords do not match"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Payment frequency"
|
||||
@@ -1104,6 +1264,10 @@ msgstr "Personal Project"
|
||||
msgid "Planning"
|
||||
msgstr "Planning"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Please confirm your new password"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Please enter a valid email address"
|
||||
@@ -1130,24 +1294,30 @@ msgstr "Please select a file to upload."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Please try again later, or contact customer support."
|
||||
|
||||
@@ -1173,7 +1343,7 @@ msgstr "Private"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Profile image updated"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Profile picture"
|
||||
|
||||
@@ -1213,17 +1383,36 @@ msgstr "Remove"
|
||||
msgid "Remove member"
|
||||
msgstr "Remove member"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "removed a label from the card"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "removed a member from the card"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "removed label <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "removed label <0>{label}</0>"
|
||||
#~ msgid "removed label <0>{label}</0>"
|
||||
#~ msgstr "removed label <0>{label}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "renamed a checklist"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "renamed checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "renamed checklist item to <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1286,7 +1475,7 @@ msgstr "Self Host"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Self host with Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "self-assigned the card"
|
||||
|
||||
@@ -1302,13 +1491,13 @@ msgstr "Send feedback"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Settings | {0}"
|
||||
|
||||
@@ -1387,6 +1576,10 @@ msgstr "Terms of service"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "Thank you for your feedback!"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "The current password you entered is incorrect."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
@@ -1409,8 +1602,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "They won't be able to access this workspace."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "This action can't be undone."
|
||||
|
||||
@@ -1451,7 +1645,7 @@ msgstr "Toggle menu"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Track all card changes with detailed activity history."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello disconnected"
|
||||
|
||||
@@ -1463,14 +1657,22 @@ msgstr "Trello imports"
|
||||
msgid "Triaging"
|
||||
msgstr "Triaging"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "Unable to add checklist item"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Unable to add comment"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "Unable to create card"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Unable to create checklist"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "Unable to create list"
|
||||
@@ -1483,6 +1685,14 @@ msgstr "Unable to create workspace"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Unable to delete card"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "Unable to delete checklist"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "Unable to delete checklist item"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "Unable to delete comment"
|
||||
@@ -1503,11 +1713,19 @@ msgstr "Unable to update board URL"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Unable to update board visibility"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "Unable to update card"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "Unable to update checklist"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "Unable to update checklist item"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "Unable to update comment"
|
||||
@@ -1517,7 +1735,7 @@ msgid "Unable to update labels"
|
||||
msgstr "Unable to update labels"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "Unable to update list"
|
||||
|
||||
@@ -1525,11 +1743,16 @@ msgstr "Unable to update list"
|
||||
msgid "Unable to update members"
|
||||
msgstr "Unable to update members"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "unassigned <0>{memberName}</0> from the card"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "unassigned <0>{0}</0> from the card"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
#~ msgid "unassigned <0>{memberName}</0> from the card"
|
||||
#~ msgstr "unassigned <0>{memberName}</0> from the card"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "unassigned themselves from the card"
|
||||
|
||||
@@ -1565,21 +1788,30 @@ msgstr "Unlimited lists"
|
||||
msgid "Update"
|
||||
msgstr "Update"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Update label"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "updated a checklist item"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "updated the description"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "updated the title"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "updated the title to <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "updated the title to <0>{toTitle}</0>"
|
||||
#~ msgid "updated the title to <0>{toTitle}</0>"
|
||||
#~ msgstr "updated the title to <0>{toTitle}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1618,11 +1850,11 @@ msgstr "User is already a member of this workspace"
|
||||
msgid "Video"
|
||||
msgstr "Video"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "View and manage your API keys."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "View and manage your billing and subscription."
|
||||
|
||||
@@ -1678,7 +1910,7 @@ msgstr "When Trello launched in 2011, it blew everyone away with its carefully d
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "Why make an open source Trello?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Workspace"
|
||||
|
||||
@@ -1686,7 +1918,7 @@ msgstr "Workspace"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Workspace deleted"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Workspace description"
|
||||
|
||||
@@ -1707,7 +1939,7 @@ msgstr "Workspace description updated"
|
||||
msgid "Workspace members"
|
||||
msgstr "Workspace members"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Workspace name"
|
||||
@@ -1728,7 +1960,7 @@ msgstr "Workspace name updated"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Workspace slug updated"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "Workspace URL"
|
||||
|
||||
@@ -1744,6 +1976,10 @@ msgstr "Yearly"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "You are about to change your password."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
@@ -1776,15 +2012,19 @@ msgstr "Your boards have been imported."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Your display name has been updated."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Your password has been changed."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "Your profile image has been updated."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Your Trello account has been disconnected."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Your Trello account is connected."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,12 +23,12 @@ msgstr ", o consulta nuestra"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} etiquetas"
|
||||
|
||||
@@ -48,8 +48,8 @@ msgstr "Una aplicación kanban potente y flexible que te ayuda a organizar el tr
|
||||
msgid "Account deleted"
|
||||
msgstr "Cuenta eliminada"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Actividad"
|
||||
|
||||
@@ -66,9 +66,21 @@ msgstr "Añadir una tarjeta"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Añadir un comentario..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Añadir descripción... (escribe '/' para abrir comandos)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Añadir un elemento..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Añadir lista de verificación"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Añadir descripción... (escribe '/' para abrir comandos o '@' para mencionar)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Añadir detalles..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -80,17 +92,36 @@ msgstr "Añadir etiqueta"
|
||||
msgid "Add member"
|
||||
msgstr "Añadir miembro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "añadió una lista de verificación"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "añadió un elemento a la lista de verificación"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "añadió una etiqueta a la tarjeta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "añadió un miembro a la tarjeta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "añadió la etiqueta <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "añadió la lista de verificación <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "añadió el elemento <0>{0}</0> a la lista de verificación"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "añadió la etiqueta <0>{0}</0>"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -108,11 +139,15 @@ msgstr "Todos los sistemas operativos"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "¿Ya tienes una cuenta? <0><1>Iniciar sesión</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "Ocurrió un error al desconectar tu cuenta de Trello."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "Ha ocurrido un error inesperado. Por favor, inténtalo de nuevo más tarde."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "Claves API"
|
||||
|
||||
@@ -141,11 +176,15 @@ msgstr "¿Estás seguro de que quieres eliminar el espacio de trabajo {0}?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "¿Estás seguro de que quieres eliminar esta tarjeta?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "¿Estás seguro de que quieres eliminar esta lista de verificación?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "¿Estás seguro de que quieres eliminar este comentario?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "¿Estás seguro de que quieres eliminar esta etiqueta?"
|
||||
|
||||
@@ -153,9 +192,10 @@ msgstr "¿Estás seguro de que quieres eliminar esta etiqueta?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "¿Estás seguro de que quieres eliminar tu cuenta?"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "asignó a <0>{memberName}</0> a la tarjeta"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "asignó <0>{0}</0> a la tarjeta"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -169,12 +209,12 @@ msgstr "Pendientes"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Kanban básico"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Facturación"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Portal de facturación"
|
||||
|
||||
@@ -182,7 +222,7 @@ msgstr "Portal de facturación"
|
||||
msgid "Blog Post"
|
||||
msgstr "Entrada de blog"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Tablero"
|
||||
|
||||
@@ -195,7 +235,7 @@ msgid "Board name is required"
|
||||
msgstr "El nombre del tablero es obligatorio"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Tablero no encontrado"
|
||||
|
||||
@@ -248,23 +288,32 @@ msgstr "Informe de error"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Cancelar"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Tarjeta no encontrada"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Título de la tarjeta"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Cambiar contraseña"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Cambiar el idioma de la aplicación."
|
||||
|
||||
@@ -273,6 +322,10 @@ msgstr "Cambiar el idioma de la aplicación."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Revisa tu bandeja de entrada"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Nombre de la lista de verificación"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Borrar filtros"
|
||||
@@ -310,11 +363,24 @@ msgstr "Completado"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Control y propiedad completos:"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "completó un elemento de la lista de verificación"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "completó el elemento <0>{0}</0> de la lista de verificación"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "Confirmar cambio de URL"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirma tu nueva contraseña"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Conectar Trello"
|
||||
@@ -323,7 +389,7 @@ msgstr "Conectar Trello"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Conecta tus herramientas favoritas para agilizar tu flujo de trabajo."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Conecta tu cuenta de Trello para importar tableros."
|
||||
|
||||
@@ -353,8 +419,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Controla quién puede ver y editar tus tableros."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Crear otro"
|
||||
|
||||
@@ -362,11 +428,15 @@ msgstr "Crear otro"
|
||||
msgid "Create board"
|
||||
msgstr "Crear tablero"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Crear tarjeta"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Crear lista de verificación"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Crear etiqueta"
|
||||
|
||||
@@ -383,11 +453,11 @@ msgid "Create new key"
|
||||
msgstr "Crear nueva clave"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Crear nueva etiqueta"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Crear nueva lista"
|
||||
|
||||
@@ -396,7 +466,7 @@ msgstr "Crear nueva lista"
|
||||
msgid "Create workspace"
|
||||
msgstr "Crear espacio de trabajo"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "creó la tarjeta"
|
||||
|
||||
@@ -404,6 +474,10 @@ msgstr "creó la tarjeta"
|
||||
msgid "Critical"
|
||||
msgstr "Crítico"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "Se requiere la contraseña actual"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Dominio personalizado"
|
||||
@@ -421,14 +495,15 @@ msgid "Dark"
|
||||
msgstr "Oscuro"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Eliminar"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Eliminar cuenta"
|
||||
@@ -437,7 +512,7 @@ msgstr "Eliminar cuenta"
|
||||
msgid "Delete board"
|
||||
msgstr "Eliminar tablero"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Eliminar tarjeta"
|
||||
|
||||
@@ -449,17 +524,35 @@ msgstr "Eliminar comentario"
|
||||
msgid "Delete list"
|
||||
msgstr "Eliminar lista"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Eliminar espacio de trabajo"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "eliminó una lista de verificación"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "eliminó un elemento de la lista de verificación"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "eliminó la lista de verificación <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "eliminó el elemento <0>{0}</0> de la lista de verificación"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Diseño"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Desconectar Trello"
|
||||
|
||||
@@ -467,7 +560,7 @@ msgstr "Desconectar Trello"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Discute y colabora en las tarjetas."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Nombre visible"
|
||||
|
||||
@@ -521,7 +614,7 @@ msgstr "Editar URL del tablero"
|
||||
msgid "Edit comment"
|
||||
msgstr "Editar comentario"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Editar etiqueta"
|
||||
|
||||
@@ -545,6 +638,14 @@ msgstr "Correo electrónico"
|
||||
msgid "Enhancement"
|
||||
msgstr "Mejora"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Introduce tu contraseña actual"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Introduce tu contraseña actual y elige una nueva contraseña segura."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Introduce tu dirección de correo electrónico"
|
||||
@@ -553,15 +654,23 @@ msgstr "Introduce tu dirección de correo electrónico"
|
||||
msgid "Enter your name"
|
||||
msgstr "Introduce tu nombre"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Introduce tu nueva contraseña"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Introduce tu contraseña"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Error al cambiar la contraseña"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Error al eliminar la cuenta"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Error al eliminar la etiqueta"
|
||||
|
||||
@@ -569,7 +678,7 @@ msgstr "Error al eliminar la etiqueta"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Error al eliminar el espacio de trabajo"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Error al desconectar Trello"
|
||||
|
||||
@@ -692,7 +801,7 @@ msgstr "Comenzar"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Comienza creando un nuevo tablero"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Comienza creando una nueva lista"
|
||||
|
||||
@@ -849,8 +958,8 @@ msgstr "Kanban reinventado"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Ten en cuenta que esta acción es irreversible."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Etiquetas"
|
||||
@@ -859,7 +968,7 @@ msgstr "Etiquetas"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Etiquetas y filtros"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Idioma"
|
||||
|
||||
@@ -883,7 +992,7 @@ msgstr "Claro"
|
||||
msgid "Link copied"
|
||||
msgstr "Enlace copiado"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "Lista"
|
||||
|
||||
@@ -911,13 +1020,22 @@ msgstr "Prioridad baja"
|
||||
msgid "magic link"
|
||||
msgstr "enlace mágico"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "marcó un elemento de la lista de verificación como incompleto"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "marcó el elemento <0>{0}</0> de la lista de verificación como incompleto"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Prioridad media"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -932,16 +1050,18 @@ msgstr "Miembros | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Mensual"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "movió la tarjeta de <0>{fromList}</0> a<1>{toList}</1>"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "movió la tarjeta de <0>{0}</0> a<1>{1}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "movió la tarjeta a otra lista"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Nombre"
|
||||
|
||||
@@ -957,23 +1077,35 @@ msgstr "Nuevo"
|
||||
msgid "New board"
|
||||
msgstr "Nuevo tablero"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "Nueva tarjeta"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "Nueva lista de verificación"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "Nueva importación"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "Nueva etiqueta"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "Nueva lista"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "Se requiere una nueva contraseña"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "La nueva contraseña debe ser diferente de la contraseña actual"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "Nuevo ticket"
|
||||
@@ -1002,7 +1134,7 @@ msgstr "No se encontraron tableros"
|
||||
msgid "No credit card required"
|
||||
msgstr "No se requiere tarjeta de crédito"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "Sin listas"
|
||||
|
||||
@@ -1014,11 +1146,11 @@ msgstr "Oferta"
|
||||
msgid "Onboarding"
|
||||
msgstr "Incorporación"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Una vez que elimines tu cuenta, no hay vuelta atrás. Esta acción no se puede deshacer."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Una vez que elimines tu espacio de trabajo, no hay vuelta atrás. Esta acción no se puede deshacer."
|
||||
|
||||
@@ -1038,6 +1170,18 @@ msgstr "Sé dueño de tus datos"
|
||||
msgid "Part-time"
|
||||
msgstr "Tiempo parcial"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Contraseña cambiada"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "La contraseña debe tener al menos 8 caracteres"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Las contraseñas no coinciden"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Frecuencia de pago"
|
||||
@@ -1059,6 +1203,10 @@ msgstr "Proyecto personal"
|
||||
msgid "Planning"
|
||||
msgstr "Planificación"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Por favor, confirma tu nueva contraseña"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Por favor, introduce una dirección de correo electrónico válida"
|
||||
@@ -1085,24 +1233,30 @@ msgstr "Por favor selecciona un archivo para subir."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Por favor, inténtalo de nuevo más tarde o contacta con atención al cliente."
|
||||
|
||||
@@ -1128,7 +1282,7 @@ msgstr "Privado"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Imagen de perfil actualizada"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Foto de perfil"
|
||||
|
||||
@@ -1168,17 +1322,32 @@ msgstr "Eliminar"
|
||||
msgid "Remove member"
|
||||
msgstr "Eliminar miembro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "eliminó una etiqueta de la tarjeta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "eliminó un miembro de la tarjeta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "eliminó la etiqueta <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "eliminó la etiqueta <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "renombró una lista de verificación"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "renombró la lista de verificación <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "renombró el elemento de la lista de verificación a <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1241,7 +1410,7 @@ msgstr "Autoalojamiento"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Autoalojamiento con Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "se autoasignó la tarjeta"
|
||||
|
||||
@@ -1253,13 +1422,13 @@ msgstr "Enviar comentarios"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Configuración"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Configuración | {0}"
|
||||
|
||||
@@ -1338,6 +1507,10 @@ msgstr "Términos de servicio"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "¡Gracias por tus comentarios!"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "La contraseña actual que has introducido es incorrecta."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "La principal diferencia entre Kan y Trello es que Kan es de código abierto, permitiendo a cualquiera ver, modificar y contribuir a nuestro código. Nuestra oferta en la nube también ofrece funciones sin restricciones para uso individual, mientras que Trello bloquea características básicas como el número de tableros que puedes crear detrás de un muro de pago."
|
||||
@@ -1360,8 +1533,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "No podrán acceder a este espacio de trabajo."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "Esta acción no se puede deshacer."
|
||||
|
||||
@@ -1398,7 +1572,7 @@ msgstr "Alternar menú"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Rastrea todos los cambios en las tarjetas con un historial de actividad detallado."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello desconectado"
|
||||
|
||||
@@ -1410,14 +1584,22 @@ msgstr "Importaciones de Trello"
|
||||
msgid "Triaging"
|
||||
msgstr "Clasificación"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "No se puede añadir el elemento a la lista de verificación"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "No se puede añadir el comentario"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "No se puede crear la tarjeta"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "No se puede crear la lista de verificación"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "No se puede crear la lista"
|
||||
@@ -1430,6 +1612,14 @@ msgstr "No se puede crear el espacio de trabajo"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "No se puede eliminar la tarjeta"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "No se puede eliminar la lista de verificación"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "No se puede eliminar el elemento de la lista de verificación"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "No se puede eliminar el comentario"
|
||||
@@ -1450,11 +1640,19 @@ msgstr "No se puede actualizar la URL del tablero"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "No se puede actualizar la visibilidad del tablero"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "No se puede actualizar la tarjeta"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "No se puede actualizar la lista de verificación"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "No se puede actualizar el elemento de la lista de verificación"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "No se puede actualizar el comentario"
|
||||
@@ -1464,7 +1662,7 @@ msgid "Unable to update labels"
|
||||
msgstr "No se pueden actualizar las etiquetas"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "No se puede actualizar la lista"
|
||||
|
||||
@@ -1472,11 +1670,12 @@ msgstr "No se puede actualizar la lista"
|
||||
msgid "Unable to update members"
|
||||
msgstr "No se pueden actualizar los miembros"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "desasignó a <0>{memberName}</0> de la tarjeta"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "desasignó <0>{0}</0> de la tarjeta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "se desasignó de la tarjeta"
|
||||
|
||||
@@ -1512,21 +1711,26 @@ msgstr "Listas ilimitadas"
|
||||
msgid "Update"
|
||||
msgstr "Actualizar"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Actualizar etiqueta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "actualizó un elemento de la lista de verificación"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "actualizó la descripción"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "actualizó el título"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "actualizó el título a <0>{toTitle}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "actualizó el título a <0>{0}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1565,11 +1769,11 @@ msgstr "El usuario ya es miembro de este espacio de trabajo"
|
||||
msgid "Video"
|
||||
msgstr "Video"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "Ver y gestionar tus claves API."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "Ver y gestionar tu facturación y suscripción."
|
||||
|
||||
@@ -1621,7 +1825,7 @@ msgstr "Cuando Trello se lanzó en 2011, impresionó a todos con su simplicidad
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "¿Por qué crear un Trello de código abierto?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Espacio de trabajo"
|
||||
|
||||
@@ -1629,7 +1833,7 @@ msgstr "Espacio de trabajo"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Espacio de trabajo eliminado"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Descripción del espacio de trabajo"
|
||||
|
||||
@@ -1650,7 +1854,7 @@ msgstr "Descripción del espacio de trabajo actualizada"
|
||||
msgid "Workspace members"
|
||||
msgstr "Miembros del espacio de trabajo"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Nombre del espacio de trabajo"
|
||||
@@ -1671,7 +1875,7 @@ msgstr "Nombre del espacio de trabajo actualizado"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Slug del espacio de trabajo actualizado"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "URL del espacio de trabajo"
|
||||
|
||||
@@ -1687,6 +1891,10 @@ msgstr "Anual"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Sí, ofrecemos un plan gratuito para siempre para uso individual. Sin restricciones, sin muros de pago, sin límites."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "Estás a punto de cambiar tu contraseña."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "Puedes obtener una URL personalizada para tu espacio de trabajo, como <0>kan.bn/kan</0>, yendo a la <1>configuración de tu espacio de trabajo</1> y comprando una suscripción pro. ¡Todas las suscripciones ayudan a financiar el desarrollo del proyecto!"
|
||||
@@ -1719,15 +1927,19 @@ msgstr "Tus tableros han sido importados."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Tu nombre de visualización ha sido actualizado."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Tu contraseña ha sido cambiada."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "Tu imagen de perfil ha sido actualizada."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Tu cuenta de Trello ha sido desconectada."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Tu cuenta de Trello está conectada."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,12 +23,12 @@ msgstr ", ou consultez notre"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} étiquettes"
|
||||
|
||||
@@ -48,8 +48,8 @@ msgstr "Une application kanban puissante et flexible qui vous aide à organiser
|
||||
msgid "Account deleted"
|
||||
msgstr "Compte supprimé"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Activité"
|
||||
|
||||
@@ -66,9 +66,21 @@ msgstr "Ajouter une carte"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Ajouter un commentaire..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Ajouter un élément..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Ajouter une checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Ajouter une description... (tapez '/' pour ouvrir les commandes ou '@' pour mentionner)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Ajouter des détails..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -80,17 +92,36 @@ msgstr "Ajouter une étiquette"
|
||||
msgid "Add member"
|
||||
msgstr "Ajouter un membre"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "a ajouté une checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "a ajouté un élément à la checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "a ajouté une étiquette à la carte"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "a ajouté un membre à la carte"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "a ajouté l'étiquette <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "a ajouté la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "a ajouté l'élément <0>{0}</0> à la checklist"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "a ajouté l'étiquette <0>{0}</0>"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -108,11 +139,15 @@ msgstr "Tous les systèmes opérationnels"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "Vous avez déjà un compte ? <0><1>Connectez-vous</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "Une erreur s'est produite lors de la déconnexion de votre compte Trello."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "Une erreur inattendue s'est produite. Veuillez réessayer plus tard."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "Clés API"
|
||||
|
||||
@@ -141,11 +176,15 @@ msgstr "Êtes-vous sûr de vouloir supprimer l'espace de travail {0} ?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer cette carte ?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer cette checklist ?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer ce commentaire ?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer cette étiquette ?"
|
||||
|
||||
@@ -153,9 +192,10 @@ msgstr "Êtes-vous sûr de vouloir supprimer cette étiquette ?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "Êtes-vous sûr de vouloir supprimer votre compte ?"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "a assigné <0>{memberName}</0> à la carte"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "a assigné <0>{0}</0> à la carte"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -169,12 +209,12 @@ msgstr "Backlog"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Kanban basique"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Facturation"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Portail de facturation"
|
||||
|
||||
@@ -182,7 +222,7 @@ msgstr "Portail de facturation"
|
||||
msgid "Blog Post"
|
||||
msgstr "Article de blog"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Tableau"
|
||||
|
||||
@@ -195,7 +235,7 @@ msgid "Board name is required"
|
||||
msgstr "Le nom du tableau est requis"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Tableau introuvable"
|
||||
|
||||
@@ -248,23 +288,32 @@ msgstr "Rapport de bug"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Annuler"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Carte introuvable"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Titre de la carte"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Modifier le mot de passe"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Changer la langue de l'application."
|
||||
|
||||
@@ -273,6 +322,10 @@ msgstr "Changer la langue de l'application."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Vérifiez votre boîte de réception"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Nom de la checklist"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Effacer les filtres"
|
||||
@@ -310,11 +363,24 @@ msgstr "Terminé"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Contrôle et propriété complets :"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "a terminé un élément de la checklist"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "a terminé l'élément <0>{0}</0> de la checklist"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "Confirmer le changement d'URL"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Confirmez votre nouveau mot de passe"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Connecter Trello"
|
||||
@@ -323,7 +389,7 @@ msgstr "Connecter Trello"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Connectez vos outils favoris pour simplifier votre flux de travail."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Connectez votre compte Trello pour importer des tableaux."
|
||||
|
||||
@@ -353,8 +419,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Contrôlez qui peut voir et modifier vos tableaux."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Créer un autre"
|
||||
|
||||
@@ -362,11 +428,15 @@ msgstr "Créer un autre"
|
||||
msgid "Create board"
|
||||
msgstr "Créer un tableau"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Créer une carte"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Créer une checklist"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Créer une étiquette"
|
||||
|
||||
@@ -383,11 +453,11 @@ msgid "Create new key"
|
||||
msgstr "Créer une nouvelle clé"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Créer une nouvelle étiquette"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Créer une nouvelle liste"
|
||||
|
||||
@@ -396,7 +466,7 @@ msgstr "Créer une nouvelle liste"
|
||||
msgid "Create workspace"
|
||||
msgstr "Créer un espace de travail"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "a créé la carte"
|
||||
|
||||
@@ -404,6 +474,10 @@ msgstr "a créé la carte"
|
||||
msgid "Critical"
|
||||
msgstr "Critique"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "Le mot de passe actuel est requis"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Domaine personnalisé"
|
||||
@@ -421,14 +495,15 @@ msgid "Dark"
|
||||
msgstr "Sombre"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Supprimer"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Supprimer le compte"
|
||||
@@ -437,7 +512,7 @@ msgstr "Supprimer le compte"
|
||||
msgid "Delete board"
|
||||
msgstr "Supprimer le tableau"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Supprimer la carte"
|
||||
|
||||
@@ -449,17 +524,35 @@ msgstr "Supprimer le commentaire"
|
||||
msgid "Delete list"
|
||||
msgstr "Supprimer la liste"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Supprimer l'espace de travail"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "a supprimé une checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "a supprimé un élément de la checklist"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "a supprimé la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "a supprimé l'élément <0>{0}</0> de la checklist"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Design"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Déconnecter Trello"
|
||||
|
||||
@@ -467,7 +560,7 @@ msgstr "Déconnecter Trello"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Discutez et collaborez sur les cartes."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Nom d'affichage"
|
||||
|
||||
@@ -521,7 +614,7 @@ msgstr "Modifier l'URL du tableau"
|
||||
msgid "Edit comment"
|
||||
msgstr "Modifier le commentaire"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Modifier l'étiquette"
|
||||
|
||||
@@ -545,6 +638,14 @@ msgstr "E-mail"
|
||||
msgid "Enhancement"
|
||||
msgstr "Amélioration"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Saisissez votre mot de passe actuel"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Saisissez votre mot de passe actuel et choisissez un nouveau mot de passe sécurisé."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Saisissez votre adresse e-mail"
|
||||
@@ -553,15 +654,23 @@ msgstr "Saisissez votre adresse e-mail"
|
||||
msgid "Enter your name"
|
||||
msgstr "Saisissez votre nom"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Saisissez votre nouveau mot de passe"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Saisissez votre mot de passe"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Erreur lors du changement de mot de passe"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Erreur lors de la suppression du compte"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Erreur lors de la suppression de l'étiquette"
|
||||
|
||||
@@ -569,7 +678,7 @@ msgstr "Erreur lors de la suppression de l'étiquette"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Erreur lors de la suppression de l'espace de travail"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Erreur lors de la déconnexion de Trello"
|
||||
|
||||
@@ -692,7 +801,7 @@ msgstr "Commencer"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Commencez par créer un nouveau tableau"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Commencez par créer une nouvelle liste"
|
||||
|
||||
@@ -849,8 +958,8 @@ msgstr "Kanban réinventé"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Gardez à l'esprit que cette action est irréversible."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Étiquettes"
|
||||
@@ -859,7 +968,7 @@ msgstr "Étiquettes"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Étiquettes & filtres"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Langue"
|
||||
|
||||
@@ -883,7 +992,7 @@ msgstr "Clair"
|
||||
msgid "Link copied"
|
||||
msgstr "Lien copié"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "Liste"
|
||||
|
||||
@@ -911,13 +1020,22 @@ msgstr "Priorité basse"
|
||||
msgid "magic link"
|
||||
msgstr "lien magique"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "a marqué un élément de la checklist comme incomplet"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "a marqué l'élément <0>{0}</0> de la checklist comme incomplet"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Priorité moyenne"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -932,16 +1050,18 @@ msgstr "Membres | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Mensuel"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "a déplacé la carte de <0>{fromList}</0> vers<1>{toList}</1>"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "a déplacé la carte de <0>{0}</0> vers <1>{1}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "a déplacé la carte vers une autre liste"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Nom"
|
||||
|
||||
@@ -957,23 +1077,35 @@ msgstr "Nouveau"
|
||||
msgid "New board"
|
||||
msgstr "Nouveau tableau"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "Nouvelle carte"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "Nouvelle checklist"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "Nouvel import"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "Nouvelle étiquette"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "Nouvelle liste"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "Le nouveau mot de passe est requis"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "Le nouveau mot de passe doit être différent du mot de passe actuel"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "Nouveau ticket"
|
||||
@@ -1002,7 +1134,7 @@ msgstr "Aucun tableau trouvé"
|
||||
msgid "No credit card required"
|
||||
msgstr "Aucune carte de crédit requise"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "Aucune liste"
|
||||
|
||||
@@ -1014,11 +1146,11 @@ msgstr "Offre"
|
||||
msgid "Onboarding"
|
||||
msgstr "Intégration"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Une fois que vous supprimez votre compte, il n'y a pas de retour possible. Cette action ne peut pas être annulée."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Une fois que vous supprimez votre espace de travail, il n'y a pas de retour possible. Cette action ne peut pas être annulée."
|
||||
|
||||
@@ -1038,6 +1170,18 @@ msgstr "Maîtrisez vos données"
|
||||
msgid "Part-time"
|
||||
msgstr "Temps partiel"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Mot de passe modifié"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "Le mot de passe doit comporter au moins 8 caractères"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Les mots de passe ne correspondent pas"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Fréquence de paiement"
|
||||
@@ -1059,6 +1203,10 @@ msgstr "Projet personnel"
|
||||
msgid "Planning"
|
||||
msgstr "Planification"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Veuillez confirmer votre nouveau mot de passe"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Veuillez saisir une adresse e-mail valide"
|
||||
@@ -1085,24 +1233,30 @@ msgstr "Veuillez sélectionner un fichier à télécharger."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Veuillez réessayer plus tard ou contacter le service client."
|
||||
|
||||
@@ -1128,7 +1282,7 @@ msgstr "Privé"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Image de profil mise à jour"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Photo de profil"
|
||||
|
||||
@@ -1168,17 +1322,32 @@ msgstr "Supprimer"
|
||||
msgid "Remove member"
|
||||
msgstr "Supprimer le membre"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "a supprimé une étiquette de la carte"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "a retiré un membre de la carte"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "a supprimé l'étiquette <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "a supprimé l'étiquette <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "a renommé une checklist"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "a renommé la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "a renommé l'élément de la liste de contrôle en <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1241,7 +1410,7 @@ msgstr "Auto-hébergement"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Auto-hébergement avec Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "s'est auto-assigné la carte"
|
||||
|
||||
@@ -1253,13 +1422,13 @@ msgstr "Envoyer des commentaires"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Paramètres"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Paramètres | {0}"
|
||||
|
||||
@@ -1338,6 +1507,10 @@ msgstr "Conditions d'utilisation"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "Merci pour vos commentaires !"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "Le mot de passe actuel que vous avez saisi est incorrect."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "La principale différence entre Kan et Trello est que Kan est open source, permettant à chacun de consulter, modifier et contribuer à notre code. Notre offre cloud ne comporte également aucune restriction sur les fonctionnalités pour un usage individuel, alors que Trello verrouille des fonctionnalités de base comme le nombre de tableaux que vous pouvez créer derrière un paywall."
|
||||
@@ -1360,8 +1533,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "Ils ne pourront plus accéder à cet espace de travail."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "Cette action ne peut pas être annulée."
|
||||
|
||||
@@ -1398,7 +1572,7 @@ msgstr "Basculer le menu"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Suivez tous les changements de cartes avec un historique d'activité détaillé."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello déconnecté"
|
||||
|
||||
@@ -1410,14 +1584,22 @@ msgstr "Importations Trello"
|
||||
msgid "Triaging"
|
||||
msgstr "Triage"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "Impossible d'ajouter l'élément à la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Impossible d'ajouter un commentaire"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "Impossible de créer la carte"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Impossible de créer la liste de contrôle"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "Impossible de créer une liste"
|
||||
@@ -1430,6 +1612,14 @@ msgstr "Impossible de créer l'espace de travail"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Impossible de supprimer la carte"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "Impossible de supprimer la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "Impossible de supprimer l'élément de la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "Impossible de supprimer le commentaire"
|
||||
@@ -1450,11 +1640,19 @@ msgstr "Impossible de mettre à jour l'URL du tableau"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Impossible de mettre à jour la visibilité du tableau"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "Impossible de mettre à jour la carte"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "Impossible de mettre à jour la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "Impossible de mettre à jour l'élément de la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "Impossible de mettre à jour le commentaire"
|
||||
@@ -1464,7 +1662,7 @@ msgid "Unable to update labels"
|
||||
msgstr "Impossible de mettre à jour les étiquettes"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "Impossible de mettre à jour la liste"
|
||||
|
||||
@@ -1472,11 +1670,12 @@ msgstr "Impossible de mettre à jour la liste"
|
||||
msgid "Unable to update members"
|
||||
msgstr "Impossible de mettre à jour les membres"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "a retiré <0>{memberName}</0> de la carte"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "a désassigné <0>{0}</0> de la carte"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "s'est retiré de la carte"
|
||||
|
||||
@@ -1512,21 +1711,26 @@ msgstr "Listes illimitées"
|
||||
msgid "Update"
|
||||
msgstr "Mettre à jour"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Mettre à jour l'étiquette"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "a mis à jour un élément de la liste de contrôle"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "a mis à jour la description"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "a mis à jour le titre"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "a mis à jour le titre en <0>{toTitle}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "a mis à jour le titre en <0>{0}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1565,11 +1769,11 @@ msgstr "L'utilisateur est déjà membre de cet espace de travail"
|
||||
msgid "Video"
|
||||
msgstr "Vidéo"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "Consultez et gérez vos clés API."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "Consultez et gérez votre facturation et votre abonnement."
|
||||
|
||||
@@ -1621,7 +1825,7 @@ msgstr "Quand Trello a été lancé en 2011, il a impressionné tout le monde pa
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "Pourquoi créer un Trello open source ?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Espace de travail"
|
||||
|
||||
@@ -1629,7 +1833,7 @@ msgstr "Espace de travail"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Espace de travail supprimé"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Description de l'espace de travail"
|
||||
|
||||
@@ -1650,7 +1854,7 @@ msgstr "Description de l'espace de travail mise à jour"
|
||||
msgid "Workspace members"
|
||||
msgstr "Membres de l'espace de travail"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Nom de l'espace de travail"
|
||||
@@ -1671,7 +1875,7 @@ msgstr "Nom de l'espace de travail mis à jour"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Slug de l'espace de travail mis à jour"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "URL de l'espace de travail"
|
||||
|
||||
@@ -1687,6 +1891,10 @@ msgstr "Annuel"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Oui, nous proposons un plan gratuit à vie pour un usage individuel. Aucune restriction, aucun paywall, aucune limite."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "Vous êtes sur le point de modifier votre mot de passe."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "Vous pouvez obtenir une URL d'espace de travail personnalisée, comme <0>kan.bn/kan</0>, en accédant à vos <1>paramètres d'espace de travail</1> et en souscrivant à un abonnement pro. Tous les abonnements contribuent à financer le développement du projet !"
|
||||
@@ -1719,15 +1927,19 @@ msgstr "Vos tableaux ont été importés."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Votre nom d'affichage a été mis à jour."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Votre mot de passe a été modifié."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "Votre image de profil a été mise à jour."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Votre compte Trello a été déconnecté."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Votre compte Trello est connecté."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,12 +23,12 @@ msgstr ", o consulta i nostri"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} etichette"
|
||||
|
||||
@@ -48,8 +48,8 @@ msgstr "Un'app kanban potente e flessibile che ti aiuta a organizzare il lavoro,
|
||||
msgid "Account deleted"
|
||||
msgstr "Account eliminato"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Attività"
|
||||
|
||||
@@ -66,9 +66,21 @@ msgstr "Aggiungi una carta"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Aggiungi un commento..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Aggiungi un elemento..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Aggiungi checklist"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Aggiungi descrizione... (digita '/' per aprire i comandi o '@' per menzionare)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Aggiungi dettagli..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -80,17 +92,36 @@ msgstr "Aggiungi etichetta"
|
||||
msgid "Add member"
|
||||
msgstr "Aggiungi membro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "ha aggiunto una checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "ha aggiunto un elemento alla checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "ha aggiunto un'etichetta alla carta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "ha aggiunto un membro alla carta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "ha aggiunto l'etichetta <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "ha aggiunto la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "ha aggiunto l'elemento <0>{0}</0> alla checklist"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "ha aggiunto l'etichetta <0>{0}</0>"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -108,11 +139,15 @@ msgstr "Tutti i sistemi operativi"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "Hai già un account? <0><1>Accedi</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "Si è verificato un errore durante la disconnessione del tuo account Trello."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "Si è verificato un errore imprevisto. Riprova più tardi."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "Chiavi API"
|
||||
|
||||
@@ -141,11 +176,15 @@ msgstr "Sei sicuro di voler eliminare lo spazio di lavoro {0}?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "Sei sicuro di voler eliminare questa carta?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "Sei sicuro di voler eliminare questa checklist?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "Sei sicuro di voler eliminare questo commento?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "Sei sicuro di voler eliminare questa etichetta?"
|
||||
|
||||
@@ -153,9 +192,10 @@ msgstr "Sei sicuro di voler eliminare questa etichetta?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "Sei sicuro di voler eliminare il tuo account?"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "ha assegnato <0>{memberName}</0> alla carta"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "ha assegnato <0>{0}</0> alla scheda"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -169,12 +209,12 @@ msgstr "Backlog"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Kanban base"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Fatturazione"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Portale di fatturazione"
|
||||
|
||||
@@ -182,7 +222,7 @@ msgstr "Portale di fatturazione"
|
||||
msgid "Blog Post"
|
||||
msgstr "Post del blog"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Bacheca"
|
||||
|
||||
@@ -195,7 +235,7 @@ msgid "Board name is required"
|
||||
msgstr "Il nome della bacheca è obbligatorio"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Bacheca non trovata"
|
||||
|
||||
@@ -248,23 +288,32 @@ msgstr "Segnalazione bug"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Annulla"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Carta non trovata"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Titolo della carta"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Cambia password"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Cambia la lingua dell'app."
|
||||
|
||||
@@ -273,6 +322,10 @@ msgstr "Cambia la lingua dell'app."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Controlla la tua casella di posta"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Nome della checklist"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Cancella filtri"
|
||||
@@ -310,11 +363,24 @@ msgstr "Completato"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Controllo e proprietà completi:"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "ha completato un elemento della checklist"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "ha completato l'elemento <0>{0}</0> della checklist"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "Conferma modifica URL"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Conferma la tua nuova password"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Connetti Trello"
|
||||
@@ -323,7 +389,7 @@ msgstr "Connetti Trello"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Connetti i tuoi strumenti preferiti per semplificare il tuo flusso di lavoro."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Connetti il tuo account Trello per importare le bacheche."
|
||||
|
||||
@@ -353,8 +419,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Controlla chi può visualizzare e modificare le tue bacheche."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Crea un altro"
|
||||
|
||||
@@ -362,11 +428,15 @@ msgstr "Crea un altro"
|
||||
msgid "Create board"
|
||||
msgstr "Crea bacheca"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Crea carta"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Crea checklist"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Crea etichetta"
|
||||
|
||||
@@ -383,11 +453,11 @@ msgid "Create new key"
|
||||
msgstr "Crea nuova chiave"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Crea nuova etichetta"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Crea nuova lista"
|
||||
|
||||
@@ -396,7 +466,7 @@ msgstr "Crea nuova lista"
|
||||
msgid "Create workspace"
|
||||
msgstr "Crea spazio di lavoro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "ha creato la carta"
|
||||
|
||||
@@ -404,6 +474,10 @@ msgstr "ha creato la carta"
|
||||
msgid "Critical"
|
||||
msgstr "Critico"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "La password attuale è obbligatoria"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Dominio personalizzato"
|
||||
@@ -421,14 +495,15 @@ msgid "Dark"
|
||||
msgstr "Scuro"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Elimina"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Elimina account"
|
||||
@@ -437,7 +512,7 @@ msgstr "Elimina account"
|
||||
msgid "Delete board"
|
||||
msgstr "Elimina bacheca"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Elimina carta"
|
||||
|
||||
@@ -449,17 +524,35 @@ msgstr "Elimina commento"
|
||||
msgid "Delete list"
|
||||
msgstr "Elimina lista"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Elimina spazio di lavoro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "ha eliminato una checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "ha eliminato un elemento della checklist"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "ha eliminato la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "ha eliminato l'elemento <0>{0}</0> della checklist"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Design"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Disconnetti Trello"
|
||||
|
||||
@@ -467,7 +560,7 @@ msgstr "Disconnetti Trello"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Discuti e collabora sulle schede."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Nome visualizzato"
|
||||
|
||||
@@ -521,7 +614,7 @@ msgstr "Modifica URL della bacheca"
|
||||
msgid "Edit comment"
|
||||
msgstr "Modifica commento"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Modifica etichetta"
|
||||
|
||||
@@ -545,6 +638,14 @@ msgstr "Email"
|
||||
msgid "Enhancement"
|
||||
msgstr "Miglioramento"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Inserisci la tua password attuale"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Inserisci la tua password attuale e scegli una nuova password sicura."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Inserisci il tuo indirizzo email"
|
||||
@@ -553,15 +654,23 @@ msgstr "Inserisci il tuo indirizzo email"
|
||||
msgid "Enter your name"
|
||||
msgstr "Inserisci il tuo nome"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Inserisci la tua nuova password"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Inserisci la tua password"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Errore durante il cambio della password"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Errore durante l'eliminazione dell'account"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Errore durante l'eliminazione dell'etichetta"
|
||||
|
||||
@@ -569,7 +678,7 @@ msgstr "Errore durante l'eliminazione dell'etichetta"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Errore durante l'eliminazione dell'area di lavoro"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Errore durante la disconnessione da Trello"
|
||||
|
||||
@@ -692,7 +801,7 @@ msgstr "Inizia ora"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Inizia creando una nuova bacheca"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Inizia creando una nuova lista"
|
||||
|
||||
@@ -849,8 +958,8 @@ msgstr "Kanban reinventato"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Tieni presente che questa azione è irreversibile."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Etichette"
|
||||
@@ -859,7 +968,7 @@ msgstr "Etichette"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Etichette & Filtri"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Lingua"
|
||||
|
||||
@@ -883,7 +992,7 @@ msgstr "Chiaro"
|
||||
msgid "Link copied"
|
||||
msgstr "Link copiato"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "Lista"
|
||||
|
||||
@@ -911,13 +1020,22 @@ msgstr "Bassa priorità"
|
||||
msgid "magic link"
|
||||
msgstr "link magico"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "ha segnato un elemento della checklist come incompleto"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "ha segnato l'elemento <0>{0}</0> della checklist come incompleto"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Media priorità"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -932,16 +1050,18 @@ msgstr "Membri | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Mensile"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "ha spostato la scheda da <0>{fromList}</0> a<1>{toList}</1>"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "ha spostato la scheda da <0>{0}</0> a<1>{1}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "ha spostato la scheda in un'altra lista"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Nome"
|
||||
|
||||
@@ -957,23 +1077,35 @@ msgstr "Nuovo"
|
||||
msgid "New board"
|
||||
msgstr "Nuova bacheca"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "Nuova carta"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "Nuova checklist"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "Nuova importazione"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "Nuova etichetta"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "Nuova lista"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "La nuova password è obbligatoria"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "La nuova password deve essere diversa dalla password attuale"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "Nuovo ticket"
|
||||
@@ -1002,7 +1134,7 @@ msgstr "Nessuna bacheca trovata"
|
||||
msgid "No credit card required"
|
||||
msgstr "Nessuna carta di credito richiesta"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "Nessuna lista"
|
||||
|
||||
@@ -1014,11 +1146,11 @@ msgstr "Offerta"
|
||||
msgid "Onboarding"
|
||||
msgstr "Inserimento"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Una volta eliminato il tuo account, non si può tornare indietro. Questa azione non può essere annullata."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Una volta eliminata l'area di lavoro, non si può tornare indietro. Questa azione non può essere annullata."
|
||||
|
||||
@@ -1038,6 +1170,18 @@ msgstr "Possiedi i tuoi dati"
|
||||
msgid "Part-time"
|
||||
msgstr "Part-time"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Password modificata"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "La password deve contenere almeno 8 caratteri"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Le password non corrispondono"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Frequenza di pagamento"
|
||||
@@ -1059,6 +1203,10 @@ msgstr "Progetto personale"
|
||||
msgid "Planning"
|
||||
msgstr "Pianificazione"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Conferma la tua nuova password"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Inserisci un indirizzo email valido"
|
||||
@@ -1085,24 +1233,30 @@ msgstr "Seleziona un file da caricare."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Riprova più tardi o contatta l'assistenza clienti."
|
||||
|
||||
@@ -1128,7 +1282,7 @@ msgstr "Privato"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Immagine del profilo aggiornata"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Immagine del profilo"
|
||||
|
||||
@@ -1168,17 +1322,32 @@ msgstr "Rimuovi"
|
||||
msgid "Remove member"
|
||||
msgstr "Rimuovi membro"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "ha rimosso un'etichetta dalla scheda"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "ha rimosso un membro dalla scheda"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "ha rimosso l'etichetta <0>{label}</0>"
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "ha rimosso l'etichetta <0>{0}</0>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "ha rinominato una checklist"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "ha rinominato la checklist <0>{0}</0>"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "ha rinominato l'elemento della checklist in <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1241,7 +1410,7 @@ msgstr "Self Host"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Self host con Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "si è auto-assegnato la scheda"
|
||||
|
||||
@@ -1253,13 +1422,13 @@ msgstr "Invia feedback"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Impostazioni"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Impostazioni | {0}"
|
||||
|
||||
@@ -1338,6 +1507,10 @@ msgstr "Termini di servizio"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "Grazie per il tuo feedback!"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "La password attuale inserita non è corretta."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "La principale differenza tra Kan e Trello è che Kan è open source, permettendo a chiunque di visualizzare, modificare e contribuire al nostro codice. La nostra offerta cloud non impone inoltre alcuna restrizione sulle funzionalità per uso individuale, mentre Trello blocca funzionalità di base come il numero di bacheche che puoi creare dietro un paywall."
|
||||
@@ -1360,8 +1533,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "Non potranno accedere a questo spazio di lavoro."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "Questa azione non può essere annullata."
|
||||
|
||||
@@ -1398,7 +1572,7 @@ msgstr "Attiva/disattiva menu"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Tieni traccia di tutte le modifiche alle schede con una cronologia dettagliata delle attività."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello disconnesso"
|
||||
|
||||
@@ -1410,14 +1584,22 @@ msgstr "Importazioni da Trello"
|
||||
msgid "Triaging"
|
||||
msgstr "Smistamento"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "Impossibile aggiungere l'elemento della checklist"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Impossibile aggiungere il commento"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "Impossibile creare la scheda"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Impossibile creare la checklist"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "Impossibile creare la lista"
|
||||
@@ -1430,6 +1612,14 @@ msgstr "Impossibile creare lo spazio di lavoro"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Impossibile eliminare la scheda"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "Impossibile eliminare la checklist"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "Impossibile eliminare l'elemento della checklist"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "Impossibile eliminare il commento"
|
||||
@@ -1450,11 +1640,19 @@ msgstr "Impossibile aggiornare l'URL della bacheca"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Impossibile aggiornare la visibilità della bacheca"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "Impossibile aggiornare la scheda"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "Impossibile aggiornare la checklist"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "Impossibile aggiornare l'elemento della checklist"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "Impossibile aggiornare il commento"
|
||||
@@ -1464,7 +1662,7 @@ msgid "Unable to update labels"
|
||||
msgstr "Impossibile aggiornare le etichette"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "Impossibile aggiornare la lista"
|
||||
|
||||
@@ -1472,11 +1670,12 @@ msgstr "Impossibile aggiornare la lista"
|
||||
msgid "Unable to update members"
|
||||
msgstr "Impossibile aggiornare i membri"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "ha rimosso l'assegnazione di <0>{memberName}</0> dalla scheda"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "ha rimosso l'assegnazione di <0>{0}</0> dalla scheda"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "si è rimosso dall'assegnazione della scheda"
|
||||
|
||||
@@ -1512,21 +1711,26 @@ msgstr "Liste illimitate"
|
||||
msgid "Update"
|
||||
msgstr "Aggiorna"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Aggiorna etichetta"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "ha aggiornato un elemento della checklist"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "ha aggiornato la descrizione"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "ha aggiornato il titolo"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "ha aggiornato il titolo in <0>{toTitle}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "ha aggiornato il titolo in <0>{0}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1565,11 +1769,11 @@ msgstr "L'utente è già membro di questo spazio di lavoro"
|
||||
msgid "Video"
|
||||
msgstr "Video"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "Visualizza e gestisci le tue chiavi API."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "Visualizza e gestisci la tua fatturazione e abbonamento."
|
||||
|
||||
@@ -1621,7 +1825,7 @@ msgstr "Quando Trello fu lanciato nel 2011, stupì tutti con la sua semplicità
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "Perché creare un Trello open source?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Spazio di lavoro"
|
||||
|
||||
@@ -1629,7 +1833,7 @@ msgstr "Spazio di lavoro"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Spazio di lavoro eliminato"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Descrizione dello spazio di lavoro"
|
||||
|
||||
@@ -1650,7 +1854,7 @@ msgstr "Descrizione dell'area di lavoro aggiornata"
|
||||
msgid "Workspace members"
|
||||
msgstr "Membri del workspace"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Nome dello spazio di lavoro"
|
||||
@@ -1671,7 +1875,7 @@ msgstr "Nome dello spazio di lavoro aggiornato"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Slug dell'area di lavoro aggiornato"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "URL dello spazio di lavoro"
|
||||
|
||||
@@ -1687,6 +1891,10 @@ msgstr "Annuale"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Sì, offriamo un piano gratuito per sempre per uso individuale. Nessuna restrizione, nessun paywall, nessun limite."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "Stai per cambiare la tua password."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "Puoi ottenere un URL personalizzato per il tuo workspace, come <0>kan.bn/kan</0>, accedendo alle tue <1>impostazioni del workspace</1> e acquistando un abbonamento pro. Tutti gli abbonamenti contribuiscono a finanziare lo sviluppo del progetto!"
|
||||
@@ -1719,15 +1927,19 @@ msgstr "Le tue bacheche sono state importate."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Il tuo nome visualizzato è stato aggiornato."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "La tua password è stata modificata."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "La tua immagine del profilo è stata aggiornata."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Il tuo account Trello è stato disconnesso."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Il tuo account Trello è connesso."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -23,12 +23,12 @@ msgstr ", of bekijk onze"
|
||||
|
||||
#. placeholder {0}: card?.title ?? "Card"
|
||||
#. placeholder {1}: board?.name ?? "Board"
|
||||
#: src/views/card/index.tsx:189
|
||||
#: src/views/card/index.tsx:213
|
||||
msgid "{0} | {1}"
|
||||
msgstr "{0} | {1}"
|
||||
|
||||
#. placeholder {0}: labelPublicIds.length
|
||||
#: src/views/board/components/NewCardForm.tsx:392
|
||||
#: src/views/board/components/NewCardForm.tsx:432
|
||||
msgid "{0} labels"
|
||||
msgstr "{0} labels"
|
||||
|
||||
@@ -48,8 +48,8 @@ msgstr "Een krachtige, flexibele kanban-app die je helpt werk te organiseren, vo
|
||||
msgid "Account deleted"
|
||||
msgstr "Account verwijderd"
|
||||
|
||||
#: src/views/public/board/CardModal.tsx:128
|
||||
#: src/views/card/index.tsx:256
|
||||
#: src/views/public/board/CardModal.tsx:140
|
||||
#: src/views/card/index.tsx:288
|
||||
msgid "Activity"
|
||||
msgstr "Activiteit"
|
||||
|
||||
@@ -66,9 +66,21 @@ msgstr "Voeg een kaart toe"
|
||||
msgid "Add a comment..."
|
||||
msgstr "Voeg een reactie toe..."
|
||||
|
||||
#: src/components/Editor.tsx:303
|
||||
msgid "Add description... (type '/' to open commands)"
|
||||
msgstr "Voeg beschrijving toe... (typ '/' om commando's te openen)"
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:140
|
||||
msgid "Add an item..."
|
||||
msgstr "Voeg een item toe..."
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:18
|
||||
msgid "Add checklist"
|
||||
msgstr "Checklist toevoegen"
|
||||
|
||||
#: src/components/Editor.tsx:442
|
||||
msgid "Add description... (type '/' to open commands or '@' to mention)"
|
||||
msgstr "Beschrijving toevoegen... (typ '/' om commando's te openen of '@' om te vermelden)"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:172
|
||||
msgid "Add details..."
|
||||
msgstr "Details toevoegen..."
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:110
|
||||
#: src/views/card/components/LabelSelector.tsx:118
|
||||
@@ -80,17 +92,36 @@ msgstr "Label toevoegen"
|
||||
msgid "Add member"
|
||||
msgstr "Lid toevoegen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:56
|
||||
#: src/views/card/components/ActivityList.tsx:69
|
||||
msgid "added a checklist"
|
||||
msgstr "heeft een checklist toegevoegd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:72
|
||||
msgid "added a checklist item"
|
||||
msgstr "heeft een checklistitem toegevoegd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:65
|
||||
msgid "added a label to the card"
|
||||
msgstr "heeft een label aan de kaart toegevoegd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:58
|
||||
#: src/views/card/components/ActivityList.tsx:67
|
||||
msgid "added a member to the card"
|
||||
msgstr "heeft een lid aan de kaart toegevoegd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "added label <0>{label}</0>"
|
||||
msgstr "heeft label <0>{label}</0> toegevoegd"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:146
|
||||
msgid "added checklist <0>{0}</0>"
|
||||
msgstr "heeft checklist <0>{0}</0> toegevoegd"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:170
|
||||
msgid "added checklist item <0>{0}</0>"
|
||||
msgstr "heeft checklistitem <0>{0}</0> toegevoegd"
|
||||
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:130
|
||||
msgid "added label <0>{0}</0>"
|
||||
msgstr "heeft label <0>{0}</0> toegevoegd"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:55
|
||||
msgid "Admin roles"
|
||||
@@ -108,11 +139,15 @@ msgstr "Alle systemen operationeel"
|
||||
msgid "Already have an account? <0><1>Sign in</1></0>"
|
||||
msgstr "Heb je al een account? <0><1>Log in</1></0>"
|
||||
|
||||
#: src/views/settings/index.tsx:100
|
||||
#: src/views/settings/index.tsx:102
|
||||
msgid "An error occurred while disconnecting your Trello account."
|
||||
msgstr "Er is een fout opgetreden bij het verbreken van de verbinding met je Trello-account."
|
||||
|
||||
#: src/views/settings/index.tsx:257
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:90
|
||||
msgid "An unexpected error occurred. Please try again later."
|
||||
msgstr "Er is een onverwachte fout opgetreden. Probeer het later opnieuw."
|
||||
|
||||
#: src/views/settings/index.tsx:259
|
||||
msgid "API keys"
|
||||
msgstr "API-sleutels"
|
||||
|
||||
@@ -141,11 +176,15 @@ msgstr "Weet je zeker dat je de werkruimte {0} wilt verwijderen?"
|
||||
msgid "Are you sure you want to delete this card?"
|
||||
msgstr "Weet je zeker dat je deze kaart wilt verwijderen?"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:55
|
||||
msgid "Are you sure you want to delete this checklist?"
|
||||
msgstr "Weet je zeker dat je deze checklist wilt verwijderen?"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:65
|
||||
msgid "Are you sure you want to delete this comment?"
|
||||
msgstr "Weet je zeker dat je deze opmerking wilt verwijderen?"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:39
|
||||
#: src/components/DeleteLabelConfirmation.tsx:41
|
||||
msgid "Are you sure you want to delete this label?"
|
||||
msgstr "Weet je zeker dat je dit label wilt verwijderen?"
|
||||
|
||||
@@ -153,9 +192,10 @@ msgstr "Weet je zeker dat je dit label wilt verwijderen?"
|
||||
msgid "Are you sure you want to delete your account?"
|
||||
msgstr "Weet je zeker dat je je account wilt verwijderen?"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:92
|
||||
msgid "assigned <0>{memberName}</0> to the card"
|
||||
msgstr "heeft <0>{memberName}</0> aan de kaart toegewezen"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:110
|
||||
msgid "assigned <0>{0}</0> to the card"
|
||||
msgstr "heeft <0>{0}</0> aan de kaart toegewezen"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:46
|
||||
msgid "Awaiting Customer"
|
||||
@@ -169,12 +209,12 @@ msgstr "Backlog"
|
||||
msgid "Basic Kanban"
|
||||
msgstr "Basis kanban"
|
||||
|
||||
#: src/views/settings/index.tsx:196
|
||||
#: src/views/settings/index.tsx:198
|
||||
#: src/views/boards/components/TemplateBoards.tsx:55
|
||||
msgid "Billing"
|
||||
msgstr "Facturering"
|
||||
|
||||
#: src/views/settings/index.tsx:206
|
||||
#: src/views/settings/index.tsx:208
|
||||
msgid "Billing portal"
|
||||
msgstr "Factureringsportaal"
|
||||
|
||||
@@ -182,7 +222,7 @@ msgstr "Factureringsportaal"
|
||||
msgid "Blog Post"
|
||||
msgstr "Blogbericht"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Board"
|
||||
msgstr "Bord"
|
||||
|
||||
@@ -195,7 +235,7 @@ msgid "Board name is required"
|
||||
msgstr "Bordnaam is verplicht"
|
||||
|
||||
#: src/views/public/board/index.tsx:143
|
||||
#: src/views/board/index.tsx:358
|
||||
#: src/views/board/index.tsx:357
|
||||
msgid "Board not found"
|
||||
msgstr "Bord niet gevonden"
|
||||
|
||||
@@ -248,23 +288,32 @@ msgstr "Bugrapport"
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:98
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:88
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:50
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:168
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:55
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:76
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:63
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:86
|
||||
#: src/views/card/components/Comment.tsx:158
|
||||
#: src/components/DeleteLabelConfirmation.tsx:47
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
msgid "Cancel"
|
||||
msgstr "Annuleren"
|
||||
|
||||
#: src/views/card/index.tsx:234
|
||||
#: src/views/card/index.tsx:259
|
||||
msgid "Card not found"
|
||||
msgstr "Kaart niet gevonden"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:278
|
||||
#: src/views/board/components/NewCardForm.tsx:307
|
||||
msgid "Card title"
|
||||
msgstr "Kaarttitel"
|
||||
|
||||
#: src/views/settings/index.tsx:188
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:301
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:109
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:178
|
||||
msgid "Change Password"
|
||||
msgstr "Wachtwoord wijzigen"
|
||||
|
||||
#: src/views/settings/index.tsx:190
|
||||
msgid "Change the language of the app."
|
||||
msgstr "Wijzig de taal van de app."
|
||||
|
||||
@@ -273,6 +322,10 @@ msgstr "Wijzig de taal van de app."
|
||||
msgid "Check your inbox"
|
||||
msgstr "Controleer je inbox"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:118
|
||||
msgid "Checklist name"
|
||||
msgstr "Naam checklist"
|
||||
|
||||
#: src/views/board/components/Filters.tsx:155
|
||||
msgid "Clear filters"
|
||||
msgstr "Filters wissen"
|
||||
@@ -310,11 +363,24 @@ msgstr "Voltooid"
|
||||
msgid "Complete control and ownership:"
|
||||
msgstr "Volledige controle en eigendom:"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:74
|
||||
msgid "completed a checklist item"
|
||||
msgstr "heeft een checklistitem voltooid"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:187
|
||||
msgid "completed checklist item <0>{0}</0>"
|
||||
msgstr "heeft checklistitem <0>{0}</0> voltooid"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:42
|
||||
msgid "Confirm URL change"
|
||||
msgstr "URL-wijziging bevestigen"
|
||||
|
||||
#: src/views/settings/index.tsx:233
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:150
|
||||
msgid "Confirm your new password"
|
||||
msgstr "Bevestig je nieuwe wachtwoord"
|
||||
|
||||
#: src/views/settings/index.tsx:235
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:157
|
||||
msgid "Connect Trello"
|
||||
msgstr "Verbind Trello"
|
||||
@@ -323,7 +389,7 @@ msgstr "Verbind Trello"
|
||||
msgid "Connect your favorite tools to streamline your workflow."
|
||||
msgstr "Verbind je favoriete tools om je werkstroom te stroomlijnen."
|
||||
|
||||
#: src/views/settings/index.tsx:220
|
||||
#: src/views/settings/index.tsx:222
|
||||
msgid "Connect your Trello account to import boards."
|
||||
msgstr "Verbind je Trello-account om borden te importeren."
|
||||
|
||||
@@ -353,8 +419,8 @@ msgid "Control who can view and edit your boards."
|
||||
msgstr "Bepaal wie je borden kan bekijken en bewerken."
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:140
|
||||
#: src/views/board/components/NewCardForm.tsx:418
|
||||
#: src/components/LabelForm.tsx:212
|
||||
#: src/views/board/components/NewCardForm.tsx:458
|
||||
#: src/components/LabelForm.tsx:213
|
||||
msgid "Create another"
|
||||
msgstr "Maak nog een"
|
||||
|
||||
@@ -362,11 +428,15 @@ msgstr "Maak nog een"
|
||||
msgid "Create board"
|
||||
msgstr "Maak bord"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:428
|
||||
#: src/views/board/components/NewCardForm.tsx:468
|
||||
msgid "Create card"
|
||||
msgstr "Maak kaart"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/views/card/components/NewChecklistForm.tsx:134
|
||||
msgid "Create checklist"
|
||||
msgstr "Checklist maken"
|
||||
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Create label"
|
||||
msgstr "Maak label"
|
||||
|
||||
@@ -383,11 +453,11 @@ msgid "Create new key"
|
||||
msgstr "Nieuwe sleutel aanmaken"
|
||||
|
||||
#: src/views/card/components/LabelSelector.tsx:98
|
||||
#: src/views/board/components/NewCardForm.tsx:354
|
||||
#: src/views/board/components/NewCardForm.tsx:394
|
||||
msgid "Create new label"
|
||||
msgstr "Maak nieuw label"
|
||||
|
||||
#: src/views/board/index.tsx:426
|
||||
#: src/views/board/index.tsx:425
|
||||
msgid "Create new list"
|
||||
msgstr "Maak nieuwe lijst"
|
||||
|
||||
@@ -396,7 +466,7 @@ msgstr "Maak nieuwe lijst"
|
||||
msgid "Create workspace"
|
||||
msgstr "Werkruimte maken"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:52
|
||||
#: src/views/card/components/ActivityList.tsx:61
|
||||
msgid "created the card"
|
||||
msgstr "heeft de kaart aangemaakt"
|
||||
|
||||
@@ -404,6 +474,10 @@ msgstr "heeft de kaart aangemaakt"
|
||||
msgid "Critical"
|
||||
msgstr "Kritiek"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:19
|
||||
msgid "Current password is required"
|
||||
msgstr "Huidig wachtwoord is vereist"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:74
|
||||
msgid "Custom domain"
|
||||
msgstr "Aangepast domein"
|
||||
@@ -421,14 +495,15 @@ msgid "Dark"
|
||||
msgstr "Donker"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:82
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:66
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:92
|
||||
#: src/components/LabelForm.tsx:226
|
||||
#: src/components/DeleteLabelConfirmation.tsx:49
|
||||
#: src/components/LabelForm.tsx:228
|
||||
#: src/components/DeleteLabelConfirmation.tsx:51
|
||||
msgid "Delete"
|
||||
msgstr "Verwijderen"
|
||||
|
||||
#: src/views/settings/index.tsx:288
|
||||
#: src/views/settings/index.tsx:298
|
||||
#: src/views/settings/index.tsx:309
|
||||
#: src/views/settings/index.tsx:319
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:96
|
||||
msgid "Delete account"
|
||||
msgstr "Account verwijderen"
|
||||
@@ -437,7 +512,7 @@ msgstr "Account verwijderen"
|
||||
msgid "Delete board"
|
||||
msgstr "Board verwijderen"
|
||||
|
||||
#: src/views/card/components/Dropdown.tsx:14
|
||||
#: src/views/card/components/Dropdown.tsx:25
|
||||
msgid "Delete card"
|
||||
msgstr "Kaart verwijderen"
|
||||
|
||||
@@ -449,17 +524,35 @@ msgstr "Reactie verwijderen"
|
||||
msgid "Delete list"
|
||||
msgstr "Lijst verwijderen"
|
||||
|
||||
#: src/views/settings/index.tsx:270
|
||||
#: src/views/settings/index.tsx:281
|
||||
#: src/views/settings/index.tsx:272
|
||||
#: src/views/settings/index.tsx:283
|
||||
#: src/views/settings/components/DeleteWorkspaceConfirmation.tsx:106
|
||||
msgid "Delete workspace"
|
||||
msgstr "Werkruimte verwijderen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:71
|
||||
msgid "deleted a checklist"
|
||||
msgstr "heeft een checklist verwijderd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:76
|
||||
msgid "deleted a checklist item"
|
||||
msgstr "heeft een checklistitem verwijderd"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:162
|
||||
msgid "deleted checklist <0>{0}</0>"
|
||||
msgstr "heeft checklist <0>{0}</0> verwijderd"
|
||||
|
||||
#. placeholder {0}: truncate(fromTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:205
|
||||
msgid "deleted checklist item <0>{0}</0>"
|
||||
msgstr "heeft checklistitem <0>{0}</0> verwijderd"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:32
|
||||
msgid "Design"
|
||||
msgstr "Ontwerp"
|
||||
|
||||
#: src/views/settings/index.tsx:248
|
||||
#: src/views/settings/index.tsx:250
|
||||
msgid "Disconnect Trello"
|
||||
msgstr "Trello ontkoppelen"
|
||||
|
||||
@@ -467,7 +560,7 @@ msgstr "Trello ontkoppelen"
|
||||
msgid "Discuss and collaborate on cards."
|
||||
msgstr "Bespreek en werk samen aan kaarten."
|
||||
|
||||
#: src/views/settings/index.tsx:149
|
||||
#: src/views/settings/index.tsx:151
|
||||
msgid "Display name"
|
||||
msgstr "Weergavenaam"
|
||||
|
||||
@@ -521,7 +614,7 @@ msgstr "Board URL bewerken"
|
||||
msgid "Edit comment"
|
||||
msgstr "Reactie bewerken"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "Edit label"
|
||||
msgstr "Label bewerken"
|
||||
|
||||
@@ -545,6 +638,14 @@ msgstr "E-mail"
|
||||
msgid "Enhancement"
|
||||
msgstr "Verbetering"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:122
|
||||
msgid "Enter your current password"
|
||||
msgstr "Voer je huidige wachtwoord in"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:111
|
||||
msgid "Enter your current password and choose a new secure password."
|
||||
msgstr "Voer je huidige wachtwoord in en kies een nieuw veilig wachtwoord."
|
||||
|
||||
#: src/components/AuthForm.tsx:302
|
||||
msgid "Enter your email address"
|
||||
msgstr "Voer je e-mailadres in"
|
||||
@@ -553,15 +654,23 @@ msgstr "Voer je e-mailadres in"
|
||||
msgid "Enter your name"
|
||||
msgstr "Voer je naam in"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:136
|
||||
msgid "Enter your new password"
|
||||
msgstr "Voer je nieuwe wachtwoord in"
|
||||
|
||||
#: src/components/AuthForm.tsx:315
|
||||
msgid "Enter your password"
|
||||
msgstr "Voer je wachtwoord in"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:89
|
||||
msgid "Error Changing Password"
|
||||
msgstr "Fout bij wijzigen wachtwoord"
|
||||
|
||||
#: src/views/settings/components/DeleteAccountConfirmation.tsx:39
|
||||
msgid "Error deleting account"
|
||||
msgstr "Fout bij verwijderen account"
|
||||
|
||||
#: src/components/DeleteLabelConfirmation.tsx:22
|
||||
#: src/components/DeleteLabelConfirmation.tsx:25
|
||||
msgid "Error deleting label"
|
||||
msgstr "Fout bij het verwijderen van label"
|
||||
|
||||
@@ -569,7 +678,7 @@ msgstr "Fout bij het verwijderen van label"
|
||||
msgid "Error deleting workspace"
|
||||
msgstr "Fout bij verwijderen werkruimte"
|
||||
|
||||
#: src/views/settings/index.tsx:99
|
||||
#: src/views/settings/index.tsx:101
|
||||
msgid "Error disconnecting Trello"
|
||||
msgstr "Fout bij ontkoppelen van Trello"
|
||||
|
||||
@@ -692,7 +801,7 @@ msgstr "Aan de slag"
|
||||
msgid "Get started by creating a new board"
|
||||
msgstr "Begin door een nieuw bord te maken"
|
||||
|
||||
#: src/views/board/index.tsx:418
|
||||
#: src/views/board/index.tsx:417
|
||||
msgid "Get started by creating a new list"
|
||||
msgstr "Begin door een nieuwe lijst te maken"
|
||||
|
||||
@@ -849,8 +958,8 @@ msgstr "Kanban opnieuw uitgevonden"
|
||||
msgid "Keep in mind that this action is irreversible."
|
||||
msgstr "Houd er rekening mee dat deze actie onomkeerbaar is."
|
||||
|
||||
#: src/views/card/index.tsx:113
|
||||
#: src/views/board/components/NewCardForm.tsx:358
|
||||
#: src/views/card/index.tsx:117
|
||||
#: src/views/board/components/NewCardForm.tsx:398
|
||||
#: src/views/board/components/Filters.tsx:101
|
||||
msgid "Labels"
|
||||
msgstr "Labels"
|
||||
@@ -859,7 +968,7 @@ msgstr "Labels"
|
||||
msgid "Labels & Filters"
|
||||
msgstr "Labels & filters"
|
||||
|
||||
#: src/views/settings/index.tsx:185
|
||||
#: src/views/settings/index.tsx:187
|
||||
msgid "Language"
|
||||
msgstr "Taal"
|
||||
|
||||
@@ -883,7 +992,7 @@ msgstr "Licht"
|
||||
msgid "Link copied"
|
||||
msgstr "Link gekopieerd"
|
||||
|
||||
#: src/views/card/index.tsx:105
|
||||
#: src/views/card/index.tsx:109
|
||||
msgid "List"
|
||||
msgstr "Lijst"
|
||||
|
||||
@@ -911,13 +1020,22 @@ msgstr "Lage prioriteit"
|
||||
msgid "magic link"
|
||||
msgstr "magische link"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:75
|
||||
msgid "marked a checklist item as incomplete"
|
||||
msgstr "heeft een checklistitem als onvoltooid gemarkeerd"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:196
|
||||
msgid "marked checklist item <0>{0}</0> as incomplete"
|
||||
msgstr "heeft checklistitem <0>{0}</0> als onvoltooid gemarkeerd"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:17
|
||||
msgid "Medium Priority"
|
||||
msgstr "Gemiddelde prioriteit"
|
||||
|
||||
#: src/views/members/index.tsx:161
|
||||
#: src/views/card/index.tsx:121
|
||||
#: src/views/board/components/NewCardForm.tsx:317
|
||||
#: src/views/card/index.tsx:125
|
||||
#: src/views/board/components/NewCardForm.tsx:357
|
||||
#: src/views/board/components/Filters.tsx:93
|
||||
#: src/components/SideNavigation.tsx:73
|
||||
msgid "Members"
|
||||
@@ -932,16 +1050,18 @@ msgstr "Leden | {0}"
|
||||
msgid "Monthly"
|
||||
msgstr "Maandelijks"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:81
|
||||
msgid "moved the card from <0>{fromList}</0> to<1>{toList}</1>"
|
||||
msgstr "heeft de kaart verplaatst van <0>{fromList}</0> naar<1>{toList}</1>"
|
||||
#. placeholder {0}: truncate(fromList)
|
||||
#. placeholder {1}: truncate(toList)
|
||||
#: src/views/card/components/ActivityList.tsx:98
|
||||
msgid "moved the card from <0>{0}</0> to<1>{1}</1>"
|
||||
msgstr "heeft de kaart verplaatst van <0>{0}</0> naar<1>{1}</1>"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:55
|
||||
#: src/views/card/components/ActivityList.tsx:64
|
||||
msgid "moved the card to another list"
|
||||
msgstr "heeft de kaart naar een andere lijst verplaatst"
|
||||
|
||||
#: src/views/boards/components/NewBoardForm.tsx:99
|
||||
#: src/components/LabelForm.tsx:134
|
||||
#: src/components/LabelForm.tsx:135
|
||||
msgid "Name"
|
||||
msgstr "Naam"
|
||||
|
||||
@@ -957,23 +1077,35 @@ msgstr "Nieuw"
|
||||
msgid "New board"
|
||||
msgstr "Nieuw bord"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:261
|
||||
#: src/views/board/components/NewCardForm.tsx:290
|
||||
msgid "New card"
|
||||
msgstr "Nieuwe kaart"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:102
|
||||
msgid "New checklist"
|
||||
msgstr "Nieuwe checklist"
|
||||
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:322
|
||||
msgid "New import"
|
||||
msgstr "Nieuwe import"
|
||||
|
||||
#: src/components/LabelForm.tsx:118
|
||||
#: src/components/LabelForm.tsx:119
|
||||
msgid "New label"
|
||||
msgstr "Nieuw label"
|
||||
|
||||
#: src/views/board/index.tsx:395
|
||||
#: src/views/board/index.tsx:394
|
||||
#: src/views/board/components/NewListForm.tsx:112
|
||||
msgid "New list"
|
||||
msgstr "Nieuwe lijst"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:23
|
||||
msgid "New password is required"
|
||||
msgstr "Nieuw wachtwoord is vereist"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:31
|
||||
msgid "New password must be different from current password"
|
||||
msgstr "Nieuw wachtwoord moet verschillen van het huidige wachtwoord"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:43
|
||||
msgid "New Ticket"
|
||||
msgstr "Nieuw ticket"
|
||||
@@ -1002,7 +1134,7 @@ msgstr "Geen borden gevonden"
|
||||
msgid "No credit card required"
|
||||
msgstr "Geen creditcard vereist"
|
||||
|
||||
#: src/views/board/index.tsx:415
|
||||
#: src/views/board/index.tsx:414
|
||||
msgid "No lists"
|
||||
msgstr "Geen lijsten"
|
||||
|
||||
@@ -1014,11 +1146,11 @@ msgstr "Aanbod"
|
||||
msgid "Onboarding"
|
||||
msgstr "Inwerktraject"
|
||||
|
||||
#: src/views/settings/index.tsx:291
|
||||
#: src/views/settings/index.tsx:312
|
||||
msgid "Once you delete your account, there is no going back. This action cannot be undone."
|
||||
msgstr "Zodra je je account verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt."
|
||||
|
||||
#: src/views/settings/index.tsx:273
|
||||
#: src/views/settings/index.tsx:275
|
||||
msgid "Once you delete your workspace, there is no going back. This action cannot be undone."
|
||||
msgstr "Zodra je je werkruimte verwijdert, is er geen weg terug. Deze actie kan niet ongedaan worden gemaakt."
|
||||
|
||||
@@ -1038,6 +1170,18 @@ msgstr "Bezit je eigen data"
|
||||
msgid "Part-time"
|
||||
msgstr "Deeltijd"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:69
|
||||
msgid "Password Changed"
|
||||
msgstr "Wachtwoord gewijzigd"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:22
|
||||
msgid "Password must be at least 8 characters"
|
||||
msgstr "Wachtwoord moet minimaal 8 tekens bevatten"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:27
|
||||
msgid "Passwords do not match"
|
||||
msgstr "Wachtwoorden komen niet overeen"
|
||||
|
||||
#: src/views/home/components/Pricing.tsx:101
|
||||
msgid "Payment frequency"
|
||||
msgstr "Betalingsfrequentie"
|
||||
@@ -1059,6 +1203,10 @@ msgstr "Persoonlijk project"
|
||||
msgid "Planning"
|
||||
msgstr "Planning"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:24
|
||||
msgid "Please confirm your new password"
|
||||
msgstr "Bevestig je nieuwe wachtwoord"
|
||||
|
||||
#: src/components/AuthForm.tsx:306
|
||||
msgid "Please enter a valid email address"
|
||||
msgstr "Voer een geldig e-mailadres in"
|
||||
@@ -1085,24 +1233,30 @@ msgstr "Selecteer een bestand om te uploaden."
|
||||
#: src/views/settings/components/Avatar.tsx:98
|
||||
#: src/views/members/components/InviteMemberForm.tsx:64
|
||||
#: src/views/members/components/DeleteMemberConfirmation.tsx:28
|
||||
#: src/views/card/index.tsx:159
|
||||
#: src/views/card/index.tsx:172
|
||||
#: src/views/card/components/NewCommentForm.tsx:31
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:89
|
||||
#: src/views/card/components/NewChecklistForm.tsx:70
|
||||
#: src/views/card/components/MemberSelector.tsx:80
|
||||
#: src/views/card/components/ListSelector.tsx:53
|
||||
#: src/views/card/components/LabelSelector.tsx:73
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:45
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:37
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:52
|
||||
#: src/views/card/components/Comment.tsx:64
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:46
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:60
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:88
|
||||
#: src/views/boards/components/ImportBoardsForm.tsx:205
|
||||
#: src/views/board/index.tsx:135
|
||||
#: src/views/board/index.tsx:191
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/board/components/VisibilityButton.tsx:53
|
||||
#: src/views/board/components/UpdateBoardSlugForm.tsx:72
|
||||
#: src/views/board/components/NewListForm.tsx:78
|
||||
#: src/views/board/components/NewCardForm.tsx:145
|
||||
#: src/views/board/components/NewCardForm.tsx:174
|
||||
#: src/components/NewWorkspaceForm.tsx:41
|
||||
#: src/components/FeedbackModal.tsx:41
|
||||
#: src/components/DeleteLabelConfirmation.tsx:23
|
||||
#: src/components/DeleteLabelConfirmation.tsx:26
|
||||
msgid "Please try again later, or contact customer support."
|
||||
msgstr "Probeer het later opnieuw of neem contact op met de klantenservice."
|
||||
|
||||
@@ -1128,7 +1282,7 @@ msgstr "Privé"
|
||||
msgid "Profile image updated"
|
||||
msgstr "Profielafbeelding bijgewerkt"
|
||||
|
||||
#: src/views/settings/index.tsx:144
|
||||
#: src/views/settings/index.tsx:146
|
||||
msgid "Profile picture"
|
||||
msgstr "Profielfoto"
|
||||
|
||||
@@ -1168,17 +1322,32 @@ msgstr "Verwijderen"
|
||||
msgid "Remove member"
|
||||
msgstr "Lid verwijderen"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:57
|
||||
#: src/views/card/components/ActivityList.tsx:66
|
||||
msgid "removed a label from the card"
|
||||
msgstr "heeft een label van de kaart verwijderd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:59
|
||||
#: src/views/card/components/ActivityList.tsx:68
|
||||
msgid "removed a member from the card"
|
||||
msgstr "heeft een lid van de kaart verwijderd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "removed label <0>{label}</0>"
|
||||
msgstr "heeft label <0>{label}</0> verwijderd"
|
||||
#. placeholder {0}: truncate(label)
|
||||
#: src/views/card/components/ActivityList.tsx:138
|
||||
msgid "removed label <0>{0}</0>"
|
||||
msgstr "heeft label <0>{0}</0> verwijderd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:70
|
||||
msgid "renamed a checklist"
|
||||
msgstr "heeft een checklist hernoemd"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:154
|
||||
msgid "renamed checklist <0>{0}</0>"
|
||||
msgstr "heeft checklist <0>{0}</0> hernoemd"
|
||||
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:178
|
||||
msgid "renamed checklist item to <0>{0}</0>"
|
||||
msgstr "checklistitem hernoemd naar <0>{0}</0>"
|
||||
|
||||
#: src/views/boards/components/TemplateBoards.tsx:76
|
||||
msgid "Research"
|
||||
@@ -1241,7 +1410,7 @@ msgstr "Zelf hosten"
|
||||
msgid "Self host with Github"
|
||||
msgstr "Zelf hosten met Github"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:89
|
||||
#: src/views/card/components/ActivityList.tsx:107
|
||||
msgid "self-assigned the card"
|
||||
msgstr "heeft de kaart aan zichzelf toegewezen"
|
||||
|
||||
@@ -1253,13 +1422,13 @@ msgstr "Feedback versturen"
|
||||
msgid "Senior"
|
||||
msgstr "Senior"
|
||||
|
||||
#: src/views/settings/index.tsx:138
|
||||
#: src/views/settings/index.tsx:140
|
||||
#: src/components/SideNavigation.tsx:78
|
||||
msgid "Settings"
|
||||
msgstr "Instellingen"
|
||||
|
||||
#. placeholder {0}: workspace.name ?? "Workspace"
|
||||
#: src/views/settings/index.tsx:134
|
||||
#: src/views/settings/index.tsx:136
|
||||
msgid "Settings | {0}"
|
||||
msgstr "Instellingen | {0}"
|
||||
|
||||
@@ -1338,6 +1507,10 @@ msgstr "Servicevoorwaarden"
|
||||
msgid "Thank you for your feedback!"
|
||||
msgstr "Bedankt voor je feedback!"
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:84
|
||||
msgid "The current password you entered is incorrect."
|
||||
msgstr "Het ingevoerde huidige wachtwoord is onjuist."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:33
|
||||
msgid "The main difference between Kan and Trello is that Kan is open source, allowing anyone to view, modify, and contribute to our code. Our cloud offering also offers no restrictions on features for individual use, whereas Trello locks basic features such as the number of boards you can create behind a paywall."
|
||||
msgstr "Het belangrijkste verschil tussen Kan en Trello is dat Kan open source is, waardoor iedereen onze code kan bekijken, wijzigen en eraan kan bijdragen. Onze cloudoplossing biedt ook geen beperkingen op functies voor individueel gebruik, terwijl Trello basisfuncties zoals het aantal borden dat je kunt maken achter een betaalmuur plaatst."
|
||||
@@ -1360,8 +1533,9 @@ msgid "They won't be able to access this workspace."
|
||||
msgstr "Ze zullen geen toegang meer hebben tot deze werkruimte."
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:68
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:58
|
||||
#: src/views/card/components/DeleteCardConfirmation.tsx:78
|
||||
#: src/components/DeleteLabelConfirmation.tsx:42
|
||||
#: src/components/DeleteLabelConfirmation.tsx:44
|
||||
msgid "This action can't be undone."
|
||||
msgstr "Deze actie kan niet ongedaan worden gemaakt."
|
||||
|
||||
@@ -1398,7 +1572,7 @@ msgstr "Menu in-/uitschakelen"
|
||||
msgid "Track all card changes with detailed activity history."
|
||||
msgstr "Volg alle kaartwijzigingen met gedetailleerde activiteitengeschiedenis."
|
||||
|
||||
#: src/views/settings/index.tsx:92
|
||||
#: src/views/settings/index.tsx:94
|
||||
msgid "Trello disconnected"
|
||||
msgstr "Trello ontkoppeld"
|
||||
|
||||
@@ -1410,14 +1584,22 @@ msgstr "Trello-imports"
|
||||
msgid "Triaging"
|
||||
msgstr "Triage"
|
||||
|
||||
#: src/views/card/components/NewChecklistItemForm.tsx:88
|
||||
msgid "Unable to add checklist item"
|
||||
msgstr "Kan checklistitem niet toevoegen"
|
||||
|
||||
#: src/views/card/components/NewCommentForm.tsx:30
|
||||
msgid "Unable to add comment"
|
||||
msgstr "Kan geen reactie toevoegen"
|
||||
|
||||
#: src/views/board/components/NewCardForm.tsx:142
|
||||
#: src/views/board/components/NewCardForm.tsx:171
|
||||
msgid "Unable to create card"
|
||||
msgstr "Kan kaart niet aanmaken"
|
||||
|
||||
#: src/views/card/components/NewChecklistForm.tsx:69
|
||||
msgid "Unable to create checklist"
|
||||
msgstr "Kan checklist niet maken"
|
||||
|
||||
#: src/views/board/components/NewListForm.tsx:77
|
||||
msgid "Unable to create list"
|
||||
msgstr "Kan geen lijst maken"
|
||||
@@ -1430,6 +1612,14 @@ msgstr "Kan werkruimte niet aanmaken"
|
||||
msgid "Unable to delete card"
|
||||
msgstr "Kan kaart niet verwijderen"
|
||||
|
||||
#: src/views/card/components/DeleteChecklistConfirmation.tsx:36
|
||||
msgid "Unable to delete checklist"
|
||||
msgstr "Kan checklist niet verwijderen"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:87
|
||||
msgid "Unable to delete checklist item"
|
||||
msgstr "Kan checklistitem niet verwijderen"
|
||||
|
||||
#: src/views/card/components/DeleteCommentConfirmation.tsx:44
|
||||
msgid "Unable to delete comment"
|
||||
msgstr "Kan opmerking niet verwijderen"
|
||||
@@ -1450,11 +1640,19 @@ msgstr "Kan board URL niet bijwerken"
|
||||
msgid "Unable to update board visibility"
|
||||
msgstr "Kan bordzichtbaarheid niet bijwerken"
|
||||
|
||||
#: src/views/card/index.tsx:158
|
||||
#: src/views/board/index.tsx:190
|
||||
#: src/views/card/index.tsx:171
|
||||
#: src/views/board/index.tsx:189
|
||||
msgid "Unable to update card"
|
||||
msgstr "Kan kaart niet bijwerken"
|
||||
|
||||
#: src/views/card/components/ChecklistNameInput.tsx:45
|
||||
msgid "Unable to update checklist"
|
||||
msgstr "Kan checklist niet bijwerken"
|
||||
|
||||
#: src/views/card/components/ChecklistItemRow.tsx:59
|
||||
msgid "Unable to update checklist item"
|
||||
msgstr "Kan checklistitem niet bijwerken"
|
||||
|
||||
#: src/views/card/components/Comment.tsx:63
|
||||
msgid "Unable to update comment"
|
||||
msgstr "Kan reactie niet bijwerken"
|
||||
@@ -1464,7 +1662,7 @@ msgid "Unable to update labels"
|
||||
msgstr "Kan labels niet bijwerken"
|
||||
|
||||
#: src/views/card/components/ListSelector.tsx:52
|
||||
#: src/views/board/index.tsx:134
|
||||
#: src/views/board/index.tsx:133
|
||||
msgid "Unable to update list"
|
||||
msgstr "Kan lijst niet bijwerken"
|
||||
|
||||
@@ -1472,11 +1670,12 @@ msgstr "Kan lijst niet bijwerken"
|
||||
msgid "Unable to update members"
|
||||
msgstr "Kan leden niet bijwerken"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:102
|
||||
msgid "unassigned <0>{memberName}</0> from the card"
|
||||
msgstr "<0>{memberName}</0> van de kaart verwijderd"
|
||||
#. placeholder {0}: truncate(memberName)
|
||||
#: src/views/card/components/ActivityList.tsx:121
|
||||
msgid "unassigned <0>{0}</0> from the card"
|
||||
msgstr "<0>{0}</0> van de kaart verwijderd"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:99
|
||||
#: src/views/card/components/ActivityList.tsx:118
|
||||
msgid "unassigned themselves from the card"
|
||||
msgstr "zichzelf van de kaart verwijderd"
|
||||
|
||||
@@ -1512,21 +1711,26 @@ msgstr "Onbeperkt aantal lijsten"
|
||||
msgid "Update"
|
||||
msgstr "Bijwerken"
|
||||
|
||||
#: src/components/LabelForm.tsx:236
|
||||
#: src/components/LabelForm.tsx:238
|
||||
msgid "Update label"
|
||||
msgstr "Label bijwerken"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:54
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated a checklist item"
|
||||
msgstr "een checklistitem bijgewerkt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:63
|
||||
msgid "updated the description"
|
||||
msgstr "beschrijving bijgewerkt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:53
|
||||
#: src/views/card/components/ActivityList.tsx:62
|
||||
msgid "updated the title"
|
||||
msgstr "titel bijgewerkt"
|
||||
|
||||
#: src/views/card/components/ActivityList.tsx:73
|
||||
msgid "updated the title to <0>{toTitle}</0>"
|
||||
msgstr "titel bijgewerkt naar <0>{toTitle}</0>"
|
||||
#. placeholder {0}: truncate(toTitle)
|
||||
#: src/views/card/components/ActivityList.tsx:90
|
||||
msgid "updated the title to <0>{0}</0>"
|
||||
msgstr "titel bijgewerkt naar <0>{0}</0>"
|
||||
|
||||
#: src/views/settings/components/CustomURLConfirmation.tsx:52
|
||||
msgid "Upgrade"
|
||||
@@ -1565,11 +1769,11 @@ msgstr "Gebruiker is al lid van deze werkruimte"
|
||||
msgid "Video"
|
||||
msgstr "Video"
|
||||
|
||||
#: src/views/settings/index.tsx:260
|
||||
#: src/views/settings/index.tsx:262
|
||||
msgid "View and manage your API keys."
|
||||
msgstr "Bekijk en beheer je API-sleutels."
|
||||
|
||||
#: src/views/settings/index.tsx:199
|
||||
#: src/views/settings/index.tsx:201
|
||||
msgid "View and manage your billing and subscription."
|
||||
msgstr "Bekijk en beheer je facturering en abonnement."
|
||||
|
||||
@@ -1621,7 +1825,7 @@ msgstr "Toen Trello in 2011 werd gelanceerd, blies het iedereen omver met zijn z
|
||||
msgid "Why make an open source Trello?"
|
||||
msgstr "Waarom een open source Trello maken?"
|
||||
|
||||
#: src/views/board/index.tsx:332
|
||||
#: src/views/board/index.tsx:331
|
||||
msgid "Workspace"
|
||||
msgstr "Werkruimte"
|
||||
|
||||
@@ -1629,7 +1833,7 @@ msgstr "Werkruimte"
|
||||
msgid "Workspace deleted"
|
||||
msgstr "Werkruimte verwijderd"
|
||||
|
||||
#: src/views/settings/index.tsx:175
|
||||
#: src/views/settings/index.tsx:177
|
||||
msgid "Workspace description"
|
||||
msgstr "Werkruimte beschrijving"
|
||||
|
||||
@@ -1650,7 +1854,7 @@ msgstr "Werkruimtebeschrijving bijgewerkt"
|
||||
msgid "Workspace members"
|
||||
msgstr "Werkruimteleden"
|
||||
|
||||
#: src/views/settings/index.tsx:156
|
||||
#: src/views/settings/index.tsx:158
|
||||
#: src/components/NewWorkspaceForm.tsx:80
|
||||
msgid "Workspace name"
|
||||
msgstr "Naam werkruimte"
|
||||
@@ -1671,7 +1875,7 @@ msgstr "Werkruimtenaam bijgewerkt"
|
||||
msgid "Workspace slug updated"
|
||||
msgstr "Werkruimte-slug bijgewerkt"
|
||||
|
||||
#: src/views/settings/index.tsx:165
|
||||
#: src/views/settings/index.tsx:167
|
||||
msgid "Workspace URL"
|
||||
msgstr "Werkruimte URL"
|
||||
|
||||
@@ -1687,6 +1891,10 @@ msgstr "Jaarlijks"
|
||||
msgid "Yes, we offer an forever free plan for individual use. No restrictions, no paywalls, no limits."
|
||||
msgstr "Ja, we bieden een voor altijd gratis plan voor individueel gebruik. Geen beperkingen, geen betaalmuren, geen limieten."
|
||||
|
||||
#: src/views/settings/index.tsx:294
|
||||
msgid "You are about to change your password."
|
||||
msgstr "Je staat op het punt je wachtwoord te wijzigen."
|
||||
|
||||
#: src/views/home/components/Faqs.tsx:67
|
||||
msgid "You can get a custom workspace URL, like <0>kan.bn/kan</0>, by going into your <1>workspace settings</1> and purchasing a pro workspace subscription. All subscriptions help fund the development of the project!"
|
||||
msgstr "Je kunt een aangepaste werkruimte-URL krijgen, zoals <0>kan.bn/kan</0>, door naar je <1>werkruimte-instellingen</1> te gaan en een pro-werkruimte-abonnement aan te schaffen. Alle abonnementen helpen de ontwikkeling van het project te financieren!"
|
||||
@@ -1719,15 +1927,19 @@ msgstr "Je borden zijn geïmporteerd."
|
||||
msgid "Your display name has been updated."
|
||||
msgstr "Je weergavenaam is bijgewerkt."
|
||||
|
||||
#: src/views/settings/components/ChangePasswordConfirmation.tsx:70
|
||||
msgid "Your password has been changed."
|
||||
msgstr "Je wachtwoord is gewijzigd."
|
||||
|
||||
#: src/views/settings/components/Avatar.tsx:27
|
||||
msgid "Your profile image has been updated."
|
||||
msgstr "Je profielafbeelding is bijgewerkt."
|
||||
|
||||
#: src/views/settings/index.tsx:93
|
||||
#: src/views/settings/index.tsx:95
|
||||
msgid "Your Trello account has been disconnected."
|
||||
msgstr "Je Trello-account is ontkoppeld."
|
||||
|
||||
#: src/views/settings/index.tsx:242
|
||||
#: src/views/settings/index.tsx:244
|
||||
msgid "Your Trello account is connected."
|
||||
msgstr "Je Trello-account is verbonden."
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -14,7 +14,7 @@ import { useEffect } from "react";
|
||||
import { LinguiProviderWrapper } from "~/providers/lingui";
|
||||
import { ModalProvider } from "~/providers/modal";
|
||||
import { PopupProvider } from "~/providers/popup";
|
||||
import { ThemeProvider } from "~/providers/theme";
|
||||
import { ThemeProvider } from "next-themes";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
const jakarta = Plus_Jakarta_Sans({
|
||||
@@ -81,9 +81,9 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
<script src="/__ENV.js" />
|
||||
<main className="font-sans">
|
||||
<LinguiProviderWrapper>
|
||||
<ThemeProvider>
|
||||
<ModalProvider>
|
||||
<PopupProvider>
|
||||
<ThemeProvider attribute="class" defaultTheme="system" enableSystem>
|
||||
<ModalProvider>
|
||||
<PopupProvider>
|
||||
{posthogKey ? (
|
||||
<PostHogProvider client={posthog}>
|
||||
{getLayout(<Component {...pageProps} />)}
|
||||
@@ -91,8 +91,8 @@ const MyApp: AppType = ({ Component, pageProps }: AppPropsWithLayout) => {
|
||||
) : (
|
||||
getLayout(<Component {...pageProps} />)
|
||||
)}
|
||||
</PopupProvider>
|
||||
</ModalProvider>
|
||||
</PopupProvider>
|
||||
</ModalProvider>
|
||||
</ThemeProvider>
|
||||
</LinguiProviderWrapper>
|
||||
</main>
|
||||
|
||||
@@ -10,7 +10,7 @@ interface Props {
|
||||
children: React.ReactNode;
|
||||
}
|
||||
|
||||
type ModalContextType = {
|
||||
interface ModalContextType {
|
||||
isOpen: boolean;
|
||||
openModal: (
|
||||
contentType: string,
|
||||
@@ -18,6 +18,8 @@ type ModalContextType = {
|
||||
entityLabel?: string,
|
||||
) => void;
|
||||
closeModal: () => void;
|
||||
closeModals: (count: number) => void;
|
||||
clearAllModals: () => void;
|
||||
modalContentType: string;
|
||||
entityId: string;
|
||||
entityLabel: string;
|
||||
@@ -26,7 +28,7 @@ type ModalContextType = {
|
||||
getModalState: (modalType: string) => any;
|
||||
clearModalState: (modalType: string) => void;
|
||||
clearAllModalStates: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const ModalContext = createContext<ModalContextType | undefined>(undefined);
|
||||
|
||||
@@ -46,11 +48,11 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
|
||||
entityLabel?: string,
|
||||
) => {
|
||||
const newModal: ModalState = { contentType, entityId, entityLabel };
|
||||
setModalStack(prev => [...prev, newModal]);
|
||||
setModalStack((prev) => [...prev, newModal]);
|
||||
};
|
||||
|
||||
const closeModal = () => {
|
||||
setModalStack(prev => {
|
||||
setModalStack((prev) => {
|
||||
if (prev.length <= 1) {
|
||||
return [];
|
||||
}
|
||||
@@ -58,10 +60,21 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
|
||||
});
|
||||
};
|
||||
|
||||
const closeModals = (count: number) => {
|
||||
setModalStack(prev => {
|
||||
const newLength = Math.max(0, prev.length - count);
|
||||
return prev.slice(0, newLength);
|
||||
});
|
||||
};
|
||||
|
||||
const clearAllModals = () => {
|
||||
setModalStack([]);
|
||||
};
|
||||
|
||||
const setModalState = (modalType: string, state: any) => {
|
||||
setModalStates(prev => ({
|
||||
setModalStates((prev) => ({
|
||||
...prev,
|
||||
[modalType]: state
|
||||
[modalType]: state,
|
||||
}));
|
||||
};
|
||||
|
||||
@@ -70,7 +83,7 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
|
||||
};
|
||||
|
||||
const clearModalState = (modalType: string) => {
|
||||
setModalStates(prev => {
|
||||
setModalStates((prev) => {
|
||||
const newStates = { ...prev };
|
||||
delete newStates[modalType];
|
||||
return newStates;
|
||||
@@ -87,6 +100,8 @@ export const ModalProvider: React.FC<Props> = ({ children }) => {
|
||||
isOpen,
|
||||
openModal,
|
||||
closeModal,
|
||||
closeModals,
|
||||
clearAllModals,
|
||||
modalContentType,
|
||||
entityId,
|
||||
entityLabel,
|
||||
|
||||
@@ -45,10 +45,12 @@ export const formatMemberDisplayName = (
|
||||
return localPart.replace(/[_-]/g, ".");
|
||||
};
|
||||
|
||||
export const getAvatarUrl = (imageOrKey: string) => {
|
||||
export const getAvatarUrl = (imageOrKey: string | null) => {
|
||||
if (!imageOrKey) return "";
|
||||
|
||||
if (imageOrKey.startsWith("http://") || imageOrKey.startsWith("https://")) {
|
||||
return imageOrKey;
|
||||
}
|
||||
|
||||
|
||||
return `${env("NEXT_PUBLIC_STORAGE_URL")}/${env("NEXT_PUBLIC_AVATAR_BUCKET_NAME")}/${imageOrKey}`;
|
||||
};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import Avatar from "~/components/Avatar";
|
||||
import Badge from "~/components/Badge";
|
||||
import CircularProgress from "~/components/CircularProgress";
|
||||
import LabelIcon from "~/components/LabelIcon";
|
||||
import { getAvatarUrl } from "~/utils/helpers";
|
||||
|
||||
@@ -7,6 +8,7 @@ const Card = ({
|
||||
title,
|
||||
labels,
|
||||
members,
|
||||
checklists,
|
||||
}: {
|
||||
title: string;
|
||||
labels: { name: string; colourCode: string | null }[];
|
||||
@@ -15,11 +17,32 @@ const Card = ({
|
||||
email: string;
|
||||
user: { name: string | null; email: string; image: string | null } | null;
|
||||
}[];
|
||||
checklists: {
|
||||
publicId: string;
|
||||
name: string;
|
||||
items: {
|
||||
publicId: string;
|
||||
title: string;
|
||||
completed: boolean;
|
||||
index: number;
|
||||
}[];
|
||||
}[];
|
||||
}) => {
|
||||
const completedItems = checklists.reduce((acc, checklist) => {
|
||||
return acc + checklist.items.filter((item) => item.completed).length;
|
||||
}, 0);
|
||||
|
||||
const totalItems = checklists.reduce((acc, checklist) => {
|
||||
return acc + checklist.items.length;
|
||||
}, 0);
|
||||
|
||||
const progress =
|
||||
totalItems > 0 ? Math.round((completedItems / totalItems) * 100) : 0;
|
||||
|
||||
return (
|
||||
<div className="flex flex-col rounded-md border border-light-200 bg-light-50 px-3 py-2 text-sm text-neutral-900 dark:border-dark-200 dark:bg-dark-200 dark:text-dark-1000 dark:hover:bg-dark-300">
|
||||
<span>{title}</span>
|
||||
{labels.length || members.length ? (
|
||||
{labels.length || members.length || checklists.length > 0 ? (
|
||||
<div className="mt-2 flex flex-col justify-end">
|
||||
<div className="space-x-0.5">
|
||||
{labels.map((label) => (
|
||||
@@ -29,21 +52,37 @@ const Card = ({
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<div className="isolate flex justify-end -space-x-1 overflow-hidden">
|
||||
{members.map(({ user, email }) => {
|
||||
const avatarUrl = user?.image
|
||||
? getAvatarUrl(user.image)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
name={user?.name ?? ""}
|
||||
email={user?.email ?? email}
|
||||
imageUrl={avatarUrl}
|
||||
<div className="flex items-center justify-end gap-1">
|
||||
{checklists.length > 0 && (
|
||||
<div className="flex items-center gap-1 rounded-full border-[1px] border-light-300 px-2 py-1 dark:border-dark-600">
|
||||
<CircularProgress
|
||||
progress={progress || 2}
|
||||
size="sm"
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
<span className="text-[10px] text-light-900 dark:text-dark-950">
|
||||
{completedItems}/{totalItems}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
{members.length > 0 && (
|
||||
<div className="isolate flex justify-end -space-x-1 overflow-hidden">
|
||||
{members.map(({ user, email }) => {
|
||||
const avatarUrl = user?.image
|
||||
? getAvatarUrl(user.image)
|
||||
: undefined;
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
name={user?.name ?? ""}
|
||||
email={user?.email ?? email}
|
||||
imageUrl={avatarUrl}
|
||||
size="sm"
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -14,7 +14,7 @@ import { generateUID } from "@kan/shared/utils";
|
||||
import Avatar from "~/components/Avatar";
|
||||
import Button from "~/components/Button";
|
||||
import CheckboxDropdown from "~/components/CheckboxDropdown";
|
||||
import Editor from "~/components/Editor";
|
||||
import Editor, { WorkspaceMember } from "~/components/Editor";
|
||||
import Input from "~/components/Input";
|
||||
import LabelIcon from "~/components/LabelIcon";
|
||||
import Toggle from "~/components/Toggle";
|
||||
@@ -46,7 +46,7 @@ export function NewCardForm({
|
||||
queryParams,
|
||||
}: NewCardFormProps) {
|
||||
const { showPopup } = usePopup();
|
||||
const { closeModal, openModal } = useModal();
|
||||
const { closeModal, openModal, modalStates, clearModalState } = useModal();
|
||||
|
||||
const utils = api.useUtils();
|
||||
|
||||
@@ -85,10 +85,39 @@ export function NewCardForm({
|
||||
return () => subscription.unsubscribe();
|
||||
}, [watch, saveFormState]);
|
||||
|
||||
|
||||
const { data: boardData } = api.board.byId.useQuery(queryParams, {
|
||||
enabled: !!boardPublicId,
|
||||
});
|
||||
|
||||
// this adds the new created label to selected labels
|
||||
useEffect(() => {
|
||||
const newLabelId = modalStates["NEW_LABEL_CREATED"];
|
||||
if (newLabelId !== undefined && !labelPublicIds.includes(newLabelId)) {
|
||||
setValue("labelPublicIds", [...labelPublicIds, newLabelId]);
|
||||
}
|
||||
}, [modalStates, labelPublicIds]);
|
||||
|
||||
// this removes the deleted label from selected labels if it is selected
|
||||
useEffect(() => {
|
||||
if (boardData?.labels) {
|
||||
const availableLabelIds = boardData.labels.map(label => label.publicId);
|
||||
const newLabelId = modalStates["NEW_LABEL_CREATED"];
|
||||
|
||||
if (newLabelId && availableLabelIds.includes(newLabelId)) {
|
||||
clearModalState("NEW_LABEL_CREATED");
|
||||
}
|
||||
|
||||
const validLabelIds = labelPublicIds.filter(id =>
|
||||
availableLabelIds.includes(id) || id === newLabelId
|
||||
);
|
||||
|
||||
if (validLabelIds.length !== labelPublicIds.length) {
|
||||
setValue("labelPublicIds", validLabelIds);
|
||||
}
|
||||
}
|
||||
}, [boardData?.labels, labelPublicIds, modalStates["NEW_LABEL_CREATED"]]);
|
||||
|
||||
const createCard = api.card.create.useMutation({
|
||||
onMutate: async (args) => {
|
||||
await utils.board.byId.cancel();
|
||||
@@ -293,6 +322,17 @@ export function NewCardForm({
|
||||
setValue("description", value);
|
||||
saveFormState({ ...formState, description: value });
|
||||
}}
|
||||
workspaceMembers={
|
||||
boardData?.workspace.members?.map((member): WorkspaceMember => ({
|
||||
publicId: member.publicId,
|
||||
email: member.email,
|
||||
user: member.user ? {
|
||||
id: member.publicId,
|
||||
name: member.user.name,
|
||||
image: member.user.image ?? null,
|
||||
} : null,
|
||||
})) ?? []
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,6 @@ import type { UpdateBoardInput } from "@kan/api/types";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { DeleteLabelConfirmation } from "~/components/DeleteLabelConfirmation";
|
||||
import FeedbackModal from "~/components/FeedbackModal";
|
||||
import { LabelForm } from "~/components/LabelForm";
|
||||
import Modal from "~/components/modal";
|
||||
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
|
||||
@@ -238,15 +237,15 @@ export default function BoardPage() {
|
||||
const renderModalContent = () => {
|
||||
return (
|
||||
<>
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_BOARD"}
|
||||
>
|
||||
<DeleteBoardConfirmation boardPublicId={boardId ?? ""} />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_LIST"}
|
||||
>
|
||||
<DeleteListConfirmation
|
||||
@@ -255,8 +254,8 @@ export default function BoardPage() {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="md"
|
||||
<Modal
|
||||
modalSize="md"
|
||||
isVisible={isOpen && modalContentType === "NEW_CARD"}
|
||||
>
|
||||
<NewCardForm
|
||||
@@ -266,8 +265,8 @@ export default function BoardPage() {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_LIST"}
|
||||
>
|
||||
<NewListForm
|
||||
@@ -276,22 +275,22 @@ export default function BoardPage() {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
|
||||
>
|
||||
<NewWorkspaceForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_LABEL"}
|
||||
>
|
||||
<LabelForm boardPublicId={boardId ?? ""} refetch={refetchBoard} />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "EDIT_LABEL"}
|
||||
>
|
||||
<LabelForm
|
||||
@@ -301,8 +300,8 @@ export default function BoardPage() {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_LABEL"}
|
||||
>
|
||||
<DeleteLabelConfirmation
|
||||
@@ -311,8 +310,8 @@ export default function BoardPage() {
|
||||
/>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "UPDATE_BOARD_SLUG"}
|
||||
>
|
||||
<UpdateBoardSlugForm
|
||||
@@ -376,7 +375,7 @@ export default function BoardPage() {
|
||||
/>
|
||||
<Filters
|
||||
labels={boardData?.labels ?? []}
|
||||
members={boardData?.workspace.members ?? []}
|
||||
members={boardData?.workspace.members?.filter(member => member.user !== null) ?? []}
|
||||
position="left"
|
||||
isLoading={!boardData}
|
||||
/>
|
||||
@@ -492,6 +491,7 @@ export default function BoardPage() {
|
||||
title={card.title}
|
||||
labels={card.labels}
|
||||
members={card.members}
|
||||
checklists={card.checklists ?? []}
|
||||
/>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ImportBoardsForm } from "./components/ImportBoardsForm";
|
||||
import { NewBoardForm } from "./components/NewBoardForm";
|
||||
|
||||
export default function BoardsPage() {
|
||||
const { openModal, modalContentType } = useModal();
|
||||
const { openModal, modalContentType, isOpen } = useModal();
|
||||
const { workspace, hasLoaded } = useWorkspace();
|
||||
|
||||
if (hasLoaded && !workspace.publicId) openModal("NEW_WORKSPACE");
|
||||
@@ -50,12 +50,35 @@ export default function BoardsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal modalSize={modalContentType === "NEW_FEEDBACK" ? "md" : "sm"}>
|
||||
{modalContentType === "NEW_FEEDBACK" && <FeedbackModal />}
|
||||
{modalContentType === "NEW_BOARD" && <NewBoardForm />}
|
||||
{modalContentType === "IMPORT_BOARDS" && <ImportBoardsForm />}
|
||||
{modalContentType === "NEW_WORKSPACE" && <NewWorkspaceForm />}
|
||||
</Modal>
|
||||
<>
|
||||
<Modal
|
||||
modalSize="md"
|
||||
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
|
||||
>
|
||||
<FeedbackModal />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_BOARD"}
|
||||
>
|
||||
<NewBoardForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "IMPORT_BOARDS"}
|
||||
>
|
||||
<ImportBoardsForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
|
||||
>
|
||||
<NewWorkspaceForm />
|
||||
</Modal>
|
||||
</>
|
||||
|
||||
<div className="flex h-full flex-row">
|
||||
<BoardsList />
|
||||
|
||||
@@ -5,9 +5,11 @@ import { de, enGB, es, fr, it, nl } from "date-fns/locale";
|
||||
import {
|
||||
HiOutlineArrowLeft,
|
||||
HiOutlineArrowRight,
|
||||
HiOutlineCheckCircle,
|
||||
HiOutlinePencil,
|
||||
HiOutlinePlus,
|
||||
HiOutlineTag,
|
||||
HiOutlineTrash,
|
||||
HiOutlineUserMinus,
|
||||
HiOutlineUserPlus,
|
||||
} from "react-icons/hi2";
|
||||
@@ -31,6 +33,11 @@ const dateLocaleMap = {
|
||||
nl: nl,
|
||||
} as const;
|
||||
|
||||
const truncate = (value: string | null, maxLength = 50) => {
|
||||
if (!value) return value;
|
||||
return value.length > maxLength ? `${value.slice(0, maxLength - 1)}…` : value;
|
||||
};
|
||||
|
||||
const getActivityText = ({
|
||||
type,
|
||||
toTitle,
|
||||
@@ -39,6 +46,7 @@ const getActivityText = ({
|
||||
memberName,
|
||||
isSelf,
|
||||
label,
|
||||
fromTitle,
|
||||
}: {
|
||||
type: ActivityType;
|
||||
toTitle: string | null;
|
||||
@@ -47,6 +55,7 @@ const getActivityText = ({
|
||||
memberName: string | null;
|
||||
isSelf: boolean;
|
||||
label: string | null;
|
||||
fromTitle?: string | null;
|
||||
}) => {
|
||||
const ACTIVITY_TYPE_MAP = {
|
||||
"card.created": t`created the card`,
|
||||
@@ -57,6 +66,14 @@ const getActivityText = ({
|
||||
"card.updated.label.removed": t`removed a label from the card`,
|
||||
"card.updated.member.added": t`added a member to the card`,
|
||||
"card.updated.member.removed": t`removed a member from the card`,
|
||||
"card.updated.checklist.added": t`added a checklist`,
|
||||
"card.updated.checklist.renamed": t`renamed a checklist`,
|
||||
"card.updated.checklist.deleted": t`deleted a checklist`,
|
||||
"card.updated.checklist.item.added": t`added a checklist item`,
|
||||
"card.updated.checklist.item.updated": t`updated a checklist item`,
|
||||
"card.updated.checklist.item.completed": t`completed a checklist item`,
|
||||
"card.updated.checklist.item.uncompleted": t`marked a checklist item as incomplete`,
|
||||
"card.updated.checklist.item.deleted": t`deleted a checklist item`,
|
||||
} as const;
|
||||
|
||||
if (!(type in ACTIVITY_TYPE_MAP)) return null;
|
||||
@@ -71,7 +88,7 @@ const getActivityText = ({
|
||||
if (type === "card.updated.title" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
updated the title to <TextHighlight>{toTitle}</TextHighlight>
|
||||
updated the title to <TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -79,8 +96,9 @@ const getActivityText = ({
|
||||
if (type === "card.updated.list" && fromList && toList) {
|
||||
return (
|
||||
<Trans>
|
||||
moved the card from <TextHighlight>{fromList}</TextHighlight> to
|
||||
<TextHighlight>{toList}</TextHighlight>
|
||||
moved the card from <TextHighlight>{truncate(fromList)}</TextHighlight>{" "}
|
||||
to
|
||||
<TextHighlight>{truncate(toList)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -90,7 +108,8 @@ const getActivityText = ({
|
||||
|
||||
return (
|
||||
<Trans>
|
||||
assigned <TextHighlight>{memberName}</TextHighlight> to the card
|
||||
assigned <TextHighlight>{truncate(memberName)}</TextHighlight> to the
|
||||
card
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -100,7 +119,8 @@ const getActivityText = ({
|
||||
|
||||
return (
|
||||
<Trans>
|
||||
unassigned <TextHighlight>{memberName}</TextHighlight> from the card
|
||||
unassigned <TextHighlight>{truncate(memberName)}</TextHighlight> from
|
||||
the card
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -108,7 +128,7 @@ const getActivityText = ({
|
||||
if (type === "card.updated.label.added" && label) {
|
||||
return (
|
||||
<Trans>
|
||||
added label <TextHighlight>{label}</TextHighlight>
|
||||
added label <TextHighlight>{truncate(label)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -116,7 +136,75 @@ const getActivityText = ({
|
||||
if (type === "card.updated.label.removed" && label) {
|
||||
return (
|
||||
<Trans>
|
||||
removed label <TextHighlight>{label}</TextHighlight>
|
||||
removed label <TextHighlight>{truncate(label)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.added" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
added checklist <TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.renamed" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
renamed checklist <TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.deleted" && fromTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
deleted checklist <TextHighlight>{truncate(fromTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.item.added" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
added checklist item <TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.item.updated" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
renamed checklist item to{" "}
|
||||
<TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.item.completed" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
completed checklist item{" "}
|
||||
<TextHighlight>{truncate(toTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.item.uncompleted" && toTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
marked checklist item <TextHighlight>{truncate(toTitle)}</TextHighlight>{" "}
|
||||
as incomplete
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
|
||||
if (type === "card.updated.checklist.item.deleted" && fromTitle) {
|
||||
return (
|
||||
<Trans>
|
||||
deleted checklist item{" "}
|
||||
<TextHighlight>{truncate(fromTitle)}</TextHighlight>
|
||||
</Trans>
|
||||
);
|
||||
}
|
||||
@@ -133,6 +221,14 @@ const ACTIVITY_ICON_MAP: Partial<Record<ActivityType, React.ReactNode | null>> =
|
||||
"card.updated.label.removed": <HiOutlineTag />,
|
||||
"card.updated.member.added": <HiOutlineUserPlus />,
|
||||
"card.updated.member.removed": <HiOutlineUserMinus />,
|
||||
"card.updated.checklist.added": <HiOutlinePlus />,
|
||||
"card.updated.checklist.renamed": <HiOutlinePencil />,
|
||||
"card.updated.checklist.deleted": <HiOutlineTrash />,
|
||||
"card.updated.checklist.item.added": <HiOutlinePlus />,
|
||||
"card.updated.checklist.item.updated": <HiOutlinePencil />,
|
||||
"card.updated.checklist.item.completed": <HiOutlineCheckCircle />,
|
||||
"card.updated.checklist.item.uncompleted": <HiOutlineCheckCircle />,
|
||||
"card.updated.checklist.item.deleted": <HiOutlineTrash />,
|
||||
} as const;
|
||||
|
||||
const getActivityIcon = (
|
||||
@@ -179,6 +275,7 @@ const ActivityList = ({
|
||||
memberName: activity.member?.user?.name ?? null,
|
||||
isSelf: activity.member?.user?.id === data?.user.id,
|
||||
label: activity.label?.name ?? null,
|
||||
fromTitle: activity.fromTitle ?? null,
|
||||
});
|
||||
|
||||
if (activity.type === "card.updated.comment.added")
|
||||
|
||||
197
apps/web/src/views/card/components/ChecklistItemRow.tsx
Normal file
197
apps/web/src/views/card/components/ChecklistItemRow.tsx
Normal file
@@ -0,0 +1,197 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect, useState } from "react";
|
||||
import ContentEditable from "react-contenteditable";
|
||||
import { HiXMark } from "react-icons/hi2";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
interface ChecklistItemRowProps {
|
||||
item: {
|
||||
publicId: string;
|
||||
title: string;
|
||||
completed: boolean;
|
||||
};
|
||||
cardPublicId: string;
|
||||
viewOnly?: boolean;
|
||||
}
|
||||
|
||||
export default function ChecklistItemRow({
|
||||
item,
|
||||
cardPublicId,
|
||||
viewOnly = false,
|
||||
}: ChecklistItemRowProps) {
|
||||
const utils = api.useUtils();
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const [title, setTitle] = useState("");
|
||||
const [completed, setCompleted] = useState(false);
|
||||
|
||||
const updateItem = api.checklist.updateItem.useMutation({
|
||||
onMutate: async (vars) => {
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const previous = utils.card.byId.getData({ cardPublicId });
|
||||
utils.card.byId.setData({ cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const updatedChecklists = old.checklists.map((cl) => ({
|
||||
...cl,
|
||||
items: cl.items.map((ci) =>
|
||||
ci.publicId === item.publicId
|
||||
? {
|
||||
...ci,
|
||||
...(vars.title !== undefined ? { title: vars.title } : {}),
|
||||
...(vars.completed !== undefined
|
||||
? { completed: vars.completed }
|
||||
: {}),
|
||||
}
|
||||
: ci,
|
||||
),
|
||||
}));
|
||||
return { ...old, checklists: updatedChecklists } as typeof old;
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData({ cardPublicId }, ctx.previous);
|
||||
showPopup({
|
||||
header: t`Unable to update checklist item`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async () => {
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
const deleteItem = api.checklist.deleteItem.useMutation({
|
||||
onMutate: async () => {
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const previous = utils.card.byId.getData({ cardPublicId });
|
||||
utils.card.byId.setData({ cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const updatedChecklists = old.checklists.map((cl) => ({
|
||||
...cl,
|
||||
items: cl.items.filter((ci) => ci.publicId !== item.publicId),
|
||||
}));
|
||||
return { ...old, checklists: updatedChecklists } as typeof old;
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData({ cardPublicId }, ctx.previous);
|
||||
showPopup({
|
||||
header: t`Unable to delete checklist item`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async () => {
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
// Only resync from props when switching items to avoid clobbering edits
|
||||
useEffect(() => {
|
||||
setTitle(item.title);
|
||||
setCompleted(item.completed);
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [item.publicId]);
|
||||
|
||||
const sanitizeHtmlToPlainText = (html: string): string =>
|
||||
html
|
||||
.replace(/<br\s*\/?>(\n)?/gi, "\n")
|
||||
.replace(/<div><br\s*\/?><\/div>/gi, "")
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/ /g, " ")
|
||||
.trim();
|
||||
|
||||
const handleToggleCompleted = () => {
|
||||
if (viewOnly) return;
|
||||
setCompleted((prev) => !prev);
|
||||
updateItem.mutate({
|
||||
checklistItemPublicId: item.publicId,
|
||||
completed: !completed,
|
||||
});
|
||||
};
|
||||
|
||||
const commitTitle = (rawHtml: string) => {
|
||||
if (viewOnly) return;
|
||||
const plain = sanitizeHtmlToPlainText(rawHtml);
|
||||
if (!plain || plain === item.title) {
|
||||
setTitle(item.title);
|
||||
return;
|
||||
}
|
||||
setTitle(plain);
|
||||
updateItem.mutate({
|
||||
checklistItemPublicId: item.publicId,
|
||||
title: plain,
|
||||
});
|
||||
};
|
||||
|
||||
const handleDelete = () => {
|
||||
if (viewOnly) return;
|
||||
deleteItem.mutate({ checklistItemPublicId: item.publicId });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="group relative flex items-start gap-3 rounded-md py-2 pl-4 hover:bg-light-100 dark:hover:bg-dark-100">
|
||||
<label
|
||||
className={`relative mt-[2px] inline-flex h-[16px] w-[16px] flex-shrink-0 items-center justify-center`}
|
||||
>
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={completed}
|
||||
onChange={(e) => {
|
||||
if (viewOnly) {
|
||||
e.preventDefault();
|
||||
return;
|
||||
}
|
||||
handleToggleCompleted();
|
||||
}}
|
||||
className={twMerge(
|
||||
"h-[16px] w-[16px] appearance-none rounded-md border border-light-500 bg-transparent outline-none ring-0 checked:bg-blue-600 focus:shadow-none focus:ring-0 focus:ring-offset-0 focus-visible:outline-none dark:border-dark-500 dark:hover:border-dark-500",
|
||||
viewOnly ? "cursor-default" : "cursor-pointer",
|
||||
)}
|
||||
/>
|
||||
</label>
|
||||
<div className="flex-1 pr-7">
|
||||
<ContentEditable
|
||||
html={title}
|
||||
disabled={viewOnly}
|
||||
onChange={(e) => setTitle(e.target.value)}
|
||||
// @ts-expect-error - valid event
|
||||
onBlur={(e: Event) => commitTitle(e.target.innerHTML as string)}
|
||||
className={twMerge(
|
||||
"m-0 min-h-[20px] w-full p-0 text-sm leading-[20px] text-light-950 outline-none focus-visible:outline-none dark:text-dark-950",
|
||||
viewOnly && "cursor-default",
|
||||
)}
|
||||
placeholder={t`Add details...`}
|
||||
onKeyDown={(e) => {
|
||||
if (viewOnly) return;
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
commitTitle(title);
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
setTitle(item.title);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
{!viewOnly && (
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleDelete}
|
||||
className="absolute right-1 top-1/2 hidden -translate-y-1/2 rounded-md p-1 text-light-900 group-hover:block hover:bg-light-200 dark:text-dark-700 dark:hover:bg-dark-200"
|
||||
>
|
||||
<HiXMark size={16} />
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
90
apps/web/src/views/card/components/ChecklistNameInput.tsx
Normal file
90
apps/web/src/views/card/components/ChecklistNameInput.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
export default function ChecklistNameInput({
|
||||
checklistPublicId,
|
||||
initialName,
|
||||
cardPublicId,
|
||||
viewOnly = false,
|
||||
}: {
|
||||
checklistPublicId: string;
|
||||
initialName: string;
|
||||
cardPublicId: string;
|
||||
viewOnly?: boolean;
|
||||
}) {
|
||||
const utils = api.useUtils();
|
||||
const { showPopup } = usePopup();
|
||||
const [name, setName] = useState(initialName);
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
setName(initialName);
|
||||
}, [initialName, checklistPublicId]);
|
||||
|
||||
const update = api.checklist.update.useMutation({
|
||||
onMutate: async (vars) => {
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const previous = utils.card.byId.getData({ cardPublicId });
|
||||
utils.card.byId.setData({ cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const updated = old.checklists.map((cl) =>
|
||||
cl.publicId === checklistPublicId ? { ...cl, name: vars.name } : cl,
|
||||
);
|
||||
return { ...old, checklists: updated } as typeof old;
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData({ cardPublicId }, ctx.previous);
|
||||
showPopup({
|
||||
header: t`Unable to update checklist`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async () => {
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
const commit = () => {
|
||||
if (viewOnly) return;
|
||||
const trimmed = name.trim();
|
||||
if (!trimmed || trimmed === initialName) return;
|
||||
update.mutate({ checklistPublicId, name: trimmed });
|
||||
};
|
||||
|
||||
return (
|
||||
<input
|
||||
ref={inputRef}
|
||||
type="text"
|
||||
value={name}
|
||||
readOnly={viewOnly}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onBlur={commit}
|
||||
onKeyDown={(e) => {
|
||||
if (viewOnly) return;
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
commit();
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
setName(initialName);
|
||||
inputRef.current?.blur();
|
||||
}
|
||||
}}
|
||||
title={name}
|
||||
className={twMerge(
|
||||
"text-md block w-full truncate border-0 bg-transparent p-0 py-0 font-medium text-light-1000 outline-none focus:ring-0 dark:text-dark-1000",
|
||||
viewOnly && "cursor-default",
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
142
apps/web/src/views/card/components/Checklists.tsx
Normal file
142
apps/web/src/views/card/components/Checklists.tsx
Normal file
@@ -0,0 +1,142 @@
|
||||
import { HiPlus, HiXMark } from "react-icons/hi2";
|
||||
|
||||
import CircularProgress from "~/components/CircularProgress";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import ChecklistItemRow from "./ChecklistItemRow";
|
||||
import ChecklistNameInput from "./ChecklistNameInput";
|
||||
import NewChecklistItemForm from "./NewChecklistItemForm";
|
||||
|
||||
interface ChecklistItem {
|
||||
publicId: string;
|
||||
title: string;
|
||||
completed: boolean;
|
||||
}
|
||||
|
||||
interface Checklist {
|
||||
publicId: string;
|
||||
name: string;
|
||||
items: ChecklistItem[];
|
||||
}
|
||||
|
||||
interface ChecklistsProps {
|
||||
checklists: Checklist[];
|
||||
cardPublicId: string;
|
||||
activeChecklistForm?: string | null;
|
||||
setActiveChecklistForm?: (id: string | null) => void;
|
||||
viewOnly?: boolean;
|
||||
}
|
||||
|
||||
export default function Checklists({
|
||||
checklists,
|
||||
cardPublicId,
|
||||
activeChecklistForm,
|
||||
setActiveChecklistForm,
|
||||
viewOnly = false,
|
||||
}: ChecklistsProps) {
|
||||
const { openModal } = useModal();
|
||||
|
||||
if (!checklists || checklists.length === 0) return null;
|
||||
|
||||
return (
|
||||
<div className="border-light-300 pb-4 dark:border-dark-300">
|
||||
<div>
|
||||
{checklists.map((checklist) => {
|
||||
const completedItems = checklist.items.filter(
|
||||
(item) => item.completed,
|
||||
);
|
||||
const progress =
|
||||
checklist.items.length > 0 && completedItems.length > 0
|
||||
? (completedItems.length / checklist.items.length) * 100
|
||||
: 2;
|
||||
|
||||
return (
|
||||
<div key={checklist.publicId} className="mb-4">
|
||||
<div className="mb-2 flex items-center font-medium text-light-1000 dark:text-dark-1000">
|
||||
<div className="min-w-0 flex-1">
|
||||
<ChecklistNameInput
|
||||
checklistPublicId={checklist.publicId}
|
||||
initialName={checklist.name}
|
||||
cardPublicId={cardPublicId}
|
||||
viewOnly={viewOnly}
|
||||
/>
|
||||
</div>
|
||||
{!viewOnly && (
|
||||
<div className="ml-2 flex flex-shrink-0 items-center gap-2">
|
||||
<div className="flex items-center gap-1 rounded-full border-[1px] border-light-300 px-2 py-1 dark:border-dark-300">
|
||||
<CircularProgress
|
||||
progress={progress}
|
||||
size="sm"
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
<span className="text-[11px] text-light-900 dark:text-dark-700">
|
||||
{completedItems.length}/{checklist.items.length}
|
||||
</span>
|
||||
</div>
|
||||
<div>
|
||||
<button
|
||||
className="rounded-md p-1 text-light-900 hover:bg-light-100 dark:text-dark-700 dark:hover:bg-dark-100"
|
||||
onClick={() =>
|
||||
openModal("DELETE_CHECKLIST", checklist.publicId)
|
||||
}
|
||||
>
|
||||
<HiXMark size={16} />
|
||||
</button>
|
||||
<button
|
||||
onClick={() =>
|
||||
setActiveChecklistForm?.(checklist.publicId)
|
||||
}
|
||||
className="rounded-md p-1 text-light-900 hover:bg-light-100 dark:text-dark-700 dark:hover:bg-dark-100"
|
||||
>
|
||||
<HiPlus size={16} />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{viewOnly && (
|
||||
<div className="ml-2 flex flex-shrink-0 items-center gap-2">
|
||||
<div className="flex items-center gap-1 rounded-full border-[1px] border-light-300 px-2 py-1 dark:border-dark-300">
|
||||
<CircularProgress
|
||||
progress={progress}
|
||||
size="sm"
|
||||
className="flex-shrink-0"
|
||||
/>
|
||||
<span className="text-[11px] text-light-900 dark:text-dark-700">
|
||||
{completedItems.length}/{checklist.items.length}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="ml-1">
|
||||
{checklist.items.map((item) => (
|
||||
<ChecklistItemRow
|
||||
key={item.publicId}
|
||||
item={{
|
||||
publicId: item.publicId,
|
||||
title: item.title,
|
||||
completed: item.completed,
|
||||
}}
|
||||
cardPublicId={cardPublicId}
|
||||
viewOnly={viewOnly}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{activeChecklistForm === checklist.publicId && !viewOnly && (
|
||||
<div className="ml-1">
|
||||
<NewChecklistItemForm
|
||||
checklistPublicId={checklist.publicId}
|
||||
cardPublicId={cardPublicId}
|
||||
onCancel={() => setActiveChecklistForm?.(null)}
|
||||
readOnly={viewOnly}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
export function DeleteChecklistConfirmation({
|
||||
cardPublicId,
|
||||
checklistPublicId,
|
||||
}: {
|
||||
cardPublicId: string;
|
||||
checklistPublicId: string;
|
||||
}) {
|
||||
const { closeModal } = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
const utils = api.useUtils();
|
||||
|
||||
const deleteChecklist = api.checklist.delete.useMutation({
|
||||
onMutate: async () => {
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const previous = utils.card.byId.getData({ cardPublicId });
|
||||
utils.card.byId.setData({ cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const updatedChecklists = old.checklists.filter(
|
||||
(cl) => cl.publicId !== checklistPublicId,
|
||||
);
|
||||
return { ...old, checklists: updatedChecklists } as typeof old;
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData({ cardPublicId }, ctx.previous);
|
||||
showPopup({
|
||||
header: t`Unable to delete checklist`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async () => {
|
||||
closeModal();
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
const handleDelete = () => {
|
||||
deleteChecklist.mutate({ checklistPublicId });
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium text-neutral-900 dark:text-dark-1000">
|
||||
{t`Are you sure you want to delete this checklist?`}
|
||||
</h2>
|
||||
<p className="text-sm font-medium text-light-900 dark:text-dark-900">
|
||||
{t`This action can't be undone.`}
|
||||
</p>
|
||||
</div>
|
||||
<div className="mt-5 flex justify-end space-x-2 sm:mt-6">
|
||||
<Button variant="secondary" onClick={() => closeModal()}>
|
||||
{t`Cancel`}
|
||||
</Button>
|
||||
<Button onClick={handleDelete} isLoading={deleteChecklist.isPending}>
|
||||
{t`Delete`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -1,5 +1,9 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { HiEllipsisHorizontal, HiOutlineTrash } from "react-icons/hi2";
|
||||
import {
|
||||
HiEllipsisHorizontal,
|
||||
HiOutlineCheckCircle,
|
||||
HiOutlineTrash,
|
||||
} from "react-icons/hi2";
|
||||
|
||||
import Dropdown from "~/components/Dropdown";
|
||||
import { useModal } from "~/providers/modal";
|
||||
@@ -10,6 +14,13 @@ export default function BoardDropdown() {
|
||||
return (
|
||||
<Dropdown
|
||||
items={[
|
||||
{
|
||||
label: t`Add checklist`,
|
||||
action: () => openModal("ADD_CHECKLIST"),
|
||||
icon: (
|
||||
<HiOutlineCheckCircle className="h-[16px] w-[16px] text-dark-900" />
|
||||
),
|
||||
},
|
||||
{
|
||||
label: t`Delete card`,
|
||||
action: () => openModal("DELETE_CARD"),
|
||||
|
||||
140
apps/web/src/views/card/components/NewChecklistForm.tsx
Normal file
140
apps/web/src/views/card/components/NewChecklistForm.tsx
Normal file
@@ -0,0 +1,140 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { HiXMark } from "react-icons/hi2";
|
||||
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import Input from "~/components/Input";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
interface NewChecklistFormInput {
|
||||
name: string;
|
||||
cardPublicId: string;
|
||||
}
|
||||
|
||||
export function NewChecklistForm({ cardPublicId }: { cardPublicId: string }) {
|
||||
const { closeModal, setModalState } = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const utils = api.useUtils();
|
||||
|
||||
const { register, handleSubmit, reset, watch } =
|
||||
useForm<NewChecklistFormInput>({
|
||||
defaultValues: {
|
||||
name: "Checklist",
|
||||
cardPublicId,
|
||||
},
|
||||
});
|
||||
|
||||
const createChecklist = api.checklist.create.useMutation({
|
||||
onMutate: async (args) => {
|
||||
await utils.card.byId.cancel({ cardPublicId: args.cardPublicId });
|
||||
const previous = utils.card.byId.getData({
|
||||
cardPublicId: args.cardPublicId,
|
||||
});
|
||||
utils.card.byId.setData({ cardPublicId: args.cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const placeholderChecklist = {
|
||||
publicId: `PLACEHOLDER_${generateUID()}`,
|
||||
name: args.name,
|
||||
index: old.checklists.length,
|
||||
items: [] as {
|
||||
publicId: string;
|
||||
title: string;
|
||||
completed: boolean;
|
||||
index: number;
|
||||
}[],
|
||||
};
|
||||
return {
|
||||
...old,
|
||||
checklists: [...old.checklists, placeholderChecklist],
|
||||
} as typeof old;
|
||||
});
|
||||
return { previous };
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
setModalState("ADD_CHECKLIST", { createdChecklistId: data.publicId });
|
||||
},
|
||||
onError: (_error, vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData(
|
||||
{ cardPublicId: vars.cardPublicId },
|
||||
ctx.previous,
|
||||
);
|
||||
showPopup({
|
||||
header: t`Unable to create checklist`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async (_data, _error, vars) => {
|
||||
await utils.card.byId.invalidate({ cardPublicId: vars.cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const nameElement: HTMLElement | null =
|
||||
document.querySelector<HTMLElement>("#checklist-name");
|
||||
if (nameElement) nameElement.focus();
|
||||
}, []);
|
||||
|
||||
const onSubmit = (data: NewChecklistFormInput) => {
|
||||
closeModal();
|
||||
reset({
|
||||
name: "",
|
||||
});
|
||||
|
||||
createChecklist.mutate({
|
||||
name: data.name,
|
||||
cardPublicId: data.cardPublicId,
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="px-5 pt-5">
|
||||
<div className="flex w-full items-center justify-between pb-4">
|
||||
<h2 className="text-sm font-bold text-neutral-900 dark:text-dark-1000">
|
||||
{t`New checklist`}
|
||||
</h2>
|
||||
<button
|
||||
type="button"
|
||||
className="rounded p-1 hover:bg-light-200 focus:outline-none dark:hover:bg-dark-300"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
closeModal();
|
||||
}}
|
||||
>
|
||||
<HiXMark size={18} className="text-light-900 dark:text-dark-900" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<Input
|
||||
id="checklist-name"
|
||||
placeholder={t`Checklist name`}
|
||||
{...register("name")}
|
||||
onKeyDown={async (e) => {
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
await handleSubmit(onSubmit)();
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-12 flex items-center justify-end border-t border-light-600 px-5 pb-5 pt-5 dark:border-dark-600">
|
||||
<div>
|
||||
<Button
|
||||
type="submit"
|
||||
disabled={createChecklist.isPending || !watch("name")}
|
||||
>
|
||||
{t`Create checklist`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
167
apps/web/src/views/card/components/NewChecklistItemForm.tsx
Normal file
167
apps/web/src/views/card/components/NewChecklistItemForm.tsx
Normal file
@@ -0,0 +1,167 @@
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect, useRef } from "react";
|
||||
import ContentEditable from "react-contenteditable";
|
||||
import { useForm } from "react-hook-form";
|
||||
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
interface FormValues {
|
||||
title: string;
|
||||
}
|
||||
|
||||
interface NewChecklistItemFormProps {
|
||||
checklistPublicId: string;
|
||||
cardPublicId: string;
|
||||
onCancel: () => void;
|
||||
readOnly?: boolean;
|
||||
}
|
||||
|
||||
const NewChecklistItemForm = ({
|
||||
checklistPublicId,
|
||||
cardPublicId,
|
||||
onCancel,
|
||||
readOnly = false,
|
||||
}: NewChecklistItemFormProps) => {
|
||||
const utils = api.useUtils();
|
||||
const { showPopup } = usePopup();
|
||||
|
||||
const { setValue, watch, reset, getValues } = useForm<FormValues>({
|
||||
defaultValues: {
|
||||
title: "",
|
||||
},
|
||||
});
|
||||
|
||||
const title = watch("title");
|
||||
|
||||
const editableRef = useRef<HTMLElement | null>(null);
|
||||
const keepOpenRef = useRef(false);
|
||||
|
||||
const refocusEditable = () => {
|
||||
const el = editableRef.current;
|
||||
if (!el) return;
|
||||
if (readOnly) return;
|
||||
el.focus();
|
||||
|
||||
// hack to ensure the input is focused after creating new checklist item
|
||||
setTimeout(() => {
|
||||
el.focus();
|
||||
}, 100);
|
||||
};
|
||||
|
||||
const addChecklistItemMutation = api.checklist.createItem.useMutation({
|
||||
onMutate: async (vars) => {
|
||||
await utils.card.byId.cancel({ cardPublicId });
|
||||
const previous = utils.card.byId.getData({ cardPublicId });
|
||||
|
||||
utils.card.byId.setData({ cardPublicId }, (old) => {
|
||||
if (!old) return old as any;
|
||||
const placeholder = {
|
||||
publicId: `PLACEHOLDER_${generateUID()}`,
|
||||
title: vars.title,
|
||||
completed: false,
|
||||
};
|
||||
const updatedChecklists = old.checklists.map((cl) =>
|
||||
cl.publicId === checklistPublicId
|
||||
? { ...cl, items: [...cl.items, placeholder] }
|
||||
: cl,
|
||||
);
|
||||
return { ...old, checklists: updatedChecklists } as typeof old;
|
||||
});
|
||||
|
||||
if (keepOpenRef.current) {
|
||||
reset({ title: "" });
|
||||
if (editableRef.current) editableRef.current.innerHTML = "";
|
||||
refocusEditable();
|
||||
} else {
|
||||
onCancel();
|
||||
}
|
||||
|
||||
return { previous };
|
||||
},
|
||||
onError: (_err, _vars, ctx) => {
|
||||
if (ctx?.previous)
|
||||
utils.card.byId.setData({ cardPublicId }, ctx.previous);
|
||||
showPopup({
|
||||
header: t`Unable to add checklist item`,
|
||||
message: t`Please try again later, or contact customer support.`,
|
||||
icon: "error",
|
||||
});
|
||||
},
|
||||
onSettled: async () => {
|
||||
await utils.card.byId.invalidate({ cardPublicId });
|
||||
},
|
||||
});
|
||||
|
||||
const sanitizeHtmlToPlainText = (html: string): string => {
|
||||
return html
|
||||
.replace(/<br\s*\/?>(\n)?/gi, "\n")
|
||||
.replace(/<div><br\s*\/?><\/div>/gi, "")
|
||||
.replace(/<[^>]*>/g, "")
|
||||
.replace(/ /g, " ")
|
||||
.trim();
|
||||
};
|
||||
|
||||
const submitIfNotEmpty = (keepOpen: boolean) => {
|
||||
if (readOnly) return;
|
||||
keepOpenRef.current = keepOpen;
|
||||
const currentHtml = getValues("title") ?? "";
|
||||
const plain = sanitizeHtmlToPlainText(currentHtml);
|
||||
if (!plain) {
|
||||
onCancel();
|
||||
return;
|
||||
}
|
||||
addChecklistItemMutation.mutate({
|
||||
checklistPublicId,
|
||||
title: plain,
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
refocusEditable();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<form onSubmit={(e) => e.preventDefault()}>
|
||||
<div className="group relative flex h-9 items-center gap-3 rounded-md pl-4 hover:bg-light-100 dark:hover:bg-dark-100">
|
||||
<label className="relative inline-flex h-[16px] w-[16px] flex-shrink-0 cursor-default items-center justify-center">
|
||||
<input
|
||||
type="checkbox"
|
||||
disabled
|
||||
className="peer h-[16px] w-[16px] appearance-none rounded-md border border-light-500 bg-transparent outline-none ring-0 hover:border-light-500 hover:bg-transparent focus:outline-none focus:ring-0 focus-visible:outline-none dark:border-dark-500 dark:hover:border-dark-500"
|
||||
/>
|
||||
</label>
|
||||
<div className="flex-1 pr-7">
|
||||
<ContentEditable
|
||||
id={`checklist-item-input-${checklistPublicId}`}
|
||||
tabIndex={readOnly ? -1 : 0}
|
||||
placeholder={t`Add an item...`}
|
||||
html={title}
|
||||
disabled={readOnly}
|
||||
onChange={(e) => setValue("title", e.target.value)}
|
||||
className="m-0 min-h-[20px] w-full p-0 text-sm leading-5 text-light-900 outline-none focus-visible:outline-none dark:text-dark-950"
|
||||
onBlur={() => submitIfNotEmpty(false)}
|
||||
onKeyDown={async (e) => {
|
||||
if (readOnly) return;
|
||||
if (e.key === "Enter") {
|
||||
e.preventDefault();
|
||||
submitIfNotEmpty(true);
|
||||
}
|
||||
if (e.key === "Escape") {
|
||||
e.preventDefault();
|
||||
onCancel();
|
||||
}
|
||||
}}
|
||||
innerRef={(el) => {
|
||||
editableRef.current = (el as unknown as HTMLElement) ?? null;
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
export default NewChecklistItemForm;
|
||||
@@ -1,6 +1,7 @@
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useEffect, useState } from "react";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { IoChevronForwardSharp } from "react-icons/io5";
|
||||
|
||||
@@ -19,12 +20,15 @@ import { api } from "~/utils/api";
|
||||
import { formatMemberDisplayName, getAvatarUrl } from "~/utils/helpers";
|
||||
import { DeleteLabelConfirmation } from "../../components/DeleteLabelConfirmation";
|
||||
import ActivityList from "./components/ActivityList";
|
||||
import Checklists from "./components/Checklists";
|
||||
import { DeleteCardConfirmation } from "./components/DeleteCardConfirmation";
|
||||
import { DeleteChecklistConfirmation } from "./components/DeleteChecklistConfirmation";
|
||||
import { DeleteCommentConfirmation } from "./components/DeleteCommentConfirmation";
|
||||
import Dropdown from "./components/Dropdown";
|
||||
import LabelSelector from "./components/LabelSelector";
|
||||
import ListSelector from "./components/ListSelector";
|
||||
import MemberSelector from "./components/MemberSelector";
|
||||
import { NewChecklistForm } from "./components/NewChecklistForm";
|
||||
import NewCommentForm from "./components/NewCommentForm";
|
||||
|
||||
interface FormValues {
|
||||
@@ -132,9 +136,19 @@ export function CardRightPanel() {
|
||||
export default function CardPage() {
|
||||
const router = useRouter();
|
||||
const utils = api.useUtils();
|
||||
const { modalContentType, entityId } = useModal();
|
||||
const {
|
||||
modalContentType,
|
||||
entityId,
|
||||
openModal,
|
||||
getModalState,
|
||||
clearModalState,
|
||||
isOpen,
|
||||
} = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
const { workspace } = useWorkspace();
|
||||
const [activeChecklistForm, setActiveChecklistForm] = useState<string | null>(
|
||||
null,
|
||||
);
|
||||
|
||||
const cardId = Array.isArray(router.query.cardId)
|
||||
? router.query.cardId[0]
|
||||
@@ -181,6 +195,17 @@ export default function CardPage() {
|
||||
});
|
||||
};
|
||||
|
||||
// Open the new item form after creating a new checklist
|
||||
useEffect(() => {
|
||||
if (!card) return;
|
||||
const state = getModalState("ADD_CHECKLIST");
|
||||
const createdId: string | undefined = state?.createdChecklistId;
|
||||
if (createdId) {
|
||||
setActiveChecklistForm(createdId);
|
||||
clearModalState("ADD_CHECKLIST");
|
||||
}
|
||||
}, [card, getModalState, clearModalState]);
|
||||
|
||||
if (!cardId) return <></>;
|
||||
|
||||
return (
|
||||
@@ -188,122 +213,179 @@ export default function CardPage() {
|
||||
<PageHead
|
||||
title={t`${card?.title ?? "Card"} | ${board?.name ?? "Board"}`}
|
||||
/>
|
||||
<div className="flex h-full flex-1 flex-row">
|
||||
<div className="m-auto flex h-full w-full max-w-[800px] flex-col overflow-hidden">
|
||||
<div className="h-full max-h-[calc(100dvh-3rem)] overflow-y-auto p-6 md:max-h-[calc(100dvh-4rem)] md:p-8">
|
||||
<div className="mb-8 flex w-full items-center justify-between md:mt-6">
|
||||
{!card && isLoading && (
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
<div className="h-[2.3rem] w-[300px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
</div>
|
||||
)}
|
||||
<div className="flex h-full flex-1 flex-row overflow-hidden">
|
||||
<div className="scrollbar-thumb-rounded-[4px] scrollbar-track-rounded-[4px] w-full flex-1 overflow-y-auto scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 hover:scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300 dark:hover:scrollbar-thumb-dark-300">
|
||||
<div className="p-auto mx-auto flex h-full w-full max-w-[800px] flex-col">
|
||||
<div className="p-6 md:p-8">
|
||||
<div className="mb-8 flex w-full items-center justify-between md:mt-6">
|
||||
{!card && isLoading && (
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
<div className="h-[2.3rem] w-[300px] animate-pulse rounded-[5px] bg-light-300 dark:bg-dark-300" />
|
||||
</div>
|
||||
)}
|
||||
{card && (
|
||||
<>
|
||||
<Link
|
||||
className="whitespace-nowrap font-bold leading-[2.3rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1.2rem]"
|
||||
href={`/boards/${board?.publicId}`}
|
||||
>
|
||||
{board?.name}
|
||||
</Link>
|
||||
<IoChevronForwardSharp
|
||||
size={18}
|
||||
className="mx-2 text-light-900 dark:text-dark-900"
|
||||
/>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
{...register("title")}
|
||||
onBlur={handleSubmit(onSubmit)}
|
||||
className="block w-full border-0 bg-transparent p-0 py-0 font-bold tracking-tight text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex">
|
||||
<Dropdown />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!card && !isLoading && (
|
||||
<p className="block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
|
||||
{t`Card not found`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{card && (
|
||||
<>
|
||||
<Link
|
||||
className="whitespace-nowrap font-bold leading-[2.3rem] tracking-tight text-light-900 dark:text-dark-900 sm:text-[1.2rem]"
|
||||
href={`/boards/${board?.publicId}`}
|
||||
>
|
||||
{board?.name}
|
||||
</Link>
|
||||
<IoChevronForwardSharp
|
||||
size={18}
|
||||
className="mx-2 text-light-900 dark:text-dark-900"
|
||||
<div className="mb-10 flex w-full max-w-2xl flex-col justify-between">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div className="mt-2">
|
||||
<Editor
|
||||
content={card.description}
|
||||
onChange={(e) => setValue("description", e)}
|
||||
onBlur={() => handleSubmit(onSubmit)()}
|
||||
workspaceMembers={board?.workspace.members ?? []}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<Checklists
|
||||
checklists={card.checklists}
|
||||
cardPublicId={cardId}
|
||||
activeChecklistForm={activeChecklistForm}
|
||||
setActiveChecklistForm={setActiveChecklistForm}
|
||||
/>
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div className="border-t-[1px] border-light-300 pt-12 dark:border-dark-300">
|
||||
<h2 className="text-md pb-4 font-medium text-light-1000 dark:text-dark-1000">
|
||||
{t`Activity`}
|
||||
</h2>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
id="title"
|
||||
{...register("title")}
|
||||
onBlur={handleSubmit(onSubmit)}
|
||||
className="block w-full border-0 bg-transparent p-0 py-0 font-bold tracking-tight text-neutral-900 focus:ring-0 dark:text-dark-1000 sm:text-[1.2rem]"
|
||||
<ActivityList
|
||||
cardPublicId={cardId}
|
||||
activities={activities ?? []}
|
||||
isLoading={!card}
|
||||
isAdmin={workspace.role === "admin"}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
<div className="flex">
|
||||
<Dropdown />
|
||||
<div className="mt-6">
|
||||
<NewCommentForm cardPublicId={cardId} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!card && !isLoading && (
|
||||
<p className="block p-0 py-0 font-bold leading-[2.3rem] tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
|
||||
{t`Card not found`}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
{card && (
|
||||
<>
|
||||
<div className="mb-10 flex w-full max-w-2xl flex-col justify-between">
|
||||
<form
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
className="w-full space-y-6"
|
||||
>
|
||||
<div className="mt-2">
|
||||
<Editor
|
||||
content={card.description}
|
||||
onChange={(e) => setValue("description", e)}
|
||||
onBlur={() => handleSubmit(onSubmit)()}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div className="border-t-[1px] border-light-300 pt-12 dark:border-dark-300">
|
||||
<h2 className="text-md pb-4 font-medium text-light-900 dark:text-dark-1000">
|
||||
{t`Activity`}
|
||||
</h2>
|
||||
<div>
|
||||
<ActivityList
|
||||
cardPublicId={cardId}
|
||||
activities={activities ?? []}
|
||||
isLoading={!card}
|
||||
isAdmin={workspace.role === "admin"}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6">
|
||||
<NewCommentForm cardPublicId={cardId} />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal modalSize={modalContentType === "NEW_FEEDBACK" ? "md" : "sm"}>
|
||||
{modalContentType === "NEW_FEEDBACK" && <FeedbackModal />}
|
||||
{modalContentType === "NEW_LABEL" && (
|
||||
<>
|
||||
<Modal
|
||||
modalSize="md"
|
||||
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
|
||||
>
|
||||
<FeedbackModal />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_LABEL"}
|
||||
>
|
||||
<LabelForm boardPublicId={boardId ?? ""} refetch={refetchCard} />
|
||||
)}
|
||||
{modalContentType === "EDIT_LABEL" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "EDIT_LABEL"}
|
||||
>
|
||||
<LabelForm
|
||||
boardPublicId={boardId ?? ""}
|
||||
refetch={refetchCard}
|
||||
isEdit
|
||||
/>
|
||||
)}
|
||||
{modalContentType === "DELETE_LABEL" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_LABEL"}
|
||||
>
|
||||
<DeleteLabelConfirmation
|
||||
refetch={refetchCard}
|
||||
labelPublicId={entityId}
|
||||
/>
|
||||
)}
|
||||
{modalContentType === "DELETE_CARD" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_CARD"}
|
||||
>
|
||||
<DeleteCardConfirmation
|
||||
boardPublicId={boardId ?? ""}
|
||||
cardPublicId={cardId}
|
||||
/>
|
||||
)}
|
||||
{modalContentType === "DELETE_COMMENT" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_COMMENT"}
|
||||
>
|
||||
<DeleteCommentConfirmation
|
||||
cardPublicId={cardId}
|
||||
commentPublicId={entityId}
|
||||
/>
|
||||
)}
|
||||
{modalContentType === "NEW_WORKSPACE" && <NewWorkspaceForm />}
|
||||
</Modal>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
|
||||
>
|
||||
<NewWorkspaceForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "ADD_CHECKLIST"}
|
||||
>
|
||||
<NewChecklistForm cardPublicId={cardId} />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_CHECKLIST"}
|
||||
>
|
||||
<DeleteChecklistConfirmation
|
||||
cardPublicId={cardId}
|
||||
checklistPublicId={entityId}
|
||||
/>
|
||||
</Modal>
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -1,17 +1,17 @@
|
||||
import PatternedBackground from "~/components/PatternedBackground";
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
import Footer from "./Footer";
|
||||
import Header from "./Header";
|
||||
import { authClient } from "@kan/auth/client";
|
||||
|
||||
export default function Layout({ children }: { children: React.ReactNode }) {
|
||||
const theme = useTheme();
|
||||
const { theme } = useTheme();
|
||||
|
||||
const { data: session } = authClient.useSession();
|
||||
|
||||
const isLoggedIn = !!session?.user;
|
||||
|
||||
const isDarkMode = theme.activeTheme === "dark";
|
||||
const isDarkMode = theme === "dark";
|
||||
|
||||
return (
|
||||
<>
|
||||
|
||||
@@ -6,7 +6,7 @@ import { IoLogoGithub, IoLogoHackernews } from "react-icons/io";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import { PageHead } from "~/components/PageHead";
|
||||
import { useTheme } from "~/providers/theme";
|
||||
import { useTheme } from "next-themes";
|
||||
import Cta from "./components/Cta";
|
||||
import FAQs from "./components/Faqs";
|
||||
import Features from "./components/Features";
|
||||
@@ -14,9 +14,10 @@ import Layout from "./components/Layout";
|
||||
import Pricing from "./components/Pricing";
|
||||
|
||||
export default function HomeView() {
|
||||
const theme = useTheme();
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const isDarkMode = resolvedTheme === "dark";
|
||||
|
||||
const isDarkMode = theme.activeTheme === "dark";
|
||||
return (
|
||||
<Layout>
|
||||
<PageHead title="Kan.bn | The open source alternative to Trello" />
|
||||
@@ -88,19 +89,27 @@ export default function HomeView() {
|
||||
</div>
|
||||
<div className="px-4">
|
||||
<div className="mb-24 rounded-[16px] border border-light-300 bg-light-50 p-1 shadow-md dark:border-dark-300 dark:bg-dark-100 lg:rounded-[24px] lg:p-2">
|
||||
<div className="overflow-hidden rounded-[12px] border border-light-300 shadow-sm dark:border-dark-300 lg:rounded-[16px]">
|
||||
<div className="relative overflow-hidden rounded-[12px] border border-light-300 shadow-sm dark:border-dark-300 lg:rounded-[16px]">
|
||||
<Image
|
||||
src={`/hero-${isDarkMode ? "dark" : "light"}.png`}
|
||||
src={`/hero-light.png`}
|
||||
alt="kanban"
|
||||
width={1100}
|
||||
height={1000}
|
||||
className="block dark:hidden"
|
||||
/>
|
||||
<Image
|
||||
src={`/hero-dark.png`}
|
||||
alt="kanban"
|
||||
width={1100}
|
||||
height={1000}
|
||||
className="hidden dark:block"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="relative pt-10">
|
||||
<div id="features" className="absolute -top-20" />
|
||||
<Features theme={theme.activeTheme} />
|
||||
<Features theme={resolvedTheme === "dark" ? "dark" : "light"} />
|
||||
</div>
|
||||
<div className="relative pt-10">
|
||||
<div id="pricing" className="absolute -top-20" />
|
||||
@@ -111,7 +120,7 @@ export default function HomeView() {
|
||||
<FAQs />
|
||||
</div>
|
||||
<div className="relative">
|
||||
<Cta theme={theme.activeTheme} />
|
||||
<Cta theme={resolvedTheme ?? "light"} />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
@@ -19,7 +19,7 @@ import { DeleteMemberConfirmation } from "./components/DeleteMemberConfirmation"
|
||||
import { InviteMemberForm } from "./components/InviteMemberForm";
|
||||
|
||||
export default function MembersPage() {
|
||||
const { modalContentType, openModal } = useModal();
|
||||
const { modalContentType, openModal, isOpen } = useModal();
|
||||
const { workspace } = useWorkspace();
|
||||
|
||||
const { data, isLoading } = api.workspace.byId.useQuery(
|
||||
@@ -222,12 +222,35 @@ export default function MembersPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal modalSize={modalContentType === "NEW_FEEDBACK" ? "md" : "sm"}>
|
||||
{modalContentType === "NEW_FEEDBACK" && <FeedbackModal />}
|
||||
{modalContentType === "NEW_WORKSPACE" && <NewWorkspaceForm />}
|
||||
{modalContentType === "INVITE_MEMBER" && <InviteMemberForm />}
|
||||
{modalContentType === "REMOVE_MEMBER" && <DeleteMemberConfirmation />}
|
||||
</Modal>
|
||||
<>
|
||||
<Modal
|
||||
modalSize="md"
|
||||
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
|
||||
>
|
||||
<FeedbackModal />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
|
||||
>
|
||||
<NewWorkspaceForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "INVITE_MEMBER"}
|
||||
>
|
||||
<InviteMemberForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "REMOVE_MEMBER"}
|
||||
>
|
||||
<DeleteMemberConfirmation />
|
||||
</Modal>
|
||||
</>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -9,6 +9,7 @@ import LabelIcon from "~/components/LabelIcon";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { api } from "~/utils/api";
|
||||
import ActivityList from "~/views/card/components/ActivityList";
|
||||
import Checklists from "~/views/card/components/Checklists";
|
||||
|
||||
export function CardModal({
|
||||
cardPublicId,
|
||||
@@ -68,17 +69,20 @@ export function CardModal({
|
||||
onClick={async (e) => {
|
||||
e.preventDefault();
|
||||
closeModal();
|
||||
try {
|
||||
await router.replace(
|
||||
`/${workspaceSlug}/${boardSlug}`,
|
||||
undefined,
|
||||
{
|
||||
shallow: true,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
|
||||
setTimeout(async () => {
|
||||
try {
|
||||
await router.replace(
|
||||
`/${workspaceSlug}/${boardSlug}`,
|
||||
undefined,
|
||||
{
|
||||
shallow: true,
|
||||
},
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}, 400);
|
||||
}}
|
||||
>
|
||||
<HiXMark
|
||||
@@ -119,10 +123,21 @@ export function CardModal({
|
||||
{data?.description && (
|
||||
<div className="mb-10 flex w-full max-w-2xl justify-between">
|
||||
<div className="mt-2">
|
||||
<Editor content={data.description} readOnly />
|
||||
<Editor
|
||||
content={data.description}
|
||||
readOnly
|
||||
workspaceMembers={data?.list.board.workspace.members ?? []}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{data?.checklists && data.checklists.length > 0 && (
|
||||
<Checklists
|
||||
checklists={data.checklists}
|
||||
cardPublicId={cardPublicId ?? ""}
|
||||
viewOnly
|
||||
/>
|
||||
)}
|
||||
<div className="border-t-[1px] border-light-600 pb-4 pt-12 dark:border-dark-400">
|
||||
<h2 className="text-md pb-4 font-medium text-light-900 dark:text-dark-1000">
|
||||
{t`Activity`}
|
||||
|
||||
@@ -2,6 +2,7 @@ import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { keepPreviousData } from "@tanstack/react-query";
|
||||
import { env } from "next-runtime-env";
|
||||
import { useEffect, useState } from "react";
|
||||
import { HiLink, HiOutlineLockClosed } from "react-icons/hi2";
|
||||
|
||||
@@ -19,6 +20,10 @@ import Card from "~/views/board/components/Card";
|
||||
import Filters from "~/views/board/components/Filters";
|
||||
import { CardModal } from "./CardModal";
|
||||
|
||||
const IS_CLOUD = env("NEXT_PUBLIC_KAN_ENV") === "cloud";
|
||||
const HIDE_POWERED_BY =
|
||||
env("NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY") === "true";
|
||||
|
||||
export default function PublicBoardView() {
|
||||
const router = useRouter();
|
||||
const { showPopup } = usePopup();
|
||||
@@ -40,7 +45,7 @@ export default function PublicBoardView() {
|
||||
members: formatToArray(router.query.members),
|
||||
labels: formatToArray(router.query.labels),
|
||||
},
|
||||
{ enabled: !!boardSlug, placeholderData: keepPreviousData },
|
||||
{ enabled: router.isReady && !!boardSlug, placeholderData: keepPreviousData },
|
||||
);
|
||||
|
||||
const CopyBoardLink = () => {
|
||||
@@ -102,7 +107,7 @@ export default function PublicBoardView() {
|
||||
<div className="relative h-full overflow-hidden rounded-md border pb-8 dark:border-dark-200">
|
||||
<PatternedBackground />
|
||||
<div className="z-10 flex w-full justify-between p-8">
|
||||
{isLoading ? (
|
||||
{isLoading || !router.isReady ? (
|
||||
<div className="flex space-x-2">
|
||||
<div className="h-[2.3rem] w-[150px] animate-pulse rounded-[5px] bg-light-200 dark:bg-dark-100" />
|
||||
</div>
|
||||
@@ -129,13 +134,13 @@ export default function PublicBoardView() {
|
||||
</div>
|
||||
|
||||
<div className="scrollbar-w-none scrollbar-track-rounded-[4px] scrollbar-thumb-rounded-[4px] scrollbar-h-[8px] relative h-full flex-1 overflow-y-hidden overflow-x-scroll overscroll-contain scrollbar scrollbar-track-light-200 scrollbar-thumb-light-400 dark:scrollbar-track-dark-100 dark:scrollbar-thumb-dark-300">
|
||||
{isLoading ? (
|
||||
{isLoading || !router.isReady ? (
|
||||
<div className="ml-[2rem] flex">
|
||||
<div className="0 mr-5 h-[500px] w-[18rem] animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
|
||||
<div className="0 mr-5 h-[275px] w-[18rem] animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
|
||||
<div className="0 mr-5 h-[375px] w-[18rem] animate-pulse rounded-md bg-light-200 dark:bg-dark-100" />
|
||||
</div>
|
||||
) : !data ? (
|
||||
) : !data && !isLoading && router.isReady && !!boardSlug ? (
|
||||
<div className="z-10 flex h-full w-full flex-col items-center justify-center space-y-8 pb-[150px]">
|
||||
<div className="flex flex-col items-center">
|
||||
<HiOutlineLockClosed className="h-10 w-10 text-light-800 dark:text-dark-800" />
|
||||
@@ -175,6 +180,7 @@ export default function PublicBoardView() {
|
||||
<Card
|
||||
title={card.title}
|
||||
labels={card.labels}
|
||||
checklists={card.checklists ?? []}
|
||||
members={[]}
|
||||
/>
|
||||
</Link>
|
||||
@@ -193,12 +199,26 @@ export default function PublicBoardView() {
|
||||
<CopyBoardLink />
|
||||
</div>
|
||||
|
||||
<Link
|
||||
className="text-lg font-bold tracking-tight text-neutral-900 dark:text-dark-1000"
|
||||
href="/"
|
||||
>
|
||||
kan.bn
|
||||
</Link>
|
||||
{IS_CLOUD && (
|
||||
<Link
|
||||
className="text-lg font-bold tracking-tight text-neutral-900 dark:text-dark-1000"
|
||||
href="/"
|
||||
>
|
||||
kan.bn
|
||||
</Link>
|
||||
)}
|
||||
|
||||
{!IS_CLOUD && !HIDE_POWERED_BY && (
|
||||
<a
|
||||
href="https://kan.bn"
|
||||
target="_blank"
|
||||
rel="noreferrer noopener"
|
||||
className="absolute right-[1rem] inline-flex items-center gap-[0.175rem] rounded-full border border-light-300 bg-light-50 px-3 py-1 text-[11px] font-medium text-light-950 shadow-sm transition-colors hover:bg-light-100 dark:border-dark-300 dark:bg-dark-50 dark:text-dark-900 dark:hover:bg-dark-100"
|
||||
>
|
||||
<span>{`Powered by`}</span>
|
||||
<span className="font-semibold">kan.bn</span>
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<Popup />
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
import { useRouter } from "next/navigation";
|
||||
import { zodResolver } from "@hookform/resolvers/zod";
|
||||
import { t } from "@lingui/core/macro";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import { env } from "next-runtime-env";
|
||||
import { useForm } from "react-hook-form";
|
||||
import { z } from "zod";
|
||||
|
||||
import { authClient } from "@kan/auth/client";
|
||||
|
||||
import Button from "~/components/Button";
|
||||
import Input from "~/components/Input";
|
||||
import { useModal } from "~/providers/modal";
|
||||
import { usePopup } from "~/providers/popup";
|
||||
import { api } from "~/utils/api";
|
||||
|
||||
const FormSchema = z
|
||||
.object({
|
||||
currentPassword: z.string().min(1, t`Current password is required`),
|
||||
newPassword: z
|
||||
.string()
|
||||
.min(8, t`Password must be at least 8 characters`)
|
||||
.min(1, t`New password is required`),
|
||||
confirmPassword: z.string().min(1, t`Please confirm your new password`),
|
||||
})
|
||||
.refine((data) => data.newPassword === data.confirmPassword, {
|
||||
message: t`Passwords do not match`,
|
||||
path: ["confirmPassword"],
|
||||
})
|
||||
.refine((data) => data.currentPassword !== data.newPassword, {
|
||||
message: t`New password must be different from current password`,
|
||||
path: ["newPassword"],
|
||||
});
|
||||
|
||||
type FormValues = z.infer<typeof FormSchema>;
|
||||
|
||||
export function ChangePasswordFormConfirmation() {
|
||||
const { closeModal } = useModal();
|
||||
const { showPopup } = usePopup();
|
||||
const router = useRouter();
|
||||
const utils = api.useUtils();
|
||||
|
||||
const {
|
||||
register,
|
||||
handleSubmit,
|
||||
formState: { errors, isValid },
|
||||
reset,
|
||||
setError,
|
||||
} = useForm<FormValues>({
|
||||
resolver: zodResolver(FormSchema),
|
||||
mode: "onChange",
|
||||
});
|
||||
|
||||
const changePasswordMutation = useMutation({
|
||||
mutationFn: async (data: FormValues) => {
|
||||
const response = await authClient.changePassword({
|
||||
newPassword: data.newPassword,
|
||||
currentPassword: data.currentPassword,
|
||||
revokeOtherSessions: true,
|
||||
});
|
||||
|
||||
if (response?.error) {
|
||||
throw new Error(response?.error.message || "Invalid Password");
|
||||
}
|
||||
},
|
||||
onSuccess: async () => {
|
||||
closeModal();
|
||||
showPopup({
|
||||
header: t`Password Changed`,
|
||||
message: t`Your password has been changed.`,
|
||||
icon: "success",
|
||||
});
|
||||
|
||||
utils.invalidate();
|
||||
reset();
|
||||
router.push("/");
|
||||
},
|
||||
onError: async (error: any) => {
|
||||
const errorMessage = error.message.toLowerCase();
|
||||
|
||||
if (errorMessage.includes("invalid password")) {
|
||||
setError("currentPassword", {
|
||||
type: "manual",
|
||||
message: t`The current password you entered is incorrect.`,
|
||||
});
|
||||
} else {
|
||||
closeModal();
|
||||
showPopup({
|
||||
header: t`Error Changing Password`,
|
||||
message: t`An unexpected error occurred. Please try again later.`,
|
||||
icon: "error",
|
||||
});
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = (data: FormValues) => {
|
||||
changePasswordMutation.mutate(data);
|
||||
};
|
||||
|
||||
const handleCancel = () => {
|
||||
reset();
|
||||
closeModal();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="p-5">
|
||||
<div className="flex w-full flex-col justify-between pb-4">
|
||||
<h2 className="text-md pb-4 font-medium dark:text-white">{t`Change Password`}</h2>
|
||||
<p className="mb-4 text-sm text-light-900">
|
||||
{t`Enter your current password and choose a new secure password.`}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div className="space-y-2">
|
||||
<div>
|
||||
<Input
|
||||
id="currentPassword"
|
||||
type="password"
|
||||
{...register("currentPassword")}
|
||||
placeholder={t`Enter your current password`}
|
||||
/>
|
||||
{errors.currentPassword && (
|
||||
<p className="mt-2 text-xs text-red-400">
|
||||
{errors.currentPassword.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
id="newPassword"
|
||||
type="password"
|
||||
{...register("newPassword")}
|
||||
placeholder={t`Enter your new password`}
|
||||
/>
|
||||
{errors.newPassword && (
|
||||
<p className="mt-2 text-xs text-red-400">
|
||||
{errors.newPassword.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Input
|
||||
id="confirmPassword"
|
||||
type="password"
|
||||
{...register("confirmPassword")}
|
||||
placeholder={t`Confirm your new password`}
|
||||
/>
|
||||
{errors.confirmPassword && (
|
||||
<p className="mt-2 text-xs text-red-400">
|
||||
{errors.confirmPassword.message}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-[1.5rem] flex items-center gap-4">
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={handleCancel}
|
||||
type="button"
|
||||
fullWidth
|
||||
size="lg"
|
||||
>
|
||||
{t`Cancel`}
|
||||
</Button>
|
||||
<Button
|
||||
variant="primary"
|
||||
type="submit"
|
||||
disabled={!isValid || changePasswordMutation.isPending}
|
||||
isLoading={changePasswordMutation.isPending}
|
||||
fullWidth
|
||||
size="lg"
|
||||
>
|
||||
{t`Change Password`}
|
||||
</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import { usePopup } from "~/providers/popup";
|
||||
import { useWorkspace } from "~/providers/workspace";
|
||||
import { api } from "~/utils/api";
|
||||
import Avatar from "./components/Avatar";
|
||||
import { ChangePasswordFormConfirmation } from "./components/ChangePasswordConfirmation";
|
||||
import CreateAPIKeyForm from "./components/CreateAPIKeyForm";
|
||||
import { CustomURLConfirmation } from "./components/CustomURLConfirmation";
|
||||
import { DeleteAccountConfirmation } from "./components/DeleteAccountConfirmation";
|
||||
@@ -25,14 +26,15 @@ import UpdateWorkspaceNameForm from "./components/UpdateWorkspaceNameForm";
|
||||
import UpdateWorkspaceUrlForm from "./components/UpdateWorkspaceUrlForm";
|
||||
|
||||
export default function SettingsPage() {
|
||||
const { modalContentType, openModal } = useModal();
|
||||
const { modalContentType, openModal, isOpen } = useModal();
|
||||
const { workspace } = useWorkspace();
|
||||
const utils = api.useUtils();
|
||||
const { showPopup } = usePopup();
|
||||
const router = useRouter();
|
||||
const workspaceUrlSectionRef = useRef<HTMLDivElement>(null);
|
||||
const scrollContainerRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const isCredentialsEnabled =
|
||||
env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true";
|
||||
const { data } = api.user.getUser.useQuery();
|
||||
|
||||
const {
|
||||
@@ -283,6 +285,25 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isCredentialsEnabled && (
|
||||
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
|
||||
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
|
||||
{t`Change Password`}
|
||||
</h2>
|
||||
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
|
||||
{t`You are about to change your password.`}
|
||||
</p>
|
||||
<div className="mt-4">
|
||||
<Button
|
||||
variant="secondary"
|
||||
onClick={() => openModal("CHANGE_PASSWORD")}
|
||||
>
|
||||
{t`Change Password`}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
|
||||
<h2 className="mb-4 mt-8 text-[14px] text-neutral-900 dark:text-dark-1000">
|
||||
{t`Delete account`}
|
||||
@@ -301,19 +322,49 @@ export default function SettingsPage() {
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Modal modalSize={modalContentType === "NEW_FEEDBACK" ? "md" : "sm"}>
|
||||
{modalContentType === "NEW_FEEDBACK" && <FeedbackModal />}
|
||||
{modalContentType === "NEW_WORKSPACE" && <NewWorkspaceForm />}
|
||||
{modalContentType === "DELETE_WORKSPACE" && (
|
||||
<>
|
||||
<Modal
|
||||
modalSize="md"
|
||||
isVisible={isOpen && modalContentType === "NEW_FEEDBACK"}
|
||||
>
|
||||
<FeedbackModal />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "NEW_WORKSPACE"}
|
||||
>
|
||||
<NewWorkspaceForm />
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_WORKSPACE"}
|
||||
>
|
||||
<DeleteWorkspaceConfirmation />
|
||||
)}
|
||||
{modalContentType === "UPDATE_WORKSPACE_URL" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "UPDATE_WORKSPACE_URL"}
|
||||
>
|
||||
<CustomURLConfirmation workspacePublicId={workspace.publicId} />
|
||||
)}
|
||||
{modalContentType === "DELETE_ACCOUNT" && (
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "DELETE_ACCOUNT"}
|
||||
>
|
||||
<DeleteAccountConfirmation />
|
||||
)}
|
||||
</Modal>
|
||||
</Modal>
|
||||
|
||||
<Modal
|
||||
modalSize="sm"
|
||||
isVisible={isOpen && modalContentType === "CHANGE_PASSWORD"}
|
||||
>
|
||||
<ChangePasswordFormConfirmation />
|
||||
</Modal>
|
||||
</>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -4,6 +4,7 @@ import { fontFamily } from "tailwindcss/defaultTheme";
|
||||
import baseConfig from "@kan/tailwind-config/web";
|
||||
|
||||
export default {
|
||||
darkMode: "class",
|
||||
content: [...baseConfig.content],
|
||||
plugins: [require("@tailwindcss/typography")],
|
||||
presets: [baseConfig],
|
||||
|
||||
@@ -35,6 +35,9 @@ services:
|
||||
- NEXT_PUBLIC_AVATAR_BUCKET_NAME=${NEXT_PUBLIC_AVATAR_BUCKET_NAME}
|
||||
- NEXT_PUBLIC_STORAGE_DOMAIN=${NEXT_PUBLIC_STORAGE_DOMAIN}
|
||||
|
||||
# White label
|
||||
- NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY=${NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY}
|
||||
|
||||
# Auth config (optional)
|
||||
- NEXT_PUBLIC_ALLOW_CREDENTIALS=${NEXT_PUBLIC_ALLOW_CREDENTIALS}
|
||||
- NEXT_PUBLIC_DISABLE_SIGN_UP=${NEXT_PUBLIC_DISABLE_SIGN_UP}
|
||||
@@ -43,6 +46,11 @@ services:
|
||||
- TRELLO_APP_API_KEY=${TRELLO_APP_API_KEY}
|
||||
- TRELLO_APP_SECRET=${TRELLO_APP_SECRET}
|
||||
|
||||
# Generic OIDC provider (optional)
|
||||
- OIDC_CLIENT_ID=${OIDC_CLIENT_ID}
|
||||
- OIDC_CLIENT_SECRET=${OIDC_CLIENT_SECRET}
|
||||
- OIDC_DISCOVERY_URL=${OIDC_DISCOVERY_URL}
|
||||
|
||||
# OAuth providers (optional)
|
||||
- BETTER_AUTH_TRUSTED_ORIGINS=${BETTER_AUTH_TRUSTED_ORIGINS}
|
||||
- GOOGLE_CLIENT_ID=${GOOGLE_CLIENT_ID}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { boardRouter } from "./routers/board";
|
||||
import { cardRouter } from "./routers/card";
|
||||
import { checklistRouter } from "./routers/checklist";
|
||||
import { feedbackRouter } from "./routers/feedback";
|
||||
import { importRouter } from "./routers/import";
|
||||
import { integrationRouter } from "./routers/integration";
|
||||
@@ -13,6 +14,7 @@ import { createTRPCRouter } from "./trpc";
|
||||
export const appRouter = createTRPCRouter({
|
||||
board: boardRouter,
|
||||
card: cardRouter,
|
||||
checklist: checklistRouter,
|
||||
feedback: feedbackRouter,
|
||||
label: labelRouter,
|
||||
list: listRouter,
|
||||
|
||||
410
packages/api/src/routers/checklist.ts
Normal file
410
packages/api/src/routers/checklist.ts
Normal file
@@ -0,0 +1,410 @@
|
||||
import { TRPCError } from "@trpc/server";
|
||||
import { z } from "zod";
|
||||
|
||||
import * as cardRepo from "@kan/db/repository/card.repo";
|
||||
import * as cardActivityRepo from "@kan/db/repository/cardActivity.repo";
|
||||
import * as checklistRepo from "@kan/db/repository/checklist.repo";
|
||||
|
||||
import { createTRPCRouter, protectedProcedure } from "../trpc";
|
||||
import { assertUserInWorkspace } from "../utils/auth";
|
||||
|
||||
const checklistSchema = z.object({
|
||||
publicId: z.string().length(12),
|
||||
name: z.string().min(1).max(255),
|
||||
});
|
||||
|
||||
const checklistItemSchema = z.object({
|
||||
publicId: z.string().length(12),
|
||||
title: z.string().min(1).max(500),
|
||||
completed: z.boolean(),
|
||||
});
|
||||
|
||||
export const checklistRouter = createTRPCRouter({
|
||||
create: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Add a checklist to a card",
|
||||
method: "POST",
|
||||
path: "/cards/{cardPublicId}/checklists",
|
||||
description: "Adds a checklist to a card",
|
||||
tags: ["Cards"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
cardPublicId: z.string().length(12),
|
||||
name: z.string().min(1).max(255),
|
||||
}),
|
||||
)
|
||||
.output(checklistSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const card = await cardRepo.getWorkspaceAndCardIdByCardPublicId(
|
||||
ctx.db,
|
||||
input.cardPublicId,
|
||||
);
|
||||
|
||||
if (!card)
|
||||
throw new TRPCError({
|
||||
message: `Card with public ID ${input.cardPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(ctx.db, userId, card.workspaceId);
|
||||
|
||||
const newChecklist = await checklistRepo.create(ctx.db, {
|
||||
name: input.name,
|
||||
createdBy: userId,
|
||||
cardId: card.id,
|
||||
});
|
||||
|
||||
if (!newChecklist?.id)
|
||||
throw new TRPCError({
|
||||
message: `Failed to create checklist`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.added",
|
||||
cardId: card.id,
|
||||
toTitle: newChecklist.name,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return newChecklist;
|
||||
}),
|
||||
update: protectedProcedure
|
||||
.input(
|
||||
z.object({
|
||||
checklistPublicId: z.string().length(12),
|
||||
name: z.string().min(1).max(255),
|
||||
}),
|
||||
)
|
||||
.output(z.object({ publicId: z.string().length(12), name: z.string() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const checklist = await checklistRepo.getChecklistByPublicId(
|
||||
ctx.db,
|
||||
input.checklistPublicId,
|
||||
);
|
||||
if (!checklist)
|
||||
throw new TRPCError({
|
||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(
|
||||
ctx.db,
|
||||
userId,
|
||||
checklist.card.list.board.workspace.id,
|
||||
);
|
||||
|
||||
const previousName = checklist.name;
|
||||
|
||||
const updated = await checklistRepo.updateChecklistById(ctx.db, {
|
||||
id: checklist.id,
|
||||
name: input.name,
|
||||
});
|
||||
|
||||
if (!updated)
|
||||
throw new TRPCError({
|
||||
message: `Failed to update checklist`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.renamed",
|
||||
cardId: checklist.cardId,
|
||||
fromTitle: previousName,
|
||||
toTitle: updated.name,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return updated;
|
||||
}),
|
||||
delete: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Delete a checklist",
|
||||
method: "DELETE",
|
||||
path: "/checklists/{checklistPublicId}",
|
||||
description: "Deletes a checklist by its public ID",
|
||||
tags: ["Cards"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(z.object({ checklistPublicId: z.string().length(12) }))
|
||||
.output(z.object({ success: z.boolean() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const checklist = await checklistRepo.getChecklistByPublicId(
|
||||
ctx.db,
|
||||
input.checklistPublicId,
|
||||
);
|
||||
if (!checklist)
|
||||
throw new TRPCError({
|
||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(
|
||||
ctx.db,
|
||||
userId,
|
||||
checklist.card.list.board.workspace.id,
|
||||
);
|
||||
|
||||
await checklistRepo.softDeleteAllItemsByChecklistId(ctx.db, {
|
||||
checklistId: checklist.id,
|
||||
deletedAt: new Date(),
|
||||
deletedBy: userId,
|
||||
});
|
||||
|
||||
const deleted = await checklistRepo.softDeleteById(ctx.db, {
|
||||
id: checklist.id,
|
||||
deletedAt: new Date(),
|
||||
deletedBy: userId,
|
||||
});
|
||||
|
||||
if (!deleted)
|
||||
throw new TRPCError({
|
||||
message: `Failed to delete checklist`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.deleted",
|
||||
cardId: checklist.cardId,
|
||||
fromTitle: checklist.name,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
createItem: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Add an item to a checklist",
|
||||
method: "POST",
|
||||
path: "/checklists/{checklistPublicId}/items",
|
||||
description: "Adds an item to a checklist",
|
||||
tags: ["Cards"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
checklistPublicId: z.string().length(12),
|
||||
title: z.string().min(1).max(500),
|
||||
}),
|
||||
)
|
||||
.output(checklistItemSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const checklist = await checklistRepo.getChecklistByPublicId(
|
||||
ctx.db,
|
||||
input.checklistPublicId,
|
||||
);
|
||||
|
||||
if (!checklist)
|
||||
throw new TRPCError({
|
||||
message: `Checklist with public ID ${input.checklistPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(
|
||||
ctx.db,
|
||||
userId,
|
||||
checklist.card.list.board.workspace.id,
|
||||
);
|
||||
|
||||
const newChecklistItem = await checklistRepo.createItem(ctx.db, {
|
||||
title: input.title,
|
||||
createdBy: userId,
|
||||
checklistId: checklist.id,
|
||||
});
|
||||
|
||||
if (!newChecklistItem?.id)
|
||||
throw new TRPCError({
|
||||
message: `Failed to create checklist item`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.item.added",
|
||||
cardId: checklist.cardId,
|
||||
toTitle: newChecklistItem.title,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return newChecklistItem;
|
||||
}),
|
||||
updateItem: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Update a checklist item",
|
||||
method: "PUT",
|
||||
path: "/checklists/items/{checklistItemPublicId}",
|
||||
description: "Updates a checklist item (title/completed)",
|
||||
tags: ["Cards"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(
|
||||
z.object({
|
||||
checklistItemPublicId: z.string().length(12),
|
||||
title: z.string().min(1).max(500).optional(),
|
||||
completed: z.boolean().optional(),
|
||||
}),
|
||||
)
|
||||
.output(checklistItemSchema)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const item = await checklistRepo.getChecklistItemByPublicIdWithChecklist(
|
||||
ctx.db,
|
||||
input.checklistItemPublicId,
|
||||
);
|
||||
|
||||
if (!item)
|
||||
throw new TRPCError({
|
||||
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(
|
||||
ctx.db,
|
||||
userId,
|
||||
item.checklist.card.list.board.workspace.id,
|
||||
);
|
||||
|
||||
const previousTitle = item.title;
|
||||
|
||||
const updated = await checklistRepo.updateItemById(ctx.db, {
|
||||
id: item.id,
|
||||
title: input.title,
|
||||
completed: input.completed,
|
||||
});
|
||||
|
||||
if (!updated)
|
||||
throw new TRPCError({
|
||||
message: `Failed to update checklist item`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
// Log completion toggle
|
||||
if (input.completed !== undefined) {
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: input.completed
|
||||
? "card.updated.checklist.item.completed"
|
||||
: "card.updated.checklist.item.uncompleted",
|
||||
cardId: item.checklist.cardId,
|
||||
toTitle: updated.title,
|
||||
createdBy: userId,
|
||||
});
|
||||
}
|
||||
|
||||
// Log title change
|
||||
if (input.title !== undefined && input.title !== previousTitle) {
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.item.updated",
|
||||
cardId: item.checklist.cardId,
|
||||
fromTitle: previousTitle,
|
||||
toTitle: updated.title,
|
||||
createdBy: userId,
|
||||
});
|
||||
}
|
||||
|
||||
return updated;
|
||||
}),
|
||||
deleteItem: protectedProcedure
|
||||
.meta({
|
||||
openapi: {
|
||||
summary: "Delete a checklist item",
|
||||
method: "DELETE",
|
||||
path: "/checklists/items/{checklistItemPublicId}",
|
||||
description: "Deletes a checklist item",
|
||||
tags: ["Cards"],
|
||||
protect: true,
|
||||
},
|
||||
})
|
||||
.input(z.object({ checklistItemPublicId: z.string().length(12) }))
|
||||
.output(z.object({ success: z.boolean() }))
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const userId = ctx.user?.id;
|
||||
if (!userId)
|
||||
throw new TRPCError({
|
||||
message: `User not authenticated`,
|
||||
code: "UNAUTHORIZED",
|
||||
});
|
||||
|
||||
const item = await checklistRepo.getChecklistItemByPublicIdWithChecklist(
|
||||
ctx.db,
|
||||
input.checklistItemPublicId,
|
||||
);
|
||||
if (!item)
|
||||
throw new TRPCError({
|
||||
message: `Checklist item with public ID ${input.checklistItemPublicId} not found`,
|
||||
code: "NOT_FOUND",
|
||||
});
|
||||
|
||||
await assertUserInWorkspace(
|
||||
ctx.db,
|
||||
userId,
|
||||
item.checklist.card.list.board.workspace.id,
|
||||
);
|
||||
|
||||
const deleted = await checklistRepo.softDeleteItemById(ctx.db, {
|
||||
id: item.id,
|
||||
deletedAt: new Date(),
|
||||
deletedBy: userId,
|
||||
});
|
||||
|
||||
if (!deleted)
|
||||
throw new TRPCError({
|
||||
message: `Failed to delete item`,
|
||||
code: "INTERNAL_SERVER_ERROR",
|
||||
});
|
||||
|
||||
await cardActivityRepo.create(ctx.db, {
|
||||
type: "card.updated.checklist.item.deleted",
|
||||
cardId: item.checklist.cardId,
|
||||
fromTitle: item.title,
|
||||
createdBy: userId,
|
||||
});
|
||||
|
||||
return { success: true };
|
||||
}),
|
||||
});
|
||||
@@ -2,7 +2,7 @@ import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
||||
import { betterAuth } from "better-auth";
|
||||
import { drizzleAdapter } from "better-auth/adapters/drizzle";
|
||||
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
|
||||
import { apiKey } from "better-auth/plugins";
|
||||
import { apiKey, genericOAuth } from "better-auth/plugins";
|
||||
import { magicLink } from "better-auth/plugins/magic-link";
|
||||
import { socialProviderList } from "better-auth/social-providers";
|
||||
import { env } from "next-runtime-env";
|
||||
@@ -83,8 +83,20 @@ export const socialProvidersPlugin = () => ({
|
||||
{
|
||||
method: "GET",
|
||||
},
|
||||
async (ctx) =>
|
||||
ctx.json(ctx.context.socialProviders.map((p) => p.id.toLowerCase())),
|
||||
async (ctx) => {
|
||||
const providers = ctx.context.socialProviders.map((p) =>
|
||||
p.id.toLowerCase(),
|
||||
);
|
||||
// Add OIDC provider if configured
|
||||
if (
|
||||
process.env.OIDC_CLIENT_ID &&
|
||||
process.env.OIDC_CLIENT_SECRET &&
|
||||
process.env.OIDC_DISCOVERY_URL
|
||||
) {
|
||||
providers.push("oidc");
|
||||
}
|
||||
return ctx.json(providers);
|
||||
},
|
||||
),
|
||||
},
|
||||
});
|
||||
@@ -162,6 +174,25 @@ export const initAuth = (db: dbClient) => {
|
||||
}
|
||||
},
|
||||
}),
|
||||
// Generic OIDC provider
|
||||
...(process.env.OIDC_CLIENT_ID &&
|
||||
process.env.OIDC_CLIENT_SECRET &&
|
||||
process.env.OIDC_DISCOVERY_URL
|
||||
? [
|
||||
genericOAuth({
|
||||
config: [
|
||||
{
|
||||
providerId: "oidc",
|
||||
clientId: process.env.OIDC_CLIENT_ID,
|
||||
clientSecret: process.env.OIDC_CLIENT_SECRET,
|
||||
discoveryUrl: process.env.OIDC_DISCOVERY_URL,
|
||||
scopes: ["openid", "email", "profile"],
|
||||
pkce: true,
|
||||
},
|
||||
],
|
||||
}),
|
||||
]
|
||||
: []),
|
||||
],
|
||||
databaseHooks: {
|
||||
user: {
|
||||
|
||||
@@ -1,8 +1,13 @@
|
||||
import { BetterAuthClientPlugin } from "better-auth";
|
||||
import { apiKeyClient, magicLinkClient } from "better-auth/client/plugins";
|
||||
import { BetterFetchOption, createAuthClient } from "better-auth/react";
|
||||
import type { BetterAuthClientPlugin } from "better-auth";
|
||||
import type { BetterFetchOption } from "better-auth/react";
|
||||
import {
|
||||
apiKeyClient,
|
||||
genericOAuthClient,
|
||||
magicLinkClient,
|
||||
} from "better-auth/client/plugins";
|
||||
import { createAuthClient } from "better-auth/react";
|
||||
|
||||
import { socialProvidersPlugin } from "./auth";
|
||||
import type { socialProvidersPlugin } from "./auth";
|
||||
|
||||
const socialProvidersPluginClient = {
|
||||
id: "social-providers-plugin",
|
||||
@@ -21,5 +26,10 @@ const socialProvidersPluginClient = {
|
||||
} satisfies BetterAuthClientPlugin;
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
plugins: [magicLinkClient(), apiKeyClient(), socialProvidersPluginClient],
|
||||
plugins: [
|
||||
magicLinkClient(),
|
||||
apiKeyClient(),
|
||||
genericOAuthClient(),
|
||||
socialProvidersPluginClient,
|
||||
],
|
||||
});
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";--> statement-breakpoint
|
||||
|
||||
CREATE TYPE "public"."board_visibility" AS ENUM('private', 'public');--> statement-breakpoint
|
||||
CREATE TYPE "public"."card_activity_type" AS ENUM('card.created', 'card.updated.title', 'card.updated.description', 'card.updated.index', 'card.updated.list', 'card.updated.label.added', 'card.updated.label.removed', 'card.updated.member.added', 'card.updated.member.removed', 'card.updated.comment.added', 'card.updated.comment.updated', 'card.updated.comment.deleted', 'card.archived');--> statement-breakpoint
|
||||
|
||||
84
packages/db/migrations/20250806202106_glossy_luminals.sql
Normal file
84
packages/db/migrations/20250806202106_glossy_luminals.sql
Normal file
@@ -0,0 +1,84 @@
|
||||
CREATE TABLE IF NOT EXISTS "card_checklist_item" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"publicId" varchar(12) NOT NULL,
|
||||
"title" varchar(500) NOT NULL,
|
||||
"completed" boolean DEFAULT false NOT NULL,
|
||||
"index" integer NOT NULL,
|
||||
"checklistId" bigint NOT NULL,
|
||||
"createdBy" uuid,
|
||||
"createdAt" timestamp DEFAULT now() NOT NULL,
|
||||
"updatedAt" timestamp,
|
||||
"deletedAt" timestamp,
|
||||
"deletedBy" uuid,
|
||||
CONSTRAINT "card_checklist_item_publicId_unique" UNIQUE("publicId")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_checklist_item" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "card_checklist" (
|
||||
"id" bigserial PRIMARY KEY NOT NULL,
|
||||
"publicId" varchar(12) NOT NULL,
|
||||
"name" varchar(255) NOT NULL,
|
||||
"index" integer NOT NULL,
|
||||
"cardId" bigint NOT NULL,
|
||||
"createdBy" uuid,
|
||||
"createdAt" timestamp DEFAULT now() NOT NULL,
|
||||
"updatedAt" timestamp,
|
||||
"deletedAt" timestamp,
|
||||
"deletedBy" uuid,
|
||||
CONSTRAINT "card_checklist_publicId_unique" UNIQUE("publicId")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "card_checklist" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
CREATE TABLE IF NOT EXISTS "integration" (
|
||||
"provider" varchar(255) NOT NULL,
|
||||
"userId" uuid NOT NULL,
|
||||
"accessToken" varchar(255) NOT NULL,
|
||||
"refreshToken" varchar(255),
|
||||
"expiresAt" timestamp NOT NULL,
|
||||
"createdAt" timestamp NOT NULL,
|
||||
"updatedAt" timestamp,
|
||||
CONSTRAINT "integration_pkey" PRIMARY KEY("userId","provider")
|
||||
);
|
||||
--> statement-breakpoint
|
||||
ALTER TABLE "integration" ENABLE ROW LEVEL SECURITY;--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist_item" ADD CONSTRAINT "card_checklist_item_checklistId_card_checklist_id_fk" FOREIGN KEY ("checklistId") REFERENCES "public"."card_checklist"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist_item" ADD CONSTRAINT "card_checklist_item_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist_item" ADD CONSTRAINT "card_checklist_item_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist" ADD CONSTRAINT "card_checklist_cardId_card_id_fk" FOREIGN KEY ("cardId") REFERENCES "public"."card"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist" ADD CONSTRAINT "card_checklist_createdBy_user_id_fk" FOREIGN KEY ("createdBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "card_checklist" ADD CONSTRAINT "card_checklist_deletedBy_user_id_fk" FOREIGN KEY ("deletedBy") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
--> statement-breakpoint
|
||||
DO $$ BEGIN
|
||||
ALTER TABLE "integration" ADD CONSTRAINT "integration_userId_user_id_fk" FOREIGN KEY ("userId") REFERENCES "public"."user"("id") ON DELETE cascade ON UPDATE no action;
|
||||
EXCEPTION
|
||||
WHEN duplicate_object THEN null;
|
||||
END $$;
|
||||
@@ -0,0 +1,8 @@
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.added' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.renamed' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.deleted' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.item.added' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.item.updated' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.item.completed' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.item.uncompleted' BEFORE 'card.archived';--> statement-breakpoint
|
||||
ALTER TYPE "public"."card_activity_type" ADD VALUE 'card.updated.checklist.item.deleted' BEFORE 'card.archived';
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "91f9a2fa-31e2-4f3a-bdb9-852292fd7501",
|
||||
"prevId": "058e8521-2814-46f0-a33f-1bbd86f450ce",
|
||||
"prevId": "d170c8e0-bf75-4c71-abd9-0ecbeeb14003",
|
||||
"version": "7",
|
||||
"dialect": "postgresql",
|
||||
"tables": {
|
||||
@@ -92,13 +92,9 @@
|
||||
"account_userId_user_id_fk": {
|
||||
"name": "account_userId_user_id_fk",
|
||||
"tableFrom": "account",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -245,13 +241,9 @@
|
||||
"apiKey_userId_user_id_fk": {
|
||||
"name": "apiKey_userId_user_id_fk",
|
||||
"tableFrom": "apiKey",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -320,13 +312,9 @@
|
||||
"session_userId_user_id_fk": {
|
||||
"name": "session_userId_user_id_fk",
|
||||
"tableFrom": "session",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -335,9 +323,7 @@
|
||||
"uniqueConstraints": {
|
||||
"session_token_unique": {
|
||||
"name": "session_token_unique",
|
||||
"columns": [
|
||||
"token"
|
||||
],
|
||||
"columns": ["token"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -523,52 +509,36 @@
|
||||
"board_createdBy_user_id_fk": {
|
||||
"name": "board_createdBy_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"board_deletedBy_user_id_fk": {
|
||||
"name": "board_deletedBy_user_id_fk",
|
||||
"tableFrom": "board",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"board_importId_import_id_fk": {
|
||||
"name": "board_importId_import_id_fk",
|
||||
"tableFrom": "board",
|
||||
"columnsFrom": [
|
||||
"importId"
|
||||
],
|
||||
"columnsFrom": ["importId"],
|
||||
"tableTo": "import",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "no action"
|
||||
},
|
||||
"board_workspaceId_workspace_id_fk": {
|
||||
"name": "board_workspaceId_workspace_id_fk",
|
||||
"tableFrom": "board",
|
||||
"columnsFrom": [
|
||||
"workspaceId"
|
||||
],
|
||||
"columnsFrom": ["workspaceId"],
|
||||
"tableTo": "workspace",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -577,9 +547,7 @@
|
||||
"uniqueConstraints": {
|
||||
"board_publicId_unique": {
|
||||
"name": "board_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -713,91 +681,63 @@
|
||||
"card_activity_cardId_card_id_fk": {
|
||||
"name": "card_activity_cardId_card_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"cardId"
|
||||
],
|
||||
"columnsFrom": ["cardId"],
|
||||
"tableTo": "card",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_activity_fromListId_list_id_fk": {
|
||||
"name": "card_activity_fromListId_list_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"fromListId"
|
||||
],
|
||||
"columnsFrom": ["fromListId"],
|
||||
"tableTo": "list",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_activity_toListId_list_id_fk": {
|
||||
"name": "card_activity_toListId_list_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"toListId"
|
||||
],
|
||||
"columnsFrom": ["toListId"],
|
||||
"tableTo": "list",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_activity_labelId_label_id_fk": {
|
||||
"name": "card_activity_labelId_label_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"labelId"
|
||||
],
|
||||
"columnsFrom": ["labelId"],
|
||||
"tableTo": "label",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_activity_workspaceMemberId_workspace_members_id_fk": {
|
||||
"name": "card_activity_workspaceMemberId_workspace_members_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"workspaceMemberId"
|
||||
],
|
||||
"columnsFrom": ["workspaceMemberId"],
|
||||
"tableTo": "workspace_members",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"card_activity_createdBy_user_id_fk": {
|
||||
"name": "card_activity_createdBy_user_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"card_activity_commentId_card_comments_id_fk": {
|
||||
"name": "card_activity_commentId_card_comments_id_fk",
|
||||
"tableFrom": "card_activity",
|
||||
"columnsFrom": [
|
||||
"commentId"
|
||||
],
|
||||
"columnsFrom": ["commentId"],
|
||||
"tableTo": "card_comments",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -806,9 +746,7 @@
|
||||
"uniqueConstraints": {
|
||||
"card_activity_publicId_unique": {
|
||||
"name": "card_activity_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -838,26 +776,18 @@
|
||||
"_card_workspace_members_cardId_card_id_fk": {
|
||||
"name": "_card_workspace_members_cardId_card_id_fk",
|
||||
"tableFrom": "_card_workspace_members",
|
||||
"columnsFrom": [
|
||||
"cardId"
|
||||
],
|
||||
"columnsFrom": ["cardId"],
|
||||
"tableTo": "card",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"_card_workspace_members_workspaceMemberId_workspace_members_id_fk": {
|
||||
"name": "_card_workspace_members_workspaceMemberId_workspace_members_id_fk",
|
||||
"tableFrom": "_card_workspace_members",
|
||||
"columnsFrom": [
|
||||
"workspaceMemberId"
|
||||
],
|
||||
"columnsFrom": ["workspaceMemberId"],
|
||||
"tableTo": "workspace_members",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -865,10 +795,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"_card_workspace_members_cardId_workspaceMemberId_pk": {
|
||||
"name": "_card_workspace_members_cardId_workspaceMemberId_pk",
|
||||
"columns": [
|
||||
"cardId",
|
||||
"workspaceMemberId"
|
||||
]
|
||||
"columns": ["cardId", "workspaceMemberId"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -959,52 +886,36 @@
|
||||
"card_createdBy_user_id_fk": {
|
||||
"name": "card_createdBy_user_id_fk",
|
||||
"tableFrom": "card",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"card_deletedBy_user_id_fk": {
|
||||
"name": "card_deletedBy_user_id_fk",
|
||||
"tableFrom": "card",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"card_listId_list_id_fk": {
|
||||
"name": "card_listId_list_id_fk",
|
||||
"tableFrom": "card",
|
||||
"columnsFrom": [
|
||||
"listId"
|
||||
],
|
||||
"columnsFrom": ["listId"],
|
||||
"tableTo": "list",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_importId_import_id_fk": {
|
||||
"name": "card_importId_import_id_fk",
|
||||
"tableFrom": "card",
|
||||
"columnsFrom": [
|
||||
"importId"
|
||||
],
|
||||
"columnsFrom": ["importId"],
|
||||
"tableTo": "import",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "no action"
|
||||
}
|
||||
@@ -1013,9 +924,7 @@
|
||||
"uniqueConstraints": {
|
||||
"card_publicId_unique": {
|
||||
"name": "card_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1045,26 +954,18 @@
|
||||
"_card_labels_cardId_card_id_fk": {
|
||||
"name": "_card_labels_cardId_card_id_fk",
|
||||
"tableFrom": "_card_labels",
|
||||
"columnsFrom": [
|
||||
"cardId"
|
||||
],
|
||||
"columnsFrom": ["cardId"],
|
||||
"tableTo": "card",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"_card_labels_labelId_label_id_fk": {
|
||||
"name": "_card_labels_labelId_label_id_fk",
|
||||
"tableFrom": "_card_labels",
|
||||
"columnsFrom": [
|
||||
"labelId"
|
||||
],
|
||||
"columnsFrom": ["labelId"],
|
||||
"tableTo": "label",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
}
|
||||
@@ -1072,10 +973,7 @@
|
||||
"compositePrimaryKeys": {
|
||||
"_card_labels_cardId_labelId_pk": {
|
||||
"name": "_card_labels_cardId_labelId_pk",
|
||||
"columns": [
|
||||
"cardId",
|
||||
"labelId"
|
||||
]
|
||||
"columns": ["cardId", "labelId"]
|
||||
}
|
||||
},
|
||||
"uniqueConstraints": {},
|
||||
@@ -1148,39 +1046,27 @@
|
||||
"card_comments_cardId_card_id_fk": {
|
||||
"name": "card_comments_cardId_card_id_fk",
|
||||
"tableFrom": "card_comments",
|
||||
"columnsFrom": [
|
||||
"cardId"
|
||||
],
|
||||
"columnsFrom": ["cardId"],
|
||||
"tableTo": "card",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"card_comments_createdBy_user_id_fk": {
|
||||
"name": "card_comments_createdBy_user_id_fk",
|
||||
"tableFrom": "card_comments",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"card_comments_deletedBy_user_id_fk": {
|
||||
"name": "card_comments_deletedBy_user_id_fk",
|
||||
"tableFrom": "card_comments",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1189,9 +1075,7 @@
|
||||
"uniqueConstraints": {
|
||||
"card_comments_publicId_unique": {
|
||||
"name": "card_comments_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1253,13 +1137,9 @@
|
||||
"feedback_createdBy_user_id_fk": {
|
||||
"name": "feedback_createdBy_user_id_fk",
|
||||
"tableFrom": "feedback",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1319,13 +1199,9 @@
|
||||
"import_createdBy_user_id_fk": {
|
||||
"name": "import_createdBy_user_id_fk",
|
||||
"tableFrom": "import",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1334,9 +1210,7 @@
|
||||
"uniqueConstraints": {
|
||||
"import_publicId_unique": {
|
||||
"name": "import_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1421,52 +1295,36 @@
|
||||
"label_createdBy_user_id_fk": {
|
||||
"name": "label_createdBy_user_id_fk",
|
||||
"tableFrom": "label",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"label_boardId_board_id_fk": {
|
||||
"name": "label_boardId_board_id_fk",
|
||||
"tableFrom": "label",
|
||||
"columnsFrom": [
|
||||
"boardId"
|
||||
],
|
||||
"columnsFrom": ["boardId"],
|
||||
"tableTo": "board",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"label_importId_import_id_fk": {
|
||||
"name": "label_importId_import_id_fk",
|
||||
"tableFrom": "label",
|
||||
"columnsFrom": [
|
||||
"importId"
|
||||
],
|
||||
"columnsFrom": ["importId"],
|
||||
"tableTo": "import",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "no action"
|
||||
},
|
||||
"label_deletedBy_user_id_fk": {
|
||||
"name": "label_deletedBy_user_id_fk",
|
||||
"tableFrom": "label",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1475,9 +1333,7 @@
|
||||
"uniqueConstraints": {
|
||||
"label_publicId_unique": {
|
||||
"name": "label_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1562,52 +1418,36 @@
|
||||
"list_createdBy_user_id_fk": {
|
||||
"name": "list_createdBy_user_id_fk",
|
||||
"tableFrom": "list",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"list_deletedBy_user_id_fk": {
|
||||
"name": "list_deletedBy_user_id_fk",
|
||||
"tableFrom": "list",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"list_boardId_board_id_fk": {
|
||||
"name": "list_boardId_board_id_fk",
|
||||
"tableFrom": "list",
|
||||
"columnsFrom": [
|
||||
"boardId"
|
||||
],
|
||||
"columnsFrom": ["boardId"],
|
||||
"tableTo": "board",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"list_importId_import_id_fk": {
|
||||
"name": "list_importId_import_id_fk",
|
||||
"tableFrom": "list",
|
||||
"columnsFrom": [
|
||||
"importId"
|
||||
],
|
||||
"columnsFrom": ["importId"],
|
||||
"tableTo": "import",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "no action"
|
||||
}
|
||||
@@ -1616,9 +1456,7 @@
|
||||
"uniqueConstraints": {
|
||||
"list_publicId_unique": {
|
||||
"name": "list_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1688,9 +1526,7 @@
|
||||
"uniqueConstraints": {
|
||||
"user_email_unique": {
|
||||
"name": "user_email_unique",
|
||||
"columns": [
|
||||
"email"
|
||||
],
|
||||
"columns": ["email"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1722,9 +1558,7 @@
|
||||
"uniqueConstraints": {
|
||||
"workspace_slugs_slug_unique": {
|
||||
"name": "workspace_slugs_slug_unique",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1818,39 +1652,27 @@
|
||||
"workspace_members_userId_user_id_fk": {
|
||||
"name": "workspace_members_userId_user_id_fk",
|
||||
"tableFrom": "workspace_members",
|
||||
"columnsFrom": [
|
||||
"userId"
|
||||
],
|
||||
"columnsFrom": ["userId"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"workspace_members_workspaceId_workspace_id_fk": {
|
||||
"name": "workspace_members_workspaceId_workspace_id_fk",
|
||||
"tableFrom": "workspace_members",
|
||||
"columnsFrom": [
|
||||
"workspaceId"
|
||||
],
|
||||
"columnsFrom": ["workspaceId"],
|
||||
"tableTo": "workspace",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "cascade"
|
||||
},
|
||||
"workspace_members_deletedBy_user_id_fk": {
|
||||
"name": "workspace_members_deletedBy_user_id_fk",
|
||||
"tableFrom": "workspace_members",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1859,9 +1681,7 @@
|
||||
"uniqueConstraints": {
|
||||
"workspace_members_publicId_unique": {
|
||||
"name": "workspace_members_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1948,26 +1768,18 @@
|
||||
"workspace_createdBy_user_id_fk": {
|
||||
"name": "workspace_createdBy_user_id_fk",
|
||||
"tableFrom": "workspace",
|
||||
"columnsFrom": [
|
||||
"createdBy"
|
||||
],
|
||||
"columnsFrom": ["createdBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
},
|
||||
"workspace_deletedBy_user_id_fk": {
|
||||
"name": "workspace_deletedBy_user_id_fk",
|
||||
"tableFrom": "workspace",
|
||||
"columnsFrom": [
|
||||
"deletedBy"
|
||||
],
|
||||
"columnsFrom": ["deletedBy"],
|
||||
"tableTo": "user",
|
||||
"columnsTo": [
|
||||
"id"
|
||||
],
|
||||
"columnsTo": ["id"],
|
||||
"onUpdate": "no action",
|
||||
"onDelete": "set null"
|
||||
}
|
||||
@@ -1976,16 +1788,12 @@
|
||||
"uniqueConstraints": {
|
||||
"workspace_publicId_unique": {
|
||||
"name": "workspace_publicId_unique",
|
||||
"columns": [
|
||||
"publicId"
|
||||
],
|
||||
"columns": ["publicId"],
|
||||
"nullsNotDistinct": false
|
||||
},
|
||||
"workspace_slug_unique": {
|
||||
"name": "workspace_slug_unique",
|
||||
"columns": [
|
||||
"slug"
|
||||
],
|
||||
"columns": ["slug"],
|
||||
"nullsNotDistinct": false
|
||||
}
|
||||
},
|
||||
@@ -1998,10 +1806,7 @@
|
||||
"public.board_visibility": {
|
||||
"name": "board_visibility",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"private",
|
||||
"public"
|
||||
]
|
||||
"values": ["private", "public"]
|
||||
},
|
||||
"public.card_activity_type": {
|
||||
"name": "card_activity_type",
|
||||
@@ -2025,53 +1830,32 @@
|
||||
"public.source": {
|
||||
"name": "source",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"trello"
|
||||
]
|
||||
"values": ["trello"]
|
||||
},
|
||||
"public.status": {
|
||||
"name": "status",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"started",
|
||||
"success",
|
||||
"failed"
|
||||
]
|
||||
"values": ["started", "success", "failed"]
|
||||
},
|
||||
"public.role": {
|
||||
"name": "role",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"admin",
|
||||
"member",
|
||||
"guest"
|
||||
]
|
||||
"values": ["admin", "member", "guest"]
|
||||
},
|
||||
"public.member_status": {
|
||||
"name": "member_status",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"invited",
|
||||
"active",
|
||||
"removed"
|
||||
]
|
||||
"values": ["invited", "active", "removed"]
|
||||
},
|
||||
"public.slug_type": {
|
||||
"name": "slug_type",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"reserved",
|
||||
"premium"
|
||||
]
|
||||
"values": ["reserved", "premium"]
|
||||
},
|
||||
"public.workspace_plan": {
|
||||
"name": "workspace_plan",
|
||||
"schema": "public",
|
||||
"values": [
|
||||
"free",
|
||||
"pro",
|
||||
"enterprise"
|
||||
]
|
||||
"values": ["free", "pro", "enterprise"]
|
||||
}
|
||||
},
|
||||
"schemas": {},
|
||||
@@ -2084,4 +1868,4 @@
|
||||
"schemas": {},
|
||||
"tables": {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
2415
packages/db/migrations/meta/20250806202106_snapshot.json
Normal file
2415
packages/db/migrations/meta/20250806202106_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
2423
packages/db/migrations/meta/20250813141748_snapshot.json
Normal file
2423
packages/db/migrations/meta/20250813141748_snapshot.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,20 @@
|
||||
"when": 1749585889984,
|
||||
"tag": "20250610200449_ReaddIntegrationTable",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 7,
|
||||
"version": "7",
|
||||
"when": 1754511666265,
|
||||
"tag": "20250806202106_glossy_luminals",
|
||||
"breakpoints": true
|
||||
},
|
||||
{
|
||||
"idx": 8,
|
||||
"version": "7",
|
||||
"when": 1755094668761,
|
||||
"tag": "20250813141748_AddChecklistActivityTypes",
|
||||
"breakpoints": true
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -39,6 +39,7 @@
|
||||
"with-env": "dotenv -e ../../.env --"
|
||||
},
|
||||
"dependencies": {
|
||||
"@electric-sql/pglite": "^0.3.7",
|
||||
"@kan/shared": "workspace:^",
|
||||
"drizzle-orm": "^0.42.0",
|
||||
"drizzle-zod": "^0.5.1",
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import type { NodePgDatabase } from "drizzle-orm/node-postgres";
|
||||
import { drizzle as drizzlePgLite } from "drizzle-orm/pglite";
|
||||
import { uuid_ossp } from "@electric-sql/pglite/contrib/uuid_ossp";
|
||||
import { drizzle as drizzlePg } from "drizzle-orm/node-postgres";
|
||||
import { Pool } from "pg";
|
||||
|
||||
import * as schema from "./schema";
|
||||
import { PGlite } from "@electric-sql/pglite";
|
||||
import { migrate } from "drizzle-orm/pglite/migrator";
|
||||
|
||||
export type dbClient = NodePgDatabase<typeof schema> & {
|
||||
$client: Pool;
|
||||
@@ -12,7 +16,14 @@ export const createDrizzleClient = (): dbClient => {
|
||||
const connectionString = process.env.POSTGRES_URL;
|
||||
|
||||
if (!connectionString) {
|
||||
throw new Error("POSTGRES_URL environment variable is not set");
|
||||
console.log("POSTGRES_URL environment variable is not set, using PGLite");
|
||||
|
||||
const client = new PGlite({ dataDir: "./pgdata", extensions: { uuid_ossp }});
|
||||
const db = drizzlePgLite(client, { schema });
|
||||
|
||||
migrate(db, { migrationsFolder: "../../packages/db/migrations" });
|
||||
|
||||
return db as unknown as dbClient;
|
||||
}
|
||||
|
||||
const pool = new Pool({
|
||||
|
||||
@@ -7,6 +7,8 @@ import {
|
||||
cards,
|
||||
cardsToLabels,
|
||||
cardToWorkspaceMembers,
|
||||
checklistItems,
|
||||
checklists,
|
||||
labels,
|
||||
lists,
|
||||
workspaceMembers,
|
||||
@@ -164,6 +166,27 @@ export const getByPublicId = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
checklists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklists.deletedAt),
|
||||
orderBy: asc(checklists.index),
|
||||
with: {
|
||||
items: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
title: true,
|
||||
completed: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklistItems.deletedAt),
|
||||
orderBy: asc(checklistItems.index),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
cardIds.length > 0 ? inArray(cards.publicId, cardIds) : undefined,
|
||||
@@ -280,6 +303,27 @@ export const getBySlug = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
checklists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklists.deletedAt),
|
||||
orderBy: asc(checklists.index),
|
||||
with: {
|
||||
items: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
title: true,
|
||||
completed: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklistItems.deletedAt),
|
||||
orderBy: asc(checklistItems.index),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
where: and(
|
||||
cardIds.length > 0 ? inArray(cards.publicId, cardIds) : undefined,
|
||||
|
||||
@@ -6,6 +6,8 @@ import {
|
||||
cards,
|
||||
cardsToLabels,
|
||||
cardToWorkspaceMembers,
|
||||
checklistItems,
|
||||
checklists,
|
||||
labels,
|
||||
lists,
|
||||
workspaceMembers,
|
||||
@@ -300,6 +302,27 @@ export const getWithListAndMembersByPublicId = async (
|
||||
},
|
||||
},
|
||||
},
|
||||
checklists: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
name: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklists.deletedAt),
|
||||
orderBy: asc(checklists.index),
|
||||
with: {
|
||||
items: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
title: true,
|
||||
completed: true,
|
||||
index: true,
|
||||
},
|
||||
where: isNull(checklistItems.deletedAt),
|
||||
orderBy: asc(checklistItems.index),
|
||||
},
|
||||
},
|
||||
},
|
||||
list: {
|
||||
columns: {
|
||||
publicId: true,
|
||||
|
||||
216
packages/db/src/repository/checklist.repo.ts
Normal file
216
packages/db/src/repository/checklist.repo.ts
Normal file
@@ -0,0 +1,216 @@
|
||||
import { and, desc, eq, isNull } from "drizzle-orm";
|
||||
|
||||
import type { dbClient } from "@kan/db/client";
|
||||
import { checklistItems, checklists } from "@kan/db/schema";
|
||||
import { generateUID } from "@kan/shared/utils";
|
||||
|
||||
export const create = async (
|
||||
db: dbClient,
|
||||
checklistInput: {
|
||||
cardId: number;
|
||||
name: string;
|
||||
createdBy: string;
|
||||
},
|
||||
) => {
|
||||
return db.transaction(async (tx) => {
|
||||
const card = await tx.query.checklists.findFirst({
|
||||
where: and(
|
||||
eq(checklists.cardId, checklistInput.cardId),
|
||||
isNull(checklists.deletedAt),
|
||||
),
|
||||
orderBy: desc(checklists.index),
|
||||
});
|
||||
|
||||
const [result] = await tx
|
||||
.insert(checklists)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
name: checklistInput.name,
|
||||
createdBy: checklistInput.createdBy,
|
||||
cardId: checklistInput.cardId,
|
||||
index: card ? card.index + 1 : 0,
|
||||
})
|
||||
.returning({
|
||||
id: checklists.id,
|
||||
publicId: checklists.publicId,
|
||||
name: checklists.name,
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
export const createItem = async (
|
||||
db: dbClient,
|
||||
checklistItemInput: {
|
||||
checklistId: number;
|
||||
title: string;
|
||||
createdBy: string;
|
||||
},
|
||||
) => {
|
||||
return db.transaction(async (tx) => {
|
||||
const lastItem = await tx.query.checklistItems.findFirst({
|
||||
where: and(
|
||||
eq(checklistItems.checklistId, checklistItemInput.checklistId),
|
||||
isNull(checklistItems.deletedAt),
|
||||
),
|
||||
orderBy: desc(checklistItems.index),
|
||||
});
|
||||
|
||||
const [result] = await tx
|
||||
.insert(checklistItems)
|
||||
.values({
|
||||
publicId: generateUID(),
|
||||
title: checklistItemInput.title,
|
||||
createdBy: checklistItemInput.createdBy,
|
||||
checklistId: checklistItemInput.checklistId,
|
||||
index: lastItem ? lastItem.index + 1 : 0,
|
||||
completed: false,
|
||||
})
|
||||
.returning({
|
||||
id: checklistItems.id,
|
||||
publicId: checklistItems.publicId,
|
||||
title: checklistItems.title,
|
||||
completed: checklistItems.completed,
|
||||
});
|
||||
|
||||
return result;
|
||||
});
|
||||
};
|
||||
|
||||
export const getChecklistByPublicId = async (
|
||||
db: dbClient,
|
||||
checklistPublicId: string,
|
||||
) => {
|
||||
const checklist = await db.query.checklists.findFirst({
|
||||
where: and(
|
||||
eq(checklists.publicId, checklistPublicId),
|
||||
isNull(checklists.deletedAt),
|
||||
),
|
||||
with: {
|
||||
card: {
|
||||
with: {
|
||||
list: {
|
||||
with: {
|
||||
board: {
|
||||
with: {
|
||||
workspace: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return checklist;
|
||||
};
|
||||
|
||||
export const getChecklistItemByPublicIdWithChecklist = async (
|
||||
db: dbClient,
|
||||
checklistItemPublicId: string,
|
||||
) => {
|
||||
const item = await db.query.checklistItems.findFirst({
|
||||
where: and(
|
||||
eq(checklistItems.publicId, checklistItemPublicId),
|
||||
isNull(checklistItems.deletedAt),
|
||||
),
|
||||
with: {
|
||||
checklist: {
|
||||
with: {
|
||||
card: {
|
||||
with: {
|
||||
list: {
|
||||
with: {
|
||||
board: {
|
||||
with: { workspace: true },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
return item;
|
||||
};
|
||||
|
||||
export const updateItemById = async (
|
||||
db: dbClient,
|
||||
args: { id: number; title?: string; completed?: boolean },
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(checklistItems)
|
||||
.set({
|
||||
...(args.title !== undefined ? { title: args.title } : {}),
|
||||
...(args.completed !== undefined ? { completed: args.completed } : {}),
|
||||
updatedAt: new Date(),
|
||||
})
|
||||
.where(eq(checklistItems.id, args.id))
|
||||
.returning({
|
||||
publicId: checklistItems.publicId,
|
||||
title: checklistItems.title,
|
||||
completed: checklistItems.completed,
|
||||
});
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDeleteItemById = async (
|
||||
db: dbClient,
|
||||
args: { id: number; deletedAt: Date; deletedBy: string },
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(checklistItems)
|
||||
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
|
||||
.where(eq(checklistItems.id, args.id))
|
||||
.returning({ id: checklistItems.id });
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDeleteAllItemsByChecklistId = async (
|
||||
db: dbClient,
|
||||
args: { checklistId: number; deletedAt: Date; deletedBy: string },
|
||||
) => {
|
||||
const result = await db
|
||||
.update(checklistItems)
|
||||
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
|
||||
.where(
|
||||
and(
|
||||
eq(checklistItems.checklistId, args.checklistId),
|
||||
isNull(checklistItems.deletedAt),
|
||||
),
|
||||
)
|
||||
.returning({ id: checklistItems.id });
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const softDeleteById = async (
|
||||
db: dbClient,
|
||||
args: { id: number; deletedAt: Date; deletedBy: string },
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(checklists)
|
||||
.set({ deletedAt: args.deletedAt, deletedBy: args.deletedBy })
|
||||
.where(eq(checklists.id, args.id))
|
||||
.returning({ id: checklists.id });
|
||||
|
||||
return result;
|
||||
};
|
||||
|
||||
export const updateChecklistById = async (
|
||||
db: dbClient,
|
||||
args: { id: number; name: string },
|
||||
) => {
|
||||
const [result] = await db
|
||||
.update(checklists)
|
||||
.set({ name: args.name, updatedAt: new Date() })
|
||||
.where(eq(checklists.id, args.id))
|
||||
.returning({ publicId: checklists.publicId, name: checklists.name });
|
||||
return result;
|
||||
};
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
|
||||
import { checklists } from "./checklists";
|
||||
import { imports } from "./imports";
|
||||
import { labels } from "./labels";
|
||||
import { lists } from "./lists";
|
||||
@@ -31,6 +32,15 @@ export const activityTypes = [
|
||||
"card.updated.comment.added",
|
||||
"card.updated.comment.updated",
|
||||
"card.updated.comment.deleted",
|
||||
// Checklist activities
|
||||
"card.updated.checklist.added",
|
||||
"card.updated.checklist.renamed",
|
||||
"card.updated.checklist.deleted",
|
||||
"card.updated.checklist.item.added",
|
||||
"card.updated.checklist.item.updated",
|
||||
"card.updated.checklist.item.completed",
|
||||
"card.updated.checklist.item.uncompleted",
|
||||
"card.updated.checklist.item.deleted",
|
||||
"card.archived",
|
||||
] as const;
|
||||
|
||||
@@ -84,6 +94,7 @@ export const cardsRelations = relations(cards, ({ one, many }) => ({
|
||||
}),
|
||||
comments: many(comments),
|
||||
activities: many(cardActivities),
|
||||
checklists: many(checklists),
|
||||
}));
|
||||
|
||||
export const cardActivities = pgTable("card_activity", {
|
||||
|
||||
90
packages/db/src/schema/checklists.ts
Normal file
90
packages/db/src/schema/checklists.ts
Normal file
@@ -0,0 +1,90 @@
|
||||
import { relations } from "drizzle-orm";
|
||||
import {
|
||||
bigint,
|
||||
bigserial,
|
||||
boolean,
|
||||
integer,
|
||||
pgTable,
|
||||
timestamp,
|
||||
uuid,
|
||||
varchar,
|
||||
} from "drizzle-orm/pg-core";
|
||||
|
||||
import { cards } from "./cards";
|
||||
import { users } from "./users";
|
||||
|
||||
export const checklists = pgTable("card_checklist", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
name: varchar("name", { length: 255 }).notNull(),
|
||||
index: integer("index").notNull(),
|
||||
cardId: bigint("cardId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => cards.id, { onDelete: "cascade" }),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
}).enableRLS();
|
||||
|
||||
export const checklistsRelations = relations(checklists, ({ one, many }) => ({
|
||||
card: one(cards, {
|
||||
fields: [checklists.cardId],
|
||||
references: [cards.id],
|
||||
relationName: "checklistsCard",
|
||||
}),
|
||||
createdBy: one(users, {
|
||||
fields: [checklists.createdBy],
|
||||
references: [users.id],
|
||||
relationName: "checklistsCreatedByUser",
|
||||
}),
|
||||
deletedBy: one(users, {
|
||||
fields: [checklists.deletedBy],
|
||||
references: [users.id],
|
||||
relationName: "checklistsDeletedByUser",
|
||||
}),
|
||||
items: many(checklistItems),
|
||||
}));
|
||||
|
||||
export const checklistItems = pgTable("card_checklist_item", {
|
||||
id: bigserial("id", { mode: "number" }).primaryKey(),
|
||||
publicId: varchar("publicId", { length: 12 }).notNull().unique(),
|
||||
title: varchar("title", { length: 500 }).notNull(),
|
||||
completed: boolean("completed").notNull().default(false),
|
||||
index: integer("index").notNull(),
|
||||
checklistId: bigint("checklistId", { mode: "number" })
|
||||
.notNull()
|
||||
.references(() => checklists.id, { onDelete: "cascade" }),
|
||||
createdBy: uuid("createdBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
createdAt: timestamp("createdAt").defaultNow().notNull(),
|
||||
updatedAt: timestamp("updatedAt"),
|
||||
deletedAt: timestamp("deletedAt"),
|
||||
deletedBy: uuid("deletedBy").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
}).enableRLS();
|
||||
|
||||
export const checklistItemsRelations = relations(checklistItems, ({ one }) => ({
|
||||
checklist: one(checklists, {
|
||||
fields: [checklistItems.checklistId],
|
||||
references: [checklists.id],
|
||||
relationName: "checklistItemsChecklist",
|
||||
}),
|
||||
createdBy: one(users, {
|
||||
fields: [checklistItems.createdBy],
|
||||
references: [users.id],
|
||||
relationName: "checklistItemsCreatedByUser",
|
||||
}),
|
||||
deletedBy: one(users, {
|
||||
fields: [checklistItems.deletedBy],
|
||||
references: [users.id],
|
||||
relationName: "checklistItemsDeletedByUser",
|
||||
}),
|
||||
}));
|
||||
@@ -2,6 +2,7 @@ export * from "./auth";
|
||||
export * from "./boards";
|
||||
export * from "./auth";
|
||||
export * from "./cards";
|
||||
export * from "./checklists";
|
||||
export * from "./feedback";
|
||||
export * from "./imports";
|
||||
export * from "./labels";
|
||||
|
||||
50
pnpm-lock.yaml
generated
50
pnpm-lock.yaml
generated
@@ -123,6 +123,9 @@ importers:
|
||||
'@tiptap/extension-link':
|
||||
specifier: ^2.22.2
|
||||
version: 2.22.2(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
|
||||
'@tiptap/extension-mention':
|
||||
specifier: ^3.0.9
|
||||
version: 3.0.9(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)(@tiptap/suggestion@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0))
|
||||
'@tiptap/extension-placeholder':
|
||||
specifier: ^2.14.0
|
||||
version: 2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
|
||||
@@ -168,6 +171,9 @@ importers:
|
||||
next-runtime-env:
|
||||
specifier: ^1.7.2
|
||||
version: 1.8.0
|
||||
next-themes:
|
||||
specifier: ^0.4.6
|
||||
version: 0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1)
|
||||
nextjs-cors:
|
||||
specifier: ^2.2.0
|
||||
version: 2.2.0(next@15.3.4(@babel/core@7.24.5)(babel-plugin-macros@3.1.0)(react-dom@18.3.1(react@18.3.1))(react@18.3.1))
|
||||
@@ -360,15 +366,18 @@ importers:
|
||||
|
||||
packages/db:
|
||||
dependencies:
|
||||
'@electric-sql/pglite':
|
||||
specifier: ^0.3.7
|
||||
version: 0.3.7
|
||||
'@kan/shared':
|
||||
specifier: workspace:^
|
||||
version: link:../shared
|
||||
drizzle-orm:
|
||||
specifier: ^0.42.0
|
||||
version: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
|
||||
version: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
|
||||
drizzle-zod:
|
||||
specifier: ^0.5.1
|
||||
version: 0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0)
|
||||
version: 0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0)
|
||||
pg:
|
||||
specifier: ^8.11.3
|
||||
version: 8.13.1
|
||||
@@ -888,6 +897,9 @@ packages:
|
||||
'@drizzle-team/brocli@0.10.2':
|
||||
resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==}
|
||||
|
||||
'@electric-sql/pglite@0.3.7':
|
||||
resolution: {integrity: sha512-5c3mybVrhxu5s47zFZtIGdG8YHkKCBENOmqxnNBjY53ZoDhADY/c5UqBDl159b7qtkzNPtbbb893wL9zi1kAuw==}
|
||||
|
||||
'@emnapi/runtime@1.3.1':
|
||||
resolution: {integrity: sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==}
|
||||
|
||||
@@ -2770,6 +2782,13 @@ packages:
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^2.7.0
|
||||
|
||||
'@tiptap/extension-mention@3.0.9':
|
||||
resolution: {integrity: sha512-DTQNAQkHZ+7Enlt3KvjqN6eECINlqPpET4Drzwj8Mmz9kMILc87cz3G2cwEKRrS9A1Xn3H3VpWvElWE2Wq9JHw==}
|
||||
peerDependencies:
|
||||
'@tiptap/core': ^3.0.9
|
||||
'@tiptap/pm': ^3.0.9
|
||||
'@tiptap/suggestion': ^3.0.9
|
||||
|
||||
'@tiptap/extension-ordered-list@2.14.0':
|
||||
resolution: {integrity: sha512-QUZcyuW9AKvSfpFHcGmbyRCqxcpY0VNf0xipEtogxbA+JDDw3ZSPqU1dUgz9wk00RahPTwNDdY5aVjdQ5N4N9Q==}
|
||||
peerDependencies:
|
||||
@@ -5441,6 +5460,12 @@ packages:
|
||||
next-runtime-env@1.8.0:
|
||||
resolution: {integrity: sha512-QJVxzmr2gTao/vZKFgcrByFrifl0YOMTvuUVxcI/X7ratlW+9zMvMmA9AGU9cFsumXJtohWkCvwPdBNdkTCYfw==}
|
||||
|
||||
next-themes@0.4.6:
|
||||
resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==}
|
||||
peerDependencies:
|
||||
react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||
react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc
|
||||
|
||||
next@15.0.4:
|
||||
resolution: {integrity: sha512-nuy8FH6M1FG0lktGotamQDCXhh5hZ19Vo0ht1AOIQWrYJLP598TIUagKtvJrfJ5AGwB/WmDqkKaKhMpVifvGPA==}
|
||||
engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0}
|
||||
@@ -6484,6 +6509,7 @@ packages:
|
||||
source-map@0.8.0-beta.0:
|
||||
resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==}
|
||||
engines: {node: '>= 8'}
|
||||
deprecated: The work that was done in this beta branch won't be included in future versions
|
||||
|
||||
space-separated-tokens@2.0.2:
|
||||
resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==}
|
||||
@@ -7852,6 +7878,8 @@ snapshots:
|
||||
|
||||
'@drizzle-team/brocli@0.10.2': {}
|
||||
|
||||
'@electric-sql/pglite@0.3.7': {}
|
||||
|
||||
'@emnapi/runtime@1.3.1':
|
||||
dependencies:
|
||||
tslib: 2.8.1
|
||||
@@ -9612,6 +9640,12 @@ snapshots:
|
||||
dependencies:
|
||||
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
|
||||
|
||||
'@tiptap/extension-mention@3.0.9(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)(@tiptap/suggestion@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
|
||||
'@tiptap/pm': 2.14.0
|
||||
'@tiptap/suggestion': 2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))(@tiptap/pm@2.14.0)
|
||||
|
||||
'@tiptap/extension-ordered-list@2.14.0(@tiptap/core@2.14.0(@tiptap/pm@2.14.0))':
|
||||
dependencies:
|
||||
'@tiptap/core': 2.14.0(@tiptap/pm@2.14.0)
|
||||
@@ -10845,8 +10879,9 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5):
|
||||
drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5):
|
||||
optionalDependencies:
|
||||
'@electric-sql/pglite': 0.3.7
|
||||
'@neondatabase/serverless': 0.10.4
|
||||
'@types/pg': 8.11.6
|
||||
'@vercel/postgres': 0.10.0(utf-8-validate@6.0.3)
|
||||
@@ -10854,9 +10889,9 @@ snapshots:
|
||||
pg: 8.13.1
|
||||
postgres: 3.4.5
|
||||
|
||||
drizzle-zod@0.5.1(drizzle-orm@0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0):
|
||||
drizzle-zod@0.5.1(drizzle-orm@0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5))(zod@3.24.0):
|
||||
dependencies:
|
||||
drizzle-orm: 0.42.0(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
|
||||
drizzle-orm: 0.42.0(@electric-sql/pglite@0.3.7)(@neondatabase/serverless@0.10.4)(@types/pg@8.11.6)(@vercel/postgres@0.10.0(utf-8-validate@6.0.3))(kysely@0.28.2)(pg@8.13.1)(postgres@3.4.5)
|
||||
zod: 3.24.0
|
||||
|
||||
dunder-proto@1.0.0:
|
||||
@@ -13002,6 +13037,11 @@ snapshots:
|
||||
dependencies:
|
||||
chalk: 4.1.2
|
||||
|
||||
next-themes@0.4.6(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
react: 18.3.1
|
||||
react-dom: 18.3.1(react@18.3.1)
|
||||
|
||||
next@15.0.4(@babel/core@7.24.5)(react-dom@18.3.1(react@18.3.1))(react@18.3.1):
|
||||
dependencies:
|
||||
'@next/env': 15.0.4
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
"VK_CLIENT_SECRET",
|
||||
"LINKEDIN_CLIENT_ID",
|
||||
"LINKEDIN_CLIENT_SECRET",
|
||||
"OIDC_CLIENT_ID",
|
||||
"OIDC_CLIENT_SECRET",
|
||||
"OIDC_DISCOVERY_URL",
|
||||
"REDDIT_CLIENT_ID",
|
||||
"REDDIT_CLIENT_SECRET",
|
||||
"ROBLOX_CLIENT_ID",
|
||||
@@ -93,6 +96,7 @@
|
||||
"SMTP_PASSWORD",
|
||||
"SMTP_SECURE",
|
||||
"NEXT_PUBLIC_KAN_ENV",
|
||||
"NEXT_PUBLIC_WHITE_LABEL_HIDE_POWERED_BY",
|
||||
"STRIPE_SECRET_KEY",
|
||||
"STRIPE_WEBHOOK_SECRET",
|
||||
"STRIPE_PRO_PLAN_PRICE_ID",
|
||||
|
||||
Reference in New Issue
Block a user