Compare commits

...

47 Commits

Author SHA1 Message Date
Maksim Eltyshev
414418130d chore: Update version 2026-02-17 15:55:56 +01:00
Maksim Eltyshev
d83ea4b146 fix(terms): Display template notice, support custom terms loading
Closes #1523
2026-02-17 15:37:26 +01:00
Fabian Reinold
addad4378a feat(helm): Add image digest pinning support (#1531)
* feat(helm): add image digest field to values

- Add optional 'digest' field under image.repository configuration
- Allows users to pin container images by SHA256 digest
- Improves security through immutable image identification
- Fully backward compatible (digest is optional)

* feat(helm): implement image digest pinning in deployment template

- Add conditional logic to support SHA256 digest in image references
- When digest is set with tag: generates 'repository:tag@sha256:digest'
- When digest is set without tag: generates 'repository@sha256:digest'
- Preserves backward compatibility with tag-only deployments
- Validates tag presence to avoid invalid image references

* docs(helm): add image digest pinning documentation

- Add 'Image Digest Pinning' section under Advanced Configuration
- Include methods for finding image digests (docker inspect, skopeo)
- Document two usage options:
  - Option 1: Digest with tag (recommended) for reference + verification
  - Option 2: Digest only for minimalist configuration
- Explain security benefits (immutability, supply chain security, reproducibility)
- Provide complete helm and values.yaml examples
2026-02-16 14:25:47 +01:00
Maksim Eltyshev
b9967feeea fix(socket): Handle transport error during reconnection after idle 2026-02-16 10:50:09 +01:00
Maksim Eltyshev
dbcdd62bdf docs: Update readme 2026-02-12 16:03:53 +01:00
Maksim Eltyshev
ff4177f27a chore: Fix index view extension in ignore files 2026-02-11 23:00:45 +01:00
Maksim Eltyshev
f68e7d156e chore: Fix data path in docker-restore script 2026-02-11 22:58:40 +01:00
Maksim Eltyshev
bda32e0247 chore: Update version 2026-02-11 14:34:56 +01:00
Maksim Eltyshev
168776aef8 chore: Bump terms 2026-02-11 14:03:37 +01:00
Maksim Eltyshev
d84b615815 ci: Fix sed when updating Dockerfile to use prebuilt client 2026-02-11 13:08:06 +01:00
Maksim Eltyshev
16b228e54e fix: Prevent collisions when generating local ids 2026-02-11 11:59:57 +01:00
Maksim Eltyshev
0db1a5cf0e chore: Support multiple term types 2026-02-10 22:53:22 +01:00
Maksim Eltyshev
1d0b3e9af8 ci: Fix path to terms 2026-02-10 21:49:33 +01:00
Maksim Eltyshev
dabdedf6c4 ref: Little refactoring 2026-02-10 21:43:58 +01:00
Maksim Eltyshev
a82ae49fe4 chore: Unify term types 2026-02-10 21:14:56 +01:00
Hayden Welch
e7326303cd docs: Validate Swagger docs (#1486) 2026-02-10 19:35:39 +01:00
Maksim Eltyshev
b2e3aac314 chore: Upgrade data structure only if S3 is enabled 2026-02-10 18:52:25 +01:00
Maksim Eltyshev
8c4859fed5 chore: Sync upgrade script with latest changes 2026-02-10 18:34:26 +01:00
Maksim Eltyshev
e219e5be42 ci: Restore latest tag 2026-02-10 15:31:05 +01:00
Maksim Eltyshev
7d613dc171 docs: Bump last updates 2026-02-10 15:00:19 +01:00
Maksim Eltyshev
d63cc28f23 ci: Optimize Docker image build by prebuilding client 2026-02-09 21:48:44 +01:00
Maksim Eltyshev
8898a0f0a2 fix: Block unsupported local Apprise schemas 2026-02-09 13:35:04 +01:00
Maksim Eltyshev
538280d197 feat: Add configurable proxy for outgoing traffic to prevent SSRF 2026-02-09 13:33:27 +01:00
Maksim Eltyshev
aa3ebd5add feat: Apply color to entire list instead of card bottoms 2026-02-08 00:06:32 +01:00
Maksim Eltyshev
f8cd7474d1 chore: Update client dependencies 2026-02-04 17:52:04 +01:00
Maksim Eltyshev
450bd875c1 chore: Update server dependencies 2026-02-04 12:53:15 +01:00
Maksim Eltyshev
8df5a111bf fix: Forward headers correctly when reading from S3 2026-02-04 11:34:47 +01:00
Maksim Eltyshev
3c33161df6 fix: Fix server error when fetching custom field group
Closes #1507
2026-02-01 00:14:07 +01:00
Maksim Eltyshev
052edc9fb1 feat: Migrate file storage to unified data directory 2026-01-31 20:27:15 +01:00
Maksim Eltyshev
6335b3bd3c fix: Enhance response headers for file attachments 2026-01-30 21:53:53 +01:00
Maksim Eltyshev
db99227f32 feat: Re-stream static files from S3, introduce protected static files 2026-01-30 21:45:18 +01:00
Maksim Eltyshev
a5dc0a64ac build: Upgrade pip at build time, bump node-redis and apprise 2026-01-29 13:21:53 +01:00
Maksim Eltyshev
b37ca68d61 chore: Auto-update internal version for nightly build, improve version display in UI 2026-01-29 00:24:57 +01:00
Maksim Eltyshev
31dd816e30 docs: Clarify nested pagination cursor in Swagger 2026-01-28 16:53:33 +01:00
Maksim Eltyshev
d688a64e36 feat: Add OIDC debug mode 2026-01-27 22:34:08 +01:00
Maksim Eltyshev
2c4369159b fix: Hide unlinking SSO when OIDC is enforced 2026-01-26 22:21:27 +01:00
Maksim Eltyshev
b2da1a5e18 docs: Add missing details to Swagger 2026-01-26 21:44:00 +01:00
Maksim Eltyshev
2b699f77f4 feat: Add ability to unlink SSO from user 2026-01-26 21:18:32 +01:00
Maksim Eltyshev
ee917c545c chore: Update dependencies 2026-01-26 14:11:20 +01:00
Maksim Eltyshev
3b8ad26169 feat: Add ability to pre-fill login credentials in demo mode 2026-01-25 20:17:13 +01:00
Maksim Eltyshev
ffdb7254b3 fix: Enable favorites by default 2026-01-25 18:37:56 +01:00
Maksim Eltyshev
b52604045d fix: Correctly track password field modification in SMTP pane 2026-01-23 20:32:23 +01:00
Maksim Eltyshev
267fce0505 fix: Prevent deactivated users from receiving socket events when possible 2026-01-23 19:38:58 +01:00
Maksim Eltyshev
6ec0bafecb fix: Prevent sending notifications to deactivated users 2026-01-23 17:20:12 +01:00
Maksim Eltyshev
b2c4c530c6 fix: Fix variable name in seeder 2026-01-23 11:42:40 +01:00
Maksim Eltyshev
59da747e75 docs: Add Notes app testing invitation 2026-01-23 11:37:29 +01:00
Maksim Eltyshev
1264fd5715 feat: Add internal runtime configuration 2026-01-22 18:02:42 +01:00
228 changed files with 7336 additions and 5023 deletions

View File

@@ -11,24 +11,13 @@ server/test
server/.tmp
server/.venv
server/views/*
!server/views/.gitkeep
server/views/index.html
server/public/*
!server/public/preloaded-favicons
!server/public/favicons
server/public/favicons/*
!server/public/favicons/.gitkeep
!server/public/user-avatars
server/public/user-avatars/*
!server/public/user-avatars/.gitkeep
!server/public/background-images
server/public/background-images/*
!server/public/background-images/.gitkeep
server/data/*
!server/data/.gitkeep
server/private/*
!server/private/attachments
server/private/attachments/*
!server/private/attachments/.gitkeep
server/terms/*
!server/terms/_template
!server/terms/cloud
client/dist

View File

@@ -12,6 +12,30 @@ jobs:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Install client dependencies
run: npm install --omit=dev
working-directory: ./client
- name: Build client
run: |
DISABLE_ESLINT_PLUGIN=true npm run build
mv dist build
working-directory: ./client
- name: Update Dockerfile to use prebuilt client
run: |
sed -i '/^FROM node:22 AS client/,/^ && DISABLE_ESLINT_PLUGIN=true npm run build$/c\
FROM node:22 AS client\n\
WORKDIR /app\n\
COPY client/build /app/dist' Dockerfile
cat Dockerfile
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
@@ -40,6 +64,10 @@ jobs:
name=ghcr.io/${{ github.repository }}
tags: |
type=raw,value=${{ steps.set-version.outputs.result }}
type=raw,value=latest
labels: |
org.opencontainers.image.licenses=Fair Use License
org.opencontainers.image.url=https://planka.app
- name: Build and push Docker image
uses: docker/build-push-action@v4

View File

@@ -17,6 +17,38 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '22'
cache: 'npm'
- name: Update version with build number
run: |
npm version "$(node -p "require('./package.json').version")-nightly.$(git rev-list --count HEAD)" --no-git-tag-version
npx --yes genversion --source . --template server/version-template.ejs server/version.js
npx --yes genversion --source . --template client/version-template.ejs client/src/version.js
- name: Install client dependencies
run: npm install --omit=dev
working-directory: ./client
- name: Build client
run: |
DISABLE_ESLINT_PLUGIN=true npm run build
mv dist build
working-directory: ./client
- name: Update Dockerfile to use prebuilt client
run: |
sed -i '/^FROM node:22 AS client/,/^ && DISABLE_ESLINT_PLUGIN=true npm run build$/c\
FROM node:22 AS client\n\
WORKDIR /app\n\
COPY client/build /app/dist' Dockerfile
cat Dockerfile
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
@@ -39,6 +71,9 @@ jobs:
name=ghcr.io/${{ github.repository }}
tags: |
type=raw,value=nightly
labels: |
org.opencontainers.image.licenses=Fair Use License
org.opencontainers.image.url=https://planka.app
- name: Build and push Docker image
uses: docker/build-push-action@v4

View File

@@ -69,7 +69,7 @@ jobs:
- name: Seed database with terms signature
run: |
TERMS_SIGNATURE=$(sha256sum terms/en-US/extended.md | awk '{print $1}')
TERMS_SIGNATURE=$(sha256sum terms/_template/en-US.md | awk '{print $1}')
PGPASSWORD=$POSTGRES_PASSWORD psql -h localhost -U $POSTGRES_USERNAME -d $POSTGRES_DATABASE -c "UPDATE user_account SET terms_signature = '$TERMS_SIGNATURE';"
working-directory: ./server

View File

@@ -28,7 +28,7 @@ RUN npm install npm --global \
FROM node:22-alpine
RUN apk -U upgrade \
&& apk add bash python3 --no-cache \
&& apk add bash python3 squid --no-cache \
&& npm install npm --global
USER node
@@ -44,15 +44,12 @@ COPY --from=client --chown=node:node /app/dist public
COPY --from=client --chown=node:node /app/dist/index.html views
RUN python3 -m venv .venv \
&& .venv/bin/pip3 install --upgrade pip \
&& .venv/bin/pip3 install -r requirements.txt --no-cache-dir \
&& mv .env.sample .env \
&& npm config set update-notifier false
VOLUME /app/public/favicons
VOLUME /app/public/user-avatars
VOLUME /app/public/background-images
VOLUME /app/private/attachments
VOLUME /app/data
EXPOSE 1337
HEALTHCHECK --interval=10s --timeout=2s --start-period=15s \

View File

@@ -1,23 +1,27 @@
# PLANKA
<div align="center">
**Project mastering driven by fun**
![Logo](https://raw.githubusercontent.com/plankanban/planka/master/assets/logo.png)
![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) [![Docker Pulls](https://img.shields.io/badge/docker_pulls-6M%2B-%23066da5?style=flat-square&color=red)](https://github.com/plankanban/planka/pkgs/container/planka) [![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square&color=blue)](https://github.com/plankanban/planka/graphs/contributors) [![Chat](https://img.shields.io/discord/1041440072953765979?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/WqqYNd7Jvt)
# PLANKA
![Demo](https://raw.githubusercontent.com/plankanban/planka/master/assets/demo.gif)
_Project mastering driven by fun_
[**Client demo**](https://plankanban.github.io/planka) (without server features).
![Version](https://img.shields.io/github/package-json/v/plankanban/planka?style=flat-square) [![Docker Pulls](https://img.shields.io/badge/docker_pulls-8M%2B-%23066da5?style=flat-square&color=red)](https://github.com/plankanban/planka/pkgs/container/planka) [![Contributors](https://img.shields.io/github/contributors/plankanban/planka?style=flat-square&color=blue)](https://github.com/plankanban/planka/graphs/contributors) [![Chat](https://img.shields.io/discord/1041440072953765979?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/WqqYNd7Jvt)
> ⚠️ The demo GIF and client demo are based on **v1** and will be updated soon.
[Install](https://docs.planka.cloud/docs/installation/docker/production-version/) · [Demo](https://planka.app) · [Docs](https://docs.planka.cloud/docs/welcome/) · [API](https://plankanban.github.io/planka/swagger-ui/) · [Cloud](https://planka.app/pricing) · [Pro version](https://planka.app/pro)
![Demo](https://raw.githubusercontent.com/plankanban/planka/master/assets/demo.gif)
</div>
## Key Features
- **Collaborative Kanban Boards**: Create projects, boards, lists, cards, and manage tasks with an intuitive drag-and-drop interface
- **Real-Time Updates**: Instant syncing across all users, no refresh needed
- **Rich Markdown Support**: Write beautifully formatted card descriptions with a powerful markdown editor
- **Flexible Notifications**: Get alerts through 100+ providers, fully customizable to your workflow
- **Seamless Authentication**: Single sign-on with OpenID Connect integration
- **Multilingual & Easy to Translate**: Full internationalization support for a global audience
- **Collaborative Kanban Boards:** Create projects, boards, lists, cards, and manage tasks with an intuitive drag-and-drop interface
- **Real-Time Updates:** Instant syncing across all users, no refresh needed
- **Rich Markdown Support:** Write beautifully formatted card descriptions with a powerful markdown editor
- **Flexible Notifications:** Get alerts through 100+ providers, fully customizable to your workflow
- **Seamless Authentication:** Single sign-on with OpenID Connect integration
- **Multilingual & Easy to Translate:** Full internationalization support for a global audience
## How to Deploy
@@ -25,9 +29,16 @@ PLANKA is easy to install using multiple methods - learn more in the [installati
For configuration and environment settings, see the [configuration section](https://docs.planka.cloud/docs/category/configuration/).
## Contact
Interested in a hosted or [Pro version](https://planka.app/pro) of PLANKA? Check out the pricing on our [website](https://planka.app/pricing).
Interested in a hosted version of PLANKA? Email us at [github@planka.group](mailto:github@planka.group).
## Notes App
A testing version of the Notes app is now available on multiple platforms:
- **iOS:** Join the [TestFlight](https://testflight.apple.com/join/5eJqTaJW) to try the app
- **Windows & Android:** Download the app [here](https://planka-notes.hillerdaniel.de)
## Contact
For any security issues, please do not create a public issue on GitHub - instead, report it privately by emailing [security@planka.group](mailto:security@planka.group).
@@ -39,10 +50,10 @@ For any security issues, please do not create a public issue on GitHub - instead
PLANKA is [fair-code](https://faircode.io) distributed under the [Fair Use License](https://github.com/plankanban/planka/blob/master/LICENSES/PLANKA%20Community%20License%20EN.md) and [PLANKA Pro/Enterprise License](https://github.com/plankanban/planka/blob/master/LICENSES/PLANKA%20Commercial%20License%20EN.md).
- **Source Available**: The source code is always visible
- **Self-Hostable**: Deploy and host it anywhere
- **Extensible**: Customize with your own functionality
- **Enterprise Licenses**: Available for additional features and support
- **Source Available:** The source code is always visible
- **Self-Hostable:** Deploy and host it anywhere
- **Extensible:** Customize with your own functionality
- **Enterprise Licenses:** Available for additional features and support
For more details, check the [License Guide](https://github.com/plankanban/planka/blob/master/LICENSES/PLANKA%20License%20Guide%20EN.md).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
assets/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 1.1.2
version: 2.0.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "2.0.0-rc.4"
appVersion: "2.0.1"
dependencies:
- alias: postgresql

View File

@@ -68,7 +68,7 @@ helm install planka . --set secretkey=$SECRETKEY \
or create a values.yaml file like:
```yaml
````yaml
secretkey: "<InsertSecretKey>"
# The admin section needs to be present for new instances of PLANKA, after the first start you can remove the lines starting with admin_. If you want the admin user to be unchangeable admin_email: has to stay
# After changing the config you have to run ```helm upgrade planka . -f values.yaml```
@@ -89,11 +89,11 @@ ingress:
- path: /
pathType: ImplementationSpecific
# Needed for HTTPS
# Needed for HTTPS
tls:
- secretName: planka-tls # existing TLS secret in k8s
hosts:
- planka.example.dev
- secretName: planka-tls # existing TLS secret in k8s
hosts:
- planka.example.dev
```
```bash
@@ -135,14 +135,14 @@ extraMounts:
subPath: ca.crt
readOnly: true
configMap:
name: ca-certificates # Must exist
name: ca-certificates # Must exist
# Mount TLS certificates from existing Secret
- name: tls-certs
mountPath: /etc/ssl/private
readOnly: true
secret:
secretName: planka-tls-secret # Must exist
secretName: planka-tls-secret # Must exist
items:
- key: tls.crt
path: server.crt
@@ -178,11 +178,13 @@ extraMounts:
A common use case is configuring OIDC with a self-hosted Keycloak instance that uses custom CA certificates.
First, create the CA certificate ConfigMap:
```bash
kubectl create configmap ca-certificates --from-file=ca.crt=/path/to/your/ca.crt
```
Then configure the chart:
```yaml
# Mount custom CA certificate from existing ConfigMap
extraMounts:
@@ -225,6 +227,67 @@ extraEnv:
key: api-key
```
### Image Digest Pinning
For enhanced security and reproducibility, you can pin the container image using its SHA256 digest instead of relying solely on tags. This ensures you always deploy the exact same image, preventing tag mutations or accidental updates.
#### Finding the Image Digest
You can find the digest of a specific image tag using:
```bash
docker inspect ghcr.io/plankanban/planka:latest --format='{{index .RepoDigests 0}}'
# Output: ghcr.io/plankanban/planka@sha256:abc123def456...
# Or with skopeo
skopeo inspect docker://ghcr.io/plankanban/planka:latest
```
#### Usage
You can use digest pinning in several ways:
**Option 1: Digest with tag (recommended)**
Includes the tag for reference while using the digest for verification:
```bash
helm install planka . --set secretkey=$SECRETKEY \
--set image.tag=latest \
--set image.digest=abc123def456... \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
--set admin_username="demo"
```
Or in values.yaml:
```yaml
image:
repository: ghcr.io/plankanban/planka
tag: latest
digest: "abc123def456ab89cd12ef34ab56cd78ef90ab12cd34ef56ab78cd90ef12ab34"
```
**Option 2: Digest only**
If you prefer to pin only by digest without specifying a tag:
```yaml
image:
repository: ghcr.io/plankanban/planka
tag: "" # Empty - digest alone identifies the image
digest: "abc123def456ab89cd12ef34ab56cd78ef90ab12cd34ef56ab78cd90ef12ab34"
```
#### Security Benefits
- **Immutability**: Ensures you always deploy the exact same image
- **Supply Chain Security**: Protects against tag mutations or registry compromise
- **Reproducibility**: Makes deployments fully reproducible across environments
- **Audit Trail**: Provides clear image identity in deployment manifests
### Complete Example
See `values-example.yaml` for a comprehensive example that demonstrates all the advanced features including OIDC configuration with custom CA certificates.

View File

@@ -39,7 +39,16 @@ spec:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
{{- $imageTag := .Values.image.tag | default .Chart.AppVersion }}
{{- if .Values.image.digest }}
{{- if $imageTag }}
image: "{{ .Values.image.repository }}:{{ $imageTag }}@sha256:{{ .Values.image.digest }}"
{{- else }}
image: "{{ .Values.image.repository }}@sha256:{{ .Values.image.digest }}"
{{- end }}
{{- else }}
image: "{{ .Values.image.repository }}:{{ $imageTag }}"
{{- end }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
@@ -54,17 +63,8 @@ spec:
path: /
port: http
volumeMounts:
- mountPath: /app/public/favicons
subPath: favicons
name: planka
- mountPath: /app/public/user-avatars
subPath: user-avatars
name: planka
- mountPath: /app/public/background-images
subPath: background-images
name: planka
- mountPath: /app/private/attachments
subPath: attachments
- mountPath: /app/data
subPath: data
name: planka
{{- if .Values.securityContext.readOnlyRootFilesystem }}
- mountPath: /app/logs

View File

@@ -9,6 +9,10 @@ image:
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
# Optional: specify the image digest for pinning by SHA256
# When set, the image reference will include the digest for enhanced security
# Example: "abc123def456..." (without sha256: prefix)
digest: ""
imagePullSecrets: []
nameOverride: ""

4735
client/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -78,18 +78,26 @@
"^.+\\.(js|jsx)$": "babel-jest"
}
},
"overrides": {
"@diplodoc/transform": {
"lodash": "^4.17.23"
},
"react-mentions": {
"@babel/runtime": "^7.28.6"
}
},
"dependencies": {
"@ballerina/highlightjs-ballerina": "^1.0.1",
"@diplodoc/cut-extension": "^0.7.4",
"@diplodoc/cut-extension": "^1.1.1",
"@diplodoc/transform": "^4.64.1",
"@gravity-ui/components": "^4.17.0",
"@gravity-ui/markdown-editor": "^15.27.2",
"@gravity-ui/uikit": "^7.29.0",
"@gravity-ui/components": "^4.18.0",
"@gravity-ui/markdown-editor": "^15.31.0",
"@gravity-ui/uikit": "^7.31.1",
"@juggle/resize-observer": "^3.4.0",
"@vitejs/plugin-react": "^4.7.0",
"@vitejs/plugin-react": "^5.1.3",
"browserslist-to-esbuild": "^2.1.1",
"classnames": "^2.5.1",
"date-fns": "^2.30.0",
"date-fns": "^4.1.0",
"dequal": "^2.0.3",
"highlight.js": "^11.11.1",
"highlightjs-4d": "^1.0.6",
@@ -102,7 +110,7 @@
"highlightjs-jolie": "^0.1.8",
"highlightjs-lean": "^1.2.0",
"highlightjs-lookml": "^1.0.2",
"highlightjs-macaulay2": "^0.2.5",
"highlightjs-macaulay2": "^0.5.0",
"highlightjs-mlir": "^0.0.1",
"highlightjs-qsharp": "^1.0.2",
"highlightjs-redbol": "^2.1.2",
@@ -115,10 +123,10 @@
"highlightjs-zenscript": "^2.0.0",
"hightlightjs-papyrus": "^0.0.4",
"history": "^5.3.0",
"i18next": "^25.7.4",
"i18next": "^25.8.1",
"i18next-browser-languagedetector": "^8.2.0",
"initials": "^3.1.2",
"javascript-time-ago": "^2.5.12",
"javascript-time-ago": "^2.6.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
"linkify-react": "^4.3.2",
@@ -133,54 +141,54 @@
"prop-types": "^15.8.1",
"react": "18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-datepicker": "^4.25.0",
"react-datepicker": "^9.1.0",
"react-dom": "18.2.0",
"react-dropzone": "^14.3.8",
"react-dropzone": "^14.4.0",
"react-frame-component": "^5.2.7",
"react-hot-toast": "^2.6.0",
"react-i18next": "^15.7.4",
"react-i18next": "^16.5.4",
"react-input-mask": "^2.0.4",
"react-intersection-observer": "^9.16.0",
"react-intersection-observer": "^10.0.2",
"react-mentions": "^4.4.10",
"react-photoswipe-gallery": "^2.2.7",
"react-redux": "^8.1.3",
"react-router-dom": "^6.30.3",
"react-photoswipe-gallery": "^4.0.0",
"react-redux": "^9.2.0",
"react-router": "^7.13.0",
"react-textarea-autosize": "^8.5.9",
"react-time-ago": "^7.3.5",
"redux": "^4.2.1",
"react-time-ago": "^7.4.1",
"redux": "^5.0.1",
"redux-logger": "^3.0.6",
"redux-orm": "^0.16.2",
"redux-saga": "^1.4.2",
"reselect": "^4.1.8",
"reselect": "^5.1.1",
"sails.io.js": "^1.2.1",
"sass-embedded": "^1.97.2",
"sass-embedded": "^1.97.3",
"semantic-ui-react": "^2.1.5",
"socket.io-client": "^2.5.0",
"socket.io-client": "^4.8.3",
"validator": "^13.15.26",
"vite": "^6.4.1",
"vite": "^7.3.1",
"vite-plugin-commonjs": "^0.10.4",
"vite-plugin-node-polyfills": "^0.23.0",
"vite-plugin-node-polyfills": "^0.25.0",
"vite-plugin-svgr": "^4.5.0",
"zxcvbn": "^4.4.2"
},
"devDependencies": {
"@babel/eslint-parser": "^7.28.6",
"@babel/preset-env": "^7.28.6",
"@cucumber/cucumber": "^11.3.0",
"@cucumber/pretty-formatter": "^1.0.1",
"@playwright/test": "^1.57.0",
"babel-jest": "^29.7.0",
"@babel/preset-env": "^7.29.0",
"@cucumber/cucumber": "^12.6.0",
"@cucumber/pretty-formatter": "^3.0.0",
"@playwright/test": "^1.58.1",
"babel-jest": "^30.2.0",
"babel-preset-airbnb": "^5.0.0",
"eslint": "^8.57.1",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-prettier": "^9.1.2",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.5",
"eslint-plugin-react-hooks": "^4.6.2",
"jest": "^29.7.0",
"playwright": "^1.57.0",
"prettier": "3.3.3"
"jest": "^30.2.0",
"playwright": "^1.58.0",
"prettier": "3.8.1"
}
}

View File

@@ -1,5 +1,5 @@
diff --git a/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js b/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
index 288d462..8851e98 100644
index dec01f0..a80b857 100644
--- a/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
+++ b/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
@@ -102,7 +102,6 @@ export const BundlePreset = (builder, opts) => {

View File

@@ -1,13 +0,0 @@
diff --git a/node_modules/react-photoswipe-gallery/dist/gallery.js b/node_modules/react-photoswipe-gallery/dist/gallery.js
index 53cc02c..f4baccb 100644
--- a/node_modules/react-photoswipe-gallery/dist/gallery.js
+++ b/node_modules/react-photoswipe-gallery/dist/gallery.js
@@ -181,7 +181,7 @@ export const Gallery = ({
alt
} = pswpInstance.currSlide.data;
// eslint-disable-next-line no-param-reassign
- el.innerHTML = caption || alt || '';
+ el.textContent = caption || alt || '';
});
}
});

View File

@@ -0,0 +1,87 @@
diff --git a/node_modules/sails.io.js/sails.io.js b/node_modules/sails.io.js/sails.io.js
index 11694b5..bb5e594 100644
--- a/node_modules/sails.io.js/sails.io.js
+++ b/node_modules/sails.io.js/sails.io.js
@@ -138,6 +138,15 @@
CONNECTION_METADATA_PARAMS.platform + '=' + SDK_INFO.platform + '&' +
CONNECTION_METADATA_PARAMS.language + '=' + SDK_INFO.language;
+ var MANAGER_EVENT_NAMES = new Set([
+ 'error',
+ 'reconnect',
+ 'reconnect_attempt',
+ 'reconnect_error',
+ 'reconnect_failed',
+ 'ping'
+ ]);
+
@@ -668,6 +677,7 @@
// Okay to change global headers while socket is connected
if (option == 'headers') {return;}
Object.defineProperty(self, option, {
+ enumerable: true,
get: function() {
if (option == 'url') {
return _opts[option] || (self._raw && self._raw.io && self._raw.io.uri);
@@ -986,7 +996,7 @@
consolog('====================================');
});
- self.on('reconnecting', function(numAttempts) {
+ self.on('reconnect_attempt', function(numAttempts) {
consolog(
'\n'+
' Socket is trying to reconnect to '+(self.url ? self.url : 'Sails')+'...\n'+
@@ -1124,7 +1134,7 @@
// off to the self._raw for consumption
for (var evName in self.eventQueue) {
for (var i in self.eventQueue[evName]) {
- self._raw.on(evName, self.eventQueue[evName][i]);
+ self._getEventTarget(evName).on(evName, self.eventQueue[evName][i]);
}
}
@@ -1150,10 +1160,11 @@
* @return {SailsSocket}
*/
SailsSocket.prototype.on = function (evName, fn){
+ var target = this._getEventTarget(evName);
// Bind the event to the raw underlying socket if possible.
- if (this._raw) {
- this._raw.on(evName, fn);
+ if (target) {
+ target.on(evName, fn);
return this;
}
@@ -1176,10 +1187,11 @@
* @return {SailsSocket}
*/
SailsSocket.prototype.off = function (evName, fn){
+ var target = this._getEventTarget(evName);
// Bind the event to the raw underlying socket if possible.
- if (this._raw) {
- this._raw.off(evName, fn);
+ if (target) {
+ target.off(evName, fn);
return this;
}
@@ -1491,6 +1503,12 @@
throw new Error('`_request()` was a private API deprecated as of v0.11 of the sails.io.js client. Use `.request()` instead.');
};
+ SailsSocket.prototype._getEventTarget = function (evName) {
+ if (!this._raw) return null;
+
+ return MANAGER_EVENT_NAMES.has(evName) ? this._raw.io : this._raw;
+ };
+

17
client/src/actions/bootstrap.js vendored Normal file
View File

@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import ActionTypes from '../constants/ActionTypes';
const handleBootstrapUpdate = (bootstrap) => ({
type: ActionTypes.BOOTSTRAP_UPDATE_HANDLE,
payload: {
bootstrap,
},
});
export default {
handleBootstrapUpdate,
};

View File

@@ -5,6 +5,7 @@
import router from './router';
import socket from './socket';
import bootstrap from './bootstrap';
import login from './login';
import core from './core';
import modals from './modals';
@@ -34,6 +35,7 @@ import notificationServices from './notification-services';
export default {
...router,
...socket,
...bootstrap,
...login,
...core,
...modals,

View File

@@ -54,6 +54,13 @@ authenticateWithOidc.failure = (error, terms) => ({
},
});
authenticateWithOidc.debug = (logs) => ({
type: ActionTypes.WITH_OIDC_AUTHENTICATE__DEBUG,
payload: {
logs,
},
});
const clearAuthenticateError = () => ({
type: ActionTypes.AUTHENTICATE_ERROR_CLEAR,
payload: {},

View File

@@ -5,6 +5,13 @@
import ActionTypes from '../constants/ActionTypes';
const handleUsersReset = (users) => ({
type: ActionTypes.USERS_RESET_HANDLE,
payload: {
users,
},
});
const createUser = (data) => ({
type: ActionTypes.USER_CREATE,
payload: {
@@ -399,6 +406,7 @@ const removeUserFromBoardFilter = (id, boardId, currentListId) => ({
});
export default {
handleUsersReset,
createUser,
handleUserCreate,
clearUserCreateError,

View File

@@ -13,6 +13,8 @@ const createAccessToken = (data, headers) =>
const exchangeForAccessTokenWithOidc = (data, headers) =>
http.post('/access-tokens/exchange-with-oidc?withHttpOnlyToken=true', data, headers);
const debugOidc = (data, headers) => http.post('/access-tokens/debug-oidc', data, headers);
// TODO: rename?
const acceptTerms = (data, headers) => http.post('/access-tokens/accept-terms', data, headers);
@@ -24,6 +26,7 @@ const deleteCurrentAccessToken = (headers) => http.delete('/access-tokens/me', u
export default {
createAccessToken,
exchangeForAccessTokenWithOidc,
debugOidc,
acceptTerms,
revokePendingToken,
deleteCurrentAccessToken,

View File

@@ -30,8 +30,8 @@ socket.connect = socket._connect; // eslint-disable-line no-underscore-dangle
headers,
url: `/api${url}`,
},
(_, { body, error }) => {
if (error) {
(body, { error }) => {
if (body instanceof Error || error) {
reject(body);
} else {
resolve(body);

View File

@@ -7,8 +7,8 @@ import http from './http';
/* Actions */
const getTerms = (type, language, headers) =>
http.get(`/terms/${type}${language ? `?language=${language}` : ''}`, undefined, headers);
const getTerms = (language, headers) =>
http.get(`/terms${language ? `?language=${language}` : ''}`, undefined, headers);
export default {
getTerms,

View File

@@ -1,84 +1,158 @@
## [2.4.0] - 2025-03-22
### Added
* Lorem ipsum dolor sit amet consectetur adipiscing elit.
* Sed do eiusmod tempor incididunt ut labore et dolore magna.
* Ut enim ad minim veniam quis nostrud exercitation ullamco.
### Changed
* Duis aute irure dolor in reprehenderit in voluptate velit esse.
* Excepteur sint occaecat cupidatat non proident sunt in culpa.
# [2.0.1] - 2026-02-17
### Fixed
* Nulla pariatur consectetur adipiscing elit sed do eiusmod.
* Tempor incididunt ut labore et dolore magna aliqua enim.
* Improve connection reliability after the app is idle
* Allow loading custom End User Terms of Service
---
## [2.3.2] - 2025-02-18
### Fixed
* Minim veniam quis nostrud exercitation ullamco laboris nisi.
* Aliquip ex ea commodo consequat duis aute irure dolor.
---
## [2.3.0] - 2025-01-29
## [2.0.0] - 2026-02-11
### Added
* Reprehenderit in voluptate velit esse cillum dolore eu fugiat.
* Excepteur sint occaecat cupidatat non proident culpa qui officia.
* Mention users in comments
* Add download button for file attachments
* Enable strikethrough for cards in closed lists
* Expand card descriptions
* Enable copy-to-clipboard for custom fields
* Include task assignees in member filters
* Link tasks to cards
* Open card actions menu on right-click
* Hide completed tasks
* Add dedicated button to make projects private
* Track navigation paths when switching cards
* Support OAuth callbacks for OIDC
* Display legal requirements in the app
* Track storage usage
* Move lists between boards
* Restore toggleable due dates
* Add Gravatar support for avatars
* Add board setting to expand task lists by default
* Configure and test SMTP via UI
* Add API key authentication
* Add create-board button on the open-board screen
* Support object-path mapping for OIDC attributes
* Add basic keyboard shortcuts for cards
* Enable copy/cut cards with keyboard shortcuts
* Enhance card actions menu with separators and action bar
* Display last updates in the About modal
* Allow unlinking SSO from user accounts
* Apply color to entire lists instead of only card bottoms
### Changed
* Deserunt mollit anim id est laborum sed ut perspiciatis.
### Deprecated
* Unde omnis iste natus error sit voluptatem accusantium doloremque.
---
## [2.2.0] - 2024-12-14
### Added
* Totam rem aperiam eaque ipsa quae ab illo inventore veritatis.
* Quasi architecto beatae vitae dicta sunt explicabo nemo.
### Changed
* Enim ipsam voluptatem quia voluptas sit aspernatur aut odit.
* Consequuntur magni dolores eos qui ratione voluptatem sequi.
* Move webhooks configuration to UI
* Parse dates as UTC without relying on TZ environment variable
* Move About and Terms into a separate modal
* Move infrequent card actions to a more-actions menu
* Improve error page display
* Enable favorites panel by default
* Improve login page appearance
* Enhance Markdown editor (colors, quote borders, disable fuzzy links)
* Improve PDF viewer compatibility across browsers
* Update background color for own comments
* Improve browser caching for public files and attachments
* Optimize and parallelize image processing tasks
* Re-stream static files from S3 with protected access
* Unify file storage directory
* Configure proxy for outgoing traffic to prevent SSRF
### Fixed
* Neque porro quisquam est qui dolorem ipsum quia dolor.
* Prevent editors from deleting other comments
* Handle escape actions in mentions input correctly
* Prevent text overflow in activities
* Prevent deactivated users from receiving notifications
* Preserve newlines in markdown with mentions
* Fix app crash when boards are added before their projects
* Enable spellcheck on all textareas
* Fix multiple UI, toolbar, and popup styling issues
* Limit attachment gallery content to prevent layout issues
* Correct translations for client, server, and Markdown editor
* Fix minor UI issues
---
## [2.1.0] - 2024-10-05
## [2.0.0-rc.4] - 2025-09-04
### Added
### Fixed
* Adipisci velit sed quia non numquam eius modi tempora incidunt.
* Ut labore et dolore magnam aliquam quaerat voluptatem neque.
* Prevent vulnerability where maliciously renamed file attachments could execute JavaScript in the gallery UI
---
## [2.0.0] - 2024-08-20
## [2.0.0-rc.3] - 2025-05-28
### Added
* Porro quisquam est qui dolorem ipsum quia dolor sit amet.
* Consectetur adipisci velit sed quia non numquam eius modi.
* Tempora incidunt ut labore et dolore magnam aliquam quaerat.
* Notify users when they are added to a card
* Emphasize cards in colored and closed lists
* Track board activity log changes
* Display total number of comments on cards
* Add CSV attachment viewer
* Log actions when a user is removed from a card
* Log actions when task completion status changes
* Support Docker secrets
### Removed
### Changed
* Voluptatem neque porro quisquam est qui dolorem ipsum quia.
* Improve notifications popup appearance
* Improve card content rendering and styling
* Limit attachment content display for clarity
* Increase maximum length of OIDC code challenge
### Fixed
* Fix disabled cards display
* Correct translations for client, server, and Markdown editor
* Fix minor UI issues
---
## [2.0.0-rc.2] - 2025-05-10
### Added
* Add global user roles and improve user management
* Enable user deactivation
* Support private and shared projects
* Search projects by name and project groups
* Add favorite projects with favorites panel
* Add project descriptions and background image gallery
* Add list types: Closed, Archive, Trash
* Add board views: List and Grid
* Add new Markdown editor
* Link attachments (attach URLs)
* Enable quick filter by current user
* Add board settings modal
* Subscribe to entire boards
* Assign users to tasks
* Support multiple task lists
* Add more label colors
* Always display card creator option
* Show notification badge for board tabs
* Display message about new version availability
### Changed
* Restrict access to users based on global roles
* Limit email visibility
* Make projects page responsive
* Redesign card appearance
* Show edit buttons only when needed
* Use time-ago format for dates
* Highlight recent cards
* Improve attachment viewers and syntax highlighting
* Restyle comments
* Restyle login page
* Enable user auto-subscription when commenting
* Navigate to adjacent cards using arrow keys
* Open same-site links in current tab
* Improve card deletion workflow
* Archive all cards in a closed list with one button
* Confirm deletion actions
* Close only active elements when clicking outside
### Fixed
* Prevent deleting the last project manager
* Prevent deleting projects with existing boards

View File

@@ -7,7 +7,7 @@ import React, { useMemo } from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import { useTranslation, Trans } from 'react-i18next';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Comment } from 'semantic-ui-react';
import selectors from '../../../selectors';

View File

@@ -7,7 +7,7 @@ import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Draggable } from 'react-beautiful-dnd';
import { Button, Icon } from 'semantic-ui-react';

View File

@@ -3,8 +3,6 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import upperFirst from 'lodash/upperFirst';
import camelCase from 'lodash/camelCase';
import React, { useCallback, useContext, useMemo, useRef, useState } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
@@ -25,15 +23,12 @@ import EditName from './EditName';
import CardActionsStep from '../CardActionsStep';
import styles from './Card.module.scss';
import globalStyles from '../../../styles.module.scss';
const Card = React.memo(({ id, isInline }) => {
const selectCardById = useMemo(() => selectors.makeSelectCardById(), []);
const selectIsCardWithIdRecent = useMemo(() => selectors.makeSelectIsCardWithIdRecent(), []);
const selectListById = useMemo(() => selectors.makeSelectListById(), []);
const card = useSelector((state) => selectCardById(state, id));
const list = useSelector((state) => selectListById(state, card.listId));
const isHighlightedAsRecent = useSelector((state) => {
const { turnOffRecentCardHighlighting } = selectors.selectCurrentUser(state);
@@ -133,15 +128,6 @@ const Card = React.memo(({ id, isInline }) => {
}
}
const colorLineNode = list.color && (
<div
className={classNames(
styles.colorLine,
globalStyles[`background${upperFirst(camelCase(list.color))}`],
)}
/>
);
return (
<div
className={classNames(styles.wrapper, isHighlightedAsRecent && styles.wrapperRecent, 'card')}
@@ -162,7 +148,6 @@ const Card = React.memo(({ id, isInline }) => {
onContextMenu={handleContextMenu}
>
<Content cardId={id} />
{colorLineNode}
</div>
{canUseActions && (
<CardActionsPopup ref={actionsPopupRef} cardId={id} onNameEdit={handleNameEdit}>
@@ -175,7 +160,6 @@ const Card = React.memo(({ id, isInline }) => {
) : (
<span className={classNames(styles.content, card.isClosed && styles.contentDisabled)}>
<Content cardId={id} />
{colorLineNode}
</span>
)}
</div>

View File

@@ -29,11 +29,6 @@
}
}
.colorLine {
border-radius: 0 0 3px 3px;
height: 4px;
}
.content {
cursor: pointer;

View File

@@ -7,7 +7,7 @@ import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Icon } from 'semantic-ui-react';
import selectors from '../../../../selectors';

View File

@@ -40,7 +40,7 @@ const AboutPane = React.memo(() => {
<a href="https://github.com/plankanban/planka" target="_blank" rel="noreferrer">
<Image centered src={aboutLogo} size="large" />
</a>
<div className={styles.version}>{version}</div>
<div className={styles.version}>Community v{version}</div>
<Divider horizontal>
<Header as="h4">
{t('common.whatsNew', {

View File

@@ -4,19 +4,15 @@
*/
import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { Loader, Tab } from 'semantic-ui-react';
import selectors from '../../../selectors';
import api from '../../../api';
import Markdown from '../Markdown';
import styles from './TermsPane.module.scss';
const TermsPane = React.memo(() => {
const type = useSelector((state) => selectors.selectCurrentUser(state).termsType);
const { i18n } = useTranslation();
const [content, setContent] = useState(null);
@@ -24,7 +20,7 @@ const TermsPane = React.memo(() => {
async function fetchTerms() {
let terms;
try {
({ item: terms } = await api.getTerms(type, i18n.resolvedLanguage));
({ item: terms } = await api.getTerms(i18n.resolvedLanguage));
} catch {
return;
}
@@ -33,7 +29,7 @@ const TermsPane = React.memo(() => {
}
fetchTerms();
}, [type, i18n.resolvedLanguage]);
}, [i18n.resolvedLanguage]);
return (
<Tab.Pane attached={false} className={styles.wrapper}>

View File

@@ -4,7 +4,8 @@
*/
import { dequal } from 'dequal';
import React, { useCallback, useMemo } from 'react';
import omit from 'lodash/omit';
import React, { useCallback, useMemo, useRef } from 'react';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
@@ -26,6 +27,7 @@ const SmtpPane = React.memo(() => {
const [t] = useTranslation();
const [passwordFieldRef, handlePasswordFieldRef] = useNestedRef('inputRef');
const isPasswordTouchedRef = useRef(false);
const defaultData = useMemo(
() => ({
@@ -68,7 +70,15 @@ const SmtpPane = React.memo(() => {
[data, isPasswordSet],
);
const isModified = useMemo(() => {
const cleanDataToCheck = omit(cleanData, 'smtpPassword');
const defaultDataToCheck = omit(defaultData, 'smtpPassword');
return !dequal(cleanDataToCheck, defaultDataToCheck) || isPasswordTouchedRef.current;
}, [defaultData, cleanData]);
const handleSubmit = useCallback(() => {
isPasswordTouchedRef.current = false;
dispatch(entryActions.updateConfig(cleanData));
}, [dispatch, cleanData]);
@@ -86,7 +96,13 @@ const SmtpPane = React.memo(() => {
dispatch(entryActions.testSmtpConfig());
}, [dispatch]);
const isModified = !dequal(cleanData, defaultData);
const handlePasswordChange = useCallback(
(event, { value, ...props }) => {
isPasswordTouchedRef.current = value !== '';
handleFieldChange(event, { value, ...props });
},
[handleFieldChange],
);
return (
<Tab.Pane attached={false} className={styles.wrapper}>
@@ -173,7 +189,7 @@ const SmtpPane = React.memo(() => {
maxLength={256}
className={styles.field}
onClear={!data.smtpPassword && isPasswordSet ? handlePasswordClear : undefined}
onChange={handleFieldChange}
onChange={handlePasswordChange}
/>
<div className={styles.text}>
{t('common.defaultFrom')} (

View File

@@ -30,6 +30,7 @@ const StepTypes = {
EDIT_PASSWORD: 'EDIT_PASSWORD',
EDIT_ROLE: 'EDIT_ROLE',
API_KEY: 'API_KEY',
UNLINK_SSO: 'UNLINK_SSO',
ACTIVATE: 'ACTIVATE',
DEACTIVATE: 'DEACTIVATE',
DELETE: 'DELETE',
@@ -38,8 +39,8 @@ const StepTypes = {
const ActionsStep = React.memo(({ userId, onClose }) => {
const selectUserById = useMemo(() => selectors.makeSelectUserById(), []);
const activeUserLimit = useSelector(selectors.selectActiveUserLimit);
const activeUserTotal = useSelector(selectors.selectActiveUserTotal);
const activeUsersLimit = useSelector(selectors.selectActiveUsersLimit);
const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal);
const user = useSelector((state) => selectUserById(state, userId));
const isCurrentUser = useSelector((state) => user.id === selectors.selectCurrentUserId(state));
@@ -58,6 +59,16 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
[userId, dispatch],
);
const handleUnlinkSsoConfirm = useCallback(() => {
dispatch(
entryActions.updateUser(userId, {
isSsoUser: false,
}),
);
onClose();
}, [userId, onClose, dispatch]);
const handleActivateConfirm = useCallback(() => {
dispatch(
entryActions.updateUser(userId, {
@@ -106,6 +117,10 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
openStep(StepTypes.API_KEY);
}, [openStep]);
const handleUnlinkSsoClick = useCallback(() => {
openStep(StepTypes.UNLINK_SSO);
}, [openStep]);
const handleActivateClick = useCallback(() => {
openStep(StepTypes.ACTIVATE);
}, [openStep]);
@@ -142,6 +157,16 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
);
case StepTypes.API_KEY:
return <ApiKeyStep userId={userId} onBack={handleBack} onClose={onClose} />;
case StepTypes.UNLINK_SSO:
return (
<ConfirmationStep
title="common.unlinkSso"
content="common.areYouSureYouWantToUnlinkSsoFromThisUser"
buttonContent="action.unlinkSso"
onConfirm={handleUnlinkSsoConfirm}
onBack={handleBack}
/>
);
case StepTypes.ACTIVATE:
return (
<ConfirmationStep
@@ -232,13 +257,21 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
context: 'title',
})}
</Menu.Item>
{user.isSsoUser && !user.lockedFieldNames.includes('isSsoUser') && !isCurrentUser && (
<Menu.Item className={styles.menuItem} onClick={handleUnlinkSsoClick}>
<Icon name="unlink" className={styles.menuItemIcon} />
{t('action.unlinkSso', {
context: 'title',
})}
</Menu.Item>
)}
{!isCurrentUser && (
<>
<Menu.Item
disabled={
user.isDeactivated &&
activeUserLimit !== null &&
activeUserTotal >= activeUserLimit
activeUsersLimit !== null &&
activeUsersTotal >= activeUsersLimit
}
className={styles.menuItem}
onClick={user.isDeactivated ? handleActivateClick : handleDeactivateClick}

View File

@@ -17,8 +17,8 @@ import AddStep from './AddStep';
import styles from './UsersPane.module.scss';
const UsersPane = React.memo(() => {
const activeUserTotal = useSelector(selectors.selectActiveUserTotal);
const activeUserLimit = useSelector(selectors.selectActiveUserLimit);
const activeUsersLimit = useSelector(selectors.selectActiveUsersLimit);
const activeUsersTotal = useSelector(selectors.selectActiveUsersTotal);
const users = useSelector(selectors.selectUsers);
const canAdd = useSelector((state) => {
@@ -106,13 +106,13 @@ const UsersPane = React.memo(() => {
<AddPopup>
<Button
positive
disabled={activeUserLimit !== null && activeUserTotal >= activeUserLimit}
disabled={activeUsersLimit !== null && activeUsersTotal >= activeUsersLimit}
className={styles.addButton}
>
{t('action.addUser')}
{activeUserLimit !== null && (
{activeUsersLimit !== null && (
<span className={styles.addButtonCounter}>
{activeUserTotal}/{activeUserLimit}
{activeUsersTotal}/{activeUsersLimit}
</span>
)}
</Button>

View File

@@ -6,7 +6,7 @@
import React, { useCallback } from 'react';
import classNames from 'classnames';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Button, Icon, Menu } from 'semantic-ui-react';
import { usePopup } from '../../../lib/popup';

View File

@@ -8,7 +8,8 @@ import React, { useCallback, useEffect, useMemo } from 'react';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation, Trans } from 'react-i18next';
import { Button, Divider, Form, Grid, Header, Message } from 'semantic-ui-react';
import TextareaAutosize from 'react-textarea-autosize';
import { Button, Divider, Form, Grid, Header, Message, TextArea } from 'semantic-ui-react';
import { useDidUpdate, usePrevious, useToggle } from '../../../lib/hooks';
import { Input } from '../../../lib/custom-ui';
@@ -23,7 +24,7 @@ import logo from '../../../assets/images/logo.png';
import styles from './Content.module.scss';
const createMessage = (error) => {
const createMessage = (error, isDebug) => {
if (!error) {
return error;
}
@@ -64,10 +65,10 @@ const createMessage = (error) => {
type: 'error',
content: 'common.usernameAlreadyInUse',
};
case 'Active user limit reached':
case 'Active users limit reached':
return {
type: 'error',
content: 'common.activeUserLimitReached',
content: 'common.activeUsersLimitReached',
};
case 'Failed to fetch':
return {
@@ -82,7 +83,7 @@ const createMessage = (error) => {
default:
return {
type: 'warning',
content: 'common.unknownError',
content: isDebug ? error.message : 'common.unknownError',
};
}
};
@@ -95,6 +96,7 @@ const Content = React.memo(() => {
isSubmitting,
isSubmittingWithOidc,
error,
debugLogs,
step,
} = useSelector(selectors.selectAuthenticateForm);
@@ -102,13 +104,33 @@ const Content = React.memo(() => {
const [t] = useTranslation();
const wasSubmitting = usePrevious(isSubmitting);
const [data, handleFieldChange, setData] = useForm(() => ({
emailOrUsername: '',
password: '',
...defaultData,
}));
const [data, handleFieldChange, setData] = useForm(() => {
const initialData = {
emailOrUsername: '',
password: '',
...defaultData,
};
const message = useMemo(() => createMessage(error), [error]);
if (bootstrap.isDemoMode) {
const params = new URLSearchParams(window.location.hash.slice(1));
Object.keys(initialData).forEach((fieldName) => {
const value = params.get(fieldName);
if (value !== null) {
initialData[fieldName] = value;
}
});
}
return initialData;
});
const withOidc = !!bootstrap.oidc;
const isOidcEnforced = withOidc && bootstrap.oidc.isEnforced;
const isOidcDebug = withOidc && bootstrap.oidc.debug;
const message = useMemo(() => createMessage(error, isOidcDebug), [error, isOidcDebug]);
const [focusPasswordFieldState, focusPasswordField] = useToggle();
const [emailOrUsernameFieldRef, handleEmailOrUsernameFieldRef] = useNestedRef('inputRef');
@@ -141,14 +163,11 @@ const Content = React.memo(() => {
dispatch(entryActions.clearAuthenticateError());
}, [dispatch]);
const withOidc = !!bootstrap.oidc;
const isOidcEnforced = withOidc && bootstrap.oidc.isEnforced;
useEffect(() => {
if (!isOidcEnforced) {
emailOrUsernameFieldRef.current.focus();
}
}, [emailOrUsernameFieldRef, isOidcEnforced]);
}, [isOidcEnforced, emailOrUsernameFieldRef]);
useDidUpdate(() => {
if (wasSubmitting && !isSubmitting && error) {
@@ -253,16 +272,27 @@ const Content = React.memo(() => {
</>
)}
{withOidc && (
<Button
fluid
primary={isOidcEnforced}
icon={isOidcEnforced ? 'right arrow' : undefined}
labelPosition={isOidcEnforced ? 'right' : undefined}
content={t('action.logInWithSso')}
loading={isSubmittingWithOidc}
disabled={isSubmitting || isSubmittingWithOidc}
onClick={handleAuthenticateWithOidcClick}
/>
<>
<Button
fluid
primary={isOidcDebug ? undefined : isOidcEnforced}
color={isOidcDebug ? 'orange' : undefined}
icon={isOidcEnforced ? 'right arrow' : undefined}
labelPosition={isOidcEnforced ? 'right' : undefined}
content={isOidcDebug ? t('action.debugSso') : t('action.logInWithSso')}
loading={isSubmittingWithOidc}
disabled={isSubmitting || isSubmittingWithOidc}
onClick={handleAuthenticateWithOidcClick}
/>
{debugLogs && (
<TextArea
readOnly
as={TextareaAutosize}
value={debugLogs.join('\n')}
className={styles.debugLog}
/>
)}
</>
)}
</div>
<div className={styles.poweredBy}>

View File

@@ -19,6 +19,16 @@
width: 100%;
}
.debugLog {
border: 1px solid rgba(9, 30, 66, 0.13);
border-radius: 3px;
color: #333;
line-height: 1.4;
margin-top: 16px;
padding: 8px 12px;
width: 100%;
}
.divider {
font-weight: normal;
}

View File

@@ -3,29 +3,65 @@
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import React, { useCallback, useState } from 'react';
import React, { useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation } from 'react-i18next';
import { Button, Checkbox, Dropdown, Modal } from 'semantic-ui-react';
import { Button, Checkbox, Dropdown, Modal, Segment } from 'semantic-ui-react';
import selectors from '../../../selectors';
import entryActions from '../../../entry-actions';
import { localeByLanguage } from '../../../locales';
import TERMS_LANGUAGES from '../../../constants/TermsLanguages';
import Markdown from '../Markdown';
import styles from './TermsModal.module.scss';
const LOCALES = TERMS_LANGUAGES.map((language) => localeByLanguage[language]);
const splitTermsAndConfirmations = (content) => {
const separator = '\n[confirmations]::\n---\n';
const index = content.lastIndexOf(separator);
if (index === -1) {
return [content.trim(), []];
}
const terms = content.slice(0, index).trim();
const confirmations = content
.slice(index + separator.length)
.split('\n')
.map((confirmation) => confirmation.replace(/^✔️\s*/, '').replace(/\*\*(.*?)\*\*/, '$1'))
.filter(Boolean);
return [terms, confirmations];
};
const TermsModal = React.memo(() => {
const { termsLanguages } = useSelector(selectors.selectBootstrap);
const {
termsForm: { payload: terms, isSubmitting, isCancelling, isLanguageUpdating },
} = useSelector(selectors.selectAuthenticateForm);
const dispatch = useDispatch();
const [t] = useTranslation();
const [isTermsAccepted, setIsTermsAccepted] = useState(false);
const [acceptedConfirmationsSet, setAcceptedConfirmationsSet] = useState(new Set());
const locales = useMemo(
() =>
termsLanguages.map(
(language) =>
localeByLanguage[language] || {
language,
country: language.split('-')[1]?.toLowerCase(),
name: language,
},
),
[termsLanguages],
);
const [content, confirmations] = useMemo(
() => splitTermsAndConfirmations(terms.content),
[terms.content],
);
const handleContinueClick = useCallback(() => {
dispatch(entryActions.acceptTerms(terms.signature));
@@ -42,17 +78,29 @@ const TermsModal = React.memo(() => {
[dispatch],
);
const handleToggleAcceptClick = useCallback((_, { checked }) => {
setIsTermsAccepted(checked);
const handleToggleConfirmationAccept = useCallback((index) => {
setAcceptedConfirmationsSet((prevAcceptedConfirmationsSet) => {
const nextAcceptedConfirmationsSet = new Set(prevAcceptedConfirmationsSet);
if (nextAcceptedConfirmationsSet.has(index)) {
nextAcceptedConfirmationsSet.delete(index);
} else {
nextAcceptedConfirmationsSet.add(index);
}
return nextAcceptedConfirmationsSet;
});
}, []);
const isAllConfirmationsAccepted = acceptedConfirmationsSet.size === confirmations.length;
return (
<Modal open centered={false}>
<Modal.Content>
<Dropdown
fluid
selection
options={LOCALES.map((locale) => ({
options={locales.map((locale) => ({
value: locale.language,
flag: locale.country,
text: locale.name,
@@ -63,7 +111,20 @@ const TermsModal = React.memo(() => {
className={styles.language}
onChange={handleLanguageChange}
/>
<Markdown>{terms.content}</Markdown>
<Markdown>{content}</Markdown>
{confirmations.length > 0 && (
<Segment size="massive" className={styles.confirmations}>
{confirmations.map((confirmation, index) => (
<Checkbox
key={confirmation}
checked={acceptedConfirmationsSet.has(index)}
label={confirmation}
className={styles.confirmationCheckbox}
onChange={() => handleToggleConfirmationAccept(index)}
/>
))}
</Segment>
)}
</Modal.Content>
<Modal.Actions>
<Button
@@ -74,15 +135,11 @@ const TermsModal = React.memo(() => {
className={styles.cancelButton}
onClick={handleCancelClick}
/>
<Checkbox
label={t('common.iHaveReadAndAgreeToTheseTerms')}
onChange={handleToggleAcceptClick}
/>
<Button
positive
content={t('action.continue')}
loading={isSubmitting}
disabled={!isTermsAccepted || isSubmitting || isCancelling}
disabled={!isAllConfirmationsAccepted || isSubmitting || isCancelling}
onClick={handleContinueClick}
/>
</Modal.Actions>

View File

@@ -8,6 +8,19 @@
margin-left: 0;
}
.confirmations {
border-color: #5aac44;
border-width: 2px;
box-shadow: none;
display: flex;
flex-direction: column;
row-gap: 12px;
}
.confirmationCheckbox {
font-weight: bold;
}
.language {
margin-bottom: 20px;
}

View File

@@ -6,7 +6,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Provider } from 'react-redux';
import { Route, Routes } from 'react-router-dom';
import { Route, Routes } from 'react-router';
import { ThemeProvider, ToasterProvider } from '@gravity-ui/uikit';
// eslint-disable-next-line import/no-unresolved
import { toaster } from '@gravity-ui/uikit/toaster-singleton';

View File

@@ -33,6 +33,7 @@
font-size: 13px;
line-height: 1;
margin-bottom: 6px;
padding: 1px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;

View File

@@ -201,6 +201,7 @@ const List = React.memo(({ id, index }) => {
className={classNames(
styles.outerWrapper,
isFavoritesActive && styles.outerWrapperWithFavorites,
list.color && globalStyles[`background${upperFirst(camelCase(list.color))}Soft`],
)}
onTransitionEnd={handleWrapperTransitionEnd}
>
@@ -261,7 +262,11 @@ const List = React.memo(({ id, index }) => {
<button
type="button"
disabled={!list.isPersisted}
className={styles.addCardButton}
className={classNames(
styles.addCardButton,
list.color &&
globalStyles[`background${upperFirst(camelCase(list.color))}Soft`],
)}
onClick={handleAddCardClick}
>
<PlusMathIcon className={styles.addCardButtonIcon} />

View File

@@ -8,7 +8,7 @@ import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { useTranslation, Trans } from 'react-i18next';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Button } from 'semantic-ui-react';
import selectors from '../../../selectors';

View File

@@ -9,7 +9,7 @@ import React, { useCallback, useMemo } from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Button, Icon } from 'semantic-ui-react';
import selectors from '../../../selectors';

View File

@@ -8,7 +8,7 @@ import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { Link } from 'react-router-dom';
import { Link } from 'react-router';
import { Draggable } from 'react-beautiful-dnd';
import { Button, Checkbox, Icon } from 'semantic-ui-react';
import { useDidUpdate } from '../../../../lib/hooks';

View File

@@ -16,6 +16,10 @@ export default {
SOCKET_RECONNECT_HANDLE: 'SOCKET_RECONNECT_HANDLE',
SOCKET_RECONNECT_HANDLE__CORE_FETCH: 'SOCKET_RECONNECT_HANDLE__CORE_FETCH',
/* Bootstrap */
BOOTSTRAP_UPDATE_HANDLE: 'BOOTSTRAP_UPDATE_HANDLE',
/* Login */
LOGIN_INITIALIZE: 'LOGIN_INITIALIZE',
@@ -25,6 +29,7 @@ export default {
WITH_OIDC_AUTHENTICATE: 'WITH_OIDC_AUTHENTICATE',
WITH_OIDC_AUTHENTICATE__SUCCESS: 'WITH_OIDC_AUTHENTICATE__SUCCESS',
WITH_OIDC_AUTHENTICATE__FAILURE: 'WITH_OIDC_AUTHENTICATE__FAILURE',
WITH_OIDC_AUTHENTICATE__DEBUG: 'WITH_OIDC_AUTHENTICATE__DEBUG',
AUTHENTICATE_ERROR_CLEAR: 'AUTHENTICATE_ERROR_CLEAR',
TERMS_ACCEPT: 'TERMS_ACCEPT',
TERMS_ACCEPT__SUCCESS: 'TERMS_ACCEPT__SUCCESS',
@@ -78,6 +83,7 @@ export default {
/* Users */
USERS_RESET_HANDLE: 'USERS_RESET_HANDLE',
USER_CREATE: 'USER_CREATE',
USER_CREATE__SUCCESS: 'USER_CREATE__SUCCESS',
USER_CREATE__FAILURE: 'USER_CREATE__FAILURE',

View File

@@ -13,6 +13,10 @@ export default {
SOCKET_DISCONNECT_HANDLE: `${PREFIX}/SOCKET_DISCONNECT_HANDLE`,
SOCKET_RECONNECT_HANDLE: `${PREFIX}/SOCKET_RECONNECT_HANDLE`,
/* Bootstrap */
BOOTSTRAP_UPDATE_HANDLE: `${PREFIX}/BOOTSTRAP_UPDATE_HANDLE`,
/* Login */
AUTHENTICATE: `${PREFIX}/AUTHENTICATE`,
@@ -51,6 +55,7 @@ export default {
/* Users */
USERS_RESET_HANDLE: `${PREFIX}/USERS_RESET_HANDLE`,
USER_CREATE: `${PREFIX}/USER_CREATE`,
USER_CREATE_HANDLE: `${PREFIX}/USER_CREATE_HANDLE`,
USER_CREATE_ERROR_CLEAR: `${PREFIX}/USER_CREATE_ERROR_CLEAR`,

View File

@@ -1,6 +0,0 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
export default ['de-DE', 'en-US'];

17
client/src/entry-actions/bootstrap.js vendored Normal file
View File

@@ -0,0 +1,17 @@
/*!
* Copyright (c) 2024 PLANKA Software GmbH
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
*/
import EntryActionTypes from '../constants/EntryActionTypes';
const handleBootstrapUpdate = (bootstrap) => ({
type: EntryActionTypes.BOOTSTRAP_UPDATE_HANDLE,
payload: {
bootstrap,
},
});
export default {
handleBootstrapUpdate,
};

View File

@@ -4,6 +4,7 @@
*/
import socket from './socket';
import bootstrap from './bootstrap';
import login from './login';
import core from './core';
import modals from './modals';
@@ -32,6 +33,7 @@ import notificationServices from './notification-services';
export default {
...socket,
...bootstrap,
...login,
...core,
...modals,

View File

@@ -5,6 +5,11 @@
import EntryActionTypes from '../constants/EntryActionTypes';
const handleUsersReset = () => ({
type: EntryActionTypes.USERS_RESET_HANDLE,
payload: {},
});
const createUser = (data) => ({
type: EntryActionTypes.USER_CREATE,
payload: {
@@ -246,6 +251,7 @@ const removeUserFromFilterInCurrentBoard = (id) => ({
});
export default {
handleUsersReset,
createUser,
handleUserCreate,
clearUserCreateError,

View File

@@ -6,7 +6,7 @@
import React, { useLayoutEffect } from 'react';
import PropTypes from 'prop-types';
import { useDispatch, useSelector } from 'react-redux';
import { Router } from 'react-router-dom';
import { Router } from 'react-router';
import { handleLocationChange } from './actions';

View File

@@ -83,6 +83,8 @@ export default {
'هل أنت متأكد أنك تريد إزالة هذا المدير من المشروع؟',
areYouSureYouWantToRemoveThisMemberFromBoard:
'هل أنت متأكد أنك تريد إزالة هذا العضو من اللوحة؟',
areYouSureYouWantToUnlinkSsoFromThisUser:
'هل أنت متأكد أنك تريد إلغاء ربط تسجيل الدخول الموحد من هذا المستخدم؟ سيسمح هذا للمستخدم بتسجيل الدخول باستخدام كلمة المرور.',
assignAsOwner_title: 'تعيين كمالك',
atLeastOneListMustBePresent: 'يجب وجود قائمة واحدة على الأقل',
attachment: 'مرفق',
@@ -320,6 +322,7 @@ export default {
turnOffRecentCardHighlighting: 'إيقاف تمييز البطاقات الحديثة',
typeNameToConfirm: 'اكتب الاسم للتأكيد.',
typeTitleToConfirm: 'اكتب العنوان للتأكيد.',
unlinkSso_title: 'إلغاء ربط تسجيل الدخول الموحد',
unsavedChanges: 'تغييرات غير محفوظة',
uploadFailedFileIsTooBig: 'فشل الرفع: الملف كبير جداً.',
uploadFailedNotEnoughStorageSpace: 'فشل الرفع: مساحة التخزين غير كافية.',
@@ -485,6 +488,8 @@ export default {
start: 'ابدأ',
stop: 'توقف',
subscribe: 'اشترك',
unlinkSso: 'إلغاء ربط تسجيل الدخول الموحد',
unlinkSso_title: 'إلغاء ربط تسجيل الدخول الموحد',
unsubscribe: 'إلغاء الاشتراك',
uploadNewAvatar: 'رفع صورة رمزية جديدة',
uploadNewImage: 'رفع صورة جديدة',

View File

@@ -1,11 +1,10 @@
export default {
translation: {
common: {
activeUserLimitReached: 'تم الوصول إلى حد المستخدمين النشطين',
activeUsersLimitReached: 'تم الوصول إلى حد المستخدمين النشطين',
adminLoginRequiredToInitializeInstance: 'مطلوب تسجيل دخول المدير لتهيئة المثيل',
emailAlreadyInUse: 'البريد الإلكتروني مستخدم بالفعل',
emailOrUsername: 'البريد الإلكتروني أو اسم المستخدم',
iHaveReadAndAgreeToTheseTerms: 'لقد قرأت ووافقت على هذه الشروط',
invalidCredentials: 'بيانات الاعتماد غير صالحة',
invalidEmailOrUsername: 'البريد الإلكتروني أو اسم المستخدم غير صالح',
invalidPassword: 'كلمة المرور غير صالحة',
@@ -25,6 +24,7 @@ export default {
action: {
cancelAndClose: 'إلغاء وإغلاق',
continue: 'متابعة',
debugSso: 'تصحيح أخطاء تسجيل الدخول الموحد',
goBack: 'العودة',
goHome: 'الذهاب للرئيسية',
logIn: 'تسجيل الدخول',

View File

@@ -92,6 +92,8 @@ export default {
'Сигурни ли сте, че искате да премахнете този мениджър от проекта?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Сигурни ли сте, че искате да премахнете този член от таблото?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Сигурни ли сте, че искате да премахнете SSO връзката от този потребител? Това ще позволи на потребителя да влиза с парола.',
assignAsOwner_title: 'Назначаване като собственик',
atLeastOneListMustBePresent: 'Трябва да присъства поне един списък',
attachment: 'Прикачен файл',
@@ -333,6 +335,7 @@ export default {
turnOffRecentCardHighlighting: 'Изключване на подчертаването на скорошни карти',
typeNameToConfirm: 'Въведете име за потвърждение.',
typeTitleToConfirm: 'Въведете заглавие за потвърждение.',
unlinkSso_title: 'Премахване на SSO връзка',
unsavedChanges: 'Незапазени промени',
uploadFailedFileIsTooBig: 'Качването неуспешно: файлът е твърде голям.',
uploadFailedNotEnoughStorageSpace:
@@ -500,6 +503,8 @@ export default {
start: 'Старт',
stop: 'Стоп',
subscribe: 'Абонирайте се',
unlinkSso: 'Премахни SSO връзка',
unlinkSso_title: 'Премахни SSO връзка',
unsubscribe: 'Отписване',
uploadNewAvatar: 'Качване на нов аватар',
uploadNewImage: 'Качване на ново изображение',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Достигнат е лимитът на активни потребители',
activeUsersLimitReached: 'Достигнат е лимитът на активни потребители',
adminLoginRequiredToInitializeInstance:
'Необходимо е влизане на администратор за инициализиране на инстанцията',
emailAlreadyInUse: 'Имейлът вече се използва',
emailOrUsername: 'Имейл или потребителско име',
iHaveReadAndAgreeToTheseTerms: 'Прочетох и се съгласявам с тези условия',
invalidCredentials: 'Невалидни данни за вход',
invalidEmailOrUsername: 'Невалиден имейл или потребителско име',
invalidPassword: 'Невалидна парола',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Отказ и затваряне',
continue: 'Продължи',
debugSso: 'Дебъгване на SSO',
goBack: 'Назад',
goHome: 'Към началото',
logIn: 'Вход',

View File

@@ -90,6 +90,8 @@ export default {
'Estàs segur que vols eliminar aquest gestor del projecte?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Estàs segur que vols eliminar aquest membre del tauler?',
areYouSureYouWantToUnlinkSsoFromThisUser:
"Estàs segur que vols desvincular SSO d'aquest usuari? Això permetrà que l'usuari iniciï sessió amb una contrasenya.",
assignAsOwner_title: 'Assignar com a propietari',
atLeastOneListMustBePresent: "Hi ha d'haver com a mínim una llista",
attachment: 'Fitxer adjunt',
@@ -334,6 +336,7 @@ export default {
turnOffRecentCardHighlighting: 'Desactivar ressaltat de targetes recents',
typeNameToConfirm: 'Escriu el nom per confirmar.',
typeTitleToConfirm: 'Escriu el títol per confirmar.',
unlinkSso_title: 'Desvinculació de SSO',
unsavedChanges: 'Canvis sense desar',
uploadFailedFileIsTooBig: 'Error en pujar: El fitxer és massa gran.',
uploadFailedNotEnoughStorageSpace: "Error en pujar: No hi ha prou espai d'emmagatzematge.",
@@ -502,6 +505,8 @@ export default {
start: 'Iniciar',
stop: 'Aturar',
subscribe: "Subscriure's",
unlinkSso: 'Desvincular SSO',
unlinkSso_title: 'Desvincular SSO',
unsubscribe: 'Cancel·lar subscripció',
uploadNewAvatar: 'Pujar nou avatar',
uploadNewImage: 'Pujar nova imatge',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: "S'ha assolit el límit d'usuaris actius",
activeUsersLimitReached: "S'ha assolit el límit d'usuaris actius",
adminLoginRequiredToInitializeInstance:
"Es requereix inici de sessió d'administrador per inicialitzar la instància",
emailAlreadyInUse: 'Correu electrònic ja en ús',
emailOrUsername: "Correu electrònic o nom d'usuari",
iHaveReadAndAgreeToTheseTerms: 'He llegit i accepto aquests termes',
invalidCredentials: 'Credencials no vàlides',
invalidEmailOrUsername: "Correu electrònic o nom d'usuari no vàlid",
invalidPassword: 'Contrasenya no vàlida',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Cancel·lar i tancar',
continue: 'Continuar',
debugSso: 'Depurar SSO',
goBack: 'Tornar',
goHome: "Anar a l'inici",
logIn: 'Iniciar sessió',

View File

@@ -85,6 +85,8 @@ export default {
'Opravdu chcete tohoto správce z projektu odebrat?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Opravdu chcete tohoto člena odebrat z nástěnky?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Opravdu chcete odpojit SSO od tohoto uživatele? Tím umožníte uživateli přihlásit se pomocí hesla.',
assignAsOwner_title: 'Přiřadit jako vlastníka',
atLeastOneListMustBePresent: 'Musí být k dispozici alespoň jeden seznam',
attachment: 'Příloha',
@@ -324,6 +326,7 @@ export default {
turnOffRecentCardHighlighting: 'Vypnout zvýraznění posledních karet',
typeNameToConfirm: 'Zadejte název pro potvrzení.',
typeTitleToConfirm: 'Zadejte titulek pro potvrzení.',
unlinkSso_title: 'Odpojení SSO',
unsavedChanges: 'Neuložené změny',
uploadFailedFileIsTooBig: 'Nahrávání se nezdařilo: Soubor je příliš velký.',
uploadFailedNotEnoughStorageSpace: 'Nahrávání se nezdařilo: Nedostatek úložného prostoru.',
@@ -490,6 +493,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Odebírat',
unlinkSso: 'Odpojit SSO',
unlinkSso_title: 'Odpojit SSO',
unsubscribe: 'Neodebírat',
uploadNewAvatar: 'Nahrát nový avatar',
uploadNewImage: 'Nahrát nový obrázek',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Dosažený limit aktivních uživatelů',
activeUsersLimitReached: 'Dosažený limit aktivních uživatelů',
adminLoginRequiredToInitializeInstance:
'K inicializaci instance je nutné přihlášení správce.',
emailAlreadyInUse: 'E-mail se již používá',
emailOrUsername: 'E-mail nebo uživatelské jméno',
iHaveReadAndAgreeToTheseTerms: 'Přečetl jsem si tyto podmínky a souhlasím s nimi.',
invalidCredentials: 'Neplatné přihlašovací údaje',
invalidEmailOrUsername: 'Nesprávný e-mail nebo uživatelské jméno',
invalidPassword: 'Nesprávné heslo',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Zrušit a zavřít',
continue: 'Pokračovat',
debugSso: 'Ladit SSO',
goBack: 'Zpět',
goHome: 'Domů',
logIn: 'Přihlásit se',

View File

@@ -88,6 +88,8 @@ export default {
'Er du sikker på at du vil fjerne denne projektleder fra projektet?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Er du sikker på at du vil fjerne dette medlem fra tavlen?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Er du sikker på, at du vil fjerne SSO-forbindelsen fra denne bruger? Dette vil tillade brugeren at logge ind med en adgangskode.',
assignAsOwner_title: 'Sæt som ejer',
atLeastOneListMustBePresent: 'Mindst én liste skal være til stede',
attachment: 'Vedhæft fil',
@@ -330,6 +332,7 @@ export default {
turnOffRecentCardHighlighting: 'Slå fremhævelse af nylige kort fra',
typeNameToConfirm: 'Skriv navnet for at bekræfte.',
typeTitleToConfirm: 'Skriv overskriften for at bekræfte.',
unlinkSso_title: 'Fjernelse af SSO-forbindelse',
unsavedChanges: 'Ikke-gemte ændringer',
uploadFailedFileIsTooBig: 'Upload mislykkedes: Filen er for stor.',
uploadFailedNotEnoughStorageSpace: 'Upload mislykkedes: Ikke nok lagerplads.',
@@ -496,6 +499,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Abonnér',
unlinkSso: 'Fjern SSO-forbindelse',
unlinkSso_title: 'Fjern SSO-forbindelse',
unsubscribe: 'Opsig abonnement',
uploadNewAvatar: 'Tilføj nyt profilbillede',
uploadNewImage: 'Tilføj nyt billede',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Grænsen for aktive brugere er nået',
activeUsersLimitReached: 'Grænsen for aktive brugere er nået',
adminLoginRequiredToInitializeInstance:
'Administrator login påkrævet for at initialisere instans',
emailAlreadyInUse: 'E-mail allerede i brug',
emailOrUsername: 'E-mail eller brugernavn',
iHaveReadAndAgreeToTheseTerms: 'Jeg har læst og accepterer disse vilkår',
invalidCredentials: 'Forkerte loginoplysninger',
invalidEmailOrUsername: 'Ugyldig e-mail eller brugernavn',
invalidPassword: 'Ugyldig adgangskode',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Annuller og luk',
continue: 'Fortsæt',
debugSso: 'Fejlfind SSO',
goBack: 'Gå tilbage',
goHome: 'Gå hjem',
logIn: 'Log på',

View File

@@ -101,6 +101,8 @@ export default {
'Sind Sie sicher, dass Sie diesen Projektleiter aus dem Projekt entfernen möchten?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Sind Sie sicher, dass Sie dieses Mitglied aus dem Arbeitsbereich entfernen möchten?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Sind Sie sicher, dass Sie die SSO-Verknüpfung von diesem Benutzer aufheben möchten? Dies ermöglicht dem Benutzer die Anmeldung mit einem Passwort.',
assignAsOwner_title: 'Als Eigentümer zuweisen',
atLeastOneListMustBePresent: 'Mindestens eine Liste muss vorhanden sein',
attachment: 'Anhang',
@@ -344,6 +346,7 @@ export default {
turnOffRecentCardHighlighting: 'Hervorhebung neuer Karten ausschalten',
typeNameToConfirm: 'Namen zur Bestätigung eingeben.',
typeTitleToConfirm: 'Titel zur Bestätigung eingeben.',
unlinkSso_title: 'SSO-Verknüpfung aufheben',
unsavedChanges: 'Ungespeicherte Änderungen',
uploadFailedFileIsTooBig: 'Upload fehlgeschlagen: Datei ist zu groß.',
uploadFailedNotEnoughStorageSpace: 'Upload fehlgeschlagen: Nicht genügend Speicherplatz.',
@@ -512,6 +515,8 @@ export default {
start: 'Start',
stop: 'Stopp',
subscribe: 'Abonnieren',
unlinkSso: 'SSO-Verknüpfung aufheben',
unlinkSso_title: 'SSO-Verknüpfung aufheben',
unsubscribe: 'De-abonnieren',
uploadNewAvatar: 'Neuen Avatar hochladen',
uploadNewImage: 'Neues Bild hochladen',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
activeUsersLimitReached: 'Maximale Anzahl aktiver Benutzer erreicht',
adminLoginRequiredToInitializeInstance:
'Admin-Anmeldung erforderlich zur Initialisierung der Instanz',
emailAlreadyInUse: 'E-mail Adresse wird bereits benutzt',
emailOrUsername: 'E-Mail-Adresse oder Benutzername',
iHaveReadAndAgreeToTheseTerms: 'Ich habe diese Bedingungen gelesen und stimme ihnen zu',
invalidCredentials: 'Ungültige Anmeldeinformationen',
invalidEmailOrUsername: 'Ungültige E-Mail-Adresse oder Benutzername',
invalidPassword: 'Ungültiges Passwort',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Abbrechen und schließen',
continue: 'Fortfahren',
debugSso: 'SSO debuggen',
goBack: 'Zurück gehen',
goHome: 'Zur Startseite',
logIn: 'Einloggen',

View File

@@ -100,6 +100,8 @@ export default {
'Είστε σίγουροι ότι θέλετε να αφαιρέσετε αυτόν τον διαχειριστή από το έργο;',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Είστε σίγουροι ότι θέλετε να αφαιρέσετε αυτό το μέλος από τον πίνακα;',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Είστε σίγουροι ότι θέλετε να αποσυνδέσετε το SSO από αυτόν τον χρήστη; Αυτό θα επιτρέψει στον χρήστη να συνδεθεί με κωδικό πρόσβασης.',
assignAsOwner_title: 'Ορισμός ως ιδιοκτήτης',
atLeastOneListMustBePresent: 'Πρέπει να υπάρχει τουλάχιστον μία λίστα',
attachment: 'Συνημμένο',
@@ -343,6 +345,7 @@ export default {
turnOffRecentCardHighlighting: 'Απενεργοποίηση επισήμανσης πρόσφατων καρτών',
typeNameToConfirm: 'Πληκτρολογήστε το όνομα για επιβεβαίωση.',
typeTitleToConfirm: 'Πληκτρολογήστε τον τίτλο για επιβεβαίωση.',
unlinkSso_title: 'Αποσύνδεση SSO',
unsavedChanges: 'Μη αποθηκευμένες αλλαγές',
uploadFailedFileIsTooBig: 'Η μεταφόρτωση απέτυχε: το αρχείο είναι πολύ μεγάλο.',
uploadFailedNotEnoughStorageSpace:
@@ -516,6 +519,8 @@ export default {
start: 'Έναρξη',
stop: 'Διακοπή',
subscribe: 'Εγγραφή',
unlinkSso: 'Αποσύνδεση SSO',
unlinkSso_title: 'Αποσύνδεση SSO',
unsubscribe: 'Απεγγραφή',
uploadNewAvatar: 'Μεταφόρτωση νέου avatar',
uploadNewImage: 'Μεταφόρτωση νέας εικόνας',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
activeUsersLimitReached: 'Έχει επιτευχθεί το όριο ενεργών χρηστών',
adminLoginRequiredToInitializeInstance:
'Απαιτείται σύνδεση διαχειριστή για την αρχικοποίηση της εφαρμογής',
emailAlreadyInUse: 'Το e-mail χρησιμοποιείται ήδη',
emailOrUsername: 'E-mail ή όνομα χρήστη',
iHaveReadAndAgreeToTheseTerms: 'Έχω διαβάσει και συμφωνώ με αυτούς τους όρους',
invalidCredentials: 'Μη έγκυρα στοιχεία σύνδεσης',
invalidEmailOrUsername: 'Μη έγκυρο e-mail ή όνομα χρήστη',
invalidPassword: 'Μη έγκυρος κωδικός',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Ακύρωση και κλείσιμο',
continue: 'Συνέχεια',
debugSso: 'Αποσφαλμάτωση SSO',
goBack: 'Επιστροφή',
goHome: 'Αρχική σελίδα',
logIn: 'Σύνδεση',

View File

@@ -88,6 +88,8 @@ export default {
'Are you sure you want to remove this manager from the project?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Are you sure you want to remove this member from the board?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Are you sure you want to unlink SSO from this user? This will allow the user to log in with a password.',
assignAsOwner_title: 'Assign As Owner',
atLeastOneListMustBePresent: 'At least one list must be present',
attachment: 'Attachment',
@@ -327,6 +329,7 @@ export default {
turnOffRecentCardHighlighting: 'Turn off recent card highlighting',
typeNameToConfirm: 'Type the name to confirm.',
typeTitleToConfirm: 'Type the title to confirm.',
unlinkSso_title: 'Unlink SSO',
unsavedChanges: 'Unsaved changes',
uploadFailedFileIsTooBig: 'Upload failed: File is too big.',
uploadFailedNotEnoughStorageSpace: 'Upload failed: Not enough storage space.',
@@ -492,6 +495,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Subscribe',
unlinkSso: 'Unlink SSO',
unlinkSso_title: 'Unlink SSO',
unsubscribe: 'Unsubscribe',
uploadNewAvatar: 'Upload new avatar',
uploadNewImage: 'Upload new image',

View File

@@ -1,11 +1,10 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Active user limit reached',
activeUsersLimitReached: 'Active users limit reached',
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
emailAlreadyInUse: 'E-mail already in use',
emailOrUsername: 'E-mail or username',
iHaveReadAndAgreeToTheseTerms: 'I have read and agree to these Terms',
invalidCredentials: 'Invalid credentials',
invalidEmailOrUsername: 'Invalid e-mail or username',
invalidPassword: 'Invalid password',
@@ -25,6 +24,7 @@ export default {
action: {
cancelAndClose: 'Cancel and close',
continue: 'Continue',
debugSso: 'Debug SSO',
goBack: 'Go back',
goHome: 'Go home',
logIn: 'Log in',

View File

@@ -83,6 +83,8 @@ export default {
'Are you sure you want to remove this manager from the project?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Are you sure you want to remove this member from the board?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Are you sure you want to unlink SSO from this user? This will allow the user to log in with a password.',
assignAsOwner_title: 'Assign As Owner',
atLeastOneListMustBePresent: 'At least one list must be present',
attachment: 'Attachment',
@@ -322,6 +324,7 @@ export default {
turnOffRecentCardHighlighting: 'Turn off recent card highlighting',
typeNameToConfirm: 'Type the name to confirm.',
typeTitleToConfirm: 'Type the title to confirm.',
unlinkSso_title: 'Inlink SSO',
unsavedChanges: 'Unsaved changes',
uploadFailedFileIsTooBig: 'Upload failed: File is too big.',
uploadFailedNotEnoughStorageSpace: 'Upload failed: Not enough storage space.',
@@ -487,6 +490,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Subscribe',
unlinkSso: 'Unlink SSO',
unlinkSso_title: 'Unlink SSO',
unsubscribe: 'Unsubscribe',
uploadNewAvatar: 'Upload new avatar',
uploadNewImage: 'Upload new image',

View File

@@ -1,11 +1,10 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Active user limit reached',
activeUsersLimitReached: 'Active users limit reached',
adminLoginRequiredToInitializeInstance: 'Admin login required to initialize instance',
emailAlreadyInUse: 'E-mail already in use',
emailOrUsername: 'E-mail or username',
iHaveReadAndAgreeToTheseTerms: 'I have read and agree to these Terms',
invalidCredentials: 'Invalid credentials',
invalidEmailOrUsername: 'Invalid e-mail or username',
invalidPassword: 'Invalid password',
@@ -25,6 +24,7 @@ export default {
action: {
cancelAndClose: 'Cancel and close',
continue: 'Continue',
debugSso: 'Debug SSO',
goBack: 'Go back',
goHome: 'Go home',
logIn: 'Log in',

View File

@@ -92,6 +92,8 @@ export default {
'¿Estás seguro de que quieres eliminar este gestor del proyecto?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'¿Estás seguro de que quieres eliminar este miembro del tablero?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'¿Estás seguro de que quieres desvincular SSO de este usuario? Esto permitirá que el usuario inicie sesión con una contraseña.',
assignAsOwner_title: 'Asignar como propietario',
atLeastOneListMustBePresent: 'Debe existir al menos una lista',
attachment: 'Archivo adjunto',
@@ -335,6 +337,7 @@ export default {
turnOffRecentCardHighlighting: 'Desactivar resaltado de tarjetas recientes',
typeNameToConfirm: 'Escribe el nombre para confirmar.',
typeTitleToConfirm: 'Escribe el título para confirmar.',
unlinkSso_title: 'Desvinculación de SSO',
unsavedChanges: 'Cambios sin guardar',
uploadFailedFileIsTooBig: 'Error al subir: El archivo es demasiado grande.',
uploadFailedNotEnoughStorageSpace:
@@ -502,6 +505,8 @@ export default {
start: 'Iniciar',
stop: 'Detener',
subscribe: 'Suscribirse',
unlinkSso: 'Desvincular SSO',
unlinkSso_title: 'Desvincular SSO',
unsubscribe: 'Cancelar suscripción',
uploadNewAvatar: 'Subir nuevo avatar',
uploadNewImage: 'Subir nueva imagen',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Se ha alcanzado el límite de usuarios activos',
activeUsersLimitReached: 'Se ha alcanzado el límite de usuarios activos',
adminLoginRequiredToInitializeInstance:
'Se requiere inicio de sesión de administrador para inicializar la instancia',
emailAlreadyInUse: 'Correo electrónico ya en uso',
emailOrUsername: 'Correo electrónico o nombre de usuario',
iHaveReadAndAgreeToTheseTerms: 'He leído y acepto estos términos',
invalidCredentials: 'Credenciales no válidas',
invalidEmailOrUsername: 'Correo electrónico o nombre de usuario no válido',
invalidPassword: 'Contraseña no válida',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Cancelar y cerrar',
continue: 'Continuar',
debugSso: 'Depurar SSO',
goBack: 'Volver',
goHome: 'Ir al inicio',
logIn: 'Iniciar sesión',

View File

@@ -89,6 +89,8 @@ export default {
'Oled kindel, et soovid seda haldurit projektist eemaldada?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Oled kindel, et soovid seda liiget tahvlilt eemaldada?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Kas olete kindel, et soovite selle kasutaja SSO sidet eemaldada? See võimaldab kasutajal sisse logida parooliga.',
assignAsOwner_title: 'Määra omanikuks',
atLeastOneListMustBePresent: 'Vähemalt üks nimekiri peab olemas olema',
attachment: 'Manus',
@@ -327,6 +329,7 @@ export default {
turnOffRecentCardHighlighting: 'Lülita välja hiljuti kuvatud kaardi üleminek',
typeNameToConfirm: 'Sisestage nimi, et kinnitada.',
typeTitleToConfirm: 'Sisestage pealkiri, et kinnitada.',
unlinkSso_title: 'SSO sidemete eemaldamine',
unsavedChanges: 'Muudetud andmed',
uploadFailedFileIsTooBig: 'Üleslaadimine ebaõnnestus: fail on liiga suur.',
uploadFailedNotEnoughStorageSpace:
@@ -494,6 +497,8 @@ export default {
start: 'Alusta',
stop: 'Peata',
subscribe: 'Telli',
unlinkSso: 'Eemalda SSO side',
unlinkSso_title: 'Eemalda SSO side',
unsubscribe: 'Tühista tellimus',
uploadNewAvatar: 'Laadi üles uus avatar',
uploadNewImage: 'Laadi üles uus pilt',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktiivsete kasutajate limiit on täis',
activeUsersLimitReached: 'Aktiivsete kasutajate limiit on täis',
adminLoginRequiredToInitializeInstance:
'Administraatori sisselogimine on vajalik rakenduse käivitamiseks',
emailAlreadyInUse: 'E-post on juba kasutusel',
emailOrUsername: 'E-post või kasutajanimi',
iHaveReadAndAgreeToTheseTerms: 'Olen lugenud ja nõustun nende tingimustega',
invalidCredentials: 'Vale kasutajanimi või parool',
invalidEmailOrUsername: 'Vale e-post või kasutajanimi',
invalidPassword: 'Vale parool',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Tühista ja sulge',
continue: 'Jätka',
debugSso: 'Siluda SSO',
goBack: 'Tagasi',
goHome: 'Koju',
logIn: 'Logi sisse',

View File

@@ -91,6 +91,8 @@ export default {
'آیا مطمئن هستید که می‌خواهید این مدیر را از پروژه حذف کنید؟',
areYouSureYouWantToRemoveThisMemberFromBoard:
'آیا مطمئن هستید که می‌خواهید این عضو را از برد حذف کنید؟',
areYouSureYouWantToUnlinkSsoFromThisUser:
'آیا مطمئن هستید که می‌خواهید پیوند SSO را از این کاربر لغو کنید؟ این به کاربر اجازه می‌دهد با رمز عبور وارد شود.',
assignAsOwner_title: 'تعیین به عنوان مالک',
atLeastOneListMustBePresent: 'حداقل یک لیست باید وجود داشته باشد',
attachment: 'پیوست',
@@ -330,6 +332,7 @@ export default {
turnOffRecentCardHighlighting: 'خاموش کردن برجسته‌سازی کارت‌های اخیر',
typeNameToConfirm: 'نام را برای تأیید تایپ کنید.',
typeTitleToConfirm: 'عنوان را برای تأیید تایپ کنید.',
unlinkSso_title: 'لغو پیوند SSO',
unsavedChanges: 'تغییرات ذخیره نشده',
uploadFailedFileIsTooBig: 'آپلود ناموفق: فایل خیلی بزرگ است.',
uploadFailedNotEnoughStorageSpace: 'آپلود ناموفق: فضای ذخیره‌سازی کافی نیست.',
@@ -496,6 +499,8 @@ export default {
start: 'شروع',
stop: 'توقف',
subscribe: 'مشترک شدن',
unlinkSso: 'لغو پیوند SSO',
unlinkSso_title: 'لغو پیوند SSO',
unsubscribe: 'لغو اشتراک',
uploadNewAvatar: 'آپلود آواتار جدید',
uploadNewImage: 'آپلود تصویر جدید',

View File

@@ -1,11 +1,10 @@
export default {
translation: {
common: {
activeUserLimitReached: 'حد کاربران فعال به پایان رسیده است',
activeUsersLimitReached: 'حد کاربران فعال به پایان رسیده است',
adminLoginRequiredToInitializeInstance: 'ورود مدیر برای راه‌اندازی نمونه مورد نیاز است',
emailAlreadyInUse: 'ایمیل قبلا استفاده شده است',
emailOrUsername: 'ایمیل یا نام کاربری',
iHaveReadAndAgreeToTheseTerms: 'این شرایط را خوانده‌ام و با آن موافقم',
invalidCredentials: 'اطلاعات ورود نامعتبر',
invalidEmailOrUsername: 'ایمیل یا نام کاربری نامعتبر است',
invalidPassword: 'رمز عبور نامعتبر است',
@@ -25,6 +24,7 @@ export default {
action: {
cancelAndClose: 'لغو و بستن',
continue: 'ادامه',
debugSso: 'اشکال‌زدایی SSO',
goBack: 'بازگشت',
goHome: 'رفتن به خانه',
logIn: 'ورود',

View File

@@ -85,6 +85,8 @@ export default {
'Haluatko varmasti poistaa tämän ylläpitäjän projektista?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Haluatko varmasti poistaa tämän jäsenen taululta?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Haluatko varmasti poistaa SSO-yhteyden tältä käyttäjältä? Tämä sallii käyttäjän kirjautua sisään salasanalla.',
assignAsOwner_title: 'Aseta omistajaksi',
atLeastOneListMustBePresent: 'Vähintään yksi lista vaaditaan',
attachment: 'Liite',
@@ -325,6 +327,7 @@ export default {
turnOffRecentCardHighlighting: 'Poista uusien korttien korostus',
typeNameToConfirm: 'Kirjoita nimi vahvistaaksesi.',
typeTitleToConfirm: 'Kirjoita otsikko vahvistaaksesi.',
unlinkSso_title: 'SSO-yhteyden poistaminen',
unsavedChanges: 'Tallentamattomat muutokset',
uploadFailedFileIsTooBig: 'Lataus epäonnistui: tiedosto on liian suuri.',
uploadFailedNotEnoughStorageSpace: 'Lataus epäonnistui: tallennustilaa ei ole tarpeeksi.',
@@ -495,6 +498,8 @@ export default {
start: 'Aloita',
stop: 'Lopeta',
subscribe: 'Tilaa',
unlinkSso: 'Poista SSO-yhteys',
unlinkSso_title: 'Poista SSO-yhteys',
unsubscribe: 'Peru tilaus',
uploadNewAvatar: 'Lataa uusi avatar',
uploadNewImage: 'Lataa uusi kuva',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
activeUsersLimitReached: 'Aktiivisten käyttäjien raja saavutettu',
adminLoginRequiredToInitializeInstance:
'Järjestelmänvalvojan kirjautuminen vaaditaan instanssin alustamiseksi',
emailAlreadyInUse: 'Sähköposti on jo käytössä',
emailOrUsername: 'Sähköposti tai käyttäjänimi',
iHaveReadAndAgreeToTheseTerms: 'Olen lukenut ja hyväksyn nämä ehdot',
invalidCredentials: 'Virheelliset tunnistetiedot',
invalidEmailOrUsername: 'Virheellinen sähköposti tai käyttäjänimi',
invalidPassword: 'Virheellinen salasana',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Peruuta ja sulje',
continue: 'Jatka',
debugSso: 'Korjaa SSO-virheitä',
goBack: 'Takaisin',
goHome: 'Kotiin',
logIn: 'Kirjaudu sisään',

View File

@@ -91,6 +91,8 @@ export default {
'Êtes-vous sûr de vouloir supprimer ce responsable du projet ?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Êtes-vous sûr de vouloir supprimer ce membre du tableau ?',
areYouSureYouWantToUnlinkSsoFromThisUser:
"Êtes-vous sûr de vouloir dissocier le SSO de cet utilisateur ? Cela permettra à l'utilisateur de se connecter avec un mot de passe.",
assignAsOwner_title: 'Assigner comme propriétaire',
atLeastOneListMustBePresent: 'Au moins une liste doit être présente',
attachment: 'Pièce jointe',
@@ -334,6 +336,7 @@ export default {
turnOffRecentCardHighlighting: 'Désactiver la mise en évidence des cartes récentes',
typeNameToConfirm: 'Saissir le nom pour confirmer.',
typeTitleToConfirm: 'Saisir le titre pour confirmer.',
unlinkSso_title: 'Dissociation du SSO',
unsavedChanges: 'Modifications non enregistrées',
uploadFailedFileIsTooBig: 'Échec du téléchargement : fichier trop volumineux.',
uploadFailedNotEnoughStorageSpace:
@@ -500,6 +503,8 @@ export default {
start: 'Commencer',
stop: 'Arrêter',
subscribe: "S'abonner",
unlinkSso: 'Dissocier le SSO',
unlinkSso_title: 'Dissocier le SSO',
unsubscribe: 'Se désabonner',
uploadNewAvatar: 'Télécharger un nouvel avatar',
uploadNewImage: 'Télécharger une nouvelle image',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'La limite dutilisateurs actifs a été atteinte',
activeUsersLimitReached: 'La limite dutilisateurs actifs a été atteinte',
adminLoginRequiredToInitializeInstance:
"Connexion administrateur requise pour initialiser l'instance",
emailAlreadyInUse: 'E-mail déjà utilisé',
emailOrUsername: "E-mail ou nom d'utilisateur",
iHaveReadAndAgreeToTheseTerms: "J'ai lu et j'accepte ces conditions",
invalidCredentials: 'Identifiants invalides',
invalidEmailOrUsername: "E-mail ou nom d'utilisateur invalide",
invalidPassword: 'Mot de passe invalide',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Annuler et fermer',
continue: 'Continuer',
debugSso: 'Déboguer le SSO',
goBack: 'Retour',
goHome: "Aller à l'accueil",
logIn: 'Se connecter',

View File

@@ -81,6 +81,8 @@ export default {
areYouSureYouWantToRemoveThisManagerFromProject:
'Biztosan eltávolítja ezt a menedzsert a projektből?',
areYouSureYouWantToRemoveThisMemberFromBoard: 'Biztosan eltávolítja ezt a tagot a tábláról?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Biztosan le szeretné választani az SSO-t ettől a felhasználótól? Ez lehetővé teszi a felhasználó számára, hogy jelszóval jelentkezzen be.',
assignAsOwner_title: 'Hozzárendelés tulajdonosnak',
atLeastOneListMustBePresent: 'Legalább egy lista szükséges.',
attachment: 'Melléklet',
@@ -321,6 +323,7 @@ export default {
turnOffRecentCardHighlighting: 'Legutóbb módosítótt kártyák kiemelésének kikapcsolása',
typeNameToConfirm: 'Írja be a nevet a megerősítéshez.',
typeTitleToConfirm: 'Írja be a címet a megerősítéshez.',
unlinkSso_title: 'SSO leválasztása',
unsavedChanges: 'Mentetlen változtatások',
uploadFailedFileIsTooBig: 'Feltöltési hiba: a fájl túl nagy.',
uploadFailedNotEnoughStorageSpace: 'Feltöltési hiba: nincs elég szabad tárhely.',
@@ -494,6 +497,8 @@ export default {
start: 'Indítás',
stop: 'Megállítás',
subscribe: 'Feliratkozás',
unlinkSso: 'SSO leválasztása',
unlinkSso_title: 'SSO leválasztása',
unsubscribe: 'Leiratkozás',
uploadNewAvatar: 'Új avatar feltöltése',
uploadNewImage: 'Új kép feltöltése',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Aktív felhasználók korlátja elérve',
activeUsersLimitReached: 'Aktív felhasználók korlátja elérve',
adminLoginRequiredToInitializeInstance:
'Rendszergazdai bejelentkezés szükséges a példány inicializálásához',
emailAlreadyInUse: 'Az e-mail cím már használatban van',
emailOrUsername: 'E-mail vagy felhasználó',
iHaveReadAndAgreeToTheseTerms: 'Elolvastam és elfogadom ezeket a feltételeket',
invalidCredentials: 'Érvénytelen hitelesítő adatok',
invalidEmailOrUsername: 'Érvénytelen e-mail vagy felhasználó',
invalidPassword: 'Érvénytelen jelszó',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Mégse és bezárás',
continue: 'Folytatás',
debugSso: 'SSO hibakeresése',
goBack: 'Vissza',
goHome: 'Kezdőlapra',
logIn: 'Belépés',

View File

@@ -88,6 +88,8 @@ export default {
'Apakah anda ingin menghapus manajer ini dari papan ini?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Apakah anda ingin menghapus anggota ini dari papan ini?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Apakah Anda yakin ingin memutuskan tautan SSO dari pengguna ini? Ini akan memungkinkan pengguna untuk masuk dengan kata sandi.',
assignAsOwner_title: 'Tetapkan sebagai pemilik',
atLeastOneListMustBePresent: 'Setidaknya satu daftar harus ada',
attachment: 'Lampiran',
@@ -329,6 +331,7 @@ export default {
turnOffRecentCardHighlighting: 'Matikan penyorotan kartu terbaru',
typeNameToConfirm: 'Ketik nama untuk mengonfirmasi.',
typeTitleToConfirm: 'Ketik judul untuk mengonfirmasi.',
unlinkSso_title: 'Pemutusan tautan SSO',
unsavedChanges: 'Perubahan yang belum disimpan',
uploadFailedFileIsTooBig: 'Unggahan gagal - file terlalu besar.',
uploadFailedNotEnoughStorageSpace: 'Unggahan gagal - ruang penyimpanan tidak cukup.',
@@ -495,6 +498,8 @@ export default {
start: 'Mulai',
stop: 'Berhenti',
subscribe: 'Berlanggan',
unlinkSso: 'Putuskan tautan SSO',
unlinkSso_title: 'Putuskan tautan SSO',
unsubscribe: 'Berhenti berlangganan',
uploadNewAvatar: 'Unggah avatar baru',
uploadNewImage: 'Unggah gambar baru',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Batas pengguna aktif tercapai',
activeUsersLimitReached: 'Batas pengguna aktif tercapai',
adminLoginRequiredToInitializeInstance:
'Login admin diperlukan untuk menginisialisasi instance',
emailAlreadyInUse: 'E-mail telah digunakan',
emailOrUsername: 'E-mail atau username',
iHaveReadAndAgreeToTheseTerms: 'Saya telah membaca dan menyetujui syarat-syarat ini',
invalidCredentials: 'Kredensial tidak valid',
invalidEmailOrUsername: 'E-mail atau username salah',
invalidPassword: 'Kata sandi salah',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Batal dan tutup',
continue: 'Lanjutkan',
debugSso: 'Debug SSO',
goBack: 'Kembali',
goHome: 'Ke beranda',
logIn: 'Masuk',

View File

@@ -88,6 +88,8 @@ export default {
'Sei sicuro di voler rimuovere questo amministratore dal progetto?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Sei sicuro di voler rimuovere questo membro dalla bacheca?',
areYouSureYouWantToUnlinkSsoFromThisUser:
"Sei sicuro di voler scollegare SSO da questo utente? Questo permetterà all'utente di accedere con una password.",
assignAsOwner_title: 'Assegna come proprietario',
atLeastOneListMustBePresent: 'Deve essere presente almeno una lista',
attachment: 'Allegato',
@@ -331,6 +333,7 @@ export default {
turnOffRecentCardHighlighting: "Disattiva l'evidenziazione delle scheda recenti",
typeNameToConfirm: 'Digita il nome per confermare.',
typeTitleToConfirm: 'Digita il titolo per confermare.',
unlinkSso_title: 'Scollegamento SSO',
unsavedChanges: 'Modifiche non salvate',
uploadFailedFileIsTooBig: 'Caricamento fallito: il file è troppo grande.',
uploadFailedNotEnoughStorageSpace:
@@ -498,6 +501,8 @@ export default {
start: 'Inizio',
stop: 'Interrompi',
subscribe: 'Iscriviti',
unlinkSso: 'Scollega SSO',
unlinkSso_title: 'Scollega SSO',
unsubscribe: 'Annulla iscrizione',
uploadNewAvatar: 'Carica nuovo avatar',
uploadNewImage: 'Carica nuova immagine',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite utenti attivi raggiunto',
activeUsersLimitReached: 'Limite utenti attivi raggiunto',
adminLoginRequiredToInitializeInstance:
"Login amministratore richiesto per inizializzare l'istanza",
emailAlreadyInUse: 'E-mail già in uso',
emailOrUsername: 'E-mail o username',
iHaveReadAndAgreeToTheseTerms: 'Ho letto e accetto questi termini',
invalidCredentials: 'Credenziali non valide',
invalidEmailOrUsername: 'E-mail o username non valido',
invalidPassword: 'Password non valida',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Annulla e chiudi',
continue: 'Continua',
debugSso: 'Debug SSO',
goBack: 'Torna indietro',
goHome: 'Vai alla home',
logIn: 'Accedi',

View File

@@ -85,6 +85,8 @@ export default {
'このマネージャーをプロジェクトから外してもよろしいですか?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'このメンバーをボードから外してもよろしいですか?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'このユーザーからSSOのリンクを解除してもよろしいですかこれにより、ユーザーはパスワードでログインできるようになります。',
assignAsOwner_title: 'オーナーとして割り当て',
atLeastOneListMustBePresent: '少なくとも1つのリストが必要です',
attachment: '添付ファイル',
@@ -324,6 +326,7 @@ export default {
turnOffRecentCardHighlighting: '最近のカードのハイライトをオフにする',
typeNameToConfirm: '確認のため名前を入力してください。',
typeTitleToConfirm: '確認のためタイトルを入力してください。',
unlinkSso_title: 'SSOのリンク解除',
unsavedChanges: '未保存の変更',
uploadFailedFileIsTooBig: 'アップロード失敗 - ファイルが大きすぎます。',
uploadFailedNotEnoughStorageSpace: 'アップロード失敗 - ストレージ容量が不足しています。',
@@ -492,6 +495,8 @@ export default {
start: 'スタート',
stop: 'ストップ',
subscribe: '購読',
unlinkSso: 'SSOのリンクを解除',
unlinkSso_title: 'SSOのリンクを解除',
unsubscribe: '購読解除',
uploadNewAvatar: '新しいアバターをアップロード',
uploadNewImage: '新しい画像をアップロード',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'アクティブユーザーの上限に達しました',
activeUsersLimitReached: 'アクティブユーザーの上限に達しました',
adminLoginRequiredToInitializeInstance:
'インスタンスを初期化するには管理者ログインが必要です',
emailAlreadyInUse: 'Eメールは既に使われています',
emailOrUsername: 'Eメールまたはユーザー名',
iHaveReadAndAgreeToTheseTerms: 'これらの利用規約を読み、同意します',
invalidCredentials: '認証情報が無効です',
invalidEmailOrUsername: 'Eメールまたはユーザー名が無効',
invalidPassword: 'パスワードが無効',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'キャンセルして閉じる',
continue: '続行',
debugSso: 'SSOをデバッグ',
goBack: '戻る',
goHome: 'ホームへ',
logIn: 'ログイン',

View File

@@ -79,6 +79,8 @@ export default {
'이 API 키를 재생성하시겠습니까? 이전 키는 더 이상 작동하지 않습니다.',
areYouSureYouWantToRemoveThisManagerFromProject: '이 관리자를 프로젝트에서 제거하시겠습니까?',
areYouSureYouWantToRemoveThisMemberFromBoard: '이 멤버를 보드에서 제거하시겠습니까?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'이 사용자로부터 SSO 연결을 해제하시겠습니까? 이렇게 하면 사용자가 비밀번호로 로그인할 수 있습니다.',
assignAsOwner_title: '소유자로 지정',
atLeastOneListMustBePresent: '최소 하나의 목록이 있어야 합니다',
attachment: '첨부 파일',
@@ -319,6 +321,7 @@ export default {
turnOffRecentCardHighlighting: '최근 카드 강조 표시 끄기',
typeNameToConfirm: '확인하려면 이름을 입력하세요.',
typeTitleToConfirm: '확인하려면 제목을 입력하세요.',
unlinkSso_title: 'SSO 연결 해제',
unsavedChanges: '저장되지 않은 변경사항',
uploadFailedFileIsTooBig: '업로드 실패: 파일이 너무 큽니다.',
uploadFailedNotEnoughStorageSpace: '업로드 실패: 저장 공간이 부족합니다.',
@@ -489,6 +492,8 @@ export default {
start: '시작',
stop: '중지',
subscribe: '구독',
unlinkSso: 'SSO 연결 해제',
unlinkSso_title: 'SSO 연결 해제',
unsubscribe: '구독 취소',
uploadNewAvatar: '새 아바타 업로드',
uploadNewImage: '새 이미지 업로드',

View File

@@ -1,11 +1,10 @@
export default {
translation: {
common: {
activeUserLimitReached: '활성 사용자 한도에 도달했습니다',
activeUsersLimitReached: '활성 사용자 한도에 도달했습니다',
adminLoginRequiredToInitializeInstance: '인스턴스 초기화를 위해 관리자 로그인이 필요합니다',
emailAlreadyInUse: '이미 사용 중인 이메일',
emailOrUsername: '이메일 또는 사용자 이름',
iHaveReadAndAgreeToTheseTerms: '이 약관을 읽고 동의합니다',
invalidCredentials: '잘못된 자격 증명',
invalidEmailOrUsername: '잘못된 이메일 또는 사용자 이름',
invalidPassword: '잘못된 비밀번호',
@@ -25,6 +24,7 @@ export default {
action: {
cancelAndClose: '취소 후 닫기',
continue: '계속',
debugSso: 'SSO 디버그',
goBack: '뒤로 가기',
goHome: '홈으로 가기',
logIn: '로그인',

View File

@@ -88,6 +88,8 @@ export default {
'Weet u zeker dat u deze manager uit het project wilt verwijderen?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Weet u zeker dat u dit lid uit het bord wilt verwijderen?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Weet je zeker dat je SSO wilt ontkoppelen van deze gebruiker? Dit stelt de gebruiker in staat om in te loggen met een wachtwoord.',
assignAsOwner_title: 'Toewijzen als eigenaar',
atLeastOneListMustBePresent: 'Er moet ten minste één lijst aanwezig zijn',
attachment: 'Bijlage',
@@ -329,6 +331,7 @@ export default {
turnOffRecentCardHighlighting: 'Recente kaartmarkering uitschakelen',
typeNameToConfirm: 'Typ naam om te bevestigen.',
typeTitleToConfirm: 'Typ titel om te bevestigen.',
unlinkSso_title: 'SSO ontkoppelen',
unsavedChanges: 'Niet-opgeslagen wijzigingen',
uploadFailedFileIsTooBig: 'Upload mislukt: bestand is te groot.',
uploadFailedNotEnoughStorageSpace: 'Upload mislukt: niet genoeg opslagruimte.',
@@ -498,6 +501,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Abonneren',
unlinkSso: 'SSO ontkoppelen',
unlinkSso_title: 'SSO ontkoppelen',
unsubscribe: 'Afmelden',
uploadNewAvatar: 'Nieuwe avatar uploaden',
uploadNewImage: 'Nieuwe afbeelding uploaden',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limiet voor actieve gebruikers bereikt',
activeUsersLimitReached: 'Limiet voor actieve gebruikers bereikt',
adminLoginRequiredToInitializeInstance:
'Beheerder login vereist om instantie te initialiseren',
emailAlreadyInUse: 'E-mail is al in gebruik',
emailOrUsername: 'E-mail of gebruikersnaam',
iHaveReadAndAgreeToTheseTerms: 'Ik heb deze voorwaarden gelezen en ga ermee akkoord',
invalidCredentials: 'Ongeldige inloggegevens',
invalidEmailOrUsername: 'Ongeldig e-mailadres of gebruikersnaam',
invalidPassword: 'Ongeldig wachtwoord',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Annuleren en sluiten',
continue: 'Doorgaan',
debugSso: 'SSO debuggen',
goBack: 'Terug gaan',
goHome: 'Naar startpagina',
logIn: 'Inloggen',

View File

@@ -87,6 +87,8 @@ export default {
'Jesteś pewien że chcesz usunąć tego zarządcę z projektu?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Jesteś pewien że chcesz usunąć tego członka z tablicy?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Czy na pewno chcesz odłączyć SSO od tego użytkownika? Pozwoli to użytkownikowi zalogować się przy użyciu hasła.',
assignAsOwner_title: 'Przypisz jako właściciela',
atLeastOneListMustBePresent: 'Przynajmniej jedna lista musi istnieć',
attachment: 'Załącznik',
@@ -328,6 +330,7 @@ export default {
turnOffRecentCardHighlighting: 'Wyłącz podświetlanie nowych kart',
typeNameToConfirm: 'Wpisz nazwę aby potwierdzić.',
typeTitleToConfirm: 'Wpisz tytuł aby potwierdzić.',
unlinkSso_title: 'Odłączanie SSO',
unsavedChanges: 'Niezapisane zmiany',
uploadFailedFileIsTooBig: 'Przesyłanie nie powiodło się: plik jest za duży.',
uploadFailedNotEnoughStorageSpace: 'Przesyłanie nie powiodło się: za mało miejsca na dysku.',
@@ -495,6 +498,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Subskrybuj',
unlinkSso: 'Odłącz SSO',
unlinkSso_title: 'Odłącz SSO',
unsubscribe: 'Odsubskrybuj',
uploadNewAvatar: 'Wgraj nowy awatar',
uploadNewImage: 'Wgraj nowy obraz',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Osiągnięto limit aktywnych użytkowników',
activeUsersLimitReached: 'Osiągnięto limit aktywnych użytkowników',
adminLoginRequiredToInitializeInstance:
'Wymagane logowanie administratora do inicjalizacji instancji',
emailAlreadyInUse: 'E-mail jest już używany',
emailOrUsername: 'E-mail lub nazwa użytkownika',
iHaveReadAndAgreeToTheseTerms: 'Przeczytałem i zgadzam się z tymi warunkami',
invalidCredentials: 'Błędne dane logowania',
invalidEmailOrUsername: 'Błędny e-mail lub nazwa użytkownika',
invalidPassword: 'Błędne hasło',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Anuluj i zamknij',
continue: 'Kontynuuj',
debugSso: 'Debuguj SSO',
goBack: 'Wróć',
goHome: 'Idź do domu',
logIn: 'Zaloguj',

View File

@@ -89,6 +89,8 @@ export default {
'Tem certeza de que deseja remover este gerente do projeto?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Tem certeza de que deseja remover este membro do quadro?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Tem certeza de que deseja desvincular o SSO deste usuário? Isso permitirá que o usuário faça login com uma senha.',
assignAsOwner_title: 'Atribuir como proprietário',
atLeastOneListMustBePresent: 'Pelo menos uma lista deve estar presente',
attachment: 'Anexo',
@@ -332,6 +334,7 @@ export default {
turnOffRecentCardHighlighting: 'Desativar destaque de cartões recentes',
typeNameToConfirm: 'Digite o nome para confirmar.',
typeTitleToConfirm: 'Digite o título para confirmar.',
unlinkSso_title: 'Desvinculação de SSO',
unsavedChanges: 'Alterações não salvas',
uploadFailedFileIsTooBig: 'Falha no upload: arquivo muito grande.',
uploadFailedNotEnoughStorageSpace: 'Falha no upload: espaço de armazenamento insuficiente.',
@@ -498,6 +501,8 @@ export default {
start: 'Iniciar',
stop: 'Parar',
subscribe: 'Inscrever-se',
unlinkSso: 'Desvincular SSO',
unlinkSso_title: 'Desvincular SSO',
unsubscribe: 'Cancelar inscrição',
uploadNewAvatar: 'Enviar novo avatar',
uploadNewImage: 'Enviar nova imagem',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite de usuários ativos atingido',
activeUsersLimitReached: 'Limite de usuários ativos atingido',
adminLoginRequiredToInitializeInstance:
'Login de administrador necessário para inicializar a instância',
emailAlreadyInUse: 'E-mail já está em uso',
emailOrUsername: 'E-mail ou nome de usuário',
iHaveReadAndAgreeToTheseTerms: 'Li e concordo com estes termos',
invalidCredentials: 'Credenciais inválidas',
invalidEmailOrUsername: 'E-mail ou nome de usuário inválido',
invalidPassword: 'Senha inválida',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Cancelar e fechar',
continue: 'Continuar',
debugSso: 'Depurar SSO',
goBack: 'Voltar',
goHome: 'Ir para início',
logIn: 'Entrar',

View File

@@ -91,6 +91,8 @@ export default {
'Tem a certeza de que pretende remover este gestor do projeto?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Tem a certeza de que pretende remover este membro do quadro?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Tem a certeza de que pretende desvincular o SSO deste utilizador? Isto permitirá que o utilizador inicie sessão com uma palavra-passe.',
assignAsOwner_title: 'Atribuir como proprietário',
atLeastOneListMustBePresent: 'Pelo menos uma lista deve estar presente',
attachment: 'Anexo',
@@ -334,6 +336,7 @@ export default {
turnOffRecentCardHighlighting: 'Desativar destaque de cartões recentes',
typeNameToConfirm: 'Digite o nome para confirmar.',
typeTitleToConfirm: 'Digite o título para confirmar.',
unlinkSso_title: 'Desvinculação de SSO',
unsavedChanges: 'Alterações não guardadas',
uploadFailedFileIsTooBig: 'Carregamento falhado - ficheiro demasiado grande.',
uploadFailedNotEnoughStorageSpace:
@@ -501,6 +504,8 @@ export default {
start: 'Iniciar',
stop: 'Parar',
subscribe: 'Subscrever',
unlinkSso: 'Desvincular SSO',
unlinkSso_title: 'Desvincular SSO',
unsubscribe: 'Cancelar subscrição',
uploadNewAvatar: 'Carregar novo avatar',
uploadNewImage: 'Carregar nova imagem',

View File

@@ -1,12 +1,11 @@
export default {
translation: {
common: {
activeUserLimitReached: 'Limite de utilizadores activos atingido',
activeUsersLimitReached: 'Limite de utilizadores activos atingido',
adminLoginRequiredToInitializeInstance:
'Início de sessão de administrador necessário para inicializar a instância',
emailAlreadyInUse: 'E-mail já está em uso',
emailOrUsername: 'E-mail ou nome de utilizador',
iHaveReadAndAgreeToTheseTerms: 'Li e concordo com estes termos',
invalidCredentials: 'Credenciais inválidas',
invalidEmailOrUsername: 'E-mail ou nome de utilizador inválido',
invalidPassword: 'Palavra-passe inválida',
@@ -26,6 +25,7 @@ export default {
action: {
cancelAndClose: 'Cancelar e fechar',
continue: 'Continuar',
debugSso: 'Depurar SSO',
goBack: 'Voltar',
goHome: 'Ir para início',
logIn: 'Iniciar sessão',

View File

@@ -85,6 +85,8 @@ export default {
'Sigur doriți să eliminați acest manager din proiect?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Sigur doriți să eliminați acest membru din consiliu?',
areYouSureYouWantToUnlinkSsoFromThisUser:
'Sigur doriți să deconectați SSO de la acest utilizator? Acest lucru va permite utilizatorului să se conecteze cu o parolă.',
assignAsOwner_title: 'Atribuie ca proprietar',
atLeastOneListMustBePresent: 'Cel puțin o listă trebuie să fie prezentă',
attachment: 'Atașament',
@@ -327,6 +329,7 @@ export default {
turnOffRecentCardHighlighting: 'Oprește evidențierea cardurilor recente',
typeNameToConfirm: 'Tastează numele pentru confirmare.',
typeTitleToConfirm: 'Tastează titlul pentru confirmare.',
unlinkSso_title: 'Deconectarea SSO',
unsavedChanges: 'Modificări nesalvate',
uploadFailedFileIsTooBig: 'Încărcarea a eșuat: fișierul este prea mare.',
uploadFailedNotEnoughStorageSpace: 'Încărcarea a eșuat: spațiu de stocare insuficient.',
@@ -495,6 +498,8 @@ export default {
start: 'Start',
stop: 'Stop',
subscribe: 'Abonati-va',
unlinkSso: 'Deconectează SSO',
unlinkSso_title: 'Deconectează SSO',
unsubscribe: 'Dezabonați-vă',
uploadNewAvatar: 'Încărcați un avatar nou',
uploadNewImage: 'Încărcați o nouă imagine',

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