Compare commits

...

24 Commits

Author SHA1 Message Date
Henry
641237de83 feat: add url validation to download attatchment endpoint 2026-03-10 21:54:35 +00:00
Henry
a6780e3e28 fix: show correct highlighting in pricing comparison table 2026-03-03 22:31:08 +00:00
hjball
2c5195a2b8 chore: update translations 2026-03-03 22:17:28 +00:00
Henry
793fa30162 fix: adjust icon size in CardPage component 2026-03-03 22:16:09 +00:00
Henry
af63719de5 fix: swap latest to only publish on version tags and add edge for builds (#428) 2026-03-03 22:14:35 +00:00
hjball
52fd624b81 chore: update translations 2026-03-03 21:37:46 +00:00
Henry
b4d4810f45 fix: migration order (#427) 2026-03-03 21:36:31 +00:00
hjball
239d152340 chore: compile translations 2026-03-01 22:41:43 +00:00
hjball
f294760747 chore: update translations 2026-03-01 22:41:39 +00:00
Morfixx
280d8f66dd feat: initial github integration with importing projects (#421)
* feat: initial github integration with importing projects

* fix: remove unused args

* chore: remove duplicate col

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
2026-03-01 22:39:25 +00:00
Henry
eeae23a24c docs: add migrate service to self hosting guide (#425)
* docs: add migrate service to self hosting guide

* chore: remove build from readme compose
2026-02-28 23:08:59 +00:00
Henry
d81950b8bd fix: publish migrate image (#423) 2026-02-27 22:38:01 +00:00
hjball
e530f39360 chore: update translations 2026-02-27 13:16:47 +00:00
Nick Meinhold
bd25fb33f7 feat(api): add webhook delivery utility and card event integration (#392)
* feat(api): add webhook delivery utility and card event integration

Add the core webhook delivery logic and wire it into card mutations:

- Add sendWebhookToUrl() with HMAC-SHA256 signing, 10s timeout
- Add sendWebhooksForWorkspace() for fan-out delivery (fire-and-forget)
- Add createCardWebhookPayload() for building webhook payloads
- Fire webhooks on card create, update, move, and delete events
- Add unit tests for webhook utility functions

Depends on #391 (DB schema & repository).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(api): use correct boardId in webhook payloads and add rejection safety

- Fix bug where workspaceId was incorrectly passed as boardId in all
  webhook payloads — now uses board's publicId via boardPublicId
- Replace void sendWebhooksForWorkspace() with .catch() to prevent
  unhandled promise rejections if the DB query inside fails

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix(api): add SSRF protection to webhook delivery

Block webhook URLs targeting internal networks:
- Require HTTPS (reject HTTP)
- Block localhost, 127.0.0.1, ::1, 0.0.0.0
- Block cloud metadata endpoints (169.254.169.254, metadata.google.internal)
- Block private IP ranges (10.x, 172.16-31.x, 192.168.x)
- Add tests for all blocked URL patterns

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(api): use WebhookEvent type from schema instead of duplicating

Replace the hardcoded WebhookEventType union with the canonical
WebhookEvent type from @kan/db/schema, addressing reviewer feedback
on PR #392.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor(api): improve webhook delivery safety and validation

Cherry-pick delivery-related changes from b2cc9ac:
- Extract URL validation into reusable webhookUrlSchema zod validator
  for SSRF checks
- Wrap sendWebhooksForWorkspace in try/catch to prevent unhandled
  promise rejections
- Document SSRF risk mitigation on sendWebhookToUrl
- Add corresponding tests

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-27 13:15:35 +00:00
hjball
93f2816b37 chore: compile translations 2026-02-26 21:41:09 +00:00
hjball
2292b972c4 chore: update translations 2026-02-26 21:41:05 +00:00
Eliott Herbert-Byrnes
af36fb133a feat: archived boards (#386)
* init: schema migration, isArchived added to
board table. refactor: board repo for isArchived filtering

* init: archived, unarchived API procedures. refactor: all query

* fix: migration error

* feat: add tabbed navigation for boards view

* Implemented a Listbox for mobile and a tabbed navigation for desktop to switch between "Boards" and "Archived" views.
* Introduced state management for active tab selection.
* Updated UI components to reflect the new navigation structure.

* init: frontend/boards lists & tabs

* chore: fixed font styling and spacing

* init:boardDropdown / boardView.

* chore:added translations

* Remove .cursor plan file from repo

* fix:build erros

* revert: remove locales changes

* fix:reverted changes under locales, replaced the archive and unarchive endpoints. Reorder migrations

* fix:migration issue

* fix: update journal.json

---------

Co-authored-by: Henry <henry_ball@hotmail.co.uk>
2026-02-26 21:39:15 +00:00
hjball
9cb1fb5218 chore: update translations 2026-02-26 21:26:17 +00:00
Nick Meinhold
5f190b92de fix: allow invited users to sign up when registration is disabled (#418)
* fix: allow invited users to sign up when registration is disabled

Move sign-up restriction logic from better-auth's disableSignUp config
to the existing user.create.before database hook, which already checks
for pending invitations. The frontend signup and login pages now detect
invite flows (?next=/invite/...) and bypass the disabled UI accordingly.

Closes #411

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add regression tests for sign-up hook invite bypass

Verify that the user.create.before database hook correctly:
- allows sign-up when registration is not disabled
- blocks sign-up when disabled and no invitation exists
- allows sign-up when disabled but a pending invitation exists
- respects BETTER_AUTH_ALLOWED_DOMAINS in combination with invites

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* test: add OIDC/social sign-up path coverage for invite bypass

Address review suggestion: add explicit tests verifying the
user.create.before hook handles OIDC/social sign-ups the same way as
email/password — invited users are allowed, uninvited users are blocked.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:24:58 +00:00
Nick Meinhold
48a1f39588 fix(api): add missing openapi meta to checklist.update (#417)
The checklist.update procedure was inheriting the default
protectedProcedure meta (GET /protected) instead of declaring
its own OpenAPI route, making it unreachable via the REST API.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 21:12:02 +00:00
hjball
c7fce10fa7 chore: update translations 2026-02-26 21:05:45 +00:00
Matej
094e1d139d fix: make links clickable in comments (#376) (#415)
Move Link extension before Markdown in the TipTap extensions array
to ensure URL detection happens before markdown processing. Also
explicitly enable linkOnPaste for paste detection.

Fixes #376

Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
2026-02-26 21:04:31 +00:00
Henry
fae169c691 fix: ensure deps are installed during translate workflow 2026-02-23 23:11:52 +00:00
Henry
91bc319cf1 fix: prevent cross-workspace access on member and permission endpoints (#413) 2026-02-23 22:56:36 +00:00
63 changed files with 14818 additions and 937 deletions

View File

@@ -6,8 +6,6 @@ name: Docker
# documentation.
on:
schedule:
- cron: "21 21 * * *"
push:
# Only trigger on tags (releases), not main branch pushes
# Main branch builds are handled by workflow_run after Translate completes
@@ -26,6 +24,7 @@ env:
REGISTRY: ghcr.io
# github.repository as <account>/<repo>
IMAGE_NAME: ${{ github.repository }}
MIGRATE_IMAGE_NAME: ${{ github.repository }}-migrate
jobs:
build:
@@ -83,7 +82,22 @@ jobs:
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable={{is_default_branch}}
type=raw,value=latest,enable=${{ github.ref_type == 'tag' }}
type=raw,value=edge,enable={{is_default_branch}}
- name: Extract Docker metadata (migrate)
id: meta-migrate
uses: docker/metadata-action@96383f45573cb7f253c731d3b3ab81c87ef81934 # v5.0.0
with:
images: ${{ env.REGISTRY }}/${{ env.MIGRATE_IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
type=raw,value=latest,enable=${{ github.ref_type == 'tag' }}
type=raw,value=edge,enable={{is_default_branch}}
# Extract version from git tag or ref
# Uses git describe to get latest tag + commit hash in SemVer format: 1.2.3+abc1234
@@ -138,6 +152,22 @@ jobs:
cache-from: type=gha
cache-to: type=gha,mode=max
- name: Build and push migrate Docker image
id: build-and-push-migrate
uses: docker/build-push-action@0565240e2d4ab88bba5387d719585280857ece09 # v5.0.0
with:
context: .
file: apps/web/Dockerfile
target: migrate
push: ${{ github.event_name != 'pull_request' }}
platforms: linux/amd64,linux/arm64
tags: ${{ steps.meta-migrate.outputs.tags }}
labels: ${{ steps.meta-migrate.outputs.labels }}
build-args: |
APP_VERSION=${{ steps.version.outputs.version }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Sign the resulting Docker image digest except on PRs.
# This will only write to the public Rekor transparency log when the Docker
# repository is public to avoid leaking data. If you would like to publish
@@ -152,3 +182,10 @@ jobs:
# This step uses the identity token to provision an ephemeral certificate
# against the sigstore community Fulcio instance.
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}
- name: Sign the published migrate Docker image
if: ${{ github.event_name != 'pull_request' }}
env:
TAGS: ${{ steps.meta-migrate.outputs.tags }}
DIGEST: ${{ steps.build-and-push-migrate.outputs.digest }}
run: echo "${TAGS}" | xargs -I {} cosign sign --yes {}@${DIGEST}

View File

@@ -14,16 +14,24 @@ jobs:
- uses: actions/checkout@v4
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 20
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 9
- name: Install dependencies
run: pnpm install --filter @kan/web...
- name: Extract translations
working-directory: apps/web
run: npx --yes @lingui/cli extract
run: pnpm lingui:extract
- name: Lingo.dev
uses: lingodotdev/lingo.dev@main
with:
@@ -33,11 +41,11 @@ jobs:
commit-author-name: "${{ github.actor }}"
commit-author-email: "${{ github.actor }}@users.noreply.github.com"
parallel: true
- name: Compile translations
working-directory: apps/web
run: npx --yes @lingui/cli compile --typescript
run: pnpm lingui:compile
- name: Commit compiled translations
run: |
git config --local user.email "${{ github.actor }}@users.noreply.github.com"
@@ -46,4 +54,3 @@ jobs:
git add apps/web/src/locales/*/messages.ts
git diff --staged --quiet || (git commit -m "chore: compile translations" && git push)
fi

View File

@@ -57,39 +57,61 @@ The easiest way to deploy Kan is through Railway. We've partnered with Railway t
### Docker Compose
Alternatively, you can self-host Kan with Docker Compose. This will set up everything for you including your postgres database.
Alternatively, you can self-host Kan with Docker Compose. This will set up everything for you including your postgres database and automatically run migrations.
1. Create a new file called `docker-compose.yml` and paste the following configuration:
1. Create a `.env` file with your environment variables (see [Environment Variables](#environment-variables-) section below)
2. Use the provided `docker-compose.yml` file or create your own with the following configuration:
```yaml
services:
migrate:
image: ghcr.io/kanbn/kan-migrate:latest
container_name: kan-migrate
networks:
- kan-network
environment:
- POSTGRES_URL=${POSTGRES_URL}
depends_on:
postgres:
condition: service_healthy
restart: "no"
web:
image: ghcr.io/kanbn/kan:latest
container_name: kan-web
ports:
- "3000:3000"
- "${WEB_PORT:-3000}:3000"
networks:
- kan-network
env_file:
- .env
environment:
NEXT_PUBLIC_BASE_URL: http://localhost:3000
BETTER_AUTH_SECRET: your_auth_secret
POSTGRES_URL: postgresql://kan:your_postgres_password@postgres:5432/kan_db
NEXT_PUBLIC_ALLOW_CREDENTIALS: true
- NEXT_PUBLIC_BASE_URL=${NEXT_PUBLIC_BASE_URL}
- BETTER_AUTH_SECRET=${BETTER_AUTH_SECRET}
- POSTGRES_URL=${POSTGRES_URL}
- NEXT_PUBLIC_ALLOW_CREDENTIALS=true
depends_on:
- postgres
migrate:
condition: service_completed_successfully
restart: unless-stopped
postgres:
image: postgres:15
container_name: kan-db
environment:
POSTGRES_DB: kan_db
POSTGRES_USER: kan
POSTGRES_PASSWORD: your_postgres_password
- POSTGRES_DB=kan_db
- POSTGRES_USER=kan
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
ports:
- 5432:5432
volumes:
- kan_postgres_data:/var/lib/postgresql/data
healthcheck:
test: ["CMD-SHELL", "pg_isready -U kan -d kan_db"]
interval: 5s
timeout: 5s
retries: 10
restart: unless-stopped
networks:
- kan-network
@@ -101,23 +123,23 @@ volumes:
kan_postgres_data:
```
2. Start the containers in detached mode:
3. Start the containers in detached mode:
```bash
docker compose up -d
```
3. Access Kan at http://localhost:3000
The `migrate` service will automatically run database migrations before the web service starts. The application will be available at http://localhost:3000 (or the port specified in `WEB_PORT`).
The application will be running in the background. You can manage the containers using these commands:
**Managing containers:**
- To stop the containers: `docker compose down`
- To view logs: `docker compose logs -f`
- To view logs for a specific service: `docker compose logs -f web` or `docker compose logs -f migrate`
- To restart the containers: `docker compose restart`
- To rebuild after code changes: `docker compose up -d --build`
For the complete Docker Compose configuration, see [docker-compose.yml](./docker-compose.yml) in the repository.
> **Note**: The Docker Compose configuration shown above is a minimal example. For a complete setup with all features (email, OAuth, file uploads, etc.), you'll need to create a `.env` file with the required environment variables. See the Environment Variables section below for the full list of available options.
For the complete Docker Compose configuration with all optional features, see [docker-compose.yml](./docker-compose.yml) in the repository.
## Local Development 🧑‍💻

View File

@@ -39,6 +39,10 @@ checksums:
0xWkkH/placeholders/boardCount/0: 8cc7c9ba5252e9266c6eb8434fae00f3
0xWkkH/origin/0/0: 3c57a918258af4b44c187f58d203345f
0xWkkH/translation: 72358c550bd1a99fcb6e8952f0f947ef
yndBF%2B/translation: 9fb995d992256a9db7822d430ad75ba0
yndBF%2B/message: 9fb995d992256a9db7822d430ad75ba0
yndBF%2B/placeholders/projectCount/0: 23257c47018d21aeae42cf5bd0aa9932
yndBF%2B/origin/0/0: 3c57a918258af4b44c187f58d203345f
9lFfqv/message: 6cb28ff89203e2eca3fdd69396dd00d6
9lFfqv/origin/0/0: fadd5a5b6963ec5f261072f7e8d2140b
9lFfqv/translation: 6cb28ff89203e2eca3fdd69396dd00d6
@@ -81,6 +85,9 @@ checksums:
7L01XJ/message: c46571856723b03262fd33f511116298
7L01XJ/origin/0/0: feacdaf2791aaddec128f463ffa2e807
7L01XJ/translation: c46571856723b03262fd33f511116298
F6pfE9/message: 3e1ec025c4a50830bbb9ad57a176630a
F6pfE9/origin/0/0: 4b563046ba98abb3777fb1c3560866aa
F6pfE9/translation: 3e1ec025c4a50830bbb9ad57a176630a
XJOV1Y/message: 1948763de8e531483a798b68195e297e
XJOV1Y/origin/0/0: 15fd9c05fc09ccbbb54aadc4aa5e5501
XJOV1Y/origin/1/0: 9c8b544f5db130cd7c5eda9064ba3957
@@ -208,6 +215,12 @@ checksums:
WnEwDO/message: 2959fd276248208b65cb27ed46b20135
WnEwDO/origin/0/0: d6f5120f072a821219608624f361384e
WnEwDO/translation: 2959fd276248208b65cb27ed46b20135
j1%2BHPc/translation: baf4c3cd580291f41458f9ed28102c49
j1%2BHPc/message: baf4c3cd580291f41458f9ed28102c49
j1%2BHPc/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
Dz63YI/translation: 8e43abcd6e039b51084937e4829f58ad
Dz63YI/message: 8e43abcd6e039b51084937e4829f58ad
Dz63YI/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
WmPhYW/message: 0aa3973b860c1faf8d9123aebf567e40
WmPhYW/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
WmPhYW/translation: 0aa3973b860c1faf8d9123aebf567e40
@@ -245,6 +258,12 @@ checksums:
yb%2Ffjw/message: 2f5426445800ecd5a3102aac940d459c
yb%2Ffjw/origin/0/0: eb63312c63f6c8d2a5b6520c89012123
yb%2Ffjw/translation: 2f5426445800ecd5a3102aac940d459c
aKJHG%2B/message: 63de765f7fd7bc5238a3e36532306b6b
aKJHG%2B/origin/0/0: 0ad2af981579a62b084b3d41462c5546
aKJHG%2B/translation: 63de765f7fd7bc5238a3e36532306b6b
TdfEV7/message: cf5127ecfd7e43a35466a1ba5fe16450
TdfEV7/origin/0/0: 4b563046ba98abb3777fb1c3560866aa
TdfEV7/translation: cf5127ecfd7e43a35466a1ba5fe16450
lo8xBK/message: f9b67026c5ef86ac4d5944380d571961
lo8xBK/placeholders/entityLabel/0: 5745fa1af326b9ac2b140cbbef90cdeb
lo8xBK/origin/0/0: 68450df287fb46ea629e818732c1291a
@@ -332,6 +351,9 @@ checksums:
YhvWXb/origin/0/0: ff4a160eca5f8da4f075fd1dd6061fa6
YhvWXb/origin/1/0: dbad0c8d7863cb41f5495264f82e7081
YhvWXb/translation: 336a8c70a91adc49c15266167ee84cc0
i0ZMQl/message: f739058266a2cb6a3d7cca14de09c69a
i0ZMQl/origin/0/0: 0ad2af981579a62b084b3d41462c5546
i0ZMQl/translation: f739058266a2cb6a3d7cca14de09c69a
wewm3j/message: 985c0177744ec56d8dac84f66ec284ca
wewm3j/origin/0/0: bcd95e286f12800a3e7ee0a71feb3ca5
wewm3j/translation: 985c0177744ec56d8dac84f66ec284ca
@@ -344,6 +366,9 @@ checksums:
XNxYxq/message: b0e6a79e1751b734e1060a1034a893d6
XNxYxq/origin/0/0: c0b59968b2b234167c488a05cc38710b
XNxYxq/translation: b0e6a79e1751b734e1060a1034a893d6
tbNcu4/message: 3817a16b436504bb8d96ca5ee62078cc
tbNcu4/origin/0/0: 0ad2af981579a62b084b3d41462c5546
tbNcu4/translation: 3817a16b436504bb8d96ca5ee62078cc
Xid3K6/message: ba018946ffdf85e55d701a9c27595b4d
Xid3K6/origin/0/0: 2e937f7560901c3de71a592b4fd80f34
Xid3K6/translation: ba018946ffdf85e55d701a9c27595b4d
@@ -368,6 +393,9 @@ checksums:
8TveY%2B/origin/0/0: 94d3e20c29bb517dd394711d7524e478
8TveY%2B/origin/1/0: c0b59968b2b234167c488a05cc38710b
8TveY%2B/translation: 8fff51c5872e051beb9b718336665e80
0RE1AJ/message: c9a1699f5037acf87aaa6515d0f16910
0RE1AJ/origin/0/0: f78c0a7870158f5dab5216bcd6092e49
0RE1AJ/translation: c9a1699f5037acf87aaa6515d0f16910
ZDo4HN/message: 736332f2e4488609e42d2be8547d296e
ZDo4HN/origin/0/0: eb63312c63f6c8d2a5b6520c89012123
ZDo4HN/translation: 736332f2e4488609e42d2be8547d296e
@@ -600,13 +628,21 @@ checksums:
479pdJ/message: a0d2935d7b63f8dd19d7c0de47524416
479pdJ/origin/0/0: 0627e0040ca4939c9a57349e98c51797
479pdJ/translation: a0d2935d7b63f8dd19d7c0de47524416
iSLIjg/translation: 8778ee245078a8be4a2ce855c8c56edc
iSLIjg/message: 8778ee245078a8be4a2ce855c8c56edc
iSLIjg/origin/0/0: 3c57a918258af4b44c187f58d203345f
3jod3l/translation: 71ca612e433a9ed61ccfbfe1cc87c78b
3jod3l/message: 71ca612e433a9ed61ccfbfe1cc87c78b
3jod3l/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
nk7caK/message: 4440a0b9e387ef7136e3958e7a089213
nk7caK/origin/0/0: 3c57a918258af4b44c187f58d203345f
nk7caK/origin/1/0: 9d4260644f1a12f41d6b72574eeb111c
nk7caK/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
nk7caK/translation: 4440a0b9e387ef7136e3958e7a089213
sDLCvT/message: 033c5dcdb059ccb634aef7fe63f2f45d
sDLCvT/origin/0/0: d77eb1f90f2fa86a55181629d88d237a
sDLCvT/translation: 033c5dcdb059ccb634aef7fe63f2f45d
MCIXdZ/translation: ad3738e5eeabcebd3478cdc2545f543f
MCIXdZ/message: ad3738e5eeabcebd3478cdc2545f543f
MCIXdZ/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
5eZwRW/message: 84a510a7485f43e43f2191bd161171d7
5eZwRW/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
5eZwRW/translation: 84a510a7485f43e43f2191bd161171d7
@@ -808,6 +844,9 @@ checksums:
f8fH8W/message: 991b75727b6784c1a063a7462b76186d
f8fH8W/origin/0/0: eb63312c63f6c8d2a5b6520c89012123
f8fH8W/translation: 991b75727b6784c1a063a7462b76186d
Odv3J6/translation: f3cc49ba2dc3f9c33917f8a749d68bf5
Odv3J6/message: f3cc49ba2dc3f9c33917f8a749d68bf5
Odv3J6/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
YBBifR/message: a2dd737d133887d34504728c7e7f05e3
YBBifR/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
YBBifR/translation: a2dd737d133887d34504728c7e7f05e3
@@ -957,6 +996,9 @@ checksums:
55xJ%2FO/message: ebecb5c1b72ba4b063117241f5ba4f2d
55xJ%2FO/origin/0/0: 0627e0040ca4939c9a57349e98c51797
55xJ%2FO/translation: ebecb5c1b72ba4b063117241f5ba4f2d
yhLUU8/translation: e879ffdeccbe5b00fa7ece09114d149f
yhLUU8/message: e879ffdeccbe5b00fa7ece09114d149f
yhLUU8/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
cji2nM/message: cbedc3f3213dfc4fdc8b7503ae1a5cd6
cji2nM/origin/0/0: 8628ddb6f4ded25c0f17e2cbda8207d3
cji2nM/translation: cbedc3f3213dfc4fdc8b7503ae1a5cd6
@@ -972,6 +1014,9 @@ checksums:
9s9O5h/message: 0aec9bd8170bc84f5ea5c9a47c52ed26
9s9O5h/origin/0/0: 83911e3eacbad4583e2b1647a784d154
9s9O5h/translation: 0aec9bd8170bc84f5ea5c9a47c52ed26
gQ%2F02p/translation: 08e8dfeafa38796abcdcc258917428d6
gQ%2F02p/message: 08e8dfeafa38796abcdcc258917428d6
gQ%2F02p/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
lKAvEd/message: a8766853864eddc480113778a708871b
lKAvEd/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
lKAvEd/translation: a8766853864eddc480113778a708871b
@@ -1137,7 +1182,14 @@ checksums:
7hktsm/translation: 8e5e7bd026b5bec46bbfdce02ab9e0b8
RkXlPZ/message: 6e1cf3c00fa6fbe24afcc78ea3b5f3e4
RkXlPZ/origin/0/0: 98e2302d0d8d12ce65c4140b87450673
RkXlPZ/origin/1/0: 9d4260644f1a12f41d6b72574eeb111c
RkXlPZ/translation: 6e1cf3c00fa6fbe24afcc78ea3b5f3e4
PVT7q7/translation: 8fa30040ec891db0b5b7d893786514ab
PVT7q7/message: 8fa30040ec891db0b5b7d893786514ab
PVT7q7/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
"%2FbBVaD/translation": 79b9a6153d695ff0175aa804b1c0286b
"%2FbBVaD/message": 79b9a6153d695ff0175aa804b1c0286b
"%2FbBVaD/origin/0/0": 9d4260644f1a12f41d6b72574eeb111c
7eMo%2BU/message: 6251589da1964d55afabdfd64c84c335
7eMo%2BU/origin/0/0: 6cda8b872e4902cbc0191d9375adf4ef
7eMo%2BU/translation: 6251589da1964d55afabdfd64c84c335
@@ -1210,9 +1262,11 @@ checksums:
l3s5ri/translation: 348b8ab981de5b7f1fca6d7302263bbd
2MPcep/message: 7e749df6f068b9cdf1055ea38c9a80af
2MPcep/origin/0/0: 3c57a918258af4b44c187f58d203345f
2MPcep/origin/1/0: 3c57a918258af4b44c187f58d203345f
2MPcep/translation: 7e749df6f068b9cdf1055ea38c9a80af
BEVzjL/message: bcec1f271c82ddffc91ebc22021b03cb
BEVzjL/origin/0/0: 3c57a918258af4b44c187f58d203345f
BEVzjL/origin/1/0: 3c57a918258af4b44c187f58d203345f
BEVzjL/translation: bcec1f271c82ddffc91ebc22021b03cb
rRM7r0/message: d66d13649f81342f8b3a4f3b54370c20
rRM7r0/origin/0/0: d77eb1f90f2fa86a55181629d88d237a
@@ -1500,6 +1554,9 @@ checksums:
"%2FglL9Q/placeholders/0/0": 07bd981d42ffe27ee81d1dffa7dc0d43
"%2FglL9Q/origin/0/0": f78c0a7870158f5dab5216bcd6092e49
"%2FglL9Q/translation": a7a95e1dfdb4396da9e2be0e27f42323
tlhgDC/message: b96a6f8fa3267ec01e68e61656382b2e
tlhgDC/origin/0/0: f78c0a7870158f5dab5216bcd6092e49
tlhgDC/translation: b96a6f8fa3267ec01e68e61656382b2e
Eg99Sc/message: f718c896810da3612202887f9a4374fa
Eg99Sc/origin/0/0: d96af8a06c2e38a72238bcd16e426859
Eg99Sc/translation: f718c896810da3612202887f9a4374fa
@@ -1524,6 +1581,9 @@ checksums:
fvLNDy/message: f18ee3d7230cc33b68bd17b429d1d442
fvLNDy/origin/0/0: fc0c18a095a68277a0f90a115942683b
fvLNDy/translation: f18ee3d7230cc33b68bd17b429d1d442
i30J2U/translation: 8b7ec59963fb26e13948600c55c8de1d
i30J2U/message: 8b7ec59963fb26e13948600c55c8de1d
i30J2U/origin/0/0: 3c57a918258af4b44c187f58d203345f
ERpq2P/message: 5db6294712528cd897b15ae36f4fd834
ERpq2P/placeholders/debouncedQuery/0: 8471823afb4210cf564ca0d8bef9dd66
ERpq2P/origin/0/0: 89a76a14edc1c0b7876d79d7571bb8fb
@@ -1679,40 +1739,41 @@ checksums:
tyHiOa/origin/10/0: fc0c18a095a68277a0f90a115942683b
tyHiOa/origin/11/0: fc0c18a095a68277a0f90a115942683b
tyHiOa/origin/12/0: 3c57a918258af4b44c187f58d203345f
tyHiOa/origin/13/0: 3a89a46ac678e34dc8eb687b07a4ad4b
tyHiOa/origin/14/0: a31bf5b0f5348dedcad98939fcf7f93f
tyHiOa/origin/13/0: 3c57a918258af4b44c187f58d203345f
tyHiOa/origin/14/0: 3a89a46ac678e34dc8eb687b07a4ad4b
tyHiOa/origin/15/0: a31bf5b0f5348dedcad98939fcf7f93f
tyHiOa/origin/16/0: 6e60e97757a446204985b5c4374ed66d
tyHiOa/origin/17/0: d2cacb98e99d5163eff64f9c4c9cbb47
tyHiOa/origin/18/0: b2059fa4b8b99cc10440da26475b234c
tyHiOa/origin/19/0: 2a382c1cdf010f01a8e95c3e05f6df53
tyHiOa/origin/20/0: d55f532bb5ae247e3a018978be0da463
tyHiOa/origin/21/0: 4b4f55c033add8db69178563832227c6
tyHiOa/origin/22/0: 2201bf679c663a732d7f1b3c3ce3897f
tyHiOa/origin/23/0: 27ce4b16f6ada6ca35ac8d1adff329c5
tyHiOa/origin/24/0: a55c169a847bdde3b119eeb97e202c30
tyHiOa/origin/25/0: faa852a0c0e3c81fe948e394029c1ba5
tyHiOa/origin/26/0: a2dd1fc876bd42b9db7ca7aaa57ac5e2
tyHiOa/origin/27/0: e59eec882722e98169cc27f545facfe7
tyHiOa/origin/28/0: b1f4eb6768222ea825703105f6014486
tyHiOa/origin/29/0: 15fd9c05fc09ccbbb54aadc4aa5e5501
tyHiOa/origin/16/0: a31bf5b0f5348dedcad98939fcf7f93f
tyHiOa/origin/17/0: 6e60e97757a446204985b5c4374ed66d
tyHiOa/origin/18/0: d2cacb98e99d5163eff64f9c4c9cbb47
tyHiOa/origin/19/0: b2059fa4b8b99cc10440da26475b234c
tyHiOa/origin/20/0: 2a382c1cdf010f01a8e95c3e05f6df53
tyHiOa/origin/21/0: d55f532bb5ae247e3a018978be0da463
tyHiOa/origin/22/0: 4b4f55c033add8db69178563832227c6
tyHiOa/origin/23/0: 2201bf679c663a732d7f1b3c3ce3897f
tyHiOa/origin/24/0: 27ce4b16f6ada6ca35ac8d1adff329c5
tyHiOa/origin/25/0: a55c169a847bdde3b119eeb97e202c30
tyHiOa/origin/26/0: faa852a0c0e3c81fe948e394029c1ba5
tyHiOa/origin/27/0: a2dd1fc876bd42b9db7ca7aaa57ac5e2
tyHiOa/origin/28/0: e59eec882722e98169cc27f545facfe7
tyHiOa/origin/29/0: b1f4eb6768222ea825703105f6014486
tyHiOa/origin/30/0: 15fd9c05fc09ccbbb54aadc4aa5e5501
tyHiOa/origin/31/0: 68450df287fb46ea629e818732c1291a
tyHiOa/origin/32/0: afee530613110e248ffde6b56872ebed
tyHiOa/origin/31/0: 15fd9c05fc09ccbbb54aadc4aa5e5501
tyHiOa/origin/32/0: 68450df287fb46ea629e818732c1291a
tyHiOa/origin/33/0: afee530613110e248ffde6b56872ebed
tyHiOa/origin/34/0: afee530613110e248ffde6b56872ebed
tyHiOa/origin/35/0: 8628ddb6f4ded25c0f17e2cbda8207d3
tyHiOa/origin/35/0: afee530613110e248ffde6b56872ebed
tyHiOa/origin/36/0: 8628ddb6f4ded25c0f17e2cbda8207d3
tyHiOa/origin/37/0: 7493592314bc3b96ad96127a949ba1ba
tyHiOa/origin/38/0: 03c00909b41be01231cd3e843c8ee44e
tyHiOa/origin/39/0: 5c60161e173f5eae9276d8e4c70b4ebb
tyHiOa/origin/40/0: 83911e3eacbad4583e2b1647a784d154
tyHiOa/origin/41/0: d465da67c0a870d198eb7f313569c137
tyHiOa/origin/42/0: 33bf266228f835e12c0bfb0e5efb3be9
tyHiOa/origin/43/0: ff48991e314b0b3e989a4dac59860fd5
tyHiOa/origin/44/0: 30791e26a172d47d3cb0693e82679246
tyHiOa/origin/45/0: dbad0c8d7863cb41f5495264f82e7081
tyHiOa/origin/46/0: 0dccc39d0debbf3e089cb6d292de762b
tyHiOa/origin/37/0: 8628ddb6f4ded25c0f17e2cbda8207d3
tyHiOa/origin/38/0: 7493592314bc3b96ad96127a949ba1ba
tyHiOa/origin/39/0: 03c00909b41be01231cd3e843c8ee44e
tyHiOa/origin/40/0: 5c60161e173f5eae9276d8e4c70b4ebb
tyHiOa/origin/41/0: 83911e3eacbad4583e2b1647a784d154
tyHiOa/origin/42/0: d465da67c0a870d198eb7f313569c137
tyHiOa/origin/43/0: 33bf266228f835e12c0bfb0e5efb3be9
tyHiOa/origin/44/0: ff48991e314b0b3e989a4dac59860fd5
tyHiOa/origin/45/0: 30791e26a172d47d3cb0693e82679246
tyHiOa/origin/46/0: dbad0c8d7863cb41f5495264f82e7081
tyHiOa/origin/47/0: 0dccc39d0debbf3e089cb6d292de762b
tyHiOa/translation: 21ffcf0b00e7cd7b64f7454a95762e1d
PZCqeW/message: 325dea6dd0348a27a6818db2c1340c98
PZCqeW/origin/0/0: 8628ddb6f4ded25c0f17e2cbda8207d3
@@ -1893,6 +1954,7 @@ checksums:
K3iLeO/translation: e3bf6f95419169f460fb6918a0afc512
wgNoIs/message: eedc7cdb02de467c15dc418a066a77f2
wgNoIs/origin/0/0: 3c57a918258af4b44c187f58d203345f
wgNoIs/origin/1/0: 3c57a918258af4b44c187f58d203345f
wgNoIs/translation: eedc7cdb02de467c15dc418a066a77f2
rYUZIe/message: c7b0ec447415ff62856803a4d7838bd6
rYUZIe/origin/0/0: 3c57a918258af4b44c187f58d203345f
@@ -2052,6 +2114,12 @@ checksums:
nhMhRr/message: 07edd8c50685a52c0969d711df26d768
nhMhRr/origin/0/0: 1fd8ccf586705354bcae6e1186108fc7
nhMhRr/translation: 07edd8c50685a52c0969d711df26d768
NcFrgC/message: bd15a7b3d8b4bce18cd42682ea1ec164
NcFrgC/origin/0/0: 0ad2af981579a62b084b3d41462c5546
NcFrgC/translation: bd15a7b3d8b4bce18cd42682ea1ec164
C6gv54/message: 1573c77059bc92df17e661befda8d9b7
C6gv54/origin/0/0: 0ad2af981579a62b084b3d41462c5546
C6gv54/translation: 1573c77059bc92df17e661befda8d9b7
jlB2RY/message: 67a76bf346ab4b48563269e9d941a64a
jlB2RY/origin/0/0: 0627e0040ca4939c9a57349e98c51797
jlB2RY/translation: 67a76bf346ab4b48563269e9d941a64a
@@ -2128,6 +2196,9 @@ checksums:
4gAX8s/message: 29dea3e0b6238874f8c7a27619df8e36
4gAX8s/origin/0/0: 634473ef965836871efe40875a36b6ab
4gAX8s/translation: 29dea3e0b6238874f8c7a27619df8e36
L5WQLg/translation: 38a978eab728978612d1dee8bdeb915b
L5WQLg/message: 38a978eab728978612d1dee8bdeb915b
L5WQLg/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
eEQyz%2B/message: 0d3bac559c71ec4b8734f9f212320de5
eEQyz%2B/origin/0/0: d77eb1f90f2fa86a55181629d88d237a
eEQyz%2B/translation: 0d3bac559c71ec4b8734f9f212320de5
@@ -2249,6 +2320,9 @@ checksums:
TFv5tM/message: 4f2240aeff6f7275feb33ca3f608e48c
TFv5tM/origin/0/0: 7493592314bc3b96ad96127a949ba1ba
TFv5tM/translation: 4f2240aeff6f7275feb33ca3f608e48c
It4%2FFS/message: ae1527c2765592f13980acb66997e570
It4%2FFS/origin/0/0: 0ad2af981579a62b084b3d41462c5546
It4%2FFS/translation: ae1527c2765592f13980acb66997e570
E8zYtd/message: b683cc07092348c1e75dba40b1262b85
E8zYtd/placeholders/0/0: 182720128698512d43d1bf43824cd7f8
E8zYtd/origin/0/0: 1d6b5f88cdad160a67842f6b65387448
@@ -2541,12 +2615,24 @@ checksums:
tca56%2F/message: 19d84e934877efc0fef285ff3d6e7849
tca56%2F/origin/0/0: 12c1fab543c8848bcb10107d47336736
tca56%2F/translation: 19d84e934877efc0fef285ff3d6e7849
HcT8J4/translation: 19478f9152e6879c9c029198e635b44d
HcT8J4/message: 19478f9152e6879c9c029198e635b44d
HcT8J4/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
AdxYds/translation: a265e2d3b01efd3fe04ac251d2ff6afc
AdxYds/message: a265e2d3b01efd3fe04ac251d2ff6afc
AdxYds/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
PELbXB/translation: 6984aed03bbcd94041c5dd20f62e56ed
PELbXB/message: 6984aed03bbcd94041c5dd20f62e56ed
PELbXB/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
Ozt2vv/message: 8f730f68d52b7efa727aa0784282ebcb
Ozt2vv/origin/0/0: 0627e0040ca4939c9a57349e98c51797
Ozt2vv/translation: 8f730f68d52b7efa727aa0784282ebcb
"%2FtOdd2/message": 099e1780348cd7bf617721344371a430
"%2FtOdd2/origin/0/0": 03c00909b41be01231cd3e843c8ee44e
"%2FtOdd2/translation": 099e1780348cd7bf617721344371a430
"%2BjbXzb/translation": c07e27183a52361fc05b919c2a3f5c1f
"%2BjbXzb/message": c07e27183a52361fc05b919c2a3f5c1f
"%2BjbXzb/origin/0/0": 3c57a918258af4b44c187f58d203345f
CJWDTP/message: 126aeeb73f7e4cad338056e4c933f39b
CJWDTP/origin/0/0: 9d4260644f1a12f41d6b72574eeb111c
CJWDTP/translation: 126aeeb73f7e4cad338056e4c933f39b

View File

@@ -463,13 +463,6 @@ export default function Editor({
StarterKit.configure({
heading: disableHeadings ? false : undefined,
}),
Markdown,
Placeholder.configure({
placeholder: readOnly
? ""
: placeholder ??
t`Add description... (type '/' to open commands or '@' to mention)`,
}),
Link.configure({
openOnClick: true,
HTMLAttributes: {
@@ -479,6 +472,14 @@ export default function Editor({
},
validate: (href) => /^https?:\/\//.test(href),
autolink: true,
linkOnPaste: true,
}),
Markdown,
Placeholder.configure({
placeholder: readOnly
? ""
: placeholder ??
t`Add description... (type '/' to open commands or '@' to mention)`,
}),
SlashCommands.configure({
commandItems: getCommandItems(disableHeadings),

View File

@@ -19,6 +19,7 @@ interface UsePermissionsResult {
canCreateBoard: boolean;
canEditBoard: boolean;
canDeleteBoard: boolean;
canArchiveBoard: boolean;
canViewComment: boolean;
canCreateComment: boolean;
canEditComment: boolean;
@@ -33,7 +34,7 @@ interface UsePermissionsResult {
export function usePermissions(): UsePermissionsResult {
// Check if WorkspaceProvider is available (for public board views, it may not be)
const workspaceContext = useContext(WorkspaceContext);
// If WorkspaceProvider is not available, return safe defaults
if (!workspaceContext) {
const emptyPermissions: UsePermissionsResult = {
@@ -51,6 +52,7 @@ export function usePermissions(): UsePermissionsResult {
canCreateBoard: false,
canEditBoard: false,
canDeleteBoard: false,
canArchiveBoard: false,
canViewComment: false,
canCreateComment: false,
canEditComment: false,
@@ -95,6 +97,7 @@ export function usePermissions(): UsePermissionsResult {
canCreateBoard: hasPermission("board:create"),
canEditBoard: hasPermission("board:edit"),
canDeleteBoard: hasPermission("board:delete"),
canArchiveBoard: hasPermission("board:edit"),
canViewComment: hasPermission("comment:view"),
canCreateComment: hasPermission("comment:create"),
canEditComment: hasPermission("comment:edit"),

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} wurde zu deinen Favoriten hinzugefügt."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} wurde aus deinen Favoriten entfernt."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Board importieren (1)} other {Boards importieren ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Projekt importieren (1)} other {Projekte importieren ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Aktionen"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Aktiv"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Aktivität"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Beschreibung hinzufügen... (/' für Befehle oder @' zum Erwähnen eingeben)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Zu Favoriten hinzufügen"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Zu Favoriten hinzugefügt"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Haben Sie bereits ein Konto? <0><1>Anmelden</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Beim Verbinden Ihres GitHub-Kontos ist ein Fehler aufgetreten."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Beim Trennen Ihres GitHub-Kontos ist ein Fehler aufgetreten."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Beim Trennen Ihres Trello-Kontos ist ein Fehler aufgetreten."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Genehmigung"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Board archivieren"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Archiviert"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Board"
@@ -785,6 +829,13 @@
],
"translation": "Board-Analyse"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Board archiviert"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Board-Vorlagen"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Board wiederhergestellt"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Boards"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Boards, die du archivierst, werden hier angezeigt."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Karte"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Karte nicht gefunden"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Überprüfen Sie Ihren Posteingang"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Klicken Sie auf den Link, den wir an {magicLinkRecipient} gesendet haben, um sich anzumelden."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Bestätigen Sie Ihr neues Passwort"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Verbinden"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "GitHub verbinden"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Trello verbinden"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Verbinden Sie Ihre bevorzugten Tools, um Ihren Workflow zu optimieren."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Verbinden Sie Ihr GitHub-Konto, um Projekte zu importieren."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Verbinden Sie Ihr Trello-Konto, um Boards zu importieren."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Neue {0} erstellen"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Board löschen"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Vorlage löschen"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "GitHub trennen"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Trello trennen"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Board-URL bearbeiten"
@@ -2265,6 +2355,13 @@
],
"translation": "Fehler beim Ändern des Passworts"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Fehler beim Verbinden von GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Fehler beim Löschen des Arbeitsbereichs"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Fehler beim Trennen von GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Fehler beim Trennen von Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Legen Sie los, indem Sie ein neues {0} erstellen"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub verbunden"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub getrennt"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importieren"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Import abgeschlossen"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Import fehlgeschlagen"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Vorlage erstellen"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Neu"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Neuer Import"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Keine {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Keine archivierten Boards"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Keine Boards gefunden"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Es wurden noch keine Listen erstellt"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Keine Projekte gefunden"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Aus Favoriten entfernen"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Aus Favoriten entfernt"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Alle auswählen"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Quelle auswählen"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Einstellungen | Integrationen"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Registrieren | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Registrierung deaktiviert"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "Die Registrierung ist derzeit deaktiviert. Bitte versuchen Sie es später erneut."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Vielen Dank für Ihr Feedback!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "Das Board wurde archiviert."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "Das Board wurde wiederhergestellt."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Menü umschalten"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Token ist erforderlich"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello getrennt"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Board konnte nicht aktualisiert werden"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Rolle konnte nicht aktualisiert werden"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Board wiederherstellen"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Sie haben keine Berechtigung"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Ihre Boards wurden importiert."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Ihre Datei wurde erfolgreich hochgeladen."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Ihr GitHub-Konto wurde verbunden."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Ihr GitHub-Konto wurde getrennt."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Ihr GitHub-Konto ist verbunden."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Ihr Profilbild wurde aktualisiert."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Ihre Projekte wurden importiert."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Ihr Trello-Konto wurde getrennt."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Ihr Trello-Konto ist verbunden."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -34,7 +34,7 @@
"origin": [
[
"src/views/boards/index.tsx",
40
53
]
],
"translation": "{0}"
@@ -55,11 +55,11 @@
"origin": [
[
"src/views/boards/index.tsx",
35
48
],
[
"src/views/card/index.tsx",
309
308
]
],
"translation": "{0} | {1}"
@@ -75,7 +75,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
54
56
]
],
"translation": "{0} has been added to your favorites."
@@ -91,7 +91,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
55
57
]
],
"translation": "{0} has been removed from your favorites."
@@ -139,11 +139,27 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
299
489
]
],
"translation": "{boardCount, plural, one {Import board (1)} other {Import boards ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": [
"projectCount"
]
},
"comments": [],
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
341
]
],
"translation": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -312,6 +328,18 @@
],
"translation": "Actions"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/index.tsx",
26
]
],
"translation": "Active"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
@@ -319,7 +347,7 @@
"origin": [
[
"src/views/card/index.tsx",
447
446
],
[
"src/views/public/board/CardModal.tsx",
@@ -411,7 +439,7 @@
"origin": [
[
"src/components/Editor.tsx",
471
482
]
],
"translation": "Add description... (type '/' to open commands or '@' to mention)"
@@ -467,7 +495,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
93
122
]
],
"translation": "Add to favorites"
@@ -622,7 +650,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
51
53
]
],
"translation": "Added to favorites"
@@ -813,11 +841,35 @@
"origin": [
[
"src/views/auth/signup/index.tsx",
88
90
]
],
"translation": "Already have an account? <0><1>Sign in</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
107
]
],
"translation": "An error occurred while connecting your GitHub account."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
130
]
],
"translation": "An error occurred while disconnecting your GitHub account."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
@@ -825,7 +877,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
61
87
]
],
"translation": "An error occurred while disconnecting your Trello account."
@@ -966,6 +1018,30 @@
],
"translation": "Approval"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
111
]
],
"translation": "Archive board"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/index.tsx",
27
]
],
"translation": "Archived"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -1289,7 +1365,7 @@
],
[
"src/views/card/index.tsx",
309
308
],
[
"src/views/public/board/index.tsx",
@@ -1314,6 +1390,18 @@
],
"translation": "Board analytics"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
44
]
],
"translation": "Board archived"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -1362,6 +1450,18 @@
],
"translation": "Board templates"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
44
]
],
"translation": "Board unarchived"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -1458,6 +1558,18 @@
],
"translation": "Boards"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/BoardsList.tsx",
66
]
],
"translation": "Boards you archive will appear here."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1949,7 +2061,7 @@
"origin": [
[
"src/views/card/index.tsx",
309
308
]
],
"translation": "Card"
@@ -1961,11 +2073,11 @@
"origin": [
[
"src/views/card/index.tsx",
355
354
],
[
"src/views/card/index.tsx",
392
391
]
],
"translation": "Card not found"
@@ -2077,7 +2189,7 @@
],
[
"src/views/auth/signup/index.tsx",
69
71
]
],
"translation": "Check your inbox"
@@ -2177,7 +2289,7 @@
],
[
"src/views/auth/signup/index.tsx",
74
76
]
],
"translation": "Click on the link we've sent to {magicLinkRecipient} to sign in."
@@ -2189,7 +2301,7 @@
"origin": [
[
"src/views/card/index.tsx",
346
345
],
[
"src/views/members/components/EditMemberPermissionsModal.tsx",
@@ -2386,18 +2498,38 @@
],
"translation": "Confirm your new password"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
195
]
],
"translation": "Connect"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
212
]
],
"translation": "Connect GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
157
],
[
"src/views/settings/IntegrationsSettings.tsx",
93
162
]
],
"translation": "Connect Trello"
@@ -2414,6 +2546,18 @@
],
"translation": "Connect your favorite tools to streamline your workflow."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
191
]
],
"translation": "Connect your GitHub account to import projects."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
@@ -2421,7 +2565,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
80
149
]
],
"translation": "Connect your Trello account to import boards."
@@ -2693,11 +2837,11 @@
"origin": [
[
"src/views/boards/components/BoardsList.tsx",
79
80
],
[
"src/views/boards/index.tsx",
28
41
]
],
"translation": "Create new {0}"
@@ -3077,7 +3221,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
104
133
]
],
"translation": "Delete board"
@@ -3125,7 +3269,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
104
133
]
],
"translation": "Delete template"
@@ -3218,6 +3362,18 @@
],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
223
]
],
"translation": "Disconnect GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
@@ -3225,7 +3381,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
108
177
]
],
"translation": "Disconnect Trello"
@@ -3513,7 +3669,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
84
102
],
[
"src/views/board/components/UpdateBoardSlugForm.tsx",
@@ -3814,6 +3970,18 @@
],
"translation": "Error Changing Password"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
106
]
],
"translation": "Error connecting GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -3874,6 +4042,18 @@
],
"translation": "Error deleting workspace"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
129
]
],
"translation": "Error disconnecting GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
@@ -3881,7 +4061,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
60
86
]
],
"translation": "Error disconnecting Trello"
@@ -4409,7 +4589,7 @@
"origin": [
[
"src/views/auth/signup/index.tsx",
69
71
],
[
"src/views/home/components/Cta.tsx",
@@ -4461,7 +4641,7 @@
"origin": [
[
"src/views/boards/components/BoardsList.tsx",
65
66
]
],
"translation": "Get started by creating a new {0}"
@@ -4534,10 +4714,38 @@
[
"src/views/home/components/Footer.tsx",
37
],
[
"src/views/settings/IntegrationsSettings.tsx",
186
]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
99
]
],
"translation": "GitHub connected"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
122
]
],
"translation": "GitHub disconnected"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -4821,7 +5029,7 @@
"origin": [
[
"src/views/boards/index.tsx",
60
73
]
],
"translation": "Import"
@@ -4833,7 +5041,11 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
191
229
],
[
"src/views/boards/components/ImportBoardsForm.tsx",
381
]
],
"translation": "Import complete"
@@ -4845,7 +5057,11 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
204
242
],
[
"src/views/boards/components/ImportBoardsForm.tsx",
394
]
],
"translation": "Import failed"
@@ -5557,7 +5773,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
73
91
]
],
"translation": "Make template"
@@ -5792,7 +6008,7 @@
"origin": [
[
"src/views/boards/index.tsx",
82
95
],
[
"src/views/home/components/Features.tsx",
@@ -5860,7 +6076,7 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
322
513
]
],
"translation": "New import"
@@ -5988,11 +6204,23 @@
"origin": [
[
"src/views/boards/components/BoardsList.tsx",
62
63
]
],
"translation": "No {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/BoardsList.tsx",
63
]
],
"translation": "No archived boards"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -6012,7 +6240,7 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
242
432
]
],
"translation": "No boards found"
@@ -6089,6 +6317,18 @@
],
"translation": "No lists have been created yet"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
283
]
],
"translation": "No projects found"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -6672,7 +6912,7 @@
],
[
"src/views/board/components/BoardDropdown.tsx",
63
65
],
[
"src/views/board/components/NewCardForm.tsx",
@@ -6708,7 +6948,11 @@
],
[
"src/views/boards/components/ImportBoardsForm.tsx",
205
243
],
[
"src/views/boards/components/ImportBoardsForm.tsx",
395
],
[
"src/views/card/components/AttachmentThumbnails.tsx",
@@ -7144,7 +7388,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
92
121
]
],
"translation": "Remove from favorites"
@@ -7239,7 +7483,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
52
54
]
],
"translation": "Removed from favorites"
@@ -7563,7 +7807,11 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
274
315
],
[
"src/views/boards/components/ImportBoardsForm.tsx",
464
]
],
"translation": "Select all"
@@ -7575,7 +7823,7 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
157
195
]
],
"translation": "Select source"
@@ -7723,7 +7971,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
69
138
]
],
"translation": "Settings | Integrations"
@@ -7807,11 +8055,11 @@
"origin": [
[
"src/views/auth/signup/index.tsx",
34
36
],
[
"src/views/auth/signup/index.tsx",
59
61
]
],
"translation": "Sign up | kan.bn"
@@ -7823,7 +8071,7 @@
"origin": [
[
"src/views/auth/signup/index.tsx",
44
46
]
],
"translation": "Sign up disabled"
@@ -7835,7 +8083,7 @@
"origin": [
[
"src/views/auth/signup/index.tsx",
47
49
]
],
"translation": "Sign up is currently disabled. Please try again later."
@@ -8200,6 +8448,30 @@
],
"translation": "Thank you for your feedback!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
46
]
],
"translation": "The board has been archived."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
47
]
],
"translation": "The board has been unarchived."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -8504,6 +8776,18 @@
],
"translation": "Toggle menu"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
19
]
],
"translation": "Token is required"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -8527,7 +8811,7 @@
],
[
"src/views/settings/IntegrationsSettings.tsx",
73
142
]
],
"translation": "Trello"
@@ -8539,7 +8823,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
53
79
]
],
"translation": "Trello disconnected"
@@ -8827,7 +9111,7 @@
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
62
64
]
],
"translation": "Unable to update board"
@@ -8988,6 +9272,18 @@
],
"translation": "Unable to update role"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/board/components/BoardDropdown.tsx",
111
]
],
"translation": "Unarchive board"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -9659,7 +9955,7 @@
],
[
"src/views/boards/index.tsx",
35
48
],
[
"src/views/members/index.tsx",
@@ -10011,15 +10307,15 @@
],
[
"src/views/boards/components/BoardsList.tsx",
70
71
],
[
"src/views/boards/index.tsx",
46
59
],
[
"src/views/boards/index.tsx",
67
80
]
],
"translation": "You don't have permission"
@@ -10127,7 +10423,7 @@
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
192
382
]
],
"translation": "Your boards have been imported."
@@ -10156,6 +10452,42 @@
],
"translation": "Your file has been uploaded successfully."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
100
]
],
"translation": "Your GitHub account has been connected."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
123
]
],
"translation": "Your GitHub account has been disconnected."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
220
]
],
"translation": "Your GitHub account is connected."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -10180,6 +10512,18 @@
],
"translation": "Your profile image has been updated."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [
[
"src/views/boards/components/ImportBoardsForm.tsx",
230
]
],
"translation": "Your projects have been imported."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
@@ -10187,7 +10531,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
54
80
]
],
"translation": "Your Trello account has been disconnected."
@@ -10199,7 +10543,7 @@
"origin": [
[
"src/views/settings/IntegrationsSettings.tsx",
102
171
]
],
"translation": "Your Trello account is connected."

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} se ha añadido a tus favoritos."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} se ha eliminado de tus favoritos."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Importar tablero (1)} other {Importar tableros ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Importar proyecto (1)} other {Importar proyectos ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Acciones"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Activo"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Actividad"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Añadir descripción... (escribe '/' para abrir comandos o '@' para mencionar)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Añadir a favoritos"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Añadido a favoritos"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "¿Ya tienes una cuenta? <0><1>Inicia sesión</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Ocurrió un error al conectar tu cuenta de GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Ocurrió un error al desconectar tu cuenta de GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Se produjo un error al desconectar tu cuenta de Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Aprobación"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Archivar tablero"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Archivado"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Tablero"
@@ -785,6 +829,13 @@
],
"translation": "Analíticas del tablero"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tablero archivado"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Plantillas de tablero"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tablero desarchivado"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Tableros"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Los tableros que archives aparecerán aquí."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Tarjeta"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Tarjeta no encontrada"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Revisa tu bandeja de entrada"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Haz clic en el enlace que hemos enviado a {magicLinkRecipient} para iniciar sesión."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Confirma tu nueva contraseña"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Conectar"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Conectar GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Conectar Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Conecta tus herramientas favoritas para optimizar tu flujo de trabajo."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Conecta tu cuenta de GitHub para importar proyectos."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Conecta tu cuenta de Trello para importar tableros."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Crear nuevo {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Eliminar tablero"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Eliminar plantilla"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Diseño"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Desconectar GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Desconectar Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Editar URL del tablero"
@@ -2265,6 +2355,13 @@
],
"translation": "Error al cambiar la contraseña"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Error al conectar GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Error al eliminar el espacio de trabajo"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Error al desconectar GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Error al desconectar Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Comienza creando un nuevo {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub conectado"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub desconectado"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importar"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Importación completada"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Importación fallida"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Crear plantilla"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Nuevo"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nueva importación"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "No hay {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "No hay tableros archivados"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "No se encontraron tableros"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Aún no se han creado listas"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "No se encontraron proyectos"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Eliminar de favoritos"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Eliminado de favoritos"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Seleccionar todo"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Seleccionar origen"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Configuración | Integraciones"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Registrarse | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Registro deshabilitado"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "El registro está actualmente deshabilitado. Por favor, inténtalo de nuevo más tarde."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "¡Gracias por tus comentarios!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "El tablero ha sido archivado."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "El tablero ha sido desarchivado."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Alternar menú"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Se requiere el token"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello desconectado"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "No se pudo actualizar el tablero"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "No se pudo actualizar el rol"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Desarchivar tablero"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "No tienes permiso"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Tus tableros han sido importados."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Tu archivo se ha subido correctamente."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Tu cuenta de GitHub ha sido conectada."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Tu cuenta de GitHub ha sido desconectada."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Tu cuenta de GitHub está conectada."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Tu imagen de perfil ha sido actualizada."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Tus proyectos han sido importados."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Tu cuenta de Trello ha sido desconectada."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Tu cuenta de Trello está conectada."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} a été ajouté à vos favoris."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} a été retiré de vos favoris."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Importer le tableau (1)} other {Importer les tableaux ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Importer le projet (1)} other {Importer les projets ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Actions"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Actif"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Activité"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Ajouter une description... (tapez « / » pour ouvrir les commandes ou « @ » pour mentionner)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Ajouter aux favoris"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Ajouté aux favoris"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Vous avez déjà un compte ? <0><1>Se connecter</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Une erreur s'est produite lors de la connexion de votre compte GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Une erreur s'est produite lors de la déconnexion de votre compte GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Une erreur s'est produite lors de la déconnexion de votre compte Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Approbation"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Archiver le tableau"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Archivé"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Tableau"
@@ -785,6 +829,13 @@
],
"translation": "Analytiques du tableau"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tableau archivé"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Modèles de tableau"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tableau désarchivé"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Tableaux"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Les tableaux que vous archivez apparaîtront ici."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Carte"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Carte introuvable"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Consultez votre boîte de réception"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Cliquez sur le lien que nous avons envoyé à {magicLinkRecipient} pour vous connecter."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Confirmez votre nouveau mot de passe"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Connecter"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Connecter GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Connecter Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Connectez vos outils préférés pour optimiser votre flux de travail."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Connectez votre compte GitHub pour importer des projets."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Connectez votre compte Trello pour importer des tableaux."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Créer un nouveau {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Supprimer le tableau"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Supprimer le modèle"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Déconnecter GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Déconnecter Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Modifier l'URL du tableau"
@@ -2265,6 +2355,13 @@
],
"translation": "Erreur lors du changement de mot de passe"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Erreur de connexion à GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Erreur lors de la suppression de l'espace de travail"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Erreur de déconnexion de GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Erreur lors de la déconnexion de Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Commencez en créant un nouveau {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub connecté"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub déconnecté"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importer"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Importation terminée"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Échec de l'importation"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Créer un modèle"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Nouveau"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nouvel import"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Aucun {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Aucun tableau archivé"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Aucun tableau trouvé"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Aucune liste n'a encore été créée"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Aucun projet trouvé"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Retirer des favoris"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Retiré des favoris"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Tout sélectionner"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Sélectionner la source"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Paramètres | Intégrations"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "S'inscrire | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Inscription désactivée"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "L'inscription est actuellement désactivée. Veuillez réessayer plus tard."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Merci pour votre retour !"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "Le tableau a été archivé."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "Le tableau a été désarchivé."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Basculer le menu"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Le jeton est requis"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello déconnecté"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Impossible de mettre à jour le tableau"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Impossible de mettre à jour le rôle"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Désarchiver le tableau"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Vous n'avez pas la permission"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Vos tableaux ont été importés."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Votre fichier a été téléchargé avec succès."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Votre compte GitHub a été connecté."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Votre compte GitHub a été déconnecté."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Votre compte GitHub est connecté."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Votre image de profil a été mise à jour."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Vos projets ont été importés."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Votre compte Trello a été déconnecté."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Votre compte Trello est connecté."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -7,7 +7,7 @@ export const locales = [
"nl",
"ru",
"pl",
"pt-BR"
"ptbr"
] as const;
export type Locale = (typeof locales)[number];
@@ -23,5 +23,5 @@ export const localeNames: Record<Locale, string> = {
nl: "Nederlands",
ru: "Русский",
pl: "Polski",
"pt-BR": "Português",
ptbr: "Português",
};

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} è stato aggiunto ai tuoi preferiti."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} è stato rimosso dai tuoi preferiti."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Importa bacheca (1)} other {Importa bacheche ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Importa progetto (1)} other {Importa progetti ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Azioni"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Attivo"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Attività"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Aggiungi descrizione... (digita '/' per aprire i comandi o '@' per menzionare)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Aggiungi ai preferiti"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Aggiunto ai preferiti"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Hai già un account? <0><1>Accedi</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Si è verificato un errore durante la connessione del tuo account GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Si è verificato un errore durante la disconnessione del tuo account GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Si è verificato un errore durante la disconnessione del tuo account Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Approvazione"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Archivia bacheca"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Archiviato"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Board"
@@ -785,6 +829,13 @@
],
"translation": "Analisi della board"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Bacheca archiviata"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Template di board"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Bacheca ripristinata"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Board"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Le bacheche che archivi appariranno qui."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Card"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Card non trovata"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Controlla la tua casella di posta"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Clicca sul link che abbiamo inviato a {magicLinkRecipient} per accedere."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Conferma la tua nuova password"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Connetti"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Connetti GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Connetti Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Connetti i tuoi strumenti preferiti per semplificare il tuo flusso di lavoro."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Connetti il tuo account GitHub per importare progetti."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Connetti il tuo account Trello per importare le bacheche."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Crea nuovo {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Elimina board"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Elimina template"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Disconnetti GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Disconnetti Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Modifica URL bacheca"
@@ -2265,6 +2355,13 @@
],
"translation": "Errore durante la modifica della password"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Errore nella connessione a GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Errore durante l'eliminazione dello spazio di lavoro"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Errore nella disconnessione da GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Errore durante la disconnessione da Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Inizia creando un nuovo {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub connesso"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub disconnesso"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importa"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Importazione completata"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Importazione fallita"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Crea template"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Nuovo"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nuova importazione"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Nessun {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Nessuna bacheca archiviata"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Nessuna board trovata"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Nessuna lista è stata ancora creata"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Nessun progetto trovato"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Rimuovi dai preferiti"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Rimosso dai preferiti"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Seleziona tutto"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Seleziona origine"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Impostazioni | Integrazioni"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Registrati | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Registrazione disabilitata"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "La registrazione è attualmente disabilitata. Riprova più tardi."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Grazie per il tuo feedback!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "La bacheca è stata archiviata."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "La bacheca è stata ripristinata."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Attiva/disattiva menu"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Il token è obbligatorio"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello disconnesso"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Impossibile aggiornare la board"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Impossibile aggiornare il ruolo"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Ripristina bacheca"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Non hai i permessi necessari"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Le tue board sono state importate."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Il tuo file è stato caricato con successo."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Il tuo account GitHub è stato connesso."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Il tuo account GitHub è stato disconnesso."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Il tuo account GitHub è connesso."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "La tua immagine del profilo è stata aggiornata."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "I tuoi progetti sono stati importati."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Il tuo account Trello è stato disconnesso."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Il tuo account Trello è connesso."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} is toegevoegd aan je favorieten."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} is verwijderd uit je favorieten."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Bord importeren (1)} other {Borden importeren ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Project importeren (1)} other {Projecten importeren ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Acties"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Actief"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Activiteit"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Voeg beschrijving toe... (typ '/' om commando's te openen of '@' om te vermelden)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Toevoegen aan favorieten"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Toegevoegd aan favorieten"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Heb je al een account? <0><1>Inloggen</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Er is een fout opgetreden bij het verbinden van je GitHub-account."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Er is een fout opgetreden bij het loskoppelen van je GitHub-account."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Er is een fout opgetreden bij het loskoppelen van je Trello-account."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Goedkeuring"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Board archiveren"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Gearchiveerd"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Bord"
@@ -785,6 +829,13 @@
],
"translation": "Bordanalyse"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Board gearchiveerd"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Bordsjablonen"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Board gedearchiveerd"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Boards"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Boards die je archiveert verschijnen hier."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Kaart"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Kaart niet gevonden"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Controleer je inbox"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Klik op de link die we naar {magicLinkRecipient} hebben gestuurd om in te loggen."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Bevestig je nieuwe wachtwoord"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Verbinden"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "GitHub verbinden"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Verbind Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Verbind je favoriete tools om je workflow te stroomlijnen."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Verbind je GitHub-account om projecten te importeren."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Verbind je Trello-account om boards te importeren."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Maak nieuwe {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Bord verwijderen"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Sjabloon verwijderen"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Ontwerp"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "GitHub loskoppelen"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Trello loskoppelen"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Bord-URL bewerken"
@@ -2265,6 +2355,13 @@
],
"translation": "Fout bij wijzigen wachtwoord"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Fout bij verbinden met GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Fout bij verwijderen werkruimte"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Fout bij loskoppelen van GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Fout bij loskoppelen Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Ga aan de slag door een nieuwe {0} te maken"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub verbonden"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub losgekoppeld"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importeren"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Import voltooid"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Import mislukt"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Sjabloon maken"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Nieuw"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nieuwe import"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Geen {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Geen gearchiveerde boards"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Geen borden gevonden"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Er zijn nog geen lijsten aangemaakt"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Geen projecten gevonden"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Verwijderen uit favorieten"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Verwijderd uit favorieten"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Alles selecteren"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Selecteer bron"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Instellingen | Integraties"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Registreren | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Registratie uitgeschakeld"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "Registratie is momenteel uitgeschakeld. Probeer het later opnieuw."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Bedankt voor je feedback!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "Het board is gearchiveerd."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "Het board is gedearchiveerd."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Menu in-/uitschakelen"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Token is vereist"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello losgekoppeld"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Kan bord niet bijwerken"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Kan rol niet bijwerken"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Board dearchiveren"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Je hebt geen toestemming"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Je borden zijn geïmporteerd."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Je bestand is succesvol geüpload."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Je GitHub-account is gekoppeld."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Je GitHub-account is ontkoppeld."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Je GitHub-account is gekoppeld."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Je profielafbeelding is bijgewerkt."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Je projecten zijn geïmporteerd."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Je Trello-account is losgekoppeld."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Je Trello-account is gekoppeld."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} został dodany do ulubionych."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} został usunięty z ulubionych."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Importuj tablicę (1)} few {Importuj tablice ({boardCount})} many {Importuj tablic ({boardCount})} other {Importuj tablice ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Importuj projekt (1)} few {Importuj projekty ({projectCount})} many {Importuj projektów ({projectCount})} other {Importuj projekty ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Akcje"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Aktywna"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Aktywność"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Dodaj opis... (wpisz '/' aby otworzyć polecenia lub '@', aby wspomnieć)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Dodaj do ulubionych"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Dodano do ulubionych"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Masz już konto? <0><1>Zaloguj się</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Wystąpił błąd podczas łączenia konta GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Wystąpił błąd podczas odłączania konta GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Wystąpił błąd podczas odłączania konta Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Zatwierdzenie"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Zarchiwizuj tablicę"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Zarchiwizowana"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Tablica"
@@ -785,6 +829,13 @@
],
"translation": "Analiza tablicy"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tablica zarchiwizowana"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Szablony tablic"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Tablica przywrócona z archiwum"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Tablice"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Zarchiwizowane tablice pojawią się tutaj."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Karta"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Nie znaleziono karty"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Sprawdź swoją skrzynkę odbiorczą"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Kliknij w link, który wysłaliśmy do {magicLinkRecipient}, aby się zalogować."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Potwierdź nowe hasło"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Połącz"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Połącz z GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Połącz Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Połącz swoje ulubione narzędzia, aby usprawnić pracę."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Połącz swoje konto GitHub, aby zaimportować projekty."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Połącz swoje konto Trello, aby zaimportować tablice."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Utwórz nową {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Usuń tablicę"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Usuń szablon"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Odłącz GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Odłącz Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Edytuj URL tablicy"
@@ -2265,6 +2355,13 @@
],
"translation": "Błąd podczas zmiany hasła"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Błąd podczas łączenia z GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Błąd podczas usuwania przestrzeni roboczej"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Błąd podczas odłączania GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Błąd podczas odłączania Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Rozpocznij, tworząc nowy {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub połączony"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub odłączony"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importuj"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Import zakończony"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Import nie powiódł się"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Utwórz szablon"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Nowy"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nowy import"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Brak {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Brak zarchiwizowanych tablic"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Nie znaleziono żadnych tablic"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Nie utworzono jeszcze żadnych list"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Nie znaleziono projektów"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Usuń z ulubionych"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Usunięto z ulubionych"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Zaznacz wszystko"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Wybierz źródło"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Ustawienia | Integracje"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Rejestracja | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Rejestracja wyłączona"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "Rejestracja jest obecnie wyłączona. Spróbuj ponownie później."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Dziękujemy za Twoją opinię!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "Tablica została zarchiwizowana."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "Tablica została przywrócona z archiwum."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Przełącz menu"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Wymagany jest token"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello zostało odłączone"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Nie można zaktualizować tablicy"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Nie można zaktualizować roli"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Przywróć tablicę z archiwum"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Nie masz uprawnień"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Twoje tablice zostały zaimportowane."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Twój plik został pomyślnie przesłany."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Twoje konto GitHub zostało połączone."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Twoje konto GitHub zostało odłączone."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Twoje konto GitHub jest połączone."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Twoje zdjęcie profilowe zostało zaktualizowane."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Twoje projekty zostały zaimportowane."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Twoje konto Trello zostało odłączone."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Twoje konto Trello jest połączone."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} foi adicionado aos seus favoritos."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} foi removido dos seus favoritos."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Importar quadro (1)} other {Importar quadros ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Importar projeto (1)} other {Importar projetos ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Ações"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Ativo"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Atividade"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Adicionar descrição... (digite '/' para abrir comandos ou '@' para mencionar)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Adicionar aos favoritos"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Adicionado aos favoritos"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Já tem uma conta? <0><1>Entrar</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Ocorreu um erro ao conectar sua conta do GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Ocorreu um erro ao desconectar sua conta do GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Ocorreu um erro ao desconectar sua conta do Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Aprovação"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Arquivar quadro"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "Arquivado"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Quadro"
@@ -785,6 +829,13 @@
],
"translation": "Análise do quadro"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Quadro arquivado"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Modelos de quadro"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Quadro desarquivado"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Quadros"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Os quadros que você arquivar aparecerão aqui."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Cartão"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Cartão não encontrado"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Verifique sua caixa de entrada"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Clique no link que enviamos para {magicLinkRecipient} para fazer login."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Confirme sua nova senha"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Conectar"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Conectar GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Conectar Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Conecte suas ferramentas favoritas para otimizar seu fluxo de trabalho."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Conecte sua conta do GitHub para importar projetos."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Conecte sua conta do Trello para importar quadros."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Criar novo {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Excluir quadro"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Excluir modelo"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Design"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Desconectar GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Desconectar Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Editar URL do quadro"
@@ -2265,6 +2355,13 @@
],
"translation": "Erro ao alterar senha"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Erro ao conectar GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Erro ao excluir workspace"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Erro ao desconectar GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Erro ao desconectar Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Comece criando um novo {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub conectado"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub desconectado"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Importar"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Importação concluída"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Falha na importação"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Criar modelo"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Novo"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Nova importação"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Nenhum {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Nenhum quadro arquivado"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Nenhum quadro encontrado"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Nenhuma lista foi criada ainda"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Nenhum projeto encontrado"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Remover dos favoritos"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Removido dos favoritos"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Selecionar tudo"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Selecionar origem"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Configurações | Integrações"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Cadastrar | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Cadastro desabilitado"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "O cadastro está temporariamente desabilitado. Por favor, tente novamente mais tarde."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Obrigado pelo seu feedback!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "O quadro foi arquivado."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "O quadro foi desarquivado."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Alternar menu"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Token é obrigatório"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello desconectado"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Não foi possível atualizar o quadro"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Não foi possível atualizar a função"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Desarquivar quadro"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "Você não tem permissão"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Seus quadros foram importados."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Seu arquivo foi enviado com sucesso."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Sua conta do GitHub foi conectada."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Sua conta do GitHub foi desconectada."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Sua conta do GitHub está conectada."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Sua imagem de perfil foi atualizada."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Seus projetos foram importados."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Sua conta do Trello foi desconectada."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Sua conta do Trello está conectada."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

View File

@@ -19,7 +19,7 @@
"0": ["isTemplate ? \"Templates\" : \"Boards\""]
},
"comments": [],
"origin": [["src/views/boards/index.tsx", 40]],
"origin": [["src/views/boards/index.tsx", 53]],
"translation": "{0}"
},
"JArWcF": {
@@ -33,8 +33,8 @@
},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 35],
["src/views/card/index.tsx", 309]
["src/views/boards/index.tsx", 48],
["src/views/card/index.tsx", 308]
],
"translation": "{0} | {1}"
},
@@ -44,7 +44,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 56]],
"translation": "{0} добавлен в избранное."
},
"bDI6VI": {
@@ -53,7 +53,7 @@
"0": ["boardName ?? \"Board\""]
},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 55]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 57]],
"translation": "{0} удалён из избранного."
},
"CJukzS": {
@@ -80,9 +80,18 @@
"boardCount": ["boardCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 299]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 489]],
"translation": "{boardCount, plural, one {Импортировать доску (1)} few {Импортировать доски ({boardCount})} many {Импортировать досок ({boardCount})} other {Импортировать доски ({boardCount})}}"
},
"yndBF+": {
"message": "{projectCount, plural, one {Import project (1)} other {Import projects ({projectCount})}}",
"placeholders": {
"projectCount": ["projectCount"]
},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 341]],
"translation": "{projectCount, plural, one {Импортировать проект (1)} few {Импортировать проекта ({projectCount})} many {Импортировать проектов ({projectCount})} other {Импортировать проекта ({projectCount})}}"
},
"9lFfqv": {
"message": "/month",
"placeholders": {},
@@ -185,12 +194,19 @@
"origin": [["src/providers/keyboard-shortcuts.tsx", 56]],
"translation": "Действия"
},
"F6pfE9": {
"message": "Active",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 26]],
"translation": "Активно"
},
"XJOV1Y": {
"message": "Activity",
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 447],
["src/views/card/index.tsx", 446],
["src/views/public/board/CardModal.tsx", 189]
],
"translation": "Активность"
@@ -246,7 +262,7 @@
"message": "Add description... (type '/' to open commands or '@' to mention)",
"placeholders": {},
"comments": [],
"origin": [["src/components/Editor.tsx", 471]],
"origin": [["src/components/Editor.tsx", 482]],
"translation": "Добавить описание... (введите '/' для открытия команд или '@' для упоминания)"
},
"abUZlY": {
@@ -280,7 +296,7 @@
"message": "Add to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 93]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 122]],
"translation": "Добавить в избранное"
},
"bmXKoX": {
@@ -368,7 +384,7 @@
"message": "Added to favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 51]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 53]],
"translation": "Добавлено в избранное"
},
"14Xi3Z": {
@@ -482,14 +498,28 @@
"message": "Already have an account? <0><1>Sign in</1></0>",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 88]],
"origin": [["src/views/auth/signup/index.tsx", 90]],
"translation": "Уже есть аккаунт? <0><1>Войти</1></0>"
},
"j1+HPc": {
"message": "An error occurred while connecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 107]],
"translation": "Произошла ошибка при подключении вашего аккаунта GitHub."
},
"Dz63YI": {
"message": "An error occurred while disconnecting your GitHub account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 130]],
"translation": "Произошла ошибка при отключении вашего аккаунта GitHub."
},
"WmPhYW": {
"message": "An error occurred while disconnecting your Trello account.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 61]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 87]],
"translation": "Произошла ошибка при отключении вашей учетной записи Trello."
},
"ZXSPJt": {
@@ -574,6 +604,20 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 46]],
"translation": "Одобрение"
},
"aKJHG+": {
"message": "Archive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Архивировать доску"
},
"TdfEV7": {
"message": "Archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 27]],
"translation": "В архиве"
},
"lo8xBK": {
"message": "Are you sure want to remove {entityLabel}?",
"placeholders": {
@@ -770,7 +814,7 @@
"comments": [],
"origin": [
["src/views/board/index.tsx", 400],
["src/views/card/index.tsx", 309],
["src/views/card/index.tsx", 308],
["src/views/public/board/index.tsx", 125]
],
"translation": "Доска"
@@ -785,6 +829,13 @@
],
"translation": "Аналитика доски"
},
"i0ZMQl": {
"message": "Board archived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Доска архивирована"
},
"wewm3j": {
"message": "Board name cannot exceed 100 characters",
"placeholders": {},
@@ -815,6 +866,13 @@
],
"translation": "Шаблоны досок"
},
"tbNcu4": {
"message": "Board unarchived",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 44]],
"translation": "Доска восстановлена из архива"
},
"Xid3K6": {
"message": "Board URL can only contain letters, numbers, and hyphens",
"placeholders": {},
@@ -873,6 +931,13 @@
],
"translation": "Доски"
},
"0RE1AJ": {
"message": "Boards you archive will appear here.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Здесь будут отображаться архивированные вами доски."
},
"ZDo4HN": {
"message": "Brainstorming",
"placeholders": {},
@@ -1163,7 +1228,7 @@
"message": "Card",
"placeholders": {},
"comments": [],
"origin": [["src/views/card/index.tsx", 309]],
"origin": [["src/views/card/index.tsx", 308]],
"translation": "Карточка"
},
"fEY2vP": {
@@ -1171,8 +1236,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 355],
["src/views/card/index.tsx", 392]
["src/views/card/index.tsx", 354],
["src/views/card/index.tsx", 391]
],
"translation": "Карточка не найдена"
},
@@ -1237,7 +1302,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 43],
["src/views/auth/signup/index.tsx", 69]
["src/views/auth/signup/index.tsx", 71]
],
"translation": "Проверьте свой почтовый ящик"
},
@@ -1305,7 +1370,7 @@
"comments": [],
"origin": [
["src/views/auth/login/index.tsx", 48],
["src/views/auth/signup/index.tsx", 74]
["src/views/auth/signup/index.tsx", 76]
],
"translation": "Перейдите по ссылке, которую мы отправили на {magicLinkRecipient}, чтобы войти."
},
@@ -1314,7 +1379,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/card/index.tsx", 346],
["src/views/card/index.tsx", 345],
["src/views/members/components/EditMemberPermissionsModal.tsx", 172],
["src/views/settings/components/NewApiKeyModal.tsx", 136]
],
@@ -1431,14 +1496,25 @@
],
"translation": "Подтвердите новый пароль"
},
"iSLIjg": {
"message": "Connect",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Подключить"
},
"3jod3l": {
"message": "Connect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 212]],
"translation": "Подключить GitHub"
},
"nk7caK": {
"message": "Connect Trello",
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 157],
["src/views/settings/IntegrationsSettings.tsx", 93]
],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 162]],
"translation": "Подключить Trello"
},
"sDLCvT": {
@@ -1448,11 +1524,18 @@
"origin": [["src/views/home/components/Features.tsx", 122]],
"translation": "Подключите любимые инструменты, чтобы упростить рабочий процесс."
},
"MCIXdZ": {
"message": "Connect your GitHub account to import projects.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 191]],
"translation": "Подключите свой аккаунт GitHub, чтобы импортировать проекты."
},
"5eZwRW": {
"message": "Connect your Trello account to import boards.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 149]],
"translation": "Подключите ваш аккаунт Trello для импорта досок."
},
"jfC/xh": {
@@ -1612,8 +1695,8 @@
},
"comments": [],
"origin": [
["src/views/boards/components/BoardsList.tsx", 79],
["src/views/boards/index.tsx", 28]
["src/views/boards/components/BoardsList.tsx", 80],
["src/views/boards/index.tsx", 41]
],
"translation": "Создать новый {0}"
},
@@ -1835,7 +1918,7 @@
"message": "Delete board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Удалить доску"
},
"nabda1": {
@@ -1863,7 +1946,7 @@
"message": "Delete template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 104]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 133]],
"translation": "Удалить шаблон"
},
"kYu0eF": {
@@ -1916,11 +1999,18 @@
"origin": [["src/views/boards/components/TemplateBoards.tsx", 45]],
"translation": "Дизайн"
},
"Odv3J6": {
"message": "Disconnect GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 223]],
"translation": "Отключить GitHub"
},
"YBBifR": {
"message": "Disconnect Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 108]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 177]],
"translation": "Отключить Trello"
},
"1sRmLC": {
@@ -2079,7 +2169,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/board/components/BoardDropdown.tsx", 84],
["src/views/board/components/BoardDropdown.tsx", 102],
["src/views/board/components/UpdateBoardSlugForm.tsx", 116]
],
"translation": "Изменить URL доски"
@@ -2265,6 +2355,13 @@
],
"translation": "Ошибка при смене пароля"
},
"yhLUU8": {
"message": "Error connecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 106]],
"translation": "Ошибка подключения GitHub"
},
"cji2nM": {
"message": "Error creating invite link",
"placeholders": {},
@@ -2304,11 +2401,18 @@
],
"translation": "Ошибка при удалении рабочего пространства"
},
"gQ/02p": {
"message": "Error disconnecting GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 129]],
"translation": "Ошибка при отключении GitHub"
},
"lKAvEd": {
"message": "Error disconnecting Trello",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 60]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 86]],
"translation": "Ошибка при отключении Trello"
},
"rarRW/": {
@@ -2622,7 +2726,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 69],
["src/views/auth/signup/index.tsx", 71],
["src/views/home/components/Cta.tsx", 61],
["src/views/home/components/Header.tsx", 106],
["src/views/pricing/components/PricingTiers.tsx", 29],
@@ -2647,7 +2751,7 @@
"0": ["isTemplate ? \"template\" : \"board\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 65]],
"origin": [["src/views/boards/components/BoardsList.tsx", 66]],
"translation": "Начните с создания нового {0}"
},
"zC8Whw": {
@@ -2689,9 +2793,26 @@
"message": "GitHub",
"placeholders": {},
"comments": [],
"origin": [["src/views/home/components/Footer.tsx", 37]],
"origin": [
["src/views/home/components/Footer.tsx", 37],
["src/views/settings/IntegrationsSettings.tsx", 186]
],
"translation": "GitHub"
},
"PVT7q7": {
"message": "GitHub connected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 99]],
"translation": "GitHub подключён"
},
"/bBVaD": {
"message": "GitHub disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 122]],
"translation": "GitHub отключён"
},
"7eMo+U": {
"message": "Go Home",
"placeholders": {},
@@ -2863,21 +2984,27 @@
"message": "Import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/index.tsx", 60]],
"origin": [["src/views/boards/index.tsx", 73]],
"translation": "Импорт"
},
"2MPcep": {
"message": "Import complete",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 191]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 229],
["src/views/boards/components/ImportBoardsForm.tsx", 381]
],
"translation": "Импорт завершён"
},
"BEVzjL": {
"message": "Import failed",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 204]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 242],
["src/views/boards/components/ImportBoardsForm.tsx", 394]
],
"translation": "Ошибка импорта"
},
"rRM7r0": {
@@ -3299,7 +3426,7 @@
"message": "Make template",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 73]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 91]],
"translation": "Создать шаблон"
},
"IDvohQ": {
@@ -3432,7 +3559,7 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/boards/index.tsx", 82],
["src/views/boards/index.tsx", 95],
["src/views/home/components/Features.tsx", 73]
],
"translation": "Новый"
@@ -3471,7 +3598,7 @@
"message": "New import",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 322]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 513]],
"translation": "Новый импорт"
},
"n1GRql": {
@@ -3550,9 +3677,16 @@
"0": ["isTemplate ? \"templates\" : \"boards\""]
},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 62]],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Нет {0}"
},
"tlhgDC": {
"message": "No archived boards",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/BoardsList.tsx", 63]],
"translation": "Нет архивированных досок"
},
"Eg99Sc": {
"message": "No authentication methods are currently available",
"placeholders": {},
@@ -3564,7 +3698,7 @@
"message": "No boards found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 242]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 432]],
"translation": "Доски не найдены"
},
"OpNhRn": {
@@ -3609,6 +3743,13 @@
"origin": [["src/views/board/index.tsx", 527]],
"translation": "Списки ещё не созданы"
},
"i30J2U": {
"message": "No projects found",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 283]],
"translation": "Проекты не найдены"
},
"ERpq2P": {
"message": "No results found for \"{debouncedQuery}\".",
"placeholders": {
@@ -3963,7 +4104,7 @@
["src/components/DeleteLabelConfirmation.tsx", 26],
["src/components/FeedbackModal.tsx", 41],
["src/components/NewWorkspaceForm.tsx", 158],
["src/views/board/components/BoardDropdown.tsx", 63],
["src/views/board/components/BoardDropdown.tsx", 65],
["src/views/board/components/NewCardForm.tsx", 184],
["src/views/board/components/NewListForm.tsx", 79],
["src/views/board/components/NewTemplateForm.tsx", 61],
@@ -3972,7 +4113,8 @@
["src/views/board/components/VisibilityButton.tsx", 57],
["src/views/board/index.tsx", 181],
["src/views/board/index.tsx", 237],
["src/views/boards/components/ImportBoardsForm.tsx", 205],
["src/views/boards/components/ImportBoardsForm.tsx", 243],
["src/views/boards/components/ImportBoardsForm.tsx", 395],
["src/views/card/components/AttachmentThumbnails.tsx", 74],
["src/views/card/components/ChecklistItemRow.tsx", 69],
["src/views/card/components/ChecklistItemRow.tsx", 97],
@@ -4178,7 +4320,7 @@
"message": "Remove from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 92]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 121]],
"translation": "Удалить из избранного"
},
"99VIgC": {
@@ -4232,7 +4374,7 @@
"message": "Removed from favorites",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 52]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 54]],
"translation": "Удалено из избранного"
},
"YVT40D": {
@@ -4426,14 +4568,17 @@
"message": "Select all",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 274]],
"origin": [
["src/views/boards/components/ImportBoardsForm.tsx", 315],
["src/views/boards/components/ImportBoardsForm.tsx", 464]
],
"translation": "Выбрать всё"
},
"rYUZIe": {
"message": "Select source",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 157]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 195]],
"translation": "Выбрать источник"
},
"ppaRWv": {
@@ -4520,7 +4665,7 @@
"message": "Settings | Integrations",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 69]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 138]],
"translation": "Настройки | Интеграции"
},
"F/FPk/": {
@@ -4570,8 +4715,8 @@
"placeholders": {},
"comments": [],
"origin": [
["src/views/auth/signup/index.tsx", 34],
["src/views/auth/signup/index.tsx", 59]
["src/views/auth/signup/index.tsx", 36],
["src/views/auth/signup/index.tsx", 61]
],
"translation": "Регистрация | kan.bn"
},
@@ -4579,14 +4724,14 @@
"message": "Sign up disabled",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 44]],
"origin": [["src/views/auth/signup/index.tsx", 46]],
"translation": "Регистрация отключена"
},
"s6iE/c": {
"message": "Sign up is currently disabled. Please try again later.",
"placeholders": {},
"comments": [],
"origin": [["src/views/auth/signup/index.tsx", 47]],
"origin": [["src/views/auth/signup/index.tsx", 49]],
"translation": "Регистрация сейчас недоступна. Пожалуйста, попробуйте позже."
},
"6FDocz": {
@@ -4809,6 +4954,20 @@
"origin": [["src/components/FeedbackModal.tsx", 34]],
"translation": "Спасибо за ваш отзыв!"
},
"NcFrgC": {
"message": "The board has been archived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 46]],
"translation": "Доска была архивирована."
},
"C6gv54": {
"message": "The board has been unarchived.",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 47]],
"translation": "Доска была восстановлена из архива."
},
"jlB2RY": {
"message": "The current password you entered is incorrect.",
"placeholders": {},
@@ -5001,6 +5160,13 @@
"origin": [["src/views/home/components/Header.tsx", 114]],
"translation": "Переключить меню"
},
"L5WQLg": {
"message": "Token is required",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 19]],
"translation": "Требуется токен"
},
"eEQyz+": {
"message": "Track all card changes with detailed activity history.",
"placeholders": {},
@@ -5014,7 +5180,7 @@
"comments": [],
"origin": [
["src/views/pricing/components/FeatureComparisonTable.tsx", 218],
["src/views/settings/IntegrationsSettings.tsx", 73]
["src/views/settings/IntegrationsSettings.tsx", 142]
],
"translation": "Trello"
},
@@ -5022,7 +5188,7 @@
"message": "Trello disconnected",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 53]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 79]],
"translation": "Trello отключён"
},
"kxEs5t": {
@@ -5196,7 +5362,7 @@
"message": "Unable to update board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 62]],
"origin": [["src/views/board/components/BoardDropdown.tsx", 64]],
"translation": "Не удалось обновить доску"
},
"XpcjLO": {
@@ -5292,6 +5458,13 @@
"origin": [["src/views/members/index.tsx", 65]],
"translation": "Не удалось обновить роль"
},
"It4/FS": {
"message": "Unarchive board",
"placeholders": {},
"comments": [],
"origin": [["src/views/board/components/BoardDropdown.tsx", 111]],
"translation": "Восстановить доску из архива"
},
"E8zYtd": {
"message": "unassigned <0>{0}</0> from the card",
"placeholders": {
@@ -5671,7 +5844,7 @@
"origin": [
["src/components/SettingsLayout.tsx", 46],
["src/views/board/index.tsx", 400],
["src/views/boards/index.tsx", 35],
["src/views/boards/index.tsx", 48],
["src/views/members/index.tsx", 258],
["src/views/public/board/index.tsx", 125],
["src/views/public/boards/index.tsx", 65]
@@ -5883,9 +6056,9 @@
["src/views/board/components/VisibilityButton.tsx", 72],
["src/views/board/index.tsx", 474],
["src/views/board/index.tsx", 532],
["src/views/boards/components/BoardsList.tsx", 70],
["src/views/boards/index.tsx", 46],
["src/views/boards/index.tsx", 67]
["src/views/boards/components/BoardsList.tsx", 71],
["src/views/boards/index.tsx", 59],
["src/views/boards/index.tsx", 80]
],
"translation": "У вас нет прав доступа"
},
@@ -5951,7 +6124,7 @@
"message": "Your boards have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 192]],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 382]],
"translation": "Ваши доски были импортированы."
},
"LqWW5F": {
@@ -5968,6 +6141,27 @@
"origin": [["src/views/card/components/AttachmentUpload.tsx", 46]],
"translation": "Ваш файл был успешно загружен."
},
"HcT8J4": {
"message": "Your GitHub account has been connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 100]],
"translation": "Ваш аккаунт GitHub был подключён."
},
"AdxYds": {
"message": "Your GitHub account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 123]],
"translation": "Ваш аккаунт GitHub был отключён."
},
"PELbXB": {
"message": "Your GitHub account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 220]],
"translation": "Ваш аккаунт GitHub подключён."
},
"Ozt2vv": {
"message": "Your password has been changed.",
"placeholders": {},
@@ -5984,18 +6178,25 @@
"origin": [["src/views/settings/components/Avatar.tsx", 190]],
"translation": "Ваше изображение профиля было обновлено."
},
"+jbXzb": {
"message": "Your projects have been imported.",
"placeholders": {},
"comments": [],
"origin": [["src/views/boards/components/ImportBoardsForm.tsx", 230]],
"translation": "Ваши проекты были импортированы."
},
"CJWDTP": {
"message": "Your Trello account has been disconnected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 54]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 80]],
"translation": "Ваш аккаунт Trello был отключён."
},
"WRsbHO": {
"message": "Your Trello account is connected.",
"placeholders": {},
"comments": [],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 102]],
"origin": [["src/views/settings/IntegrationsSettings.tsx", 171]],
"translation": "Ваш аккаунт Trello подключён."
},
"25fAUC": {

File diff suppressed because one or more lines are too long

View File

@@ -2,48 +2,74 @@ import type { NextApiRequest, NextApiResponse } from "next";
import { withRateLimit } from "@kan/api/utils/rateLimit";
import { env } from "~/env";
export default withRateLimit(
{ points: 100, duration: 60 },
async (req: NextApiRequest, res: NextApiResponse) => {
if (req.method !== "GET") {
return res.status(405).json({ message: "Method not allowed" });
}
const { url, filename } = req.query;
if (!url || typeof url !== "string") {
return res.status(400).json({
message: "url parameter is required",
});
}
try {
const downloadFilename = typeof filename === "string"
? encodeURIComponent(filename)
: "attachment";
const upstream = await fetch(url);
if (!upstream.ok) {
return res.status(upstream.status).json({
message: "Failed to fetch attachment",
});
if (req.method !== "GET") {
return res.status(405).json({ message: "Method not allowed" });
}
const contentType =
upstream.headers.get("Content-Type") ?? "application/octet-stream";
const { url, filename } = req.query;
res.setHeader("Content-Type", contentType);
res.setHeader(
"Content-Disposition",
`attachment; filename="${downloadFilename}"; filename*=UTF-8''${downloadFilename}`,
);
if (!url || typeof url !== "string") {
return res.status(400).json({ message: "url parameter is required" });
}
const buffer = await upstream.arrayBuffer();
return res.send(Buffer.from(buffer));
} catch (error) {
console.error("Error downloading attachment:", error);
return res.status(500).json({ message: "Failed to download attachment" });
}
const s3Endpoint = env.S3_ENDPOINT;
if (s3Endpoint) {
let parsed: URL;
try {
parsed = new URL(url);
} catch {
return res.status(400).json({ message: "Invalid URL" });
}
const hostname = parsed.hostname.toLowerCase();
let allowedHost: string;
try {
allowedHost = new URL(s3Endpoint).hostname.toLowerCase();
} catch {
return res.status(500).json({ message: "Storage endpoint misconfigured" });
}
if (hostname !== allowedHost && !hostname.endsWith(`.${allowedHost}`)) {
return res.status(403).json({ message: "URL not allowed" });
}
}
try {
const downloadFilename =
typeof filename === "string"
? encodeURIComponent(filename)
: "attachment";
const upstream = await fetch(url);
if (!upstream.ok) {
return res
.status(upstream.status)
.json({ message: "Failed to fetch attachment" });
}
const contentType =
upstream.headers.get("Content-Type") ?? "application/octet-stream";
res.setHeader("Content-Type", contentType);
res.setHeader(
"Content-Disposition",
`attachment; filename="${downloadFilename}"; filename*=UTF-8''${downloadFilename}`,
);
const buffer = await upstream.arrayBuffer();
return res.send(Buffer.from(buffer));
} catch (error) {
console.error("Error downloading attachment:", error);
return res
.status(500)
.json({ message: "Failed to download attachment" });
}
},
);

View File

@@ -58,7 +58,7 @@ export default function LoginPage() {
</div>
</div>
)}
{!isSignUpDisabled && (
{(!isSignUpDisabled || redirect?.startsWith("/invite/")) && (
<p className="mt-4 text-sm text-light-1000 dark:text-dark-1000">
<Trans>
Don't have an account?{" "}

View File

@@ -28,7 +28,9 @@ export default function SignUpPage() {
setMagicLinkRecipient(recipient);
};
if (isSignUpDisabled) {
const isInviteFlow = redirect?.startsWith("/invite/");
if (isSignUpDisabled && !isInviteFlow) {
return (
<>
<PageHead title={t`Sign up | kan.bn`} />

View File

@@ -7,7 +7,7 @@ import {
HiOutlineStar,
HiStar,
} from "react-icons/hi2";
import { IoArchiveOutline } from "react-icons/io5";
import Dropdown from "~/components/Dropdown";
import { usePermissions } from "~/hooks/usePermissions";
import { useModal } from "~/providers/modal";
@@ -17,6 +17,7 @@ import { api } from "~/utils/api";
export default function BoardDropdown({
isTemplate,
isLoading,
isArchived,
boardPublicId,
isFavorite,
boardName,
@@ -24,28 +25,29 @@ export default function BoardDropdown({
isTemplate: boolean;
isLoading: boolean;
boardPublicId: string;
isArchived?: boolean;
isFavorite?: boolean;
boardName?: string;
}) {
const { openModal } = useModal();
const { canEditBoard, canDeleteBoard, canCreateBoard } = usePermissions();
const { showPopup } = usePopup();
const { canEditBoard, canDeleteBoard, canCreateBoard, canArchiveBoard } =
usePermissions();
const utils = api.useUtils();
const handleToggleFavorite = () => {
updateBoard.mutate({
boardPublicId,
favorite: !isFavorite,
});
};
const updateBoard = api.board.update.useMutation({
onSuccess: (data, variables) => {
onSuccess: (_data, variables) => {
void utils.board.all.invalidate();
void utils.board.byId.invalidate();
// Show popup notification
if (variables.favorite !== undefined) {
if (variables.isArchived !== undefined) {
showPopup({
header: variables.isArchived ? t`Board archived` : t`Board unarchived`,
message: variables.isArchived
? t`The board has been archived.`
: t`The board has been unarchived.`,
icon: "success",
});
} else if (variables.favorite !== undefined) {
showPopup({
header: variables.favorite
? t`Added to favorites`
@@ -65,27 +67,54 @@ export default function BoardDropdown({
});
},
});
const handleToggleFavorite = () => {
updateBoard.mutate({
boardPublicId,
favorite: !isFavorite,
});
};
const handleArchiveOrUnarchive = () => {
updateBoard.mutate({
boardPublicId,
isArchived: !isArchived,
});
};
const isArchiveActionPending = updateBoard.isPending;
const items = [
...(isTemplate && canCreateBoard
? [
{
label: t`Make template`,
action: () => openModal("CREATE_TEMPLATE"),
icon: (
<HiOutlineDocumentDuplicate className="h-[16px] w-[16px] text-dark-900" />
),
},
]
{
label: t`Make template`,
action: () => openModal("CREATE_TEMPLATE"),
icon: (
<HiOutlineDocumentDuplicate className="h-[16px] w-[16px] text-dark-900" />
),
},
]
: []),
...(!isTemplate && canEditBoard
? [
{
label: t`Edit board URL`,
action: () => openModal("UPDATE_BOARD_SLUG"),
icon: <HiLink className="h-[16px] w-[16px] text-dark-900" />,
},
]
{
label: t`Edit board URL`,
action: () => openModal("UPDATE_BOARD_SLUG"),
icon: <HiLink className="h-[16px] w-[16px] text-dark-900" />,
},
]
: []),
...(!isTemplate && canArchiveBoard
? [
{
label: isArchived ? t`Unarchive board` : t`Archive board`,
action: handleArchiveOrUnarchive,
icon: (
<IoArchiveOutline className="h-[16px] w-[16px] text-dark-900" />
),
},
]
: []),
{
label: isFavorite
@@ -100,22 +129,26 @@ export default function BoardDropdown({
},
...(canDeleteBoard
? [
{
label: isTemplate ? t`Delete template` : t`Delete board`,
action: () => openModal("DELETE_BOARD"),
icon: <HiOutlineTrash className="h-[16px] w-[16px] text-dark-900" />,
},
]
{
label: isTemplate ? t`Delete template` : t`Delete board`,
action: () => openModal("DELETE_BOARD"),
icon: (
<HiOutlineTrash className="h-[16px] w-[16px] text-dark-900" />
),
},
]
: []),
];
if (items.length === 0) {
return null;
}
return (
<Dropdown disabled={isLoading} items={items}>
<Dropdown
disabled={isLoading || isArchiveActionPending}
items={items}
>
<HiEllipsisHorizontal className="h-5 w-5 text-dark-900" />
</Dropdown>
);

View File

@@ -494,7 +494,7 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
isTemplate={!!isTemplate}
isLoading={!boardData}
boardPublicId={boardId ?? ""}
workspacePublicId={workspace.publicId}
isArchived={boardData?.isArchived ?? false}
isFavorite={boardData?.favorite}
boardName={boardData?.name}
/>
@@ -598,13 +598,12 @@ export default function BoardPage({ isTemplate }: { isTemplate?: boolean }) {
? `/templates/${boardId}/cards/${card.publicId}`
: `/cards/${card.publicId}`
}
className={`mb-2 flex !cursor-pointer flex-col ${
card.publicId.startsWith(
"PLACEHOLDER",
)
? "pointer-events-none"
: ""
}`}
className={`mb-2 flex !cursor-pointer flex-col ${card.publicId.startsWith(
"PLACEHOLDER",
)
? "pointer-events-none"
: ""
}`}
ref={provided.innerRef}
{...provided.draggableProps}
{...provided.dragHandleProps}

View File

@@ -10,7 +10,7 @@ import { useModal } from "~/providers/modal";
import { useWorkspace } from "~/providers/workspace";
import { api } from "~/utils/api";
export function BoardsList({ isTemplate }: { isTemplate?: boolean }) {
export function BoardsList({ isTemplate, archived = false }: { isTemplate?: boolean; archived?: boolean }) {
const { workspace } = useWorkspace();
const { openModal } = useModal();
const { canCreateBoard } = usePermissions();
@@ -26,6 +26,7 @@ export function BoardsList({ isTemplate }: { isTemplate?: boolean }) {
{
workspacePublicId: workspace.publicId,
type: isTemplate ? "template" : "regular",
archived: archived,
},
{ enabled: workspace.publicId ? true : false },
);
@@ -59,10 +60,10 @@ export function BoardsList({ isTemplate }: { isTemplate?: boolean }) {
<div className="flex flex-col items-center">
<HiOutlineRectangleStack className="h-10 w-10 text-light-800 dark:text-dark-800" />
<p className="mb-2 mt-4 text-[14px] font-bold text-light-1000 dark:text-dark-950">
{t`No ${isTemplate ? "templates" : "boards"}`}
{archived ? t`No archived boards` : t`No ${isTemplate ? "templates" : "boards"}`}
</p>
<p className="text-[14px] text-light-900 dark:text-dark-900">
{t`Get started by creating a new ${isTemplate ? "template" : "board"}`}
{archived ? t`Boards you archive will appear here.` : t`Get started by creating a new ${isTemplate ? "template" : "board"}`}
</p>
</div>
<Tooltip
@@ -109,18 +110,18 @@ export function BoardsList({ isTemplate }: { isTemplate?: boolean }) {
>
<div className="group relative mr-5 flex h-[150px] w-full items-center justify-center rounded-md border border-dashed border-light-400 bg-light-50 shadow-sm hover:bg-light-200 dark:border-dark-600 dark:bg-dark-50 dark:hover:bg-dark-100">
<PatternedBackground />
<button
onClick={(e) => handleToggleFavorite(e, board.publicId, board.favorite)}
className={`absolute right-3 top-3 z-10 rounded p-1 transition-all hover:bg-light-300 dark:hover:bg-dark-200 ${board.favorite ? "" : "md:opacity-0 md:group-hover:opacity-100"
}`}
aria-label={board.favorite ? "Remove from favorites" : "Add to favorites"}
>
{board.favorite ? (
<HiStar className="h-5 w-5 text-neutral-700 dark:text-dark-1000" />
) : (
<HiOutlineStar className="h-5 w-5 text-neutral-700 dark:text-dark-800" />
)}
</button>
<button
onClick={(e) => handleToggleFavorite(e, board.publicId, board.favorite)}
className={`absolute right-3 top-3 z-10 rounded p-1 transition-all hover:bg-light-300 dark:hover:bg-dark-200 ${board.favorite ? "" : "md:opacity-0 md:group-hover:opacity-100"
}`}
aria-label={board.favorite ? "Remove from favorites" : "Add to favorites"}
>
{board.favorite ? (
<HiStar className="h-5 w-5 text-neutral-700 dark:text-dark-1000" />
) : (
<HiOutlineStar className="h-5 w-5 text-neutral-700 dark:text-dark-800" />
)}
</button>
<p className="px-4 text-[14px] font-bold text-neutral-700 dark:text-dark-1000">
{board.name}
</p>

View File

@@ -4,7 +4,7 @@ import { t } from "@lingui/core/macro";
import { Plural, Trans } from "@lingui/react/macro";
import { Fragment, useEffect, useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { FaTrello } from "react-icons/fa";
import { FaGithub, FaTrello } from "react-icons/fa";
import {
HiChevronUpDown,
HiMiniArrowTopRightOnSquare,
@@ -27,12 +27,23 @@ const integrationProviders: Record<
name: "Trello",
icon: <FaTrello />,
},
github: {
name: "GitHub",
icon: <FaGithub />,
},
};
const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
const SelectSource = ({
handleNextStep,
}: {
handleNextStep: (provider: string) => void;
}) => {
const { data: integrations, refetch: refetchIntegrations } =
api.integration.providers.useQuery();
const { control, handleSubmit } = useForm({
const { data: githubStatus, refetch: refetchGithubStatus } =
api.integration.getGitHubStatus.useQuery();
const { control, handleSubmit, watch } = useForm({
defaultValues: {
source: integrations?.[0]?.provider ?? "trello",
},
@@ -47,23 +58,36 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
},
);
const hasIntegrations = integrations && integrations.length > 0;
const availableIntegrations = [
...(integrations ?? []),
...(githubStatus?.connected ? [{ provider: "github" }] : []),
];
const hasIntegrations = availableIntegrations.length > 0;
useEffect(() => {
const handleFocus = () => {
refetchIntegrations();
void refetchIntegrations();
void refetchGithubStatus();
};
window.addEventListener("focus", handleFocus);
return () => {
window.removeEventListener("focus", handleFocus);
};
}, [refetchIntegrations]);
}, [refetchIntegrations, refetchGithubStatus]);
const onSubmit = () => {
if (!hasIntegrations && trelloUrl) {
window.open(trelloUrl.url, "trello_auth", "height=800,width=600");
const selected = watch("source");
if (
selected === "trello" &&
!integrations?.some((i) => i.provider === "trello")
) {
if (trelloUrl)
window.open(trelloUrl.url, "trello_auth", "height=800,width=600");
} else if (selected === "github" && !githubStatus?.connected) {
window.open("/settings/integrations", "_blank");
} else {
handleNextStep();
handleNextStep(selected);
}
};
@@ -102,7 +126,7 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
>
<Listbox.Options className="absolute z-10 mt-1 max-h-60 w-full overflow-auto rounded-md bg-light-50 py-1 text-base text-neutral-900 shadow-lg ring-1 ring-light-600 ring-opacity-5 focus:outline-none dark:bg-dark-300 dark:text-dark-1000 sm:text-sm">
{hasIntegrations ? (
integrations.map((integration, index) => (
availableIntegrations.map((integration, index) => (
<Listbox.Option
key={`source_${index}`}
className="relative cursor-default select-none px-1"
@@ -123,18 +147,32 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
</Listbox.Option>
))
) : (
<Listbox.Option
key="trello_placeholder"
className="font-sm relative cursor-default select-none px-1"
value="trello"
>
<div className="flex items-center rounded-[5px] p-1 text-sm hover:bg-light-200 dark:hover:bg-dark-400">
{integrationProviders.trello?.icon}
<span className="ml-2 block truncate text-sm">
{integrationProviders.trello?.name}
</span>
</div>
</Listbox.Option>
<>
<Listbox.Option
key="trello_placeholder"
className="font-sm relative cursor-default select-none px-1"
value="trello"
>
<div className="flex items-center rounded-[5px] p-1 text-sm hover:bg-light-200 dark:hover:bg-dark-400">
{integrationProviders.trello?.icon}
<span className="ml-2 block truncate text-sm">
{integrationProviders.trello?.name}
</span>
</div>
</Listbox.Option>
<Listbox.Option
key="github_placeholder"
className="font-sm relative cursor-default select-none px-1"
value="github"
>
<div className="flex items-center rounded-[5px] p-1 text-sm hover:bg-light-200 dark:hover:bg-dark-400">
{integrationProviders.github?.icon}
<span className="ml-2 block truncate text-sm">
{integrationProviders.github?.name}
</span>
</div>
</Listbox.Option>
</>
)}
</Listbox.Options>
</Transition>
@@ -154,7 +192,159 @@ const SelectSource = ({ handleNextStep }: { handleNextStep: () => void }) => {
!hasIntegrations ? <HiMiniArrowTopRightOnSquare /> : undefined
}
>
{hasIntegrations ? t`Select source` : t`Connect Trello`}
{hasIntegrations ? t`Select source` : t`Connect`}
</Button>
</div>
</div>
</form>
);
};
const ImportGithub: React.FC = () => {
const utils = api.useUtils();
const { closeModal } = useModal();
const { workspace } = useWorkspace();
const { showPopup } = usePopup();
const [isSelectAllEnabled, setIsSelectAllEnabled] = useState(false);
const refetchBoards = () => utils.board.all.refetch();
const { data: projects, isLoading: projectsLoading } =
api.import.github.getProjects.useQuery();
const {
register: registerProjects,
handleSubmit: handleSubmitProjects,
setValue,
watch,
} = useForm({
defaultValues: Object.fromEntries(
projects?.map((project) => [project.id, true]) ?? [],
),
});
const importProjects = api.import.github.importProjects.useMutation({
onSuccess: async () => {
showPopup({
header: t`Import complete`,
message: t`Your projects have been imported.`,
icon: "success",
});
try {
await refetchBoards();
closeModal();
} catch (e) {
console.log(e);
}
},
onError: () => {
showPopup({
header: t`Import failed`,
message: t`Please try again later, or contact customer support.`,
icon: "error",
});
},
});
const projectWatchers = projects?.map((project) => ({
id: project.id,
value: watch(project.id),
}));
const projectCount =
projectWatchers?.filter((w) => w.value === true).length ?? 0;
const onSubmitProjects = (values: Record<string, boolean>) => {
const projectIds = Object.keys(values).filter(
(key) => values[key] === true,
);
importProjects.mutate({
projectIds,
workspacePublicId: workspace.publicId,
});
};
const renderContent = () => {
if (projectsLoading) {
return (
<div className="flex h-full w-full flex-col items-center justify-center gap-1">
<div className="h-[30px] w-full animate-pulse rounded-[5px] bg-light-200 dark:bg-dark-300" />
<div className="h-[30px] w-full animate-pulse rounded-[5px] bg-light-200 dark:bg-dark-300" />
<div className="h-[30px] w-full animate-pulse rounded-[5px] bg-light-200 dark:bg-dark-300" />
</div>
);
}
if (!projects?.length) {
return (
<div className="flex h-full w-full items-center justify-center">
<p className="text-sm text-neutral-500 dark:text-dark-900">
{t`No projects found`}
</p>
</div>
);
}
return projects.map((project) => (
<div key={project.id}>
<label
className="flex cursor-pointer items-center rounded-[5px] p-2 hover:bg-light-100 dark:hover:bg-dark-300"
htmlFor={project.id}
>
<input
id={project.id}
type="checkbox"
className="h-[14px] w-[14px] rounded bg-transparent ring-0 focus:outline-none focus:ring-0 focus:ring-offset-0"
{...registerProjects(project.id)}
/>
<span className="ml-3 text-sm text-neutral-900 dark:text-dark-1000">
{project.name}
</span>
</label>
</div>
));
};
return (
<form onSubmit={handleSubmitProjects(onSubmitProjects)}>
<div className="h-[105px] overflow-auto px-5">{renderContent()}</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">
<Toggle
label={t`Select all`}
isChecked={!!isSelectAllEnabled}
onChange={() => {
const newState = !isSelectAllEnabled;
setIsSelectAllEnabled(newState);
for (const project of projects ?? []) {
setValue(project.id, newState);
}
}}
/>
<div className="space-x-2">
<Button
type="submit"
isLoading={importProjects.isPending}
disabled={
importProjects.isPending ||
projectsLoading ||
!projects?.length ||
!projects.some(
(project) =>
projectWatchers?.find((w) => w.id === project.id)?.value ===
true,
)
}
>
<Trans>
<Plural
value={projectCount}
one={`Import project (1)`}
other={`Import projects (${projectCount})`}
/>
</Trans>
</Button>
</div>
</div>
@@ -213,7 +403,7 @@ const ImportTrello: React.FC = () => {
value: watch(board.id),
}));
const boardCount = boardWatchers?.filter((w) => w.value === true).length || 0;
const boardCount = boardWatchers?.filter((w) => w.value === true).length ?? 0;
const onSubmitBoards = (values: Record<string, boolean>) => {
const boardIds = Object.keys(values).filter((key) => values[key] === true);
@@ -267,7 +457,7 @@ const ImportTrello: React.FC = () => {
return (
<form onSubmit={handleSubmitBoards(onSubmitBoards)}>
<div className="h-[105px] overflow-scroll px-5">{renderContent()}</div>
<div className="h-[105px] overflow-auto px-5">{renderContent()}</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">
<Toggle
@@ -277,7 +467,7 @@ const ImportTrello: React.FC = () => {
const newState = !isSelectAllEnabled;
setIsSelectAllEnabled(newState);
for (const board of boards || []) {
for (const board of boards ?? []) {
setValue(board.id, newState);
}
}}
@@ -313,6 +503,7 @@ const ImportTrello: React.FC = () => {
export function ImportBoardsForm() {
const { closeModal } = useModal();
const [step, setStep] = useState(1);
const [provider, setProvider] = useState<string | null>(null);
return (
<div>
@@ -339,8 +530,16 @@ export function ImportBoardsForm() {
</button>
</div>
{step === 1 && <SelectSource handleNextStep={() => setStep(step + 1)} />}
{step === 2 && <ImportTrello />}
{step === 1 && (
<SelectSource
handleNextStep={(p) => {
setProvider(p);
setStep(step + 1);
}}
/>
)}
{step === 2 && provider === "trello" && <ImportTrello />}
{step === 2 && provider === "github" && <ImportGithub />}
</div>
);
}

View File

@@ -1,5 +1,12 @@
import {
Listbox,
ListboxButton,
ListboxOption,
ListboxOptions,
} from "@headlessui/react";
import { t } from "@lingui/core/macro";
import { HiArrowDownTray, HiOutlinePlusSmall } from "react-icons/hi2";
import { HiArrowDownTray, HiChevronDown, HiOutlinePlusSmall } from "react-icons/hi2";
import { useState } from "react";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
@@ -15,9 +22,15 @@ import { BoardsList } from "./components/BoardsList";
import { ImportBoardsForm } from "./components/ImportBoardsForm";
import { NewBoardForm } from "./components/NewBoardForm";
const boardsTabs = [
{ key: "boards" as const, label: t`Active` },
{ key: "archived" as const, label: t`Archived` },
];
export default function BoardsPage({ isTemplate }: { isTemplate?: boolean }) {
const { openModal, modalContentType, isOpen } = useModal();
const { workspace } = useWorkspace();
const [activeTab, setActiveTab] = useState<"boards" | "archived">("boards");
const { canCreateBoard } = usePermissions();
const { tooltipContent: createModalShortcutTooltipContent } =
@@ -34,7 +47,7 @@ export default function BoardsPage({ isTemplate }: { isTemplate?: boolean }) {
<PageHead
title={t`${isTemplate ? "Templates" : "Boards"} | ${workspace.name ?? t`Workspace`}`}
/>
<div className="m-auto h-full max-w-[1100px] p-6 px-5 md:px-28 md:py-12">
<div className="m-auto h-full max-w-[1100px] p-8 px-5 md:px-28 md:py-12">
<div className="relative z-10 mb-8 flex w-full items-center justify-between">
<h1 className="font-bold tracking-tight text-neutral-900 dark:text-dark-1000 sm:text-[1.2rem]">
{t`${isTemplate ? "Templates" : "Boards"}`}
@@ -115,9 +128,79 @@ export default function BoardsPage({ isTemplate }: { isTemplate?: boolean }) {
</Modal>
</>
<div className="flex h-full flex-row">
<BoardsList isTemplate={!!isTemplate} />
</div>
{!isTemplate ? (
<div className="flex h-full w-full flex-col">
<div className="focus:outline-none">
<div className="sm:hidden">
<Listbox
value={activeTab}
onChange={(tab) => setActiveTab(tab)}
>
<div className="relative mb-4">
<ListboxButton className="w-full appearance-none rounded-md border-0 bg-light-50 py-3 pl-3 pr-10 text-left text-sm font-semibold text-light-1000 shadow-sm ring-1 ring-inset ring-light-300 dark:bg-dark-50 dark:text-dark-1000 dark:ring-dark-300 dark:focus:ring-dark-500">
{boardsTabs.find((tab) => tab.key === activeTab)?.label ??
"Select a tab"}
<HiChevronDown
aria-hidden="true"
className="pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-light-900 dark:text-dark-900"
/>
</ListboxButton>
<ListboxOptions className="absolute z-10 mt-1 w-full rounded-md bg-light-50 py-1 text-sm shadow-lg ring-1 ring-inset ring-light-300 dark:bg-dark-50 dark:ring-dark-300">
{boardsTabs.map((tab) => (
<ListboxOption
key={tab.key}
value={tab.key}
className={({ selected }) =>
`relative cursor-pointer select-none py-2 pl-3 pr-9 ${selected
? "font-bold text-light-1000 dark:text-dark-1000"
: "font-normal text-light-1000 dark:text-dark-1000"
}`
}
>
{tab.label}
</ListboxOption>
))}
</ListboxOptions>
</div>
</Listbox>
</div>
<div className="hidden sm:block">
<div>
<nav
aria-label="Tabs"
className="-mb-px flex space-x-8 focus:outline-none"
>
{boardsTabs.map((tab) => (
<button
key={tab.key}
type="button"
onClick={() => setActiveTab(tab.key)}
className={`whitespace-nowrap px-1 py-0 mt-2 mb-8 text-sm font-semibold transition-colors focus:outline-none ${activeTab === tab.key
? "border-light-1000 text-light-1000 dark:border-dark-1000 dark:text-dark-1000"
: "border-transparent text-light-900 hover:border-light-950 hover:text-light-950 dark:text-dark-900 dark:hover:border-white/20 dark:hover:text-dark-950"
}`}
>
{tab.label}
</button>
))}
</nav>
</div>
</div>
</div>
<div className="flex h-full flex-row focus:outline-none">
{activeTab === "boards" && (
<BoardsList isTemplate={false} archived={false} />
)}
{activeTab === "archived" && (
<BoardsList isTemplate={false} archived={true} />
)}
</div>
</div>
) : (
<div className="flex h-full flex-row">
<BoardsList isTemplate={!!isTemplate} />
</div>
)}
</div>
</>
);

View File

@@ -3,8 +3,8 @@ 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";
import { HiXMark } from "react-icons/hi2";
import { IoChevronForwardSharp } from "react-icons/io5";
import { authClient } from "@kan/auth/client";
@@ -302,7 +302,6 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
if (!cardId) return <></>;
return (
<>
<PageHead
@@ -345,7 +344,7 @@ export default function CardPage({ isTemplate }: { isTemplate?: boolean }) {
className="flex h-7 w-7 items-center justify-center rounded-[5px] text-light-900 hover:bg-light-200 dark:text-dark-900 dark:hover:bg-dark-200"
aria-label={t`Close`}
>
<HiXMark className="h-5 w-5" />
<HiXMark className="h-4 w-4" />
</Link>
</div>
</>

View File

@@ -8,10 +8,10 @@ type FrequencyValue = "monthly" | "annually";
interface PlanFeature {
key: string;
label: string;
free: string | boolean | { text: string; highlight?: string };
teams: string | boolean | { text: string; highlight?: string };
pro: string | boolean | { text: string; highlight?: string };
enterprise: string | boolean | { text: string; highlight?: string };
free: string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean };
teams: string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean };
pro: string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean };
enterprise: string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean };
}
interface FeatureSection {
@@ -71,34 +71,34 @@ const FeatureComparisonTable = ({
{
key: "boards",
label: t`Boards`,
free: { text: t`Unlimited boards`, highlight: "Unlimited" },
teams: { text: t`Unlimited boards`, highlight: "Unlimited" },
pro: { text: t`Unlimited boards`, highlight: "Unlimited" },
enterprise: { text: t`Unlimited boards`, highlight: "Unlimited" },
free: { text: t`Unlimited boards`, highlightFirstWord: true },
teams: { text: t`Unlimited boards`, highlightFirstWord: true },
pro: { text: t`Unlimited boards`, highlightFirstWord: true },
enterprise: { text: t`Unlimited boards`, highlightFirstWord: true },
},
{
key: "members",
label: t`Members`,
free: { text: t`1 user`, highlight: "1" },
teams: { text: t`Per-seat pricing`, highlight: "Per-seat" },
pro: { text: t`Unlimited members`, highlight: "Unlimited" },
enterprise: { text: t`Unlimited members`, highlight: "Unlimited" },
free: { text: t`1 user`, highlightFirstWord: true },
teams: { text: t`Per-seat pricing`, highlightFirstWord: true },
pro: { text: t`Unlimited members`, highlightFirstWord: true },
enterprise: { text: t`Unlimited members`, highlightFirstWord: true },
},
{
key: "file-uploads",
label: t`File uploads`,
free: { text: t`10mb file uploads`, highlight: "10mb" },
teams: { text: t`Unlimited file uploads`, highlight: "Unlimited" },
pro: { text: t`Unlimited file uploads`, highlight: "Unlimited" },
enterprise: { text: t`Unlimited file uploads`, highlight: "Unlimited" },
free: { text: t`10mb file uploads`, highlightFirstWord: true },
teams: { text: t`Unlimited file uploads`, highlightFirstWord: true },
pro: { text: t`Unlimited file uploads`, highlightFirstWord: true },
enterprise: { text: t`Unlimited file uploads`, highlightFirstWord: true },
},
{
key: "workspace-username",
label: t`Workspace username`,
free: { text: t`Default username`, highlight: "Default" },
teams: { text: t`Default username`, highlight: "Default" },
pro: { text: t`Custom username`, highlight: "Custom" },
enterprise: { text: t`Custom username`, highlight: "Custom" },
free: { text: t`Default username`, highlightFirstWord: true },
teams: { text: t`Default username`, highlightFirstWord: true },
pro: { text: t`Custom username`, highlightFirstWord: true },
enterprise: { text: t`Custom username`, highlightFirstWord: true },
},
];
@@ -236,9 +236,9 @@ const FeatureComparisonTable = ({
key: "rest-api",
label: t`API`,
free: { text: t`Limited API access` },
teams: { text: t`Full API access` },
pro: { text: t`Full API access` },
enterprise: { text: t`Full API access` },
teams: { text: t`Full API access`, highlight: true },
pro: { text: t`Full API access`, highlight: true },
enterprise: { text: t`Full API access`, highlight: true },
},
{
key: "self-hostable",
@@ -254,18 +254,18 @@ const FeatureComparisonTable = ({
{
key: "sso",
label: t`SSO`,
free: { text: t`Google SSO` },
teams: { text: t`Google SSO` },
pro: { text: t`Google SSO` },
enterprise: { text: t`Google SSO + SAML` },
free: { text: t`Google SSO`, highlight: true },
teams: { text: t`Google SSO`, highlight: true },
pro: { text: t`Google SSO`, highlight: true },
enterprise: { text: t`Google SSO + SAML`, highlight: true },
},
{
key: "admin-roles",
label: t`Admin roles`,
free: { text: t`Admin roles` },
teams: { text: t`Admin roles` },
pro: { text: t`Admin roles` },
enterprise: { text: t`Advanced admin roles` },
free: { text: t`Admin roles`, highlight: true },
teams: { text: t`Admin roles`, highlight: true },
pro: { text: t`Admin roles`, highlight: true },
enterprise: { text: t`Advanced admin roles`, highlight: true },
},
];
@@ -334,59 +334,37 @@ const FeatureComparisonTable = ({
{ id: "enterprise", name: t`Enterprise`, tierId: "tier-enterprise" },
];
const isHighlightValue = (
value: string | boolean | { text: string; highlight?: string },
): value is { text: string; highlight?: string } => {
return typeof value === "object" && value !== null && "text" in value;
};
const shouldHighlight = (text: string): boolean => {
const lowerText = text.toLowerCase();
return ["unlimited", "multiple", "per-seat", "custom", "mentions", "full", "sso", "admin"].some(
(keyword) => lowerText.includes(keyword),
);
};
const CellValue = ({
value,
label,
}: {
value: string | boolean | { text: string; highlight?: string };
value: string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean };
label: string;
}) => {
// Handle object with text and highlight
if (isHighlightValue(value)) {
const { text, highlight } = value;
const isUnlimited = shouldHighlight(text);
let displayText;
if (highlight) {
const parts = text.split(new RegExp(`(${highlight})`, "gi"));
displayText = (
<>
{parts.map((part, index) =>
part.toLowerCase() === highlight.toLowerCase() ? (
<span key={index} className="text-light-1000 dark:text-dark-1000">
{part}
</span>
) : (
<span key={index} className="text-light-950 dark:text-dark-800">
{part}
</span>
),
)}
</>
if (typeof value === "object" && value !== null) {
const { text, highlight, highlightFirstWord } = value;
if (highlightFirstWord) {
const spaceIndex = text.indexOf(" ");
const firstWord = spaceIndex === -1 ? text : text.slice(0, spaceIndex);
const rest = spaceIndex === -1 ? "" : text.slice(spaceIndex);
return (
<div className="flex items-center gap-2.5">
<HiCheckCircle className="mt-0.5 h-4 w-4 shrink-0 text-light-1000 dark:text-dark-1000" />
<span className="text-sm font-medium">
<span className="text-light-1000 dark:text-dark-1000">{firstWord}</span>
<span className="text-light-950 dark:text-dark-800">{rest}</span>
</span>
</div>
);
} else {
displayText = text;
}
return (
<div className="flex items-center gap-2.5">
<HiCheckCircle
className={twMerge(
"mt-0.5 h-4 w-4 shrink-0",
isUnlimited
highlight
? "text-light-1000 dark:text-dark-1000"
: "text-light-400 dark:text-dark-600",
)}
@@ -394,44 +372,18 @@ const FeatureComparisonTable = ({
<span
className={twMerge(
"text-sm font-medium",
isUnlimited
highlight
? "text-light-1000 dark:text-dark-950"
: "text-light-950 dark:text-dark-800",
)}
>
{displayText}
</span>
</div>
);
}
if (typeof value === "string") {
const isUnlimited = shouldHighlight(value);
return (
<div className="flex items-center gap-2.5">
<HiCheckCircle
className={twMerge(
"mt-0.5 h-4 w-4 shrink-0",
isUnlimited
? "text-light-1000 dark:text-dark-1000"
: "text-light-400 dark:text-dark-600",
)}
/>
<span
className={twMerge(
"text-sm font-medium",
isUnlimited
? "text-light-1000 dark:text-dark-950"
: "text-light-950 dark:text-dark-800",
)}
>
{value}
{text}
</span>
</div>
);
}
if (value) {
// Boolean true - show checkmark icon
return (
<div className="flex items-center gap-2.5">
<HiCheckCircle className="mt-0.5 h-4 w-4 shrink-0 text-light-1000 dark:text-dark-1000" />
@@ -441,7 +393,7 @@ const FeatureComparisonTable = ({
</div>
);
}
// Boolean false - show cross icon
return (
<div className="flex items-center gap-2.5">
<HiXCircle className="mt-0.5 h-4 w-4 shrink-0 text-light-400 dark:text-dark-600" />
@@ -455,7 +407,7 @@ const FeatureComparisonTable = ({
const getFeatureValue = (
feature: PlanFeature,
planId: string,
): string | boolean | { text: string; highlight?: string } => {
): string | boolean | { text: string; highlight?: boolean; highlightFirstWord?: boolean } => {
switch (planId) {
case "free":
return feature.free;

View File

@@ -1,9 +1,13 @@
import { zodResolver } from "@hookform/resolvers/zod";
import { t } from "@lingui/core/macro";
import { useEffect } from "react";
import { useForm } from "react-hook-form";
import { HiMiniArrowTopRightOnSquare } from "react-icons/hi2";
import { z } from "zod";
import Button from "~/components/Button";
import FeedbackModal from "~/components/FeedbackModal";
import Input from "~/components/Input";
import Modal from "~/components/modal";
import { NewWorkspaceForm } from "~/components/NewWorkspaceForm";
import { PageHead } from "~/components/PageHead";
@@ -11,10 +15,28 @@ import { useModal } from "~/providers/modal";
import { usePopup } from "~/providers/popup";
import { api } from "~/utils/api";
const githubTokenSchema = z.object({
token: z.string().min(1, { message: t`Token is required` }),
});
type GitHubTokenFormValues = z.infer<typeof githubTokenSchema>;
export default function IntegrationsSettings() {
const { modalContentType, isOpen } = useModal();
const { showPopup } = usePopup();
const {
register,
handleSubmit,
formState: { isDirty, errors },
reset,
} = useForm<GitHubTokenFormValues>({
resolver: zodResolver(githubTokenSchema),
defaultValues: {
token: "",
},
});
const {
data: integrations,
refetch: refetchIntegrations,
@@ -34,21 +56,25 @@ export default function IntegrationsSettings() {
},
);
const { data: githubStatus, refetch: refetchGithubStatus } =
api.integration.getGitHubStatus.useQuery();
useEffect(() => {
const handleFocus = () => {
refetchIntegrations();
void refetchIntegrations();
void refetchGithubStatus();
};
window.addEventListener("focus", handleFocus);
return () => {
window.removeEventListener("focus", handleFocus);
};
}, [refetchIntegrations]);
}, [refetchIntegrations, refetchGithubStatus]);
const { mutateAsync: disconnectTrello } =
api.integration.disconnect.useMutation({
onSuccess: () => {
refetchIntegrations();
refetchTrelloUrl();
void refetchIntegrations();
void refetchTrelloUrl();
showPopup({
header: t`Trello disconnected`,
message: t`Your Trello account has been disconnected.`,
@@ -64,6 +90,49 @@ export default function IntegrationsSettings() {
},
});
const { mutateAsync: saveGithubToken, isPending: isSavingGithubToken } =
api.integration.saveGitHubToken.useMutation({
onSuccess: () => {
void refetchGithubStatus();
reset();
showPopup({
header: t`GitHub connected`,
message: t`Your GitHub account has been connected.`,
icon: "success",
});
},
onError: () => {
showPopup({
header: t`Error connecting GitHub`,
message: t`An error occurred while connecting your GitHub account.`,
icon: "error",
});
},
});
const onSubmitGithubToken = (data: GitHubTokenFormValues) => {
void saveGithubToken({ token: data.token });
};
const { mutateAsync: disconnectGithub } =
api.integration.disconnectGitHub.useMutation({
onSuccess: () => {
void refetchGithubStatus();
showPopup({
header: t`GitHub disconnected`,
message: t`Your GitHub account has been disconnected.`,
icon: "success",
});
},
onError: () => {
showPopup({
header: t`Error disconnecting GitHub`,
message: t`An error occurred while disconnecting your GitHub account.`,
icon: "error",
});
},
});
return (
<>
<PageHead title={t`Settings | Integrations`} />
@@ -112,6 +181,51 @@ export default function IntegrationsSettings() {
)}
</div>
<div className="mb-8 border-t border-light-300 dark:border-dark-300">
<h2 className="mb-4 mt-8 text-[14px] font-bold text-neutral-900 dark:text-dark-1000">
{t`GitHub`}
</h2>
{!githubStatus?.connected ? (
<>
<p className="mb-4 text-sm text-neutral-500 dark:text-dark-900">
{t`Connect your GitHub account to import projects.`}
</p>
<form
onSubmit={handleSubmit(onSubmitGithubToken)}
className="flex gap-2"
>
<div className="mb-4 flex w-full max-w-[325px] items-center gap-2">
<Input
type="password"
placeholder="Personal Access Token"
{...register("token")}
errorMessage={errors.token?.message}
/>
</div>
<div>
<Button
variant="secondary"
type="submit"
disabled={!isDirty || isSavingGithubToken}
isLoading={isSavingGithubToken}
>
{t`Connect GitHub`}
</Button>
</div>
</form>
</>
) : (
<>
<p className="mb-8 text-sm text-neutral-500 dark:text-dark-900">
{t`Your GitHub account is connected.`}
</p>
<Button variant="secondary" onClick={() => disconnectGithub()}>
{t`Disconnect GitHub`}
</Button>
</>
)}
</div>
{/* Global modals */}
<Modal
modalSize="md"

View File

@@ -34,6 +34,7 @@ export const boardRouter = createTRPCRouter({
z.object({
workspacePublicId: z.string().min(12),
type: z.enum(["regular", "template"]).optional(),
archived: z.boolean().optional(),
}),
)
.output(
@@ -65,7 +66,10 @@ export const boardRouter = createTRPCRouter({
ctx.db,
workspace.id,
userId,
{ type: input.type }
{
type: input.type,
archived: input.archived ?? false,
}
);
return result;
@@ -153,24 +157,24 @@ export const boardRouter = createTRPCRouter({
// Generate presigned URLs for workspace member avatars
const workspaceWithAvatarUrls = result.workspace
? {
...result.workspace,
members: await Promise.all(
result.workspace.members.map(async (member) => {
if (!member.user?.image) {
return member;
}
...result.workspace,
members: await Promise.all(
result.workspace.members.map(async (member) => {
if (!member.user?.image) {
return member;
}
const avatarUrl = await generateAvatarUrl(member.user.image);
return {
...member,
user: {
...member.user,
image: avatarUrl,
},
};
}),
),
}
const avatarUrl = await generateAvatarUrl(member.user.image);
return {
...member,
user: {
...member.user,
image: avatarUrl,
},
};
}),
),
}
: result.workspace;
// Generate presigned URLs for card member avatars
@@ -461,7 +465,8 @@ export const boardRouter = createTRPCRouter({
.regex(/^(?![-]+$)[a-zA-Z0-9-]+$/)
.optional(),
visibility: z.enum(["public", "private"]).optional(),
favorite: z.boolean().optional()
favorite: z.boolean().optional(),
isArchived: z.boolean().optional(),
}),
)
.output(z.object({ success: z.boolean() }).or(z.custom<Awaited<ReturnType<typeof boardRepo.update>>>()))
@@ -503,7 +508,7 @@ export const boardRouter = createTRPCRouter({
}
// Handle other updates (name, slug, visibility)
const hasOtherUpdates = input.name || input.slug || input.visibility !== undefined;
const hasOtherUpdates = input.name || input.slug || input.visibility !== undefined || input.isArchived !== undefined;
if (!hasOtherUpdates) {
// Only favorite was updated, return success
@@ -530,6 +535,7 @@ export const boardRouter = createTRPCRouter({
slug: input.slug,
boardPublicId: input.boardPublicId,
visibility: input.visibility,
isArchived: input.isArchived,
});
if (!result)

View File

@@ -13,6 +13,10 @@ import { mergeActivities } from "../utils/activities";
import { sendMentionEmails } from "../utils/notifications";
import { assertCanDelete, assertCanEdit, assertPermission } from "../utils/permissions";
import { generateAttachmentUrl, generateAvatarUrl } from "@kan/shared/utils";
import {
createCardWebhookPayload,
sendWebhooksForWorkspace,
} from "../utils/webhook";
export const cardRouter = createTRPCRouter({
create: protectedProcedure
@@ -165,6 +169,32 @@ export const cardRouter = createTRPCRouter({
});
}
// Fire webhooks (non-blocking)
sendWebhooksForWorkspace(
ctx.db,
list.workspaceId,
createCardWebhookPayload(
"card.created",
{
id: String(newCard.id),
title: input.title,
description: input.description,
dueDate: input.dueDate ?? null,
listId: String(newCard.listId),
},
{
boardId: list.boardPublicId,
boardName: list.boardName,
listName: list.name,
user: ctx.user
? { id: ctx.user.id, name: ctx.user.name }
: undefined,
},
),
).catch((error) => {
console.error("Webhook delivery failed:", error);
});
return newCard;
}),
addComment: protectedProcedure
@@ -1007,6 +1037,59 @@ export const cardRouter = createTRPCRouter({
await cardActivityRepo.bulkCreate(ctx.db, activities);
}
// Build changes object for webhook
const webhookChanges: Record<string, { from: unknown; to: unknown }> = {};
if (input.title && existingCard.title !== input.title) {
webhookChanges.title = { from: existingCard.title, to: input.title };
}
if (input.description && existingCard.description !== input.description) {
webhookChanges.description = {
from: existingCard.description,
to: input.description,
};
}
if (
input.dueDate !== undefined &&
previousDueDate?.getTime() !== input.dueDate?.getTime()
) {
webhookChanges.dueDate = { from: previousDueDate, to: input.dueDate };
}
if (newListId && existingCard.listId !== newListId) {
webhookChanges.listId = { from: existingCard.listId, to: newListId };
}
// Fire webhooks (non-blocking)
sendWebhooksForWorkspace(
ctx.db,
card.workspaceId,
createCardWebhookPayload(
newListId && existingCard.listId !== newListId
? "card.moved"
: "card.updated",
{
id: String(result.id),
title: result.title,
description: result.description,
dueDate: result.dueDate,
listId: String(newListId ?? existingCard.listId),
},
{
boardId: card.boardPublicId,
boardName: card.boardName,
listName: card.listName,
user: ctx.user
? { id: ctx.user.id, name: ctx.user.name }
: undefined,
changes:
Object.keys(webhookChanges).length > 0
? webhookChanges
: undefined,
},
),
).catch((error) => {
console.error("Webhook delivery failed:", error);
});
return result;
}),
delete: protectedProcedure
@@ -1054,6 +1137,9 @@ export const cardRouter = createTRPCRouter({
card.createdBy,
);
// Fetch full card data before delete for webhook
const fullCard = await cardRepo.getByPublicId(ctx.db, input.cardPublicId);
const deletedAt = new Date();
await cardRepo.softDelete(ctx.db, {
@@ -1068,6 +1154,34 @@ export const cardRouter = createTRPCRouter({
createdBy: userId,
});
// Fire webhooks (non-blocking)
if (fullCard) {
sendWebhooksForWorkspace(
ctx.db,
card.workspaceId,
createCardWebhookPayload(
"card.deleted",
{
id: String(fullCard.id),
title: fullCard.title,
description: fullCard.description,
dueDate: fullCard.dueDate,
listId: String(fullCard.listId),
},
{
boardId: card.boardPublicId,
boardName: card.boardName,
listName: card.listName,
user: ctx.user
? { id: ctx.user.id, name: ctx.user.name }
: undefined,
},
),
).catch((error) => {
console.error("Webhook delivery failed:", error);
});
}
return { success: true };
}),
});

View File

@@ -81,6 +81,16 @@ export const checklistRouter = createTRPCRouter({
return newChecklist;
}),
update: protectedProcedure
.meta({
openapi: {
summary: "Update a checklist",
method: "PUT",
path: "/checklists/{checklistPublicId}",
description: "Updates a checklist by its public ID",
tags: ["Cards"],
protect: true,
},
})
.input(
z.object({
checklistPublicId: z.string().length(12),

View File

@@ -11,10 +11,12 @@ import * as labelRepo from "@kan/db/repository/label.repo";
import * as listRepo from "@kan/db/repository/list.repo";
import * as workspaceRepo from "@kan/db/repository/workspace.repo";
import { colours } from "@kan/shared/constants";
import { generateUID } from "@kan/shared/utils";
import { generateSlug, generateUID } from "@kan/shared/utils";
import { createTRPCRouter, protectedProcedure } from "../trpc";
import { assertPermission } from "../utils/permissions";
import { assertUserInWorkspace } from "../utils/auth";
import { decryptToken } from "../utils/encryption";
import { apiKeys, urls } from "./integration";
export interface TrelloBoard {
@@ -50,6 +52,51 @@ interface TrelloCheckItem {
pos: number;
}
interface GitHubProjectsResponse {
data: {
viewer: {
projectsV2: {
nodes?: { id: string; title: string }[];
};
organizations: {
nodes: {
projectsV2: {
nodes?: { id: string; title: string }[];
};
}[];
};
};
};
errors?: unknown[];
}
interface GitHubGraphQLResponse {
data?: {
node?: GitHubProjectV2Node;
};
errors?: unknown[];
}
interface GitHubProjectV2Node {
title: string;
field?: {
options?: { id: string; name: string }[];
};
areaField?: {
options?: { id: string; name: string; color: string }[];
};
items?: {
nodes: {
fieldValueByName?: { name: string };
areaValue?: { name: string };
content?: {
title?: string;
body?: string;
};
}[];
};
}
interface TrelloCard {
id: string;
name: string | null;
@@ -464,4 +511,436 @@ export const importRouter = createTRPCRouter({
return { boardsCreated };
}),
}),
github: createTRPCRouter({
getProjects: protectedProcedure
.meta({
openapi: {
summary: "Get projects from GitHub",
method: "GET",
path: "/integrations/github/projects",
description: "Retrieves all projects from GitHub",
tags: ["Integrations"],
protect: true,
},
})
.input(z.void())
.output(z.array(z.object({ id: z.string(), name: z.string() })))
.query(async ({ ctx }) => {
const user = ctx.user;
if (!user)
throw new TRPCError({
message: "User not authenticated",
code: "UNAUTHORIZED",
});
const integration = await integrationsRepo.getProviderForUser(
ctx.db,
user.id,
"github",
);
if (!integration)
throw new TRPCError({
message: "GitHub token not found",
code: "UNAUTHORIZED",
});
const token = decryptToken(integration.accessToken);
// GraphQL query to fetch Projects V2 for the user and their organizations
const query = `
query {
viewer {
projectsV2(first: 20) {
nodes {
id
title
}
}
organizations(first: 10) {
nodes {
projectsV2(first: 10) {
nodes {
id
title
}
}
}
}
}
}
`;
const response = await fetch("https://api.github.com/graphql", {
method: "POST",
headers: {
Authorization: `token ${token}`,
"Content-Type": "application/json",
"User-Agent": "Kan-App",
},
body: JSON.stringify({ query }),
});
if (!response.ok) {
const errorText = await response.text();
console.error(
`GitHub API Error: ${response.status} ${response.statusText}`,
);
console.error(`GitHub API Response: ${errorText}`);
throw new TRPCError({
message: `Failed to fetch GitHub projects: ${response.status} ${response.statusText}`,
code: "INTERNAL_SERVER_ERROR",
});
}
const result = (await response.json()) as GitHubProjectsResponse;
if (result.errors) {
console.error("GitHub GraphQL Errors:", result.errors);
throw new TRPCError({
message: "Failed to fetch GitHub projects (GraphQL Error)",
code: "INTERNAL_SERVER_ERROR",
});
}
const userProjects = result.data.viewer.projectsV2.nodes ?? [];
const orgProjects = result.data.viewer.organizations.nodes.flatMap(
(org) => org.projectsV2.nodes ?? [],
);
const allProjects = [...userProjects, ...orgProjects];
return allProjects.map((project) => ({
id: project.id,
name: project.title,
}));
}),
importProjects: protectedProcedure
.meta({
openapi: {
summary: "Import projects from GitHub",
method: "POST",
path: "/imports/github/projects",
description: "Imports projects from GitHub",
tags: ["Imports"],
protect: true,
},
})
.input(
z.object({
projectIds: z.array(z.string()),
workspacePublicId: z.string().min(12),
}),
)
.output(z.object({ projectsImported: z.number() }))
.mutation(async ({ ctx, input }) => {
const userId = ctx.user?.id;
if (!userId) throw new TRPCError({ code: "UNAUTHORIZED" });
const integration = await integrationsRepo.getProviderForUser(
ctx.db,
userId,
"github",
);
if (!integration)
throw new TRPCError({
code: "UNAUTHORIZED",
message: "GitHub token not found",
});
const token = decryptToken(integration.accessToken);
const workspace = await workspaceRepo.getByPublicId(
ctx.db,
input.workspacePublicId,
);
if (!workspace)
throw new TRPCError({
code: "NOT_FOUND",
message: "Workspace not found",
});
await assertUserInWorkspace(ctx.db, userId, workspace.id);
const newImport = await importRepo.create(ctx.db, {
source: "github",
createdBy: userId,
});
if (!newImport) {
throw new TRPCError({
code: "INTERNAL_SERVER_ERROR",
message: "Failed to create import record",
});
}
const newImportId = newImport.id;
let projectsImported = 0;
for (const projectId of input.projectIds) {
// GraphQL query to fetch Project V2 details, status options, area options, and items
const query = `
query($id: ID!) {
node(id: $id) {
... on ProjectV2 {
title
field(name: "Status") {
... on ProjectV2SingleSelectField {
options {
id
name
}
}
}
areaField: field(name: "Area") {
... on ProjectV2SingleSelectField {
options {
id
name
color
}
}
}
items(first: 100) {
nodes {
fieldValueByName(name: "Status") {
... on ProjectV2ItemFieldSingleSelectValue {
name
}
}
areaValue: fieldValueByName(name: "Area") {
... on ProjectV2ItemFieldSingleSelectValue {
name
}
}
content {
... on Issue {
title
body
}
... on PullRequest {
title
body
}
... on DraftIssue {
title
body
}
}
}
}
}
}
}
`;
const response = await fetch("https://api.github.com/graphql", {
method: "POST",
headers: {
Authorization: `token ${token}`,
"Content-Type": "application/json",
"User-Agent": "Kan-App",
},
body: JSON.stringify({ query, variables: { id: projectId } }),
});
const result = (await response.json()) as GitHubGraphQLResponse;
if (result.errors || !result.data?.node) continue;
const projectData = result.data.node;
const statusOptions = projectData.field?.options ?? [];
const areaOptions = projectData.areaField?.options ?? [];
const items = projectData.items?.nodes ?? [];
const boardPublicId = generateUID();
const board = await boardRepo.create(ctx.db, {
publicId: boardPublicId,
name: projectData.title,
workspaceId: workspace.id,
slug: generateSlug(projectData.title),
createdBy: userId,
importId: newImportId,
});
if (!board) continue;
// Prepare Labels
const labelsInsert = areaOptions.map((option) => {
let colourCode = "#0d9488"; // Default Teal
const ghColor = option.color;
// Map GitHub colors to Kan colors
if (ghColor === "BLUE") colourCode = "#0284c7";
else if (ghColor === "GREEN") colourCode = "#65a30d";
else if (ghColor === "YELLOW") colourCode = "#ca8a04";
else if (ghColor === "ORANGE") colourCode = "#ea580c";
else if (ghColor === "RED") colourCode = "#dc2626";
else if (ghColor === "PINK") colourCode = "#db2777";
else if (ghColor === "PURPLE") colourCode = "#4f46e5";
else if (ghColor === "GRAY") colourCode = "#0d9488";
return {
publicId: generateUID(),
name: option.name,
colourCode,
createdBy: userId,
boardId: board.id,
importId: newImportId,
};
});
const createdLabels = await labelRepo.bulkCreate(
ctx.db,
labelsInsert,
);
const labelMap = new Map<string, number>();
createdLabels.forEach((label, index) => {
const originalName = areaOptions[index]?.name;
if (originalName) {
labelMap.set(originalName, label.id);
}
});
// Prepare Lists
const listsInsert: {
publicId: string;
name: string;
createdBy: string;
boardId: number;
index: number;
importId: number;
}[] = [];
if (statusOptions.length === 0) {
listsInsert.push({
publicId: generateUID(),
name: "To Do",
createdBy: userId,
boardId: board.id,
index: 0,
importId: newImportId,
});
} else {
statusOptions.forEach((option, index) => {
listsInsert.push({
publicId: generateUID(),
name: option.name,
createdBy: userId,
boardId: board.id,
index: index,
importId: newImportId,
});
});
}
const createdLists = await listRepo.bulkCreate(ctx.db, listsInsert);
const listIdMap = new Map<string, number>();
createdLists.forEach((list, index) => {
const originalName = listsInsert[index]?.name;
if (originalName) {
listIdMap.set(originalName, list.id);
}
});
// Prepare Cards
const itemsToInsert: {
item: NonNullable<
NonNullable<
NonNullable<GitHubProjectV2Node["items"]>["nodes"]
>[number]
>;
listId: number;
title: string;
description: string;
}[] = [];
for (const item of items) {
const statusName = item.fieldValueByName?.name;
const content = item.content ?? {};
const title = content.title ?? "Untitled Card";
const description = content.body ?? "";
let listId = statusName ? listIdMap.get(statusName) : undefined;
// Fallback to first list
if (!listId && createdLists.length > 0) {
listId = createdLists[0]?.id;
}
if (listId) {
itemsToInsert.push({
item,
listId,
title,
description,
});
}
}
const cardsInput = itemsToInsert.map((data, index) => ({
publicId: generateUID(),
title: data.title,
description: data.description,
createdBy: userId,
listId: data.listId,
index: index,
importId: newImportId,
}));
const createdCards = await cardRepo.bulkCreate(ctx.db, cardsInput);
// Create Activities
const activities = createdCards.map((card) => ({
type: "card.created" as const,
cardId: card.id,
createdBy: userId,
}));
if (activities.length > 0) {
await cardActivityRepo.bulkCreate(ctx.db, activities);
}
// Link Labels
const cardLabelRelations: { cardId: number; labelId: number }[] = [];
createdCards.forEach((card, index) => {
const originalItem = itemsToInsert[index]?.item;
const areaName = originalItem?.areaValue?.name;
if (areaName) {
const labelId = labelMap.get(areaName);
if (labelId) {
cardLabelRelations.push({
cardId: card.id,
labelId: labelId,
});
}
}
});
if (cardLabelRelations.length > 0) {
await cardRepo.bulkCreateCardLabelRelationships(
ctx.db,
cardLabelRelations,
);
}
projectsImported++;
}
if (projectsImported > 0 && newImportId) {
await importRepo.update(
ctx.db,
{ status: "success" },
{ importId: newImportId },
);
}
return { projectsImported };
}),
}),
});

View File

@@ -14,7 +14,65 @@ export const apiKeys = {
trello: process.env.TRELLO_APP_API_KEY,
};
import { encryptToken } from "../utils/encryption";
export const integrationRouter = createTRPCRouter({
saveGitHubToken: protectedProcedure
.input(z.object({ token: z.string() }))
.mutation(async ({ ctx, input }) => {
const user = ctx.user;
if (!user)
throw new TRPCError({
message: "User not authenticated",
code: "UNAUTHORIZED",
});
const encryptedToken = encryptToken(input.token);
const expiresAt = new Date();
expiresAt.setFullYear(expiresAt.getFullYear() + 1);
await integrationsRepo.createOrUpdateProvider(ctx.db, {
provider: "github",
userId: user.id,
accessToken: encryptedToken,
expiresAt,
});
return { success: true };
}),
disconnectGitHub: protectedProcedure.mutation(async ({ ctx }) => {
const user = ctx.user;
if (!user)
throw new TRPCError({
message: "User not authenticated",
code: "UNAUTHORIZED",
});
await integrationsRepo.deleteProviderForUser(ctx.db, user.id, "github");
return { success: true };
}),
getGitHubStatus: protectedProcedure.query(async ({ ctx }) => {
const user = ctx.user;
if (!user)
throw new TRPCError({
message: "User not authenticated",
code: "UNAUTHORIZED",
});
const connected = await integrationsRepo.isProviderAvailableForUser(
ctx.db,
user.id,
"github",
);
return { connected };
}),
providers: protectedProcedure
.meta({
openapi: {
@@ -67,7 +125,7 @@ export const integrationRouter = createTRPCRouter({
protect: true,
},
})
.input(z.object({ provider: z.enum(["trello"]) }))
.input(z.object({ provider: z.enum(["trello", "github"]) }))
.output(z.object({}))
.mutation(async ({ ctx, input }) => {
const user = ctx.user;

View File

@@ -210,11 +210,12 @@ export const memberRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member)
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: `Member with public ID ${input.memberPublicId} not found`,
code: "NOT_FOUND",
});
}
const deletedMember = await memberRepo.softDelete(ctx.db, {
memberId: member.id,
@@ -720,7 +721,7 @@ export const memberRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member) {
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: "Member not found",
code: "NOT_FOUND",

View File

@@ -133,7 +133,7 @@ export const permissionRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member) {
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: "Member not found",
code: "NOT_FOUND",
@@ -209,7 +209,7 @@ export const permissionRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member) {
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: "Member not found",
code: "NOT_FOUND",
@@ -274,7 +274,7 @@ export const permissionRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member) {
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: "Member not found",
code: "NOT_FOUND",
@@ -339,7 +339,7 @@ export const permissionRouter = createTRPCRouter({
input.memberPublicId,
);
if (!member) {
if (!member || member.workspaceId !== workspace.id) {
throw new TRPCError({
message: "Member not found",
code: "NOT_FOUND",

View File

@@ -0,0 +1,53 @@
import crypto from "crypto";
const ALGORITHM = "aes-256-gcm";
const SECRET_KEY = process.env.BETTER_AUTH_SECRET;
if (!SECRET_KEY) {
throw new Error("Encryption key is missing. Set BETTER_AUTH_SECRET.");
}
// Ensure the key is exactly 32 bytes
const key = crypto.createHash("sha256").update(String(SECRET_KEY)).digest();
export const encryptToken = (text: string) => {
const iv = crypto.randomBytes(12); // 12 bytes is the recommended IV size for GCM
const cipher = crypto.createCipheriv(ALGORITHM, key, iv);
// buffer concat is faster/cleaner for raw binary manipulation
const encrypted = Buffer.concat([
cipher.update(text, "utf8"),
cipher.final(),
]);
const authTag = cipher.getAuthTag();
// Combine IV + AuthTag + EncryptedData into one buffer
// This saves space compared to storing them as separate hex strings
const combined = Buffer.concat([iv, authTag, encrypted]);
// Return as URL-safe Base64 (ideal for cookies)
return combined.toString("base64url");
};
export const decryptToken = (text: string) => {
// Convert URL-safe Base64 back to a Buffer
const combined = Buffer.from(text, "base64url");
// Extract the parts based on fixed lengths
// IV is 12 bytes (standard for GCM)
// AuthTag is 16 bytes (standard for GCM)
const iv = combined.subarray(0, 12);
const authTag = combined.subarray(12, 28);
const encryptedText = combined.subarray(28);
const decipher = crypto.createDecipheriv(ALGORITHM, key, iv);
decipher.setAuthTag(authTag);
// If the cookie was tampered with, this will throw an error
const decrypted = Buffer.concat([
decipher.update(encryptedText),
decipher.final(),
]);
return decrypted.toString("utf8");
};

View File

@@ -0,0 +1,528 @@
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
vi.mock("@kan/db/repository/webhook.repo", () => ({
getActiveByWorkspaceId: vi.fn(),
}));
import * as webhookRepo from "@kan/db/repository/webhook.repo";
import {
sendWebhookToUrl,
sendWebhooksForWorkspace,
createCardWebhookPayload,
webhookUrlSchema,
type WebhookPayload,
} from "./webhook";
const mockGetActiveByWorkspaceId = webhookRepo.getActiveByWorkspaceId as ReturnType<typeof vi.fn>;
describe("webhook utilities", () => {
beforeEach(() => {
vi.clearAllMocks();
vi.useFakeTimers();
vi.setSystemTime(new Date("2024-01-15T12:00:00.000Z"));
});
afterEach(() => {
vi.useRealTimers();
});
describe("createCardWebhookPayload", () => {
it("creates a payload with required card fields", () => {
const payload = createCardWebhookPayload(
"card.created",
{
id: "card-123",
title: "Test Card",
listId: "list-456",
},
{
boardId: "board-789",
},
);
expect(payload.event).toBe("card.created");
expect(payload.timestamp).toBe("2024-01-15T12:00:00.000Z");
expect(payload.data.card).toEqual({
id: "card-123",
title: "Test Card",
description: undefined,
dueDate: null,
listId: "list-456",
boardId: "board-789",
});
});
it("includes optional card fields when provided", () => {
const dueDate = new Date("2024-02-01T10:00:00.000Z");
const payload = createCardWebhookPayload(
"card.updated",
{
id: "card-123",
title: "Test Card",
description: "A description",
dueDate,
listId: "list-456",
},
{
boardId: "board-789",
},
);
expect(payload.data.card.description).toBe("A description");
expect(payload.data.card.dueDate).toBe("2024-02-01T10:00:00.000Z");
});
it("includes board context when provided", () => {
const payload = createCardWebhookPayload(
"card.created",
{
id: "card-123",
title: "Test Card",
listId: "list-456",
},
{
boardId: "board-789",
boardName: "My Board",
},
);
expect(payload.data.board).toEqual({
id: "board-789",
name: "My Board",
});
});
it("includes list context when provided", () => {
const payload = createCardWebhookPayload(
"card.created",
{
id: "card-123",
title: "Test Card",
listId: "list-456",
},
{
boardId: "board-789",
listName: "To Do",
},
);
expect(payload.data.list).toEqual({
id: "list-456",
name: "To Do",
});
});
it("includes user context when provided", () => {
const payload = createCardWebhookPayload(
"card.created",
{
id: "card-123",
title: "Test Card",
listId: "list-456",
},
{
boardId: "board-789",
user: {
id: "user-111",
name: "John Doe",
},
},
);
expect(payload.data.user).toEqual({
id: "user-111",
name: "John Doe",
});
});
it("includes changes for card.updated events", () => {
const payload = createCardWebhookPayload(
"card.updated",
{
id: "card-123",
title: "Updated Title",
listId: "list-456",
},
{
boardId: "board-789",
changes: {
title: { from: "Old Title", to: "Updated Title" },
},
},
);
expect(payload.data.changes).toEqual({
title: { from: "Old Title", to: "Updated Title" },
});
});
});
describe("sendWebhookToUrl", () => {
const originalFetch = global.fetch;
beforeEach(() => {
global.fetch = vi.fn();
});
afterEach(() => {
global.fetch = originalFetch;
});
const mockPayload: WebhookPayload = {
event: "card.created",
timestamp: "2024-01-15T12:00:00.000Z",
data: {
card: {
id: "card-123",
title: "Test Card",
listId: "list-456",
boardId: "board-789",
},
},
};
describe("SSRF protection", () => {
it("blocks HTTP URLs", async () => {
const result = await sendWebhookToUrl("http://example.com/webhook", undefined, mockPayload);
expect(result.success).toBe(false);
expect(result.error).toContain("HTTPS");
expect(global.fetch).not.toHaveBeenCalled();
});
it("blocks localhost", async () => {
const result = await sendWebhookToUrl("https://localhost/webhook", undefined, mockPayload);
expect(result.success).toBe(false);
expect(result.error).toContain("Localhost");
expect(global.fetch).not.toHaveBeenCalled();
});
it("blocks 127.0.0.1", async () => {
const result = await sendWebhookToUrl("https://127.0.0.1/webhook", undefined, mockPayload);
expect(result.success).toBe(false);
expect(global.fetch).not.toHaveBeenCalled();
});
it("blocks cloud metadata endpoint", async () => {
const result = await sendWebhookToUrl("https://169.254.169.254/latest/meta-data/", undefined, mockPayload);
expect(result.success).toBe(false);
expect(result.error).toContain("metadata");
expect(global.fetch).not.toHaveBeenCalled();
});
it("blocks private 10.x.x.x IPs", async () => {
const result = await sendWebhookToUrl("https://10.0.0.1/webhook", undefined, mockPayload);
expect(result.success).toBe(false);
expect(result.error).toContain("Private");
expect(global.fetch).not.toHaveBeenCalled();
});
it("blocks private 192.168.x.x IPs", async () => {
const result = await sendWebhookToUrl("https://192.168.1.1/webhook", undefined, mockPayload);
expect(result.success).toBe(false);
expect(global.fetch).not.toHaveBeenCalled();
});
it("allows valid HTTPS URLs", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({ ok: true, status: 200 });
const result = await sendWebhookToUrl("https://example.com/webhook", undefined, mockPayload);
expect(result.success).toBe(true);
expect(global.fetch).toHaveBeenCalled();
});
});
it("sends POST request with correct headers", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
ok: true,
status: 200,
});
await sendWebhookToUrl("https://example.com/webhook", undefined, mockPayload);
expect(global.fetch).toHaveBeenCalledWith(
"https://example.com/webhook",
expect.objectContaining({
method: "POST",
headers: expect.objectContaining({
"Content-Type": "application/json",
"X-Webhook-Event": "card.created",
"X-Webhook-Timestamp": "2024-01-15T12:00:00.000Z",
}),
body: JSON.stringify(mockPayload),
}),
);
});
it("includes signature header when secret is provided", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
ok: true,
status: 200,
});
await sendWebhookToUrl("https://example.com/webhook", "my-secret", mockPayload);
expect(global.fetch).toHaveBeenCalledWith(
"https://example.com/webhook",
expect.objectContaining({
headers: expect.objectContaining({
"X-Webhook-Signature": expect.stringMatching(/^[a-f0-9]{64}$/),
}),
}),
);
});
it("returns success for 2xx responses", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
ok: true,
status: 200,
});
const result = await sendWebhookToUrl(
"https://example.com/webhook",
undefined,
mockPayload,
);
expect(result).toEqual({ success: true, statusCode: 200 });
});
it("returns failure for non-2xx responses", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValueOnce({
ok: false,
status: 500,
statusText: "Internal Server Error",
});
const result = await sendWebhookToUrl(
"https://example.com/webhook",
undefined,
mockPayload,
);
expect(result).toEqual({
success: false,
statusCode: 500,
error: "500 Internal Server Error",
});
});
it("returns failure on network error", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockRejectedValueOnce(
new Error("Network error"),
);
const result = await sendWebhookToUrl(
"https://example.com/webhook",
undefined,
mockPayload,
);
expect(result).toEqual({
success: false,
error: "Network error",
});
});
it("returns timeout error when request takes too long", async () => {
(global.fetch as ReturnType<typeof vi.fn>).mockImplementationOnce(
() =>
new Promise((_, reject) => {
setTimeout(() => {
const error = new Error("Aborted");
error.name = "AbortError";
reject(error);
}, 15000);
}),
);
const resultPromise = sendWebhookToUrl(
"https://example.com/webhook",
undefined,
mockPayload,
);
// Advance timers to trigger the abort
vi.advanceTimersByTime(15000);
const result = await resultPromise;
expect(result).toEqual({
success: false,
error: "Request timed out",
});
});
});
describe("sendWebhooksForWorkspace", () => {
const originalFetch = global.fetch;
beforeEach(() => {
global.fetch = vi.fn();
});
afterEach(() => {
global.fetch = originalFetch;
});
const mockDb = {} as Parameters<typeof sendWebhooksForWorkspace>[0];
const mockPayload: WebhookPayload = {
event: "card.created",
timestamp: "2024-01-15T12:00:00.000Z",
data: {
card: {
id: "card-123",
title: "Test Card",
listId: "list-456",
boardId: "board-789",
},
},
};
it("sends to all active webhooks subscribed to the event", async () => {
mockGetActiveByWorkspaceId.mockResolvedValueOnce([
{
id: 1,
publicId: "wh-1",
url: "https://example.com/webhook1",
secret: "secret1",
events: ["card.created", "card.updated"],
active: true,
},
{
id: 2,
publicId: "wh-2",
url: "https://example.com/webhook2",
secret: null,
events: ["card.created"],
active: true,
},
]);
(global.fetch as ReturnType<typeof vi.fn>).mockResolvedValue({
ok: true,
status: 200,
});
await sendWebhooksForWorkspace(mockDb, 1, mockPayload);
// Event filtering now happens at DB level
expect(mockGetActiveByWorkspaceId).toHaveBeenCalledWith(
mockDb,
1,
"card.created",
);
expect(global.fetch).toHaveBeenCalledTimes(2);
expect(global.fetch).toHaveBeenCalledWith(
"https://example.com/webhook1",
expect.any(Object),
);
expect(global.fetch).toHaveBeenCalledWith(
"https://example.com/webhook2",
expect.any(Object),
);
});
it("does not send when no webhooks match the event (DB-level filtering)", async () => {
// DB-level event filter returns empty array when no webhooks match
mockGetActiveByWorkspaceId.mockResolvedValueOnce([]);
await sendWebhooksForWorkspace(mockDb, 1, mockPayload);
expect(mockGetActiveByWorkspaceId).toHaveBeenCalledWith(
mockDb,
1,
"card.created",
);
expect(global.fetch).not.toHaveBeenCalled();
});
it("continues sending to other webhooks when one fails", async () => {
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
mockGetActiveByWorkspaceId.mockResolvedValueOnce([
{
id: 1,
publicId: "wh-1",
url: "https://example.com/webhook1",
secret: null,
events: ["card.created"],
active: true,
},
{
id: 2,
publicId: "wh-2",
url: "https://example.com/webhook2",
secret: null,
events: ["card.created"],
active: true,
},
]);
(global.fetch as ReturnType<typeof vi.fn>)
.mockResolvedValueOnce({ ok: false, status: 500, statusText: "Error" })
.mockResolvedValueOnce({ ok: true, status: 200 });
await sendWebhooksForWorkspace(mockDb, 1, mockPayload);
expect(global.fetch).toHaveBeenCalledTimes(2);
expect(consoleSpy).toHaveBeenCalledWith(
expect.stringContaining("Webhook delivery failed"),
);
consoleSpy.mockRestore();
});
it("handles empty webhook list", async () => {
mockGetActiveByWorkspaceId.mockResolvedValueOnce([]);
await sendWebhooksForWorkspace(mockDb, 1, mockPayload);
expect(global.fetch).not.toHaveBeenCalled();
});
it("catches and logs DB errors without throwing", async () => {
const consoleSpy = vi
.spyOn(console, "error")
.mockImplementation(() => {});
mockGetActiveByWorkspaceId.mockRejectedValueOnce(
new Error("DB connection failed"),
);
// Should not throw — the try/catch absorbs the error
await expect(
sendWebhooksForWorkspace(mockDb, 1, mockPayload),
).resolves.toBeUndefined();
expect(consoleSpy).toHaveBeenCalledWith(
"Failed to send webhooks for workspace:",
expect.any(Error),
);
consoleSpy.mockRestore();
});
});
describe("webhookUrlSchema", () => {
it("accepts valid HTTPS URLs", () => {
expect(webhookUrlSchema.safeParse("https://example.com/webhook").success).toBe(true);
});
it("rejects HTTP URLs", () => {
const result = webhookUrlSchema.safeParse("http://example.com/webhook");
expect(result.success).toBe(false);
});
it("rejects localhost", () => {
const result = webhookUrlSchema.safeParse("https://localhost/webhook");
expect(result.success).toBe(false);
});
it("rejects private IPs", () => {
expect(webhookUrlSchema.safeParse("https://10.0.0.1/webhook").success).toBe(false);
expect(webhookUrlSchema.safeParse("https://192.168.1.1/webhook").success).toBe(false);
});
it("rejects cloud metadata endpoints", () => {
expect(webhookUrlSchema.safeParse("https://169.254.169.254/latest").success).toBe(false);
});
});
});

View File

@@ -0,0 +1,258 @@
import crypto from "crypto";
import { z } from "zod";
import type { dbClient } from "@kan/db/client";
import type { WebhookEvent } from "@kan/db/schema";
import * as webhookRepo from "@kan/db/repository/webhook.repo";
export type WebhookEventType = WebhookEvent;
export interface WebhookPayload {
event: WebhookEventType;
timestamp: string;
data: {
card: {
id: string;
title: string;
description?: string | null;
dueDate?: string | null; // ISO string after JSON serialization
listId: string;
boardId: string;
};
board?: {
id: string;
name: string;
};
list?: {
id: string;
name: string;
};
user?: {
id: string;
name: string | null;
};
changes?: Record<string, { from: unknown; to: unknown }>;
};
}
function generateSignature(payload: string, secret: string): string {
return crypto.createHmac("sha256", secret).update(payload).digest("hex");
}
/**
* Zod schema for webhook URLs with SSRF mitigation.
* Requires HTTPS and blocks private/internal IP ranges, localhost,
* and cloud metadata endpoints.
*/
export const webhookUrlSchema = z
.string()
.url()
.max(2048)
.refine(
(url) => {
try {
return new URL(url).protocol === "https:";
} catch {
return false;
}
},
{ message: "Only HTTPS URLs are allowed" },
)
.refine(
(url) => {
try {
const hostname = new URL(url).hostname.toLowerCase();
return !(
hostname === "localhost" ||
hostname === "127.0.0.1" ||
hostname === "::1" ||
hostname === "0.0.0.0"
);
} catch {
return false;
}
},
{ message: "Localhost URLs are not allowed" },
)
.refine(
(url) => {
try {
const hostname = new URL(url).hostname.toLowerCase();
return !(
hostname === "169.254.169.254" ||
hostname === "metadata.google.internal"
);
} catch {
return false;
}
},
{ message: "Cloud metadata endpoints are not allowed" },
)
.refine(
(url) => {
try {
const hostname = new URL(url).hostname.toLowerCase();
const ipv4Match = /^(\d+)\.(\d+)\.(\d+)\.(\d+)$/.exec(hostname);
if (ipv4Match) {
const [, a, b] = ipv4Match.map(Number);
if (
a === 10 ||
(a === 172 && b! >= 16 && b! <= 31) ||
(a === 192 && b === 168)
) {
return false;
}
}
return true;
} catch {
return false;
}
},
{ message: "Private IP addresses are not allowed" },
);
/**
* Send a webhook payload to a specific URL.
*
* SSRF note: URL validation (HTTPS-only, no private IPs, no cloud metadata)
* is enforced both here at delivery time and at webhook creation via
* webhookUrlSchema. This function is only reachable by workspace admins.
*/
export async function sendWebhookToUrl(
url: string,
secret: string | undefined,
payload: WebhookPayload,
): Promise<{ success: boolean; statusCode?: number; error?: string }> {
const result = webhookUrlSchema.safeParse(url);
if (!result.success) {
return { success: false, error: result.error.issues[0]?.message };
}
const body = JSON.stringify(payload);
const headers: Record<string, string> = {
"Content-Type": "application/json",
"X-Webhook-Event": payload.event,
"X-Webhook-Timestamp": payload.timestamp,
};
if (secret) {
headers["X-Webhook-Signature"] = generateSignature(body, secret);
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(url, {
method: "POST",
headers,
body,
signal: controller.signal,
});
clearTimeout(timeoutId);
if (!response.ok) {
return {
success: false,
statusCode: response.status,
error: `${response.status} ${response.statusText}`,
};
}
return { success: true, statusCode: response.status };
} catch (error) {
clearTimeout(timeoutId);
if (error instanceof Error && error.name === "AbortError") {
return { success: false, error: "Request timed out" };
}
return {
success: false,
error: error instanceof Error ? error.message : "Unknown error",
};
}
}
/**
* Send webhook to all active webhooks for a workspace that are subscribed to the event.
* Wrapped in try/catch so callers using fire-and-forget don't risk unhandled rejections.
*/
export async function sendWebhooksForWorkspace(
db: dbClient,
workspaceId: number,
payload: WebhookPayload,
): Promise<void> {
try {
// Get active webhooks for this workspace
const webhooks = await webhookRepo.getActiveByWorkspaceId(db, workspaceId);
// Filter webhooks that are subscribed to this specific event
const webhooksForEvent = webhooks.filter((webhook) =>
webhook.events.includes(payload.event),
);
// Send to all subscribed webhooks in parallel (fire and forget)
const promises = webhooksForEvent.map((webhook) =>
sendWebhookToUrl(webhook.url, webhook.secret ?? undefined, payload).then(
(result) => {
if (!result.success) {
console.error(
`Webhook delivery failed to ${webhook.url}: ${result.error}`,
);
}
},
),
);
// Wait for all to complete but don't block on failures
await Promise.allSettled(promises);
} catch (error) {
console.error("Failed to send webhooks for workspace:", error);
}
}
export function createCardWebhookPayload(
event: WebhookEventType,
card: {
id: string;
title: string;
description?: string | null;
dueDate?: Date | null;
listId: string;
},
context: {
boardId: string;
boardName?: string;
listName?: string;
user?: {
id: string;
name: string | null;
};
changes?: Record<string, { from: unknown; to: unknown }>;
},
): WebhookPayload {
return {
event,
timestamp: new Date().toISOString(),
data: {
card: {
id: card.id,
title: card.title,
description: card.description,
dueDate: card.dueDate?.toISOString() ?? null,
listId: card.listId,
boardId: context.boardId,
},
board: context.boardName
? { id: context.boardId, name: context.boardName }
: undefined,
list: context.listName
? { id: card.listId, name: context.listName }
: undefined,
user: context.user,
changes: context.changes,
},
};
}

View File

@@ -21,6 +21,7 @@
"dev": "tsc",
"format": "prettier --check . --ignore-path ../../.gitignore",
"lint": "eslint",
"test": "vitest run",
"typecheck": "tsc --noEmit --emitDeclarationOnly false"
},
"devDependencies": {

View File

@@ -33,8 +33,10 @@ export const initAuth = (db: dbClient) => {
},
emailAndPassword: {
enabled: env("NEXT_PUBLIC_ALLOW_CREDENTIALS")?.toLowerCase() === "true",
disableSignUp:
env("NEXT_PUBLIC_DISABLE_SIGN_UP")?.toLowerCase() === "true",
// Sign-up restriction is handled by the user.create.before database
// hook which checks for pending invitations, allowing invited users
// to register even when public sign-up is disabled.
disableSignUp: false,
sendResetPassword: async (data) => {
await sendEmail(data.user.email, "Reset Password", "RESET_PASSWORD", {
resetPasswordUrl: data.url,

View File

@@ -0,0 +1,195 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
vi.mock("next-runtime-env", () => ({
env: vi.fn(),
}));
vi.mock("@kan/db/repository/member.repo", () => ({
getByEmailAndStatus: vi.fn(),
getByPublicId: vi.fn(),
acceptInvite: vi.fn(),
}));
vi.mock("@kan/db/repository/user.repo", () => ({
update: vi.fn(),
}));
vi.mock("@kan/email", () => ({
notificationClient: null,
}));
vi.mock("@kan/shared", () => ({
createEmailUnsubscribeLink: vi.fn(),
createS3Client: vi.fn(),
}));
vi.mock("@aws-sdk/client-s3", () => ({
PutObjectCommand: vi.fn(),
}));
vi.mock("@novu/api/models/components", () => ({
ChatOrPushProviderEnum: { Discord: "discord" },
}));
import { env } from "next-runtime-env";
import * as memberRepo from "@kan/db/repository/member.repo";
import { createDatabaseHooks } from "./hooks";
const mockEnv = env as ReturnType<typeof vi.fn>;
const mockGetByEmailAndStatus =
memberRepo.getByEmailAndStatus as ReturnType<typeof vi.fn>;
const db = {} as Parameters<typeof createDatabaseHooks>[0];
const fakeUser = {
id: "user-1",
createdAt: new Date(),
updatedAt: new Date(),
email: "test@example.com",
emailVerified: false,
name: "Test User",
};
describe("createDatabaseHooks", () => {
const hooks = createDatabaseHooks(db);
beforeEach(() => {
vi.clearAllMocks();
});
describe("user.create.before", () => {
it("allows sign-up when DISABLE_SIGN_UP is not set", async () => {
mockEnv.mockReturnValue(undefined);
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(true);
expect(mockGetByEmailAndStatus).not.toHaveBeenCalled();
});
it("allows sign-up when DISABLE_SIGN_UP is false", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "false" : undefined,
);
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(true);
expect(mockGetByEmailAndStatus).not.toHaveBeenCalled();
});
it("blocks sign-up when disabled and user has no pending invitation", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
mockGetByEmailAndStatus.mockResolvedValue(undefined);
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(false);
expect(mockGetByEmailAndStatus).toHaveBeenCalledWith(
db,
"test@example.com",
"invited",
);
});
it("allows sign-up when disabled but user has a pending invitation", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
mockGetByEmailAndStatus.mockResolvedValue({
id: "member-1",
email: "test@example.com",
status: "invited",
});
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(true);
expect(mockGetByEmailAndStatus).toHaveBeenCalledWith(
db,
"test@example.com",
"invited",
);
});
it("blocks sign-up when disabled and invitation exists but domain is not allowed", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
process.env.BETTER_AUTH_ALLOWED_DOMAINS = "acme.com";
mockGetByEmailAndStatus.mockResolvedValue({
id: "member-1",
email: "test@example.com",
status: "invited",
});
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(false);
delete process.env.BETTER_AUTH_ALLOWED_DOMAINS;
});
// The user.create.before hook fires for ALL sign-up paths including
// OIDC/social — verify invite bypass works regardless of auth method.
it("allows OIDC/social sign-up when disabled but user has a pending invitation", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
const oidcUser = {
...fakeUser,
id: "user-oidc",
email: "sso@corp.com",
image: "https://provider.com/avatar.jpg",
};
mockGetByEmailAndStatus.mockResolvedValue({
id: "member-2",
email: "sso@corp.com",
status: "invited",
});
const result = await hooks.user.create.before(oidcUser, {});
expect(result).toBe(true);
expect(mockGetByEmailAndStatus).toHaveBeenCalledWith(
db,
"sso@corp.com",
"invited",
);
});
it("blocks OIDC/social sign-up when disabled and user has no pending invitation", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
const oidcUser = {
...fakeUser,
id: "user-oidc",
email: "random@external.com",
image: "https://provider.com/avatar.jpg",
};
mockGetByEmailAndStatus.mockResolvedValue(undefined);
const result = await hooks.user.create.before(oidcUser, {});
expect(result).toBe(false);
expect(mockGetByEmailAndStatus).toHaveBeenCalledWith(
db,
"random@external.com",
"invited",
);
});
it("allows sign-up when disabled, invitation exists, and domain is allowed", async () => {
mockEnv.mockImplementation((key: string) =>
key === "NEXT_PUBLIC_DISABLE_SIGN_UP" ? "true" : undefined,
);
process.env.BETTER_AUTH_ALLOWED_DOMAINS = "example.com";
mockGetByEmailAndStatus.mockResolvedValue({
id: "member-1",
email: "test@example.com",
status: "invited",
});
const result = await hooks.user.create.before(fakeUser, {});
expect(result).toBe(true);
delete process.env.BETTER_AUTH_ALLOWED_DOMAINS;
});
});
});

View File

@@ -0,0 +1,14 @@
import { defineConfig } from "vitest/config";
import { resolve } from "path";
export default defineConfig({
test: {
root: __dirname,
include: ["src/**/*.test.ts"],
},
resolve: {
alias: {
"@kan/db": resolve(__dirname, "../db/src"),
},
},
});

View File

@@ -0,0 +1,2 @@
ALTER TYPE "public"."source" ADD VALUE 'github';--> statement-breakpoint
ALTER TABLE "integration" ALTER COLUMN "accessToken" SET DATA TYPE text;--> statement-breakpoint

View File

@@ -0,0 +1,2 @@
ALTER TABLE "board" ADD COLUMN "isArchived" boolean DEFAULT false NOT NULL;--> statement-breakpoint
CREATE INDEX IF NOT EXISTS "board_is_archived_idx" ON "board" USING btree ("isArchived");

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -197,6 +197,20 @@
"when": 1771192000000,
"tag": "20260129210000_AddWorkspaceWebhooks",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1772049587901,
"tag": "20260225195947_AddIsArchivedToBoard",
"breakpoints": true
},
{
"idx": 28,
"version": "7",
"when": 1771930355536,
"tag": "20260224105235_AddGitHubIntegrationSupport",
"breakpoints": true
}
]
}
}

View File

@@ -44,7 +44,7 @@ export const getAllByWorkspaceId = async (
db: dbClient,
workspaceId: number,
userId: string,
opts?: { type?: "regular" | "template" },
opts?: { type?: "regular" | "template"; archived?: boolean },
) => {
const boardsData = await db.query.boards.findMany({
columns: {
@@ -78,6 +78,7 @@ export const getAllByWorkspaceId = async (
eq(boards.workspaceId, workspaceId),
isNull(boards.deletedAt),
opts?.type ? eq(boards.type, opts.type) : undefined,
opts?.archived !== undefined ? eq(boards.isArchived, opts.archived) : undefined,
),
});
@@ -102,6 +103,7 @@ export const getIdByPublicId = async (db: dbClient, boardPublicId: string) => {
columns: {
id: true,
type: true,
isArchived: true,
},
where: eq(boards.publicId, boardPublicId),
});
@@ -195,6 +197,7 @@ export const getByPublicId = async (
name: true,
slug: true,
visibility: true,
isArchived: true,
},
with: {
userFavorites: {
@@ -628,6 +631,7 @@ export const update = async (
slug: string | undefined;
visibility: BoardVisibilityStatus | undefined;
boardPublicId: string;
isArchived?: boolean;
},
) => {
const [result] = await db
@@ -637,6 +641,7 @@ export const update = async (
slug: boardInput.slug,
visibility: boardInput.visibility,
updatedAt: new Date(),
...(boardInput.isArchived !== undefined && { isArchived: boardInput.isArchived })
})
.where(eq(boards.publicId, boardInput.boardPublicId))
.returning({

View File

@@ -46,6 +46,35 @@ export const getProvidersForUser = async (db: dbClient, userId: string) => {
return integration;
};
export const createOrUpdateProvider = async (
db: dbClient,
data: {
userId: string;
provider: string;
accessToken: string;
refreshToken?: string | null;
expiresAt: Date;
},
) => {
await db
.insert(integrations)
.values({
provider: data.provider,
userId: data.userId,
accessToken: data.accessToken,
refreshToken: data.refreshToken ?? null,
expiresAt: data.expiresAt,
})
.onConflictDoUpdate({
target: [integrations.userId, integrations.provider],
set: {
accessToken: data.accessToken,
refreshToken: data.refreshToken ?? null,
expiresAt: data.expiresAt,
},
});
};
export const deleteProviderForUser = async (
db: dbClient,
userId: string,

View File

@@ -30,22 +30,22 @@ const SYSTEM_ROLES: {
description: string;
hierarchyLevel: number;
}[] = [
{
name: "admin",
description: "Full access to all workspace features",
hierarchyLevel: 100,
},
{
name: "member",
description: "Standard member with create and edit permissions",
hierarchyLevel: 50,
},
{
name: "guest",
description: "View-only access",
hierarchyLevel: 10,
},
];
{
name: "admin",
description: "Full access to all workspace features",
hierarchyLevel: 100,
},
{
name: "member",
description: "Standard member with create and edit permissions",
hierarchyLevel: 50,
},
{
name: "guest",
description: "View-only access",
hierarchyLevel: 10,
},
];
export const getCount = async (db: dbClient) => {
const result = await db
@@ -250,7 +250,7 @@ export const getBySlugWithBoards = (db: dbClient, workspaceSlug: string) => {
slug: true,
name: true,
},
where: and(isNull(boards.deletedAt), eq(boards.visibility, "public")),
where: and(isNull(boards.deletedAt), eq(boards.visibility, "public"), eq(boards.isArchived, false)),
orderBy: [asc(boards.name)]
},
},

View File

@@ -2,7 +2,6 @@ import { relations, sql } from "drizzle-orm";
import {
bigint,
bigserial,
boolean,
index,
pgEnum,
pgTable,
@@ -12,8 +11,8 @@ import {
uniqueIndex,
uuid,
varchar,
boolean,
} from "drizzle-orm/pg-core";
import { imports } from "./imports";
import { labels } from "./labels";
import { lists } from "./lists";
@@ -56,9 +55,11 @@ export const boards = pgTable(
.references(() => workspaces.id, { onDelete: "cascade" }),
visibility: boardVisibilityEnum("visibility").notNull().default("private"),
type: boardTypeEnum("type").notNull().default("regular"),
isArchived: boolean("isArchived").notNull().default(false),
sourceBoardId: bigint("sourceBoardId", { mode: "number" }),
},
(table) => [
index("board_is_archived_idx").on(table.isArchived),
index("board_visibility_idx").on(table.visibility),
index("board_type_idx").on(table.type),
index("board_source_idx").on(table.sourceBoardId),

View File

@@ -14,7 +14,7 @@ import { labels } from "./labels";
import { lists } from "./lists";
import { users } from "./users";
export const importSourceEnum = pgEnum("source", ["trello"]);
export const importSourceEnum = pgEnum("source", ["trello", "github"]);
export const importStatusEnum = pgEnum("status", [
"started",
"success",

View File

@@ -2,6 +2,7 @@ import { relations } from "drizzle-orm";
import {
pgTable,
primaryKey,
text,
timestamp,
uuid,
varchar,
@@ -16,7 +17,7 @@ export const integrations = pgTable(
userId: uuid("userId")
.notNull()
.references(() => users.id, { onDelete: "cascade" }),
accessToken: varchar("accessToken", { length: 255 }).notNull(),
accessToken: text("accessToken").notNull(),
refreshToken: varchar("refreshToken", { length: 255 }),
expiresAt: timestamp("expiresAt").notNull(),
createdAt: timestamp("createdAt")