Compare commits

...
79 Commits
Author SHA1 Message Date
Maksim Eltyshev da63598de3 chore: Update version 2023-12-11 00:18:14 +01:00
Gilberto Vidal 517cb34cfe fix: Fix eslint rules for Windows (#508) 2023-12-11 00:13:04 +01:00
NavyStack 079b8eba53 fix: Fine-tune Korean and Japanese translations, fix full stops (#561) 2023-12-10 23:47:04 +01:00
Maksim Eltyshev af02cdd8bf docs: Little readme fixes 2023-12-10 22:20:23 +01:00
Maksim Eltyshev e1bc189b88 chore: Bump chart-releaser-action version 2023-12-10 17:55:15 +01:00
Maksim Eltyshev 5f2723623a chore: Update version 2023-12-09 17:23:01 +01:00
Maksim Eltyshev fee6841d0a fix: Attempt to fix error that occurs during reconnection 2023-12-09 17:19:40 +01:00
Maksim Eltyshev ca6fb3b962 fix: Add state parameter to OIDC authorization url
Closes #558
2023-12-09 17:06:45 +01:00
Maksim Eltyshev 28c3f28e01 fix: Add issuer to OIDC callback parameters
Closes #562
2023-12-09 16:28:24 +01:00
Maksim Eltyshev 80d12aaeeb fix: Fix Korean translation linting 2023-12-04 11:42:15 +01:00
NavyStack 89af209a2e fix: Update Korean translation (#560) 2023-12-04 11:40:04 +01:00
Maksim Eltyshev f1fed3e533 build: Stop using base image 2023-12-01 18:02:19 +01:00
Maksim Eltyshev eddeb96b16 fix: Fix Romanian translation linting 2023-11-24 12:43:00 +01:00
Maksim Eltyshev 9e8ff3b579 chore: Revert remark-gfm update 2023-11-23 14:40:44 +01:00
Maksim Eltyshev fc1278011c build: Use pnpm import before installing dependencies 2023-11-23 11:54:28 +01:00
Andrei Covali 24163463fc feat: Add Romanian translation (#555) 2023-11-22 14:58:13 +01:00
Yu Inoue fdef87e3b9 fix: Add support for OIDC configuration thru Helm (#550)
Closes #548
2023-11-20 14:16:19 +01:00
Maksim Eltyshev 964498dbaa chore: Use Node v18 2023-11-18 09:26:31 +01:00
Maksim Eltyshev 5b519cb62f chore: Update version 2023-11-17 22:13:04 +01:00
Yu Inoue 11fc3b4485 fix: Separate service port and container port in Helm (#549) 2023-11-17 22:11:35 +01:00
Maksim Eltyshev 37c0b59f82 chore: Update vips version 2023-11-17 21:48:26 +01:00
Maksim Eltyshev 239611ad51 chore: Update dependencies 2023-11-17 14:34:10 +01:00
Yu Inoue 0575e665fe fix: Fix time format in Japanese locale (#546)
Closes #542
2023-11-13 12:51:00 +01:00
Maksim Eltyshev 019766dced chore: Update version 2023-10-25 23:41:48 +02:00
Maksim Eltyshev 6dc9e4ed99 fix: Disable role change when OIDC roles are not ignored 2023-10-25 23:39:34 +02:00
Balthasar Hofer d4b64b90fc feat: Add ability to ignore roles when logging in with SSO (#534)
Closes #533
2023-10-26 02:01:35 +05:00
Daniel Hiller 1a49826b85 docs: adjust filenames to match the docs 2023-10-24 13:17:49 +02:00
Daniel Hiller 815643eb2c ci: ignore some paths on push 2023-10-22 22:47:39 +02:00
Daniel Hiller bcc4c0d923 chore: update version 2023-10-22 22:31:10 +02:00
Daniel Hiller cf7810b067 fix: add admin user variables 2023-10-22 22:27:25 +02:00
Maksim Eltyshev f1c72df8b6 chore: Update version 2023-10-20 22:38:43 +02:00
Maksim Eltyshev 5056d38848 fix: Fix logging out with invalid token 2023-10-20 22:34:58 +02:00
Maksim Eltyshev 3ef5b3ead8 fix: Make default admin environment variables optional
Closes #526
2023-10-20 21:52:12 +02:00
Vishnu Kaushik ded58dc8b0 fix: Add task counter in card modal (#525)
Closes #467
2023-10-21 00:20:04 +05:00
Maksim Eltyshev d8ee1ecdd1 ci: Do not mark released chart as latest 2023-10-19 23:30:58 +02:00
Maksim Eltyshev fc2f4cd5d3 chore: Update version 2023-10-19 23:08:40 +02:00
Maksim Eltyshev 7ef457157e fix: Fallback to query if there is no fragment 2023-10-19 23:06:37 +02:00
Maksim Eltyshev 23ee815200 chore: Update version 2023-10-19 16:07:52 +02:00
Maksim Eltyshev 40c04c35ff ref: Refactoring 2023-10-19 16:05:34 +02:00
Lorenz Brun 743f2956c8 feat: Improve OIDC SSO (#524)
The OIDC implementation merged in https://github.com/plankanban/planka/pull/491 is flawed for multiple reasons.

It assumes that the access_token returned by the IDP has to be a JWT parseable by the RP which is not the case [1].
Many major IDPs do issue tokens which are not JWTs and RPs should not rely on the contents of these at all.
The only signed token which has a standardized format for direct RP consumption is the OIDC ID token (id_token), but this by default doesn't contain many claims, especially role claims are omitted from them by default for size reasons. To get these additional claims into the ID token, one needs an IDP with support for the "claims" parameter.

It requires manual specification of the JWKS URL which is mandatory in any OIDC discovery document and thus never needs to be manually specified.

It also makes the questionable decision to use a client-side code flow with PKCE where a normal code flow would be much more appropriate as all user data is processed in the backend which can securely hold a client secret (confidential client). This has far wider IDP support, is safer (due to direct involvement of the IDP in obtaining user information) and doesn't require working with ID tokens and claim parameters.

By using a server-side code flow we can also offload most complexity to the server alone, no longer requiring an additional OIDC library on the web client.

Also silent logout doesn't work on most IDPs for security reasons, one needs to actually redirect the user over to the IDP, which then prompts them once more if they actually want to log out.

This implementation should work with any OIDC-compliant IDP and even OAuth 2.0-only IDPs as long as they serve and OIDC discovery document.

[1] rfc-editor.org/rfc/rfc6749#section-5.1
2023-10-19 17:39:21 +05:00
Maksim Eltyshev 5bf5db27d8 chore: Update chart version 2023-10-18 23:33:30 +02:00
Maksim Eltyshev 667c5daf25 chore: Update version 2023-10-18 23:20:30 +02:00
Maksim Eltyshev 6662b0a717 fix: Fix order of checks when logging in 2023-10-18 23:07:57 +02:00
Maksim Eltyshev 348bf4d6c4 Merge branch 'master' of github.com:gorrilla10101/planka 2023-10-17 22:31:16 +02:00
Maksim Eltyshev 3ac2d289d0 chore: Update version 2023-10-17 19:31:21 +02:00
Maksim Eltyshev 3bc73c43ea chore: Bump sails version 2023-10-17 19:23:09 +02:00
Maksim Eltyshev 8e0c60f5be fix: OIDC finalization and refactoring 2023-10-17 19:18:19 +02:00
Daniel Hiller aae69cb5e4 CI: Add prebuild planka package on release 2023-09-30 01:59:09 +02:00
Daniel Hiller 782c0356c8 Meta: Add missing return 2023-09-23 03:48:32 +02:00
Daniel Hiller 757cdb14a4 Meta: Add Automated installation 2023-09-23 03:47:46 +02:00
gorrilla10101 8a4bdbd1fe Merge branch 'plankanban:master' into master 2023-09-16 22:15:54 -05:00
Jeffrey 5bf42be786 dynamic environment variables 2023-09-16 21:37:12 -05:00
Daniel Hiller d896c3183b chore: fix docker dev build 2023-09-14 01:27:29 +02:00
Daniel Hiller 13ee0c3466 chore: fix runs-on name 2023-09-13 22:55:09 +02:00
Daniel Hiller 211c841379 chore: Switch to self hostet action runner 2023-09-13 22:47:08 +02:00
Daniel Hiller 90a30961ff chore: Add dev container, based on latest commit 2023-09-13 22:39:37 +02:00
Daniel Hiller 7cb9774e05 chore: Switch to pnpm package manager 2023-09-13 22:38:37 +02:00
Maksim Eltyshev 875895b331 fix: Fix starting without OIDC environment variables
Closes #503
2023-09-12 01:20:21 +02:00
Maksim Eltyshev 91bc889fed feat: Use environment variables for default admin configuration 2023-09-12 01:12:38 +02:00
Gilberto Vidal a34d8e9753 fix: Fix Turkish translation linting (#504) 2023-09-11 22:21:46 +05:00
gorrilla10101 107cb85ba2 feat: OIDC with PKCE flow (#491) 2023-09-04 20:06:59 +05:00
creador30 9333ef562e feat: Add Turkish translation (#501) 2023-09-04 19:41:11 +05:00
RocketProto 7d28abc7e6 fix: Decouple BASE_URL from Ingress host (#498)
Closes #496
2023-08-27 02:26:45 +05:00
Andrey 5317950b5c fix: Update Russian translation (#497) 2023-08-22 14:34:45 +05:00
Maksim Eltyshev 7501619b7e fix: Fix Czech translation linting
Closes #487
2023-07-31 11:54:50 +02:00
leroyloren 080e29aa03 fix: Update Czech translation (#485) 2023-07-27 04:07:47 +05:00
[object Object] 48c532b2c2 feat: Add edit icon to project name (#457) 2023-07-09 20:49:08 +05:00
Maksim Eltyshev a62815f825 ref: Little refactoring 2023-06-13 12:06:28 +02:00
Maksim Eltyshev 6938232dc4 fix: Keep task edits when textarea loses focus 2023-06-13 12:04:49 +02:00
[object Object] 4c4cfa9c66 fix: Keep comment edits when textarea loses focus (#443)
Closes #441
2023-06-13 14:49:54 +05:00
Maksim Eltyshev ba89d41b19 chore: Update chart version 2023-06-13 00:46:17 +02:00
Maksim Eltyshev 5c435414f7 chore: Update version 2023-06-13 00:25:40 +02:00
Maksim Eltyshev 2d7812a679 fix: Use creation timestamp instead of id for ordering
Closes #465
2023-06-13 00:19:17 +02:00
Maksim Eltyshev d386c82973 fix: Fix saving milliseconds for timestamps 2023-06-12 23:54:57 +02:00
ULiiAn 6c4db967c2 fix: Fix Chinese translation (#464)
Closes #463
2023-06-12 14:51:31 +05:00
Christopher Greaves 932d8225ed feat: Add official Helm Chart (#442)
Closes #192
2023-05-25 20:23:11 +05:00
orbatschow 0d481703da feat: Allow postgres connections that require ssl mode (#409)
Closes #261
2023-03-06 17:54:52 +05:00
Zsh 23e2b4a622 fix: Update Chinese translation (#410) 2023-03-06 17:12:59 +05:00
LuisLiu f4cc51e1c0 feat: Add Chinese translation (#398) 2023-03-06 17:07:00 +05:00
150 changed files with 11235 additions and 24849 deletions
@@ -0,0 +1,57 @@
name: Build and publish release package
on:
release:
types: [created]
jobs:
build-and-publish-release-package:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v3
with:
node-version: '18'
cache: 'npm'
- name: Workflow install pnpm
run: npm install pnpm -g
- name: Client install dependencies
run: pnpm install
- name: Server install dependencies
run: pnpm install
- name: Server include into dist
run: mv server/ dist/
- name: Client build production
run: |
npm run build
working-directory: ./client
- name: Client include into dist
run: |
mv build/index.html ../dist/views/index.ejs
mv build/* ../dist/public/
working-directory: ./client
- name: Dist include README.md SECURITY.md LICENSE start.sh
run: mv README.md SECURITY.md LICENSE start.sh dist/
- name: Dist Remove node modules
run: rm -R dist/node_modules
- name: Dist create .zip file
run: |
mv dist/ planka/
zip -r planka-prebuild-${{ github.event.release.tag_name }}.zip planka
- name: Dist upload assets
run: |
gh release upload ${{ github.event.release.tag_name }} planka-prebuild-${{ github.event.release.tag_name }}.zip
env:
GH_TOKEN: ${{ github.token }}
@@ -13,26 +13,26 @@ env:
jobs: jobs:
build-and-push-docker-base-image: build-and-push-docker-base-image:
runs-on: ubuntu-latest runs-on: self-hosted
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }} password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2 uses: docker/build-push-action@v4
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7
@@ -0,0 +1,39 @@
name: Build and push Docker DEV image
on:
push:
paths-ignore:
- '.github/**'
- 'charts/**'
- 'docker-*.sh'
- '*.md'
branches: [master]
jobs:
build-and-push-docker-image-dev:
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry
uses: docker/login-action@v2
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7
push: true
tags: |
ghcr.io/plankanban/planka:dev
@@ -6,19 +6,19 @@ on:
jobs: jobs:
build-and-push-docker-image: build-and-push-docker-image:
runs-on: ubuntu-latest runs-on: self-hosted
steps: steps:
- name: Checkout - name: Checkout
uses: actions/checkout@v3 uses: actions/checkout@v4
- name: Set up QEMU - name: Set up QEMU
uses: docker/setup-qemu-action@v1 uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx - name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1 uses: docker/setup-buildx-action@v2
- name: Login to GitHub Container Registry - name: Login to GitHub Container Registry
uses: docker/login-action@v1 uses: docker/login-action@v2
with: with:
registry: ghcr.io registry: ghcr.io
username: ${{ github.repository_owner }} username: ${{ github.repository_owner }}
@@ -32,7 +32,7 @@ jobs:
script: return context.payload.release.tag_name.replace('v', '') script: return context.payload.release.tag_name.replace('v', '')
- name: Build and push - name: Build and push
uses: docker/build-push-action@v2 uses: docker/build-push-action@v4
with: with:
context: . context: .
platforms: linux/amd64,linux/arm64,linux/arm/v7 platforms: linux/amd64,linux/arm64,linux/arm/v7
+43
View File
@@ -0,0 +1,43 @@
name: Release Charts
on:
push:
paths:
- "charts/**"
branches:
- master
jobs:
release:
# depending on default permission settings for your org (contents being read-only or read-write for workloads), you will have to add permissions
# see: https://docs.github.com/en/actions/security-guides/automatic-token-authentication#modifying-the-permissions-for-the-github_token
permissions:
contents: write
runs-on: self-hosted
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Git
run: |
git config user.name "$GITHUB_ACTOR"
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
- name: Install Helm
uses: azure/setup-helm@v3
- name: Add repositories
run: |
for dir in $(ls -d charts/*/); do
helm dependency list $dir 2> /dev/null | tail +2 | head -n -1 | awk '{ print "helm repo add " $1 " " $3 }' | while read cmd; do $cmd; done
done
- name: Run chart-releaser for stable
uses: helm/chart-releaser-action@v1.6.0
with:
charts_dir: charts
mark_as_latest: false
env:
CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}"
+3
View File
@@ -10,3 +10,6 @@ docker-compose.override.yml
# `npm i --package-lock-only` # `npm i --package-lock-only`
pnpm-lock.yaml pnpm-lock.yaml
yarn.lock yarn.lock
# Chart dependencies
**/charts/*.tgz
+15 -5
View File
@@ -1,11 +1,17 @@
FROM ghcr.io/plankanban/planka:base-latest as server-dependencies FROM node:18-alpine as server-dependencies
RUN apk -U upgrade \
&& apk add build-base python3 \
--no-cache
WORKDIR /app WORKDIR /app
COPY server/package.json server/package-lock.json . COPY server/package.json server/package-lock.json .
RUN npm install npm@latest --global \ RUN npm install npm@latest --global \
&& npm clean-install --omit=dev && npm install pnpm --global \
&& pnpm import \
&& pnpm install --prod
FROM node:lts AS client FROM node:lts AS client
@@ -14,14 +20,18 @@ WORKDIR /app
COPY client/package.json client/package-lock.json . COPY client/package.json client/package-lock.json .
RUN npm install npm@latest --global \ RUN npm install npm@latest --global \
&& npm clean-install --omit=dev && npm install pnpm --global \
&& pnpm import \
&& pnpm install --prod
COPY client . COPY client .
RUN DISABLE_ESLINT_PLUGIN=true npm run build RUN DISABLE_ESLINT_PLUGIN=true npm run build
FROM ghcr.io/plankanban/planka:base-latest FROM node:18-alpine
RUN apk del vips-dependencies --purge RUN apk -U upgrade \
&& apk add bash \
--no-cache
USER node USER node
WORKDIR /app WORKDIR /app
+12 -17
View File
@@ -1,27 +1,22 @@
FROM node:lts-alpine FROM node:18-alpine
ARG ALPINE_VERSION=3.16 ARG VIPS_VERSION=8.14.5
ARG VIPS_VERSION=8.13.3
RUN apk -U upgrade \ RUN apk -U upgrade \
&& apk add \ && apk add \
bash giflib glib lcms2 libexif \ bash pkgconf \
libgsf libjpeg-turbo libpng librsvg libwebp \ libjpeg-turbo libexif librsvg cgif tiff libspng libimagequant \
orc pango tiff \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
--no-cache \ --no-cache \
&& apk add \ && apk add \
build-base giflib-dev glib-dev lcms2-dev libexif-dev \ build-base gobject-introspection-dev meson \
libgsf-dev libjpeg-turbo-dev libpng-dev librsvg-dev libwebp-dev \ libjpeg-turbo-dev libexif-dev librsvg-dev cgif-dev tiff-dev libspng-dev libimagequant-dev \
orc-dev pango-dev tiff-dev \
--virtual vips-dependencies \ --virtual vips-dependencies \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/community/ \
--repository https://alpine.global.ssl.fastly.net/alpine/v${ALPINE_VERSION}/main/ \
--no-cache \ --no-cache \
&& wget -O- https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.gz | tar xzC /tmp \ && wget -O- https://github.com/libvips/libvips/releases/download/v${VIPS_VERSION}/vips-${VIPS_VERSION}.tar.xz | tar xJC /tmp \
&& cd /tmp/vips-${VIPS_VERSION} \ && cd /tmp/vips-${VIPS_VERSION} \
&& ./configure \ && meson setup build-dir \
&& make \ && cd build-dir \
&& make install-strip \ && ninja \
&& ninja test \
&& ninja install \
&& rm -rf /tmp/vips-${VIPS_VERSION} && rm -rf /tmp/vips-${VIPS_VERSION}
+2 -4
View File
@@ -1,5 +1,5 @@
# Planka # Planka
#### Elegant open source project tracking #### Elegant open source project tracking.
![David (path)](https://img.shields.io/github/package-json/v/plankanban/planka) ![Docker Pulls](https://img.shields.io/docker/pulls/meltyshev/planka) ![GitHub](https://img.shields.io/github/license/plankanban/planka) ![David (path)](https://img.shields.io/github/package-json/v/plankanban/planka) ![Docker Pulls](https://img.shields.io/docker/pulls/meltyshev/planka) ![GitHub](https://img.shields.io/github/license/plankanban/planka)
@@ -20,9 +20,7 @@
## How to deploy Planka ## How to deploy Planka
There are 2 types of installation: There are many ways to install Planka, [check them out](https://docs.planka.cloud/docs/intro).
- [Without Docker](https://docs.planka.cloud/docs/installl-planka/Debian%20&%20Ubuntu) ([for Windows](https://docs.planka.cloud/docs/installl-planka/Windows))
- [Dockerized](https://docs.planka.cloud/docs/installl-planka/Docker%20Compose)
For configuration, please see the [configuration section](https://docs.planka.cloud/docs/category/configuration). For configuration, please see the [configuration section](https://docs.planka.cloud/docs/category/configuration).
+23
View File
@@ -0,0 +1,23 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
+6
View File
@@ -0,0 +1,6 @@
dependencies:
- name: postgresql
repository: https://charts.bitnami.com/bitnami
version: 12.5.1
digest: sha256:01dfb2d07ab6800b4a5a6c81f20f3377a758124b2b96b891d0cd6b4f64cf783b
generated: "2023-05-15T00:54:48.1308917+01:00"
+31
View File
@@ -0,0 +1,31 @@
apiVersion: v2
name: planka
description: A Helm chart to deploy Planka and it's dependencies.
# A chart can be either an 'application' or a 'library' chart.
#
# Application charts are a collection of templates that can be packaged into versioned archives
# to be deployed.
#
# Library charts provide useful utilities or functions for the chart developer. They're included as
# a dependency of application charts to inject those utilities and functions into the rendering
# pipeline. Library charts do not define any templates and therefore cannot be deployed.
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: 0.1.13
# 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: "1.15.2"
dependencies:
- alias: postgresql
condition: postgresql.enabled
name: postgresql
repository: &bitnami-repo https://charts.bitnami.com/bitnami
version: 12.5.1
+106
View File
@@ -0,0 +1,106 @@
# Planka Helm Chart
[Planka](https://github.com/plankanban/planka) is an OSS alternative to Trello that you can host yourself, and this is a Helm Chart to make it easier to deploy to K8s.
Shoutout to [this issue](https://github.com/plankanban/planka/issues/192) who have been asking for this Helm Chart.
## Issues
By using the Bitnami chart for PostgreSQL, there is an issue where once deployed, if trying to use a different password then it will be ignored as the Persistant Volume (PV) will already exist with the previous password. See warning from Bitnami below:
> **Warning!** Setting a password will be ignored on new installation in the case when previous Posgresql release was deleted through the helm command. In that case, old PVC will have an old password, and setting it through helm won't take effect. Deleting persistent volumes (PVs) will solve the issue. Refer to [issue 2061](https://github.com/bitnami/charts/issues/2061) for more details
If you want to fully uninstall this chart including the data, follow [these steps](https://github.com/bitnami/charts/blob/main/bitnami/postgresql/README.md#uninstalling-the-chart) from the Bitnami Chart's docs.
## Usage
The basic usage of the chart can be found below:
```bash
git clone https://github.com/Chris-Greaves/planka-helm-chart.git
cd planka-helm-chart
helm dependency build
export SECRETKEY=$(openssl rand -hex 64)
helm install planka . --set secretkey=$SECRETKEY \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
--set admin_username="demo"
```
> **NOTE:** The command `openssl rand -hex 64` is needed to create a random hexadecimal key for planka. On Windows you can use Git Bash to run that command.
To access Planka you can port forward using the following command:
```bash
kubectl port-forward $POD_NAME 3000:1337
```
### Accessing Externally
To access Planka externally you can use the following configuration
```bash
# HTTP only
helm install planka . --set secretkey=$SECRETKEY \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
--set admin_username="demo"
--set ingress.enabled=true \
--set ingress.hosts[0].host=planka.example.dev \
# HTTPS
helm install planka . --set secretkey=$SECRETKEY \
--set admin_email="demo@demo.demo" \
--set admin_password="demo" \
--set admin_name="Demo Demo" \
--set admin_username="demo"
--set ingress.enabled=true \
--set ingress.hosts[0].host=planka.example.dev \
--set ingress.tls[0].secretName=planka-tls \
--set ingress.tls[0].hosts[0]=planka.example.dev \
```
or create a values.yaml file like:
```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```
# Admin user
admin_email: "demo@demo.demo" # Do not remove if you want to prevent this user from being edited/deleted
admin_password: "demo"
admin_name: "Demo Demo"
admin_username: "demo"
# Admin user
ingress:
enabled: true
hosts:
- host: planka.example.dev
paths:
- path: /
pathType: ImplementationSpecific
# Needed for HTTPS
tls:
- secretName: planka-tls # existing TLS secret in k8s
hosts:
- planka.example.dev
```
```bash
helm install planka . -f values.yaml
```
### Things to consider if production hosting
If you want to host Planka for more than just playing around with, you might want to do the following things:
- Create a `values.yaml` with your config, as this will make applying upgrades much easier in the future.
- Create your `secretkey` once and store it either in a secure vault, or in your `values.yaml` file so it will be the same for upgrading in the future.
- Specify a password for `postgresql.auth.password` as there have been issues with the postgresql chart generating new passwords locking you out of the data you've already stored. (see [this issue](https://github.com/bitnami/charts/issues/2061))
Any questions or concerns, [raise an issue](https://github.com/Chris-Greaves/planka-helm-chart/issues/new).
+22
View File
@@ -0,0 +1,22 @@
1. Get the application URL by running these commands:
{{- if .Values.ingress.enabled }}
{{- range $host := .Values.ingress.hosts }}
{{- range .paths }}
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
{{- end }}
{{- end }}
{{- else if contains "NodePort" .Values.service.type }}
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "planka.fullname" . }})
export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}")
echo http://$NODE_IP:$NODE_PORT
{{- else if contains "LoadBalancer" .Values.service.type }}
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "planka.fullname" . }}'
export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "planka.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}")
echo http://$SERVICE_IP:{{ .Values.service.port }}
{{- else if contains "ClusterIP" .Values.service.type }}
export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "planka.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}")
export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}")
echo "Visit http://localhost:3000 to use your application"
kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 3000:$CONTAINER_PORT
{{- end }}
+62
View File
@@ -0,0 +1,62 @@
{{/*
Expand the name of the chart.
*/}}
{{- define "planka.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "planka.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "planka.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "planka.labels" -}}
helm.sh/chart: {{ include "planka.chart" . }}
{{ include "planka.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "planka.selectorLabels" -}}
app.kubernetes.io/name: {{ include "planka.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "planka.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "planka.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
+136
View File
@@ -0,0 +1,136 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ include "planka.fullname" . }}
labels:
{{- include "planka.labels" . | nindent 4 }}
spec:
{{- if not .Values.autoscaling.enabled }}
replicas: {{ .Values.replicaCount }}
{{- end }}
selector:
matchLabels:
{{- include "planka.selectorLabels" . | nindent 6 }}
template:
metadata:
{{- with .Values.podAnnotations }}
annotations:
{{- toYaml . | nindent 8 }}
{{- end }}
labels:
{{- include "planka.selectorLabels" . | nindent 8 }}
spec:
{{- with .Values.imagePullSecrets }}
imagePullSecrets:
{{- toYaml . | nindent 8 }}
{{- end }}
serviceAccountName: {{ include "planka.serviceAccountName" . }}
securityContext:
{{- toYaml .Values.podSecurityContext | nindent 8 }}
containers:
- name: {{ .Chart.Name }}
securityContext:
{{- toYaml .Values.securityContext | nindent 12 }}
image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
containerPort: {{ .Values.service.containerPort | default 1337 }}
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
readinessProbe:
httpGet:
path: /
port: http
volumeMounts:
- mountPath: /app/public/user-avatars
subPath: user-avatars
name: planka
- mountPath: /app/public/project-background-images
subPath: project-background-images
name: planka
- mountPath: /app/private/attachments
subPath: attachments
name: planka
resources:
{{- toYaml .Values.resources | nindent 12 }}
env:
- name: DATABASE_URL
valueFrom:
secretKeyRef:
name: planka-postgresql-svcbind-custom-user
key: uri
- name: BASE_URL
{{- if .Values.baseUrl }}
value: {{ .Values.baseUrl }}
{{- else if .Values.ingress.enabled }}
value: {{ printf "https://%s" (first .Values.ingress.hosts).host }}
{{- else }}
value: http://localhost:3000
{{- end }}
- name: SECRET_KEY
value: {{ required "A secret key needs to be generated using 'openssl rand -hex 64' and assigned to secretkey." .Values.secretkey }}
- name: TRUST_PROXY
value: "0"
- name: DEFAULT_ADMIN_EMAIL
value: {{ .Values.admin_email }}
- name: DEFAULT_ADMIN_PASSWORD
value: {{ .Values.admin_password }}
- name: DEFAULT_ADMIN_NAME
value: {{ .Values.admin_name }}
- name: DEFAULT_ADMIN_USERNAME
value: {{ .Values.admin_username }}
{{ range $k, $v := .Values.env }}
- name: {{ $k | quote }}
value: {{ $v | quote }}
{{- end }}
{{- if .Values.oidc.enabled }}
{{- $secretName := default (printf "%s-oidc" (include "planka.fullname" .)) .Values.oidc.existingSecret }}
- name: OIDC_CLIENT_ID
valueFrom:
secretKeyRef:
key: clientId
name: {{ $secretName }}
- name: OIDC_CLIENT_SECRET
valueFrom:
secretKeyRef:
key: clientSecret
name: {{ $secretName }}
- name: OIDC_ISSUER
value: {{ required "issuerUrl is required when configuring OIDC" .Values.oidc.issuerUrl | quote }}
- name: OIDC_SCOPES
value: {{ join " " .Values.oidc.scopes | default "openid profile email" | quote }}
{{- if .Values.oidc.admin.roles }}
- name: OIDC_ADMIN_ROLES
value: {{ join "," .Values.oidc.admin.roles | quote }}
{{- end }}
- name: OIDC_ROLES_ATTRIBUTE
value: {{ .Values.oidc.admin.rolesAttribute | default "groups" | quote }}
{{- if .Values.oidc.admin.ignoreRoles }}
- name: OIDC_IGNORE_ROLES
value: {{ .Values.oidc.admin.ignoreRoles | quote }}
{{- end }}
{{- end }}
{{- with .Values.nodeSelector }}
nodeSelector:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.affinity }}
affinity:
{{- toYaml . | nindent 8 }}
{{- end }}
{{- with .Values.tolerations }}
tolerations:
{{- toYaml . | nindent 8 }}
{{- end }}
volumes:
- name: planka
{{- if .Values.persistence.enabled }}
persistentVolumeClaim:
claimName: {{ .Values.persistence.existingClaim | default (include "planka.fullname" .) }}
{{- else }}
emptyDir: {}
{{- end }}
+28
View File
@@ -0,0 +1,28 @@
{{- if .Values.autoscaling.enabled }}
apiVersion: autoscaling/v2beta1
kind: HorizontalPodAutoscaler
metadata:
name: {{ include "planka.fullname" . }}
labels:
{{- include "planka.labels" . | nindent 4 }}
spec:
scaleTargetRef:
apiVersion: apps/v1
kind: Deployment
name: {{ include "planka.fullname" . }}
minReplicas: {{ .Values.autoscaling.minReplicas }}
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
metrics:
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
- type: Resource
resource:
name: cpu
targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
{{- end }}
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
- type: Resource
resource:
name: memory
targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
{{- end }}
{{- end }}
+61
View File
@@ -0,0 +1,61 @@
{{- if .Values.ingress.enabled -}}
{{- $fullName := include "planka.fullname" . -}}
{{- $svcPort := .Values.service.port -}}
{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }}
{{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }}
{{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}}
{{- end }}
{{- end }}
{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1
{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}}
apiVersion: networking.k8s.io/v1beta1
{{- else -}}
apiVersion: extensions/v1beta1
{{- end }}
kind: Ingress
metadata:
name: {{ $fullName }}
labels:
{{- include "planka.labels" . | nindent 4 }}
{{- with .Values.ingress.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
spec:
{{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }}
ingressClassName: {{ .Values.ingress.className }}
{{- end }}
{{- if .Values.ingress.tls }}
tls:
{{- range .Values.ingress.tls }}
- hosts:
{{- range .hosts }}
- {{ . | quote }}
{{- end }}
secretName: {{ .secretName }}
{{- end }}
{{- end }}
rules:
{{- range .Values.ingress.hosts }}
- host: {{ .host | quote }}
http:
paths:
{{- range .paths }}
- path: {{ .path }}
{{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }}
pathType: {{ .pathType }}
{{- end }}
backend:
{{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }}
service:
name: {{ $fullName }}
port:
number: {{ $svcPort }}
{{- else }}
serviceName: {{ $fullName }}
servicePort: {{ $svcPort }}
{{- end }}
{{- end }}
{{- end }}
{{- end }}
+25
View File
@@ -0,0 +1,25 @@
{{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }}
---
kind: PersistentVolumeClaim
apiVersion: v1
metadata:
name: {{ include "planka.fullname" . }}
labels:
app.kubernetes.io/name: {{ include "planka.name" . }}
helm.sh/chart: {{ include "planka.chart" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
spec:
accessModes:
- {{ .Values.persistence.accessMode }}
resources:
requests:
storage: {{ .Values.persistence.size | quote }}
{{- if .Values.persistence.storageClass }}
{{- if (eq "-" .Values.persistence.storageClass) }}
storageClassName: ""
{{- else }}
storageClassName: "{{ .Values.persistence.storageClass }}"
{{- end }}
{{- end }}
{{- end }}
+17
View File
@@ -0,0 +1,17 @@
{{- if .Values.oidc.enabled }}
{{- if eq (and (not (empty .Values.oidc.clientId)) (not (empty .Values.oidc.clientSecret))) (not (empty .Values.oidc.existingSecret)) -}}
{{- fail "Either specify inline `clientId` and `clientSecret` or refer to them via `existingSecret`" -}}
{{- end }}
{{- if (and (and (not (empty .Values.oidc.clientId)) (not (empty .Values.oidc.clientSecret))) (empty .Values.oidc.existingSecret)) -}}
apiVersion: v1
kind: Secret
metadata:
name: {{ include "planka.fullname" . }}-oidc
labels:
{{- include "planka.labels" . | nindent 4 }}
type: Opaque
data:
clientId: {{ .Values.oidc.clientId | b64enc | quote }}
clientSecret: {{ .Values.oidc.clientSecret | b64enc | quote }}
{{- end }}
{{- end }}
+15
View File
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Service
metadata:
name: {{ include "planka.fullname" . }}
labels:
{{- include "planka.labels" . | nindent 4 }}
spec:
type: {{ .Values.service.type }}
ports:
- port: {{ .Values.service.port }}
targetPort: http
protocol: TCP
name: http
selector:
{{- include "planka.selectorLabels" . | nindent 4 }}
@@ -0,0 +1,12 @@
{{- if .Values.serviceAccount.create -}}
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "planka.serviceAccountName" . }}
labels:
{{- include "planka.labels" . | nindent 4 }}
{{- with .Values.serviceAccount.annotations }}
annotations:
{{- toYaml . | nindent 4 }}
{{- end }}
{{- end }}
@@ -0,0 +1,15 @@
apiVersion: v1
kind: Pod
metadata:
name: "{{ include "planka.fullname" . }}-test-connection"
labels:
{{- include "planka.labels" . | nindent 4 }}
annotations:
"helm.sh/hook": test
spec:
containers:
- name: wget
image: busybox
command: ['wget']
args: ['{{ include "planka.fullname" . }}:{{ .Values.service.port }}']
restartPolicy: Never
+180
View File
@@ -0,0 +1,180 @@
# Default values for planka.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.
replicaCount: 1
image:
repository: ghcr.io/plankanban/planka
pullPolicy: IfNotPresent
# Overrides the image tag whose default is the chart appVersion.
tag: ""
imagePullSecrets: []
nameOverride: ""
fullnameOverride: ""
# Generate a secret using openssl rand -base64 45
secretkey: ""
# Base url for Planka. Will override `ingress.hosts[0].host`
# Defaults to `http://localhost:3000` if ingress is disabled.
baseUrl: ""
serviceAccount:
# Specifies whether a service account should be created
create: true
# Annotations to add to the service account
annotations: {}
# The name of the service account to use.
# If not set and create is true, a name is generated using the fullname template
name: ""
podAnnotations: {}
podSecurityContext: {}
# fsGroup: 2000
securityContext: {}
# capabilities:
# drop:
# - ALL
# readOnlyRootFilesystem: true
# runAsNonRoot: true
# runAsUser: 1000
service:
type: ClusterIP
port: 1337
## @param service.containerPort Planka HTTP container port
## If empty will default to 1337
##
containerPort: 1337
ingress:
enabled: false
className: ""
annotations: {}
# kubernetes.io/ingress.class: nginx
# kubernetes.io/tls-acme: "true"
hosts:
# Used to set planka BASE_URL if no `baseurl` is provided.
- host: planka.local
paths:
- path: /
pathType: ImplementationSpecific
tls: []
# - secretName: planka-tls
# hosts:
# - planka.local
resources: {}
# We usually recommend not to specify default resources and to leave this as a conscious
# choice for the user. This also increases chances charts run on environments with little
# resources, such as Minikube. If you do want to specify resources, uncomment the following
# lines, adjust them as necessary, and remove the curly braces after 'resources:'.
# limits:
# cpu: 100m
# memory: 128Mi
# requests:
# cpu: 100m
# memory: 128Mi
autoscaling:
enabled: false
minReplicas: 1
maxReplicas: 100
targetCPUUtilizationPercentage: 80
# targetMemoryUtilizationPercentage: 80
nodeSelector: {}
tolerations: []
affinity: {}
postgresql:
enabled: true
auth:
database: planka
username: planka
password: ""
postgresPassword: ""
replicationPassword: ""
# existingSecret: planka-postgresql
serviceBindings:
enabled: true
## PVC-based data storage configuration
persistence:
enabled: false
# existingClaim: netbox-data
# storageClass: "-"
accessMode: ReadWriteOnce
size: 10Gi
## OpenID Identity Management configuration
##
## Example:
## ---------------
## oidc:
## enabled: true
## clientId: sxxaAIAxVXlCxTmc1YLHBbQr8NL8MqLI2DUbt42d
## clientSecret: om4RTMRVHRszU7bqxB7RZNkHIzA8e4sGYWxeCwIMYQXPwEBWe4SY5a0wwCe9ltB3zrq5f0dnFnp34cEHD7QSMHsKvV9AiV5Z7eqDraMnv0I8IFivmuV5wovAECAYreSI
## issuerUrl: https://auth.local/application/o/planka/
## admin:
## roles:
## - planka-admin
##
## ---------------
## NOTE: A minimal configuration requires setting `clientId`, `clientSecret` and `issuerUrl`. (plus `admin.roles` for administrators)
## ref: https://docs.planka.cloud/docs/Configuration/OIDC
##
oidc:
## @param oidc.enabled Enable single sign-on (SSO) with OpenID Connect (OIDC)
##
enabled: false
## OIDC credentials
## @param oidc.clientId A string unique to the provider that identifies your app.
## @param oidc.clientSecret A secret string that the provider uses to confirm ownership of a client ID.
##
## NOTE: Either specify inline `clientId` and `clientSecret` or refer to them via `existingSecret`
##
clientId: ""
clientSecret: ""
## @param oidc.existingSecret Name of an existing secret containing OIDC credentials
## NOTE: Must contain key `clientId` and `clientSecret`
## NOTE: When it's set, the `clientId` and `clientSecret` parameters are ignored
##
existingSecret: ""
## @param oidc.issuerUrl The OpenID connect metadata document endpoint
##
issuerUrl: ""
## @param oidc.scopes A list of scopes required for OIDC client.
## If empty will default to `openid`, `profile` and `email`
## NOTE: Planka needs the email and name claims
##
scopes: []
## Admin permissions configuration
admin:
## @param oidc.admin.ignoreRoles If set to true, the admin roles will be ignored.
## It is useful if you want to use OIDC for authentication but not for authorization.
## If empty will default to `false`
##
ignoreRoles: false
## @param oidc.admin.rolesAttribute The name of a custom group claim that you have configured in your OIDC provider
## If empty will default to `groups`
##
rolesAttribute: groups
## @param oidc.admin.roles The names of the admin groups
##
roles: []
# - planka-admin
+1 -1
View File
@@ -1 +1 @@
REACT_APP_VERSION=1.10.3 REACT_APP_VERSION=1.15.2
+3379 -21947
View File
File diff suppressed because it is too large Load Diff
+36 -29
View File
@@ -49,65 +49,72 @@
"**/*.test.js" "**/*.test.js"
] ]
} }
],
"prettier/prettier": [
"error",
{
"endOfLine": "auto"
}
] ]
} }
}, },
"dependencies": { "dependencies": {
"@juggle/resize-observer": "^3.4.0", "@juggle/resize-observer": "^3.4.0",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"date-fns": "^2.29.3", "date-fns": "^2.30.0",
"dequal": "^2.0.3", "dequal": "^2.0.3",
"easymde": "^2.18.0", "easymde": "^2.18.0",
"history": "^5.3.0", "history": "^5.3.0",
"i18next": "^22.0.6", "i18next": "^23.7.6",
"i18next-browser-languagedetector": "^7.0.1", "i18next-browser-languagedetector": "^7.2.0",
"initials": "^3.1.2", "initials": "^3.1.2",
"js-cookie": "^3.0.1", "js-cookie": "^3.0.5",
"jwt-decode": "^3.1.2", "jwt-decode": "^4.0.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"node-sass": "^8.0.0", "nanoid": "^5.0.3",
"photoswipe": "^5.3.3", "node-sass": "^9.0.0",
"photoswipe": "^5.4.2",
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"react": "^18.2.0", "react": "^18.2.0",
"react-app-rewired": "^2.2.1", "react-app-rewired": "^2.2.1",
"react-beautiful-dnd": "^13.1.1", "react-beautiful-dnd": "^13.1.1",
"react-datepicker": "^4.8.0", "react-datepicker": "^4.21.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-i18next": "^12.0.0", "react-i18next": "^13.5.0",
"react-input-mask": "^2.0.4", "react-input-mask": "^2.0.4",
"react-markdown": "^8.0.3", "react-markdown": "^8.0.7",
"react-photoswipe-gallery": "^2.2.2", "react-photoswipe-gallery": "^2.2.7",
"react-redux": "^8.0.5", "react-redux": "^8.1.3",
"react-router-dom": "^6.4.3", "react-router-dom": "^6.19.0",
"react-scripts": "5.0.1", "react-scripts": "5.0.1",
"react-simplemde-editor": "^5.2.0", "react-simplemde-editor": "^5.2.0",
"react-textarea-autosize": "^8.4.0", "react-textarea-autosize": "^8.5.3",
"redux": "^4.2.0", "redux": "^4.2.1",
"redux-logger": "^3.0.6", "redux-logger": "^3.0.6",
"redux-orm": "^0.16.2", "redux-orm": "^0.16.2",
"redux-saga": "^1.2.1", "redux-saga": "^1.2.3",
"remark-breaks": "^3.0.2", "remark-breaks": "^4.0.0",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"reselect": "^4.1.7", "reselect": "^4.1.8",
"sails.io.js": "^1.2.1", "sails.io.js": "^1.2.1",
"semantic-ui-react": "^2.1.3", "semantic-ui-react": "^2.1.4",
"socket.io-client": "^2.5.0", "socket.io-client": "^2.5.0",
"validator": "^13.7.0", "validator": "^13.11.0",
"whatwg-fetch": "^3.6.2", "whatwg-fetch": "^3.6.19",
"zxcvbn": "^4.4.2" "zxcvbn": "^4.4.2"
}, },
"devDependencies": { "devDependencies": {
"@testing-library/jest-dom": "^5.16.5", "@testing-library/jest-dom": "^6.1.4",
"@testing-library/react": "^13.4.0", "@testing-library/react": "^14.1.0",
"@testing-library/user-event": "^13.5.0", "@testing-library/user-event": "^14.5.1",
"babel-preset-airbnb": "^5.0.0", "babel-preset-airbnb": "^5.0.0",
"chai": "^4.3.7", "chai": "^4.3.10",
"eslint": "^8.28.0", "eslint": "^8.53.0",
"eslint-config-airbnb": "^19.0.4", "eslint-config-airbnb": "^19.0.4",
"eslint-plugin-import": "^2.26.0", "eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.31.11", "eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-hooks": "^4.6.0",
"react-test-renderer": "^18.2.0" "react-test-renderer": "^18.2.0"
} }
+8
View File
@@ -39,6 +39,14 @@ const initializeCore = (
}, },
}); });
// TODO: with success?
initializeCore.fetchConfig = (config) => ({
type: ActionTypes.CORE_INITIALIZE__CONFIG_FETCH,
payload: {
config,
},
});
const logout = () => ({ const logout = () => ({
type: ActionTypes.LOGOUT, type: ActionTypes.LOGOUT,
payload: {}, payload: {},
+28
View File
@@ -1,5 +1,12 @@
import ActionTypes from '../constants/ActionTypes'; import ActionTypes from '../constants/ActionTypes';
const initializeLogin = (config) => ({
type: ActionTypes.LOGIN_INITIALIZE,
payload: {
config,
},
});
const authenticate = (data) => ({ const authenticate = (data) => ({
type: ActionTypes.AUTHENTICATE, type: ActionTypes.AUTHENTICATE,
payload: { payload: {
@@ -21,12 +28,33 @@ authenticate.failure = (error) => ({
}, },
}); });
const authenticateUsingOidc = () => ({
type: ActionTypes.USING_OIDC_AUTHENTICATE,
payload: {},
});
authenticateUsingOidc.success = (accessToken) => ({
type: ActionTypes.USING_OIDC_AUTHENTICATE__SUCCESS,
payload: {
accessToken,
},
});
authenticateUsingOidc.failure = (error) => ({
type: ActionTypes.USING_OIDC_AUTHENTICATE__FAILURE,
payload: {
error,
},
});
const clearAuthenticateError = () => ({ const clearAuthenticateError = () => ({
type: ActionTypes.AUTHENTICATE_ERROR_CLEAR, type: ActionTypes.AUTHENTICATE_ERROR_CLEAR,
payload: {}, payload: {},
}); });
export default { export default {
initializeLogin,
authenticate, authenticate,
authenticateUsingOidc,
clearAuthenticateError, clearAuthenticateError,
}; };
+4
View File
@@ -5,10 +5,14 @@ import socket from './socket';
const createAccessToken = (data, headers) => http.post('/access-tokens', data, headers); const createAccessToken = (data, headers) => http.post('/access-tokens', data, headers);
const exchangeForAccessTokenUsingOidc = (data, headers) =>
http.post('/access-tokens/exchange-using-oidc', data, headers);
const deleteCurrentAccessToken = (headers) => const deleteCurrentAccessToken = (headers) =>
socket.delete('/access-tokens/me', undefined, headers); socket.delete('/access-tokens/me', undefined, headers);
export default { export default {
createAccessToken, createAccessToken,
exchangeForAccessTokenUsingOidc,
deleteCurrentAccessToken, deleteCurrentAccessToken,
}; };
+5
View File
@@ -1,4 +1,5 @@
import socket from './socket'; import socket from './socket';
import { transformUser } from './users';
/* Transformers */ /* Transformers */
@@ -13,6 +14,10 @@ const getActivities = (cardId, data, headers) =>
socket.get(`/cards/${cardId}/actions`, data, headers).then((body) => ({ socket.get(`/cards/${cardId}/actions`, data, headers).then((body) => ({
...body, ...body,
items: body.items.map(transformActivity), items: body.items.map(transformActivity),
included: {
...body.included,
users: body.included.users.map(transformUser),
},
})); }));
/* Event handlers */ /* Event handlers */
+35 -3
View File
@@ -1,18 +1,50 @@
import socket from './socket'; import socket from './socket';
/* Transformers */
export const transformBoardMembership = (boardMembership) => ({
...boardMembership,
createdAt: new Date(boardMembership.createdAt),
});
/* Actions */ /* Actions */
const createBoardMembership = (boardId, data, headers) => const createBoardMembership = (boardId, data, headers) =>
socket.post(`/boards/${boardId}/memberships`, data, headers); socket.post(`/boards/${boardId}/memberships`, data, headers).then((body) => ({
...body,
item: transformBoardMembership(body.item),
}));
const updateBoardMembership = (id, data, headers) => const updateBoardMembership = (id, data, headers) =>
socket.patch(`/board-memberships/${id}`, data, headers); socket.patch(`/board-memberships/${id}`, data, headers).then((body) => ({
...body,
item: transformBoardMembership(body.item),
}));
const deleteBoardMembership = (id, headers) => const deleteBoardMembership = (id, headers) =>
socket.delete(`/board-memberships/${id}`, undefined, headers); socket.delete(`/board-memberships/${id}`, undefined, headers).then((body) => ({
...body,
item: transformBoardMembership(body.item),
}));
/* Event handlers */
const makeHandleBoardMembershipCreate = (next) => (body) => {
next({
...body,
item: transformBoardMembership(body.item),
});
};
const makeHandleBoardMembershipUpdate = makeHandleBoardMembershipCreate;
const makeHandleBoardMembershipDelete = makeHandleBoardMembershipCreate;
export default { export default {
createBoardMembership, createBoardMembership,
updateBoardMembership, updateBoardMembership,
deleteBoardMembership, deleteBoardMembership,
makeHandleBoardMembershipCreate,
makeHandleBoardMembershipUpdate,
makeHandleBoardMembershipDelete,
}; };
+11 -1
View File
@@ -1,12 +1,20 @@
import socket from './socket'; import socket from './socket';
import http from './http'; import http from './http';
import { transformUser } from './users';
import { transformBoardMembership } from './board-memberships';
import { transformCard } from './cards'; import { transformCard } from './cards';
import { transformAttachment } from './attachments'; import { transformAttachment } from './attachments';
/* Actions */ /* Actions */
const createBoard = (projectId, data, headers) => const createBoard = (projectId, data, headers) =>
socket.post(`/projects/${projectId}/boards`, data, headers); socket.post(`/projects/${projectId}/boards`, data, headers).then((body) => ({
...body,
included: {
...body.included,
boardMemberships: body.included.boardMemberships.map(transformBoardMembership),
},
}));
const createBoardWithImport = (projectId, data, requestId, headers) => const createBoardWithImport = (projectId, data, requestId, headers) =>
http.post(`/projects/${projectId}/boards?requestId=${requestId}`, data, headers); http.post(`/projects/${projectId}/boards?requestId=${requestId}`, data, headers);
@@ -18,6 +26,8 @@ const getBoard = (id, subscribe, headers) =>
...body, ...body,
included: { included: {
...body.included, ...body.included,
users: body.included.users.map(transformUser),
boardMemberships: body.included.boardMemberships.map(transformBoardMembership),
cards: body.included.cards.map(transformCard), cards: body.included.cards.map(transformCard),
attachments: body.included.attachments.map(transformAttachment), attachments: body.included.attachments.map(transformAttachment),
}, },
+7 -5
View File
@@ -5,13 +5,15 @@ import Config from '../constants/Config';
const http = {}; const http = {};
// TODO: add all methods // TODO: add all methods
['POST'].forEach((method) => { ['GET', 'POST'].forEach((method) => {
http[method.toLowerCase()] = (url, data, headers) => { http[method.toLowerCase()] = (url, data, headers) => {
const formData = Object.keys(data).reduce((result, key) => { const formData =
result.append(key, data[key]); data &&
Object.keys(data).reduce((result, key) => {
result.append(key, data[key]);
return result; return result;
}, new FormData()); }, new FormData());
return fetch(`${Config.SERVER_BASE_URL}/api${url}`, { return fetch(`${Config.SERVER_BASE_URL}/api${url}`, {
method, method,
+2
View File
@@ -1,5 +1,6 @@
import http from './http'; import http from './http';
import socket from './socket'; import socket from './socket';
import root from './root';
import accessTokens from './access-tokens'; import accessTokens from './access-tokens';
import users from './users'; import users from './users';
import projects from './projects'; import projects from './projects';
@@ -20,6 +21,7 @@ import notifications from './notifications';
export { http, socket }; export { http, socket };
export default { export default {
...root,
...accessTokens, ...accessTokens,
...users, ...users,
...projects, ...projects,
+3
View File
@@ -1,6 +1,7 @@
import omit from 'lodash/omit'; import omit from 'lodash/omit';
import socket from './socket'; import socket from './socket';
import { transformUser } from './users';
import { transformCard } from './cards'; import { transformCard } from './cards';
import { transformActivity } from './activities'; import { transformActivity } from './activities';
@@ -19,6 +20,7 @@ const getNotifications = (headers) =>
items: body.items.map(transformNotification), items: body.items.map(transformNotification),
included: { included: {
...omit(body.included, 'actions'), ...omit(body.included, 'actions'),
users: body.included.users.map(transformUser),
cards: body.included.cards.map(transformCard), cards: body.included.cards.map(transformCard),
activities: body.included.actions.map(transformActivity), activities: body.included.actions.map(transformActivity),
}, },
@@ -30,6 +32,7 @@ const getNotification = (id, headers) =>
item: transformNotification(body.item), item: transformNotification(body.item),
included: { included: {
...omit(body.included, 'actions'), ...omit(body.included, 'actions'),
users: body.included.users.map(transformUser),
cards: body.included.cards.map(transformCard), cards: body.included.cards.map(transformCard),
activities: body.included.actions.map(transformActivity), activities: body.included.actions.map(transformActivity),
}, },
+28 -2
View File
@@ -1,14 +1,40 @@
import socket from './socket'; import socket from './socket';
/* Transformers */
export const transformProjectManager = (projectManager) => ({
...projectManager,
createdAt: new Date(projectManager.createdAt),
});
/* Actions */ /* Actions */
const createProjectManager = (projectId, data, headers) => const createProjectManager = (projectId, data, headers) =>
socket.post(`/projects/${projectId}/managers`, data, headers); socket.post(`/projects/${projectId}/managers`, data, headers).then((body) => ({
...body,
item: transformProjectManager(body.item),
}));
const deleteProjectManager = (id, headers) => const deleteProjectManager = (id, headers) =>
socket.delete(`/project-managers/${id}`, undefined, headers); socket.delete(`/project-managers/${id}`, undefined, headers).then((body) => ({
...body,
item: transformProjectManager(body.item),
}));
/* Event handlers */
const makeHandleProjectManagerCreate = (next) => (body) => {
next({
...body,
item: transformProjectManager(body.item),
});
};
const makeHandleProjectManagerDelete = makeHandleProjectManagerCreate;
export default { export default {
createProjectManager, createProjectManager,
deleteProjectManager, deleteProjectManager,
makeHandleProjectManagerCreate,
makeHandleProjectManagerDelete,
}; };
+31 -3
View File
@@ -1,13 +1,41 @@
import http from './http'; import http from './http';
import socket from './socket'; import socket from './socket';
import { transformUser } from './users';
import { transformProjectManager } from './project-managers';
import { transformBoardMembership } from './board-memberships';
/* Actions */ /* Actions */
const getProjects = (headers) => socket.get('/projects', undefined, headers); const getProjects = (headers) =>
socket.get('/projects', undefined, headers).then((body) => ({
...body,
included: {
...body.included,
users: body.included.users.map(transformUser),
projectManagers: body.included.projectManagers.map(transformProjectManager),
boardMemberships: body.included.boardMemberships.map(transformBoardMembership),
},
}));
const createProject = (data, headers) => socket.post('/projects', data, headers); const createProject = (data, headers) =>
socket.post('/projects', data, headers).then((body) => ({
...body,
included: {
...body.included,
projectManagers: body.included.projectManagers.map(transformProjectManager),
},
}));
const getProject = (id, headers) => socket.get(`/projects/${id}`, undefined, headers); const getProject = (id, headers) =>
socket.get(`/projects/${id}`, undefined, headers).then((body) => ({
...body,
included: {
...body.included,
users: body.included.users.map(transformUser),
projectManagers: body.included.projectManagers.map(transformProjectManager),
boardMemberships: body.included.boardMemberships.map(transformBoardMembership),
},
}));
const updateProject = (id, data, headers) => socket.patch(`/projects/${id}`, data, headers); const updateProject = (id, data, headers) => socket.patch(`/projects/${id}`, data, headers);
+9
View File
@@ -0,0 +1,9 @@
import http from './http';
/* Actions */
const getConfig = (headers) => http.get('/config', undefined, headers);
export default {
getConfig,
};
+70 -10
View File
@@ -1,30 +1,87 @@
import http from './http'; import http from './http';
import socket from './socket'; import socket from './socket';
/* Transformers */
export const transformUser = (user) => ({
...user,
createdAt: new Date(user.createdAt),
});
/* Actions */ /* Actions */
const getUsers = (headers) => socket.get('/users', undefined, headers); const getUsers = (headers) =>
socket.get('/users', undefined, headers).then((body) => ({
...body,
items: body.items.map(transformUser),
}));
const createUser = (data, headers) => socket.post('/users', data, headers); const createUser = (data, headers) =>
socket.post('/users', data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const getUser = (id, headers) => socket.get(`/users/${id}`, undefined, headers); const getUser = (id, headers) =>
socket.get(`/users/${id}`, undefined, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const getCurrentUser = (subscribe, headers) => const getCurrentUser = (subscribe, headers) =>
socket.get(`/users/me${subscribe ? '?subscribe=true' : ''}`, undefined, headers); socket.get(`/users/me${subscribe ? '?subscribe=true' : ''}`, undefined, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const updateUser = (id, data, headers) => socket.patch(`/users/${id}`, data, headers); const updateUser = (id, data, headers) =>
socket.patch(`/users/${id}`, data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const updateUserEmail = (id, data, headers) => socket.patch(`/users/${id}/email`, data, headers); const updateUserEmail = (id, data, headers) =>
socket.patch(`/users/${id}/email`, data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const updateUserPassword = (id, data, headers) => const updateUserPassword = (id, data, headers) =>
socket.patch(`/users/${id}/password`, data, headers); socket.patch(`/users/${id}/password`, data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const updateUserUsername = (id, data, headers) => const updateUserUsername = (id, data, headers) =>
socket.patch(`/users/${id}/username`, data, headers); socket.patch(`/users/${id}/username`, data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const updateUserAvatar = (id, data, headers) => http.post(`/users/${id}/avatar`, data, headers); const updateUserAvatar = (id, data, headers) =>
http.post(`/users/${id}/avatar`, data, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
const deleteUser = (id, headers) => socket.delete(`/users/${id}`, undefined, headers); const deleteUser = (id, headers) =>
socket.delete(`/users/${id}`, undefined, headers).then((body) => ({
...body,
item: transformUser(body.item),
}));
/* Event handlers */
const makeHandleUserCreate = (next) => (body) => {
next({
...body,
item: transformUser(body.item),
});
};
const makeHandleUserUpdate = makeHandleUserCreate;
const makeHandleUserDelete = makeHandleUserCreate;
export default { export default {
getUsers, getUsers,
@@ -37,4 +94,7 @@ export default {
updateUserUsername, updateUserUsername,
updateUserAvatar, updateUserAvatar,
deleteUser, deleteUser,
makeHandleUserCreate,
makeHandleUserUpdate,
makeHandleUserDelete,
}; };
@@ -5,7 +5,7 @@ import { useTranslation } from 'react-i18next';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { Button, Form, TextArea } from 'semantic-ui-react'; import { Button, Form, TextArea } from 'semantic-ui-react';
import { useClosableForm, useForm } from '../../../hooks'; import { useForm } from '../../../hooks';
import styles from './CommentEdit.module.scss'; import styles from './CommentEdit.module.scss';
@@ -35,12 +35,7 @@ const CommentEdit = React.forwardRef(({ children, defaultData, onUpdate }, ref)
text: data.text.trim(), text: data.text.trim(),
}; };
if (!cleanData.text) { if (cleanData.text && !dequal(cleanData, defaultData)) {
textField.current.ref.current.select();
return;
}
if (!dequal(cleanData, defaultData)) {
onUpdate(cleanData); onUpdate(cleanData);
} }
@@ -65,10 +60,9 @@ const CommentEdit = React.forwardRef(({ children, defaultData, onUpdate }, ref)
[submit], [submit],
); );
const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( const handleFieldBlur = useCallback(() => {
close, submit();
isOpened, }, [submit]);
);
const handleSubmit = useCallback(() => { const handleSubmit = useCallback(() => {
submit(); submit();
@@ -99,13 +93,7 @@ const CommentEdit = React.forwardRef(({ children, defaultData, onUpdate }, ref)
onBlur={handleFieldBlur} onBlur={handleFieldBlur}
/> />
<div className={styles.controls}> <div className={styles.controls}>
{/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} <Button positive content={t('action.save')} />
<Button
positive
content={t('action.save')}
onMouseOver={handleControlMouseOver}
onMouseOut={handleControlMouseOut}
/>
</div> </div>
</Form> </Form>
); );
@@ -217,6 +217,7 @@ const CardModal = React.memo(
onUserSelect={onUserAdd} onUserSelect={onUserAdd}
onUserDeselect={onUserRemove} onUserDeselect={onUserRemove}
> >
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<button <button
type="button" type="button"
className={classNames(styles.attachment, styles.dueDate)} className={classNames(styles.attachment, styles.dueDate)}
@@ -266,6 +267,7 @@ const CardModal = React.memo(
onMove={onLabelMove} onMove={onLabelMove}
onDelete={onLabelDelete} onDelete={onLabelDelete}
> >
{/* eslint-disable-next-line jsx-a11y/control-has-associated-label */}
<button <button
type="button" type="button"
className={classNames(styles.attachment, styles.dueDate)} className={classNames(styles.attachment, styles.dueDate)}
@@ -314,10 +316,11 @@ const CardModal = React.memo(
)} )}
</span> </span>
{canEdit && ( {canEdit && (
// eslint-disable-next-line jsx-a11y/control-has-associated-label
<button <button
onClick={handleToggleStopwatchClick}
type="button" type="button"
className={classNames(styles.attachment, styles.dueDate)} className={classNames(styles.attachment, styles.dueDate)}
onClick={handleToggleStopwatchClick}
> >
<Icon <Icon
name={stopwatch.startedAt ? 'pause' : 'play'} name={stopwatch.startedAt ? 'pause' : 'play'}
@@ -100,7 +100,6 @@ const DescriptionEdit = React.forwardRef(({ children, defaultValue, onUpdate },
onChange={setValue} onChange={setValue}
/> />
<div className={styles.controls}> <div className={styles.controls}>
{/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */}
<Button positive content={t('action.save')} /> <Button positive content={t('action.save')} />
</div> </div>
</Form> </Form>
@@ -4,7 +4,7 @@ import { useTranslation } from 'react-i18next';
import TextareaAutosize from 'react-textarea-autosize'; import TextareaAutosize from 'react-textarea-autosize';
import { Button, Form, TextArea } from 'semantic-ui-react'; import { Button, Form, TextArea } from 'semantic-ui-react';
import { useClosableForm, useField } from '../../../hooks'; import { useField } from '../../../hooks';
import styles from './NameEdit.module.scss'; import styles from './NameEdit.module.scss';
@@ -28,12 +28,7 @@ const NameEdit = React.forwardRef(({ children, defaultValue, onUpdate }, ref) =>
const submit = useCallback(() => { const submit = useCallback(() => {
const cleanValue = value.trim(); const cleanValue = value.trim();
if (!cleanValue) { if (cleanValue && cleanValue !== defaultValue) {
field.current.ref.current.select();
return;
}
if (cleanValue !== defaultValue) {
onUpdate(cleanValue); onUpdate(cleanValue);
} }
@@ -60,10 +55,9 @@ const NameEdit = React.forwardRef(({ children, defaultValue, onUpdate }, ref) =>
[submit], [submit],
); );
const [handleFieldBlur, handleControlMouseOver, handleControlMouseOut] = useClosableForm( const handleFieldBlur = useCallback(() => {
close, submit();
isOpened, }, [submit]);
);
const handleSubmit = useCallback(() => { const handleSubmit = useCallback(() => {
submit(); submit();
@@ -93,13 +87,7 @@ const NameEdit = React.forwardRef(({ children, defaultValue, onUpdate }, ref) =>
onBlur={handleFieldBlur} onBlur={handleFieldBlur}
/> />
<div className={styles.controls}> <div className={styles.controls}>
{/* eslint-disable-next-line jsx-a11y/mouse-events-have-key-events */} <Button positive content={t('action.save')} />
<Button
positive
content={t('action.save')}
onMouseOver={handleControlMouseOver}
onMouseOut={handleControlMouseOut}
/>
</div> </div>
</Form> </Form>
); );
@@ -48,14 +48,21 @@ const Tasks = React.memo(({ items, canEdit, onCreate, onUpdate, onMove, onDelete
return ( return (
<> <>
{items.length > 0 && ( {items.length > 0 && (
<Progress <>
autoSuccess <span className={styles.progressWrapper}>
value={completedItems.length} <Progress
total={items.length} autoSuccess
color="blue" value={completedItems.length}
size="tiny" total={items.length}
className={styles.progress} color="blue"
/> size="tiny"
className={styles.progress}
/>
</span>
<span className={styles.count}>
{completedItems.length}/{items.length}
</span>
</>
)} )}
<DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}> <DragDropContext onDragStart={handleDragStart} onDragEnd={handleDragEnd}>
<Droppable droppableId="tasks" type={DroppableTypes.TASK}> <Droppable droppableId="tasks" type={DroppableTypes.TASK}>
@@ -3,6 +3,23 @@
margin: 0 0 16px; margin: 0 0 16px;
} }
.progressWrapper {
display: inline-block;
padding: 3px 0;
vertical-align: top;
width: calc(100% - 50px);
}
.count {
color: #8c8c8c;
display: inline-block;
font-size: 14px;
line-height: 14px;
text-align: right;
vertical-align: top;
width: 50px;
}
.taskButton { .taskButton {
background: transparent; background: transparent;
border: none; border: none;
+10 -9
View File
@@ -2,7 +2,7 @@ import React, { useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { Icon, Menu } from 'semantic-ui-react'; import { Button, Icon, Menu } from 'semantic-ui-react';
import { usePopup } from '../../lib/popup'; import { usePopup } from '../../lib/popup';
import Paths from '../../constants/Paths'; import Paths from '../../constants/Paths';
@@ -55,15 +55,16 @@ const Header = React.memo(
> >
<Icon fitted name="arrow left" /> <Icon fitted name="arrow left" />
</Menu.Item> </Menu.Item>
<Menu.Item <Menu.Item className={classNames(styles.item, styles.title)}>
className={classNames(
styles.item,
canEditProject && styles.itemHoverable,
styles.title,
)}
onClick={handleProjectSettingsClick}
>
{project.name} {project.name}
{canEditProject && (
<Button
className={classNames(styles.editButton, styles.target)}
onClick={handleProjectSettingsClick}
>
<Icon fitted name="pencil" size="small" />
</Button>
)}
</Menu.Item> </Menu.Item>
</Menu.Menu> </Menu.Menu>
)} )}
@@ -1,4 +1,20 @@
:global(#app) { :global(#app) {
.editButton {
background: transparent;
box-shadow: none;
color: #fff;
font-size: 15px;
line-height: 34px;
margin-left: 8px;
opacity: 0;
padding: 0;
width: 34px;
&:hover {
background: rgba(255, 255, 255, 0.08);
}
}
.item { .item {
cursor: auto; cursor: auto;
user-select: auto; user-select: auto;
@@ -11,6 +27,10 @@
&:hover { &:hover {
background: transparent; background: transparent;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
.target {
opacity: 1;
}
} }
} }
+43 -4
View File
@@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import classNames from 'classnames'; import classNames from 'classnames';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
import { Form, Grid, Header, Message } from 'semantic-ui-react'; import { Button, Form, Grid, Header, Message } from 'semantic-ui-react';
import { useDidUpdate, usePrevious, useToggle } from '../../lib/hooks'; import { useDidUpdate, usePrevious, useToggle } from '../../lib/hooks';
import { Input } from '../../lib/custom-ui'; import { Input } from '../../lib/custom-ui';
@@ -28,6 +28,21 @@ const createMessage = (error) => {
type: 'error', type: 'error',
content: 'common.invalidPassword', content: 'common.invalidPassword',
}; };
case 'Use single sign-on':
return {
type: 'error',
content: 'common.useSingleSignOn',
};
case 'Email already in use':
return {
type: 'error',
content: 'common.emailAlreadyInUse',
};
case 'Username already in use':
return {
type: 'error',
content: 'common.usernameAlreadyInUse',
};
case 'Failed to fetch': case 'Failed to fetch':
return { return {
type: 'warning', type: 'warning',
@@ -47,7 +62,16 @@ const createMessage = (error) => {
}; };
const Login = React.memo( const Login = React.memo(
({ defaultData, isSubmitting, error, onAuthenticate, onMessageDismiss }) => { ({
defaultData,
isSubmitting,
isSubmittingUsingOidc,
error,
withOidc,
onAuthenticate,
onAuthenticateUsingOidc,
onMessageDismiss,
}) => {
const [t] = useTranslation(); const [t] = useTranslation();
const wasSubmitting = usePrevious(isSubmitting); const wasSubmitting = usePrevious(isSubmitting);
@@ -168,9 +192,19 @@ const Login = React.memo(
content={t('action.logIn')} content={t('action.logIn')}
floated="right" floated="right"
loading={isSubmitting} loading={isSubmitting}
disabled={isSubmitting} disabled={isSubmitting || isSubmittingUsingOidc}
/> />
</Form> </Form>
{withOidc && (
<Button
type="button"
loading={isSubmittingUsingOidc}
disabled={isSubmitting || isSubmittingUsingOidc}
onClick={onAuthenticateUsingOidc}
>
{t('action.logInWithSSO')}
</Button>
)}
</div> </div>
</div> </div>
</Grid.Column> </Grid.Column>
@@ -201,10 +235,15 @@ const Login = React.memo(
); );
Login.propTypes = { Login.propTypes = {
defaultData: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types /* eslint-disable react/forbid-prop-types */
defaultData: PropTypes.object.isRequired,
/* eslint-enable react/forbid-prop-types */
isSubmitting: PropTypes.bool.isRequired, isSubmitting: PropTypes.bool.isRequired,
isSubmittingUsingOidc: PropTypes.bool.isRequired,
error: PropTypes.object, // eslint-disable-line react/forbid-prop-types error: PropTypes.object, // eslint-disable-line react/forbid-prop-types
withOidc: PropTypes.bool.isRequired,
onAuthenticate: PropTypes.func.isRequired, onAuthenticate: PropTypes.func.isRequired,
onAuthenticateUsingOidc: PropTypes.func.isRequired,
onMessageDismiss: PropTypes.func.isRequired, onMessageDismiss: PropTypes.func.isRequired,
}; };
+19
View File
@@ -0,0 +1,19 @@
import React from 'react';
import PropTypes from 'prop-types';
import { Loader } from 'semantic-ui-react';
import LoginContainer from '../containers/LoginContainer';
const LoginWrapper = React.memo(({ isInitializing }) => {
if (isInitializing) {
return <Loader active size="massive" />;
}
return <LoginContainer />;
});
LoginWrapper.propTypes = {
isInitializing: PropTypes.bool.isRequired,
};
export default LoginWrapper;
+3 -3
View File
@@ -5,7 +5,7 @@ import { Route, Routes } from 'react-router-dom';
import { ReduxRouter } from '../lib/redux-router'; import { ReduxRouter } from '../lib/redux-router';
import Paths from '../constants/Paths'; import Paths from '../constants/Paths';
import LoginContainer from '../containers/LoginContainer'; import LoginWrapperContainer from '../containers/LoginWrapperContainer';
import CoreContainer from '../containers/CoreContainer'; import CoreContainer from '../containers/CoreContainer';
import NotFound from './NotFound'; import NotFound from './NotFound';
@@ -13,7 +13,6 @@ import 'react-datepicker/dist/react-datepicker.css';
import 'photoswipe/dist/photoswipe.css'; import 'photoswipe/dist/photoswipe.css';
import 'easymde/dist/easymde.min.css'; import 'easymde/dist/easymde.min.css';
import '../lib/custom-ui/styles.css'; import '../lib/custom-ui/styles.css';
import '../styles.module.scss'; import '../styles.module.scss';
function Root({ store, history }) { function Root({ store, history }) {
@@ -21,7 +20,8 @@ function Root({ store, history }) {
<Provider store={store}> <Provider store={store}>
<ReduxRouter history={history}> <ReduxRouter history={history}>
<Routes> <Routes>
<Route path={Paths.LOGIN} element={<LoginContainer />} /> <Route path={Paths.LOGIN} element={<LoginWrapperContainer />} />
<Route path={Paths.OIDC_CALLBACK} element={<LoginWrapperContainer />} />
<Route path={Paths.ROOT} element={<CoreContainer />} /> <Route path={Paths.ROOT} element={<CoreContainer />} />
<Route path={Paths.PROJECTS} element={<CoreContainer />} /> <Route path={Paths.PROJECTS} element={<CoreContainer />} />
<Route path={Paths.BOARDS} element={<CoreContainer />} /> <Route path={Paths.BOARDS} element={<CoreContainer />} />
@@ -1,4 +1,5 @@
import { dequal } from 'dequal'; import { dequal } from 'dequal';
import omit from 'lodash/omit';
import pickBy from 'lodash/pickBy'; import pickBy from 'lodash/pickBy';
import React, { useCallback, useMemo, useRef } from 'react'; import React, { useCallback, useMemo, useRef } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
@@ -9,7 +10,7 @@ import { useForm } from '../../hooks';
import styles from './UserInformationEdit.module.scss'; import styles from './UserInformationEdit.module.scss';
const UserInformationEdit = React.memo(({ defaultData, onUpdate }) => { const UserInformationEdit = React.memo(({ defaultData, isNameEditable, onUpdate }) => {
const [t] = useTranslation(); const [t] = useTranslation();
const [data, handleFieldChange] = useForm(() => ({ const [data, handleFieldChange] = useForm(() => ({
@@ -32,13 +33,17 @@ const UserInformationEdit = React.memo(({ defaultData, onUpdate }) => {
const nameField = useRef(null); const nameField = useRef(null);
const handleSubmit = useCallback(() => { const handleSubmit = useCallback(() => {
if (!cleanData.name) { if (isNameEditable) {
nameField.current.select(); if (!cleanData.name) {
return; nameField.current.select();
} return;
}
onUpdate(cleanData); onUpdate(cleanData);
}, [onUpdate, cleanData]); } else {
onUpdate(omit(cleanData, 'name'));
}
}, [isNameEditable, onUpdate, cleanData]);
return ( return (
<Form onSubmit={handleSubmit}> <Form onSubmit={handleSubmit}>
@@ -48,6 +53,7 @@ const UserInformationEdit = React.memo(({ defaultData, onUpdate }) => {
ref={nameField} ref={nameField}
name="name" name="name"
value={data.name} value={data.name}
disabled={!isNameEditable}
className={styles.field} className={styles.field}
onChange={handleFieldChange} onChange={handleFieldChange}
/> />
@@ -74,6 +80,7 @@ const UserInformationEdit = React.memo(({ defaultData, onUpdate }) => {
UserInformationEdit.propTypes = { UserInformationEdit.propTypes = {
defaultData: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types defaultData: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
isNameEditable: PropTypes.bool.isRequired,
onUpdate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired,
}; };
@@ -5,33 +5,40 @@ import { Popup } from '../lib/custom-ui';
import UserInformationEdit from './UserInformationEdit'; import UserInformationEdit from './UserInformationEdit';
const UserInformationEditStep = React.memo(({ defaultData, onUpdate, onBack, onClose }) => { const UserInformationEditStep = React.memo(
const [t] = useTranslation(); ({ defaultData, isNameEditable, onUpdate, onBack, onClose }) => {
const [t] = useTranslation();
const handleUpdate = useCallback( const handleUpdate = useCallback(
(data) => { (data) => {
onUpdate(data); onUpdate(data);
onClose(); onClose();
}, },
[onUpdate, onClose], [onUpdate, onClose],
); );
return ( return (
<> <>
<Popup.Header onBack={onBack}> <Popup.Header onBack={onBack}>
{t('common.editInformation', { {t('common.editInformation', {
context: 'title', context: 'title',
})} })}
</Popup.Header> </Popup.Header>
<Popup.Content> <Popup.Content>
<UserInformationEdit defaultData={defaultData} onUpdate={handleUpdate} /> <UserInformationEdit
</Popup.Content> defaultData={defaultData}
</> isNameEditable={isNameEditable}
); onUpdate={handleUpdate}
}); />
</Popup.Content>
</>
);
},
);
UserInformationEditStep.propTypes = { UserInformationEditStep.propTypes = {
defaultData: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types defaultData: PropTypes.object.isRequired, // eslint-disable-line react/forbid-prop-types
isNameEditable: PropTypes.bool.isRequired,
onUpdate: PropTypes.func.isRequired, onUpdate: PropTypes.func.isRequired,
onBack: PropTypes.func, onBack: PropTypes.func,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
@@ -23,6 +23,7 @@ const AccountPane = React.memo(
phone, phone,
organization, organization,
language, language,
isLocked,
isAvatarUpdating, isAvatarUpdating,
usernameUpdateForm, usernameUpdateForm,
emailUpdateForm, emailUpdateForm,
@@ -74,6 +75,7 @@ const AccountPane = React.memo(
phone, phone,
organization, organization,
}} }}
isNameEditable={!isLocked}
onUpdate={onUpdate} onUpdate={onUpdate}
/> />
<Divider horizontal section> <Divider horizontal section>
@@ -102,63 +104,67 @@ const AccountPane = React.memo(
value={language || 'auto'} value={language || 'auto'}
onChange={handleLanguageChange} onChange={handleLanguageChange}
/> />
<Divider horizontal section> {!isLocked && (
<Header as="h4"> <>
{t('common.authentication', { <Divider horizontal section>
context: 'title', <Header as="h4">
})} {t('common.authentication', {
</Header> context: 'title',
</Divider> })}
<div className={styles.action}> </Header>
<UserUsernameEditPopup </Divider>
usePasswordConfirmation <div className={styles.action}>
defaultData={usernameUpdateForm.data} <UserUsernameEditPopup
username={username} usePasswordConfirmation
isSubmitting={usernameUpdateForm.isSubmitting} defaultData={usernameUpdateForm.data}
error={usernameUpdateForm.error} username={username}
onUpdate={onUsernameUpdate} isSubmitting={usernameUpdateForm.isSubmitting}
onMessageDismiss={onUsernameUpdateMessageDismiss} error={usernameUpdateForm.error}
> onUpdate={onUsernameUpdate}
<Button className={styles.actionButton}> onMessageDismiss={onUsernameUpdateMessageDismiss}
{t('action.editUsername', { >
context: 'title', <Button className={styles.actionButton}>
})} {t('action.editUsername', {
</Button> context: 'title',
</UserUsernameEditPopup> })}
</div> </Button>
<div className={styles.action}> </UserUsernameEditPopup>
<UserEmailEditPopup </div>
usePasswordConfirmation <div className={styles.action}>
defaultData={emailUpdateForm.data} <UserEmailEditPopup
email={email} usePasswordConfirmation
isSubmitting={emailUpdateForm.isSubmitting} defaultData={emailUpdateForm.data}
error={emailUpdateForm.error} email={email}
onUpdate={onEmailUpdate} isSubmitting={emailUpdateForm.isSubmitting}
onMessageDismiss={onEmailUpdateMessageDismiss} error={emailUpdateForm.error}
> onUpdate={onEmailUpdate}
<Button className={styles.actionButton}> onMessageDismiss={onEmailUpdateMessageDismiss}
{t('action.editEmail', { >
context: 'title', <Button className={styles.actionButton}>
})} {t('action.editEmail', {
</Button> context: 'title',
</UserEmailEditPopup> })}
</div> </Button>
<div className={styles.action}> </UserEmailEditPopup>
<UserPasswordEditPopup </div>
usePasswordConfirmation <div className={styles.action}>
defaultData={passwordUpdateForm.data} <UserPasswordEditPopup
isSubmitting={passwordUpdateForm.isSubmitting} usePasswordConfirmation
error={passwordUpdateForm.error} defaultData={passwordUpdateForm.data}
onUpdate={onPasswordUpdate} isSubmitting={passwordUpdateForm.isSubmitting}
onMessageDismiss={onPasswordUpdateMessageDismiss} error={passwordUpdateForm.error}
> onUpdate={onPasswordUpdate}
<Button className={styles.actionButton}> onMessageDismiss={onPasswordUpdateMessageDismiss}
{t('action.editPassword', { >
context: 'title', <Button className={styles.actionButton}>
})} {t('action.editPassword', {
</Button> context: 'title',
</UserPasswordEditPopup> })}
</div> </Button>
</UserPasswordEditPopup>
</div>
</>
)}
</Tab.Pane> </Tab.Pane>
); );
}, },
@@ -172,6 +178,7 @@ AccountPane.propTypes = {
phone: PropTypes.string, phone: PropTypes.string,
organization: PropTypes.string, organization: PropTypes.string,
language: PropTypes.string, language: PropTypes.string,
isLocked: PropTypes.bool.isRequired,
isAvatarUpdating: PropTypes.bool.isRequired, isAvatarUpdating: PropTypes.bool.isRequired,
/* eslint-disable react/forbid-prop-types */ /* eslint-disable react/forbid-prop-types */
usernameUpdateForm: PropTypes.object.isRequired, usernameUpdateForm: PropTypes.object.isRequired,
@@ -17,6 +17,7 @@ const UserSettingsModal = React.memo(
organization, organization,
language, language,
subscribeToOwnCards, subscribeToOwnCards,
isLocked,
isAvatarUpdating, isAvatarUpdating,
usernameUpdateForm, usernameUpdateForm,
emailUpdateForm, emailUpdateForm,
@@ -48,6 +49,7 @@ const UserSettingsModal = React.memo(
phone={phone} phone={phone}
organization={organization} organization={organization}
language={language} language={language}
isLocked={isLocked}
isAvatarUpdating={isAvatarUpdating} isAvatarUpdating={isAvatarUpdating}
usernameUpdateForm={usernameUpdateForm} usernameUpdateForm={usernameUpdateForm}
emailUpdateForm={emailUpdateForm} emailUpdateForm={emailUpdateForm}
@@ -105,6 +107,7 @@ UserSettingsModal.propTypes = {
organization: PropTypes.string, organization: PropTypes.string,
language: PropTypes.string, language: PropTypes.string,
subscribeToOwnCards: PropTypes.bool.isRequired, subscribeToOwnCards: PropTypes.bool.isRequired,
isLocked: PropTypes.bool.isRequired,
isAvatarUpdating: PropTypes.bool.isRequired, isAvatarUpdating: PropTypes.bool.isRequired,
/* eslint-disable react/forbid-prop-types */ /* eslint-disable react/forbid-prop-types */
usernameUpdateForm: PropTypes.object.isRequired, usernameUpdateForm: PropTypes.object.isRequired,
@@ -64,6 +64,7 @@ const ActionsStep = React.memo(
return ( return (
<UserInformationEditStep <UserInformationEditStep
defaultData={pick(user, ['name', 'phone', 'organization'])} defaultData={pick(user, ['name', 'phone', 'organization'])}
isNameEditable={!user.isLocked}
onUpdate={onUpdate} onUpdate={onUpdate}
onBack={handleBack} onBack={handleBack}
onClose={onClose} onClose={onClose}
@@ -135,26 +136,32 @@ const ActionsStep = React.memo(
context: 'title', context: 'title',
})} })}
</Menu.Item> </Menu.Item>
<Menu.Item className={styles.menuItem} onClick={handleEditUsernameClick}> {!user.isLocked && (
{t('action.editUsername', { <>
context: 'title', <Menu.Item className={styles.menuItem} onClick={handleEditUsernameClick}>
})} {t('action.editUsername', {
</Menu.Item> context: 'title',
<Menu.Item className={styles.menuItem} onClick={handleEditEmailClick}> })}
{t('action.editEmail', { </Menu.Item>
context: 'title', <Menu.Item className={styles.menuItem} onClick={handleEditEmailClick}>
})} {t('action.editEmail', {
</Menu.Item> context: 'title',
<Menu.Item className={styles.menuItem} onClick={handleEditPasswordClick}> })}
{t('action.editPassword', { </Menu.Item>
context: 'title', <Menu.Item className={styles.menuItem} onClick={handleEditPasswordClick}>
})} {t('action.editPassword', {
</Menu.Item> context: 'title',
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}> })}
{t('action.deleteUser', { </Menu.Item>
context: 'title', </>
})} )}
</Menu.Item> {!user.isDeletionLocked && (
<Menu.Item className={styles.menuItem} onClick={handleDeleteClick}>
{t('action.deleteUser', {
context: 'title',
})}
</Menu.Item>
)}
</Menu> </Menu>
</Popup.Content> </Popup.Content>
</> </>
@@ -17,6 +17,9 @@ const Item = React.memo(
organization, organization,
phone, phone,
isAdmin, isAdmin,
isLocked,
isRoleLocked,
isDeletionLocked,
emailUpdateForm, emailUpdateForm,
passwordUpdateForm, passwordUpdateForm,
usernameUpdateForm, usernameUpdateForm,
@@ -46,7 +49,7 @@ const Item = React.memo(
<Table.Cell>{username || '-'}</Table.Cell> <Table.Cell>{username || '-'}</Table.Cell>
<Table.Cell>{email}</Table.Cell> <Table.Cell>{email}</Table.Cell>
<Table.Cell> <Table.Cell>
<Radio toggle checked={isAdmin} onChange={handleIsAdminChange} /> <Radio toggle checked={isAdmin} disabled={isRoleLocked} onChange={handleIsAdminChange} />
</Table.Cell> </Table.Cell>
<Table.Cell textAlign="right"> <Table.Cell textAlign="right">
<ActionsPopup <ActionsPopup
@@ -57,6 +60,8 @@ const Item = React.memo(
organization, organization,
phone, phone,
isAdmin, isAdmin,
isLocked,
isDeletionLocked,
emailUpdateForm, emailUpdateForm,
passwordUpdateForm, passwordUpdateForm,
usernameUpdateForm, usernameUpdateForm,
@@ -88,6 +93,9 @@ Item.propTypes = {
organization: PropTypes.string, organization: PropTypes.string,
phone: PropTypes.string, phone: PropTypes.string,
isAdmin: PropTypes.bool.isRequired, isAdmin: PropTypes.bool.isRequired,
isLocked: PropTypes.bool.isRequired,
isRoleLocked: PropTypes.bool.isRequired,
isDeletionLocked: PropTypes.bool.isRequired,
/* eslint-disable react/forbid-prop-types */ /* eslint-disable react/forbid-prop-types */
emailUpdateForm: PropTypes.object.isRequired, emailUpdateForm: PropTypes.object.isRequired,
passwordUpdateForm: PropTypes.object.isRequired, passwordUpdateForm: PropTypes.object.isRequired,
@@ -110,6 +110,9 @@ const UsersModal = React.memo(
organization={item.organization} organization={item.organization}
phone={item.phone} phone={item.phone}
isAdmin={item.isAdmin} isAdmin={item.isAdmin}
isLocked={item.isLocked}
isRoleLocked={item.isRoleLocked}
isDeletionLocked={item.isDeletionLocked}
emailUpdateForm={item.emailUpdateForm} emailUpdateForm={item.emailUpdateForm}
passwordUpdateForm={item.passwordUpdateForm} passwordUpdateForm={item.passwordUpdateForm}
usernameUpdateForm={item.usernameUpdateForm} usernameUpdateForm={item.usernameUpdateForm}
+5
View File
@@ -12,14 +12,19 @@ export default {
/* Login */ /* Login */
LOGIN_INITIALIZE: 'LOGIN_INITIALIZE',
AUTHENTICATE: 'AUTHENTICATE', AUTHENTICATE: 'AUTHENTICATE',
AUTHENTICATE__SUCCESS: 'AUTHENTICATE__SUCCESS', AUTHENTICATE__SUCCESS: 'AUTHENTICATE__SUCCESS',
AUTHENTICATE__FAILURE: 'AUTHENTICATE__FAILURE', AUTHENTICATE__FAILURE: 'AUTHENTICATE__FAILURE',
USING_OIDC_AUTHENTICATE: 'USING_OIDC_AUTHENTICATE',
USING_OIDC_AUTHENTICATE__SUCCESS: 'USING_OIDC_AUTHENTICATE__SUCCESS',
USING_OIDC_AUTHENTICATE__FAILURE: 'USING_OIDC_AUTHENTICATE__FAILURE',
AUTHENTICATE_ERROR_CLEAR: 'AUTHENTICATE_ERROR_CLEAR', AUTHENTICATE_ERROR_CLEAR: 'AUTHENTICATE_ERROR_CLEAR',
/* Core */ /* Core */
CORE_INITIALIZE: 'CORE_INITIALIZE', CORE_INITIALIZE: 'CORE_INITIALIZE',
CORE_INITIALIZE__CONFIG_FETCH: 'CORE_INITIALIZE__CONFIG_FETCH',
LOGOUT: 'LOGOUT', LOGOUT: 'LOGOUT',
LOGOUT__ACCESS_TOKEN_INVALIDATE: 'LOGOUT__ACCESS_TOKEN_INVALIDATE', LOGOUT__ACCESS_TOKEN_INVALIDATE: 'LOGOUT__ACCESS_TOKEN_INVALIDATE',
+1 -1
View File
@@ -11,11 +11,11 @@ export default {
/* Login */ /* Login */
AUTHENTICATE: `${PREFIX}/AUTHENTICATE`, AUTHENTICATE: `${PREFIX}/AUTHENTICATE`,
USING_OIDC_AUTHENTICATE: `${PREFIX}/USING_OIDC_AUTHENTICATE`,
AUTHENTICATE_ERROR_CLEAR: `${PREFIX}/AUTHENTICATE_ERROR_CLEAR`, AUTHENTICATE_ERROR_CLEAR: `${PREFIX}/AUTHENTICATE_ERROR_CLEAR`,
/* Core */ /* Core */
CORE_INITIALIZE: `${PREFIX}/CORE_INITIALIZE`,
LOGOUT: `${PREFIX}/LOGOUT`, LOGOUT: `${PREFIX}/LOGOUT`,
/* Modals */ /* Modals */
+2
View File
@@ -2,6 +2,7 @@ import Config from './Config';
const ROOT = `${Config.BASE_PATH}/`; const ROOT = `${Config.BASE_PATH}/`;
const LOGIN = `${Config.BASE_PATH}/login`; const LOGIN = `${Config.BASE_PATH}/login`;
const OIDC_CALLBACK = `${Config.BASE_PATH}/oidc-callback`;
const PROJECTS = `${Config.BASE_PATH}/projects/:id`; const PROJECTS = `${Config.BASE_PATH}/projects/:id`;
const BOARDS = `${Config.BASE_PATH}/boards/:id`; const BOARDS = `${Config.BASE_PATH}/boards/:id`;
const CARDS = `${Config.BASE_PATH}/cards/:id`; const CARDS = `${Config.BASE_PATH}/cards/:id`;
@@ -9,6 +10,7 @@ const CARDS = `${Config.BASE_PATH}/cards/:id`;
export default { export default {
ROOT, ROOT,
LOGIN, LOGIN,
OIDC_CALLBACK,
PROJECTS, PROJECTS,
BOARDS, BOARDS,
CARDS, CARDS,
+2 -2
View File
@@ -4,18 +4,18 @@ import selectors from '../selectors';
import Core from '../components/Core'; import Core from '../components/Core';
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const isCoreInitializing = selectors.selectIsCoreInitializing(state); const isInitializing = selectors.selectIsInitializing(state);
const isSocketDisconnected = selectors.selectIsSocketDisconnected(state); const isSocketDisconnected = selectors.selectIsSocketDisconnected(state);
const currentModal = selectors.selectCurrentModal(state); const currentModal = selectors.selectCurrentModal(state);
const currentProject = selectors.selectCurrentProject(state); const currentProject = selectors.selectCurrentProject(state);
const currentBoard = selectors.selectCurrentBoard(state); const currentBoard = selectors.selectCurrentBoard(state);
return { return {
isInitializing,
isSocketDisconnected, isSocketDisconnected,
currentModal, currentModal,
currentProject, currentProject,
currentBoard, currentBoard,
isInitializing: isCoreInitializing,
}; };
}; };
+19 -9
View File
@@ -1,23 +1,33 @@
import { bindActionCreators } from 'redux'; import { bindActionCreators } from 'redux';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import selectors from '../selectors';
import entryActions from '../entry-actions'; import entryActions from '../entry-actions';
import Login from '../components/Login'; import Login from '../components/Login';
const mapStateToProps = ({ const mapStateToProps = (state) => {
ui: { const oidcConfig = selectors.selectOidcConfig(state);
authenticateForm: { data: defaultData, isSubmitting, error },
}, const {
}) => ({ ui: {
defaultData, authenticateForm: { data: defaultData, isSubmitting, isSubmittingUsingOidc, error },
isSubmitting, },
error, } = state;
});
return {
defaultData,
isSubmitting,
isSubmittingUsingOidc,
error,
withOidc: !!oidcConfig,
};
};
const mapDispatchToProps = (dispatch) => const mapDispatchToProps = (dispatch) =>
bindActionCreators( bindActionCreators(
{ {
onAuthenticate: entryActions.authenticate, onAuthenticate: entryActions.authenticate,
onAuthenticateUsingOidc: entryActions.authenticateUsingOidc,
onMessageDismiss: entryActions.clearAuthenticateError, onMessageDismiss: entryActions.clearAuthenticateError,
}, },
dispatch, dispatch,
@@ -0,0 +1,14 @@
import { connect } from 'react-redux';
import selectors from '../selectors';
import LoginWrapper from '../components/LoginWrapper';
const mapStateToProps = (state) => {
const isInitializing = selectors.selectIsInitializing(state);
return {
isInitializing,
};
};
export default connect(mapStateToProps)(LoginWrapper);
@@ -15,6 +15,7 @@ const mapStateToProps = (state) => {
organization, organization,
language, language,
subscribeToOwnCards, subscribeToOwnCards,
isLocked,
isAvatarUpdating, isAvatarUpdating,
emailUpdateForm, emailUpdateForm,
passwordUpdateForm, passwordUpdateForm,
@@ -30,6 +31,7 @@ const mapStateToProps = (state) => {
organization, organization,
language, language,
subscribeToOwnCards, subscribeToOwnCards,
isLocked,
isAvatarUpdating, isAvatarUpdating,
emailUpdateForm, emailUpdateForm,
passwordUpdateForm, passwordUpdateForm,
-6
View File
@@ -1,16 +1,10 @@
import EntryActionTypes from '../constants/EntryActionTypes'; import EntryActionTypes from '../constants/EntryActionTypes';
const initializeCore = () => ({
type: EntryActionTypes.CORE_INITIALIZE,
payload: {},
});
const logout = () => ({ const logout = () => ({
type: EntryActionTypes.LOGOUT, type: EntryActionTypes.LOGOUT,
payload: {}, payload: {},
}); });
export default { export default {
initializeCore,
logout, logout,
}; };
+6
View File
@@ -7,6 +7,11 @@ const authenticate = (data) => ({
}, },
}); });
const authenticateUsingOidc = () => ({
type: EntryActionTypes.USING_OIDC_AUTHENTICATE,
payload: {},
});
const clearAuthenticateError = () => ({ const clearAuthenticateError = () => ({
type: EntryActionTypes.AUTHENTICATE_ERROR_CLEAR, type: EntryActionTypes.AUTHENTICATE_ERROR_CLEAR,
payload: {}, payload: {},
@@ -14,5 +19,6 @@ const clearAuthenticateError = () => ({
export default { export default {
authenticate, authenticate,
authenticateUsingOidc,
clearAuthenticateError, clearAuthenticateError,
}; };
+28 -4
View File
@@ -13,6 +13,7 @@ export default {
translation: { translation: {
common: { common: {
aboutPlanka: 'O aplikaci Planka',
account: 'Účet', account: 'Účet',
actions: 'Akce', actions: 'Akce',
addAttachment_title: 'Přidat přílohu', addAttachment_title: 'Přidat přílohu',
@@ -23,7 +24,7 @@ export default {
administrator: 'Administrátor', administrator: 'Administrátor',
all: 'Vše', all: 'Vše',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Všechny změny budou automaticky uloženy<br />po obnově spojení', 'Všechny změny budou automaticky uloženy<br />po obnově spojení.',
areYouSureYouWantToDeleteThisAttachment: 'Opravdu chcete smazat tuto přílohu?', areYouSureYouWantToDeleteThisAttachment: 'Opravdu chcete smazat tuto přílohu?',
areYouSureYouWantToDeleteThisBoard: 'Opravdu chcete smazat tuto tabuli?', areYouSureYouWantToDeleteThisBoard: 'Opravdu chcete smazat tuto tabuli?',
areYouSureYouWantToDeleteThisCard: 'Opravdu chcete smazat tuto kartu?', areYouSureYouWantToDeleteThisCard: 'Opravdu chcete smazat tuto kartu?',
@@ -45,13 +46,16 @@ export default {
background: 'Pozadí', background: 'Pozadí',
board: 'Tabule', board: 'Tabule',
boardNotFound_title: 'Tabule nenalezena', boardNotFound_title: 'Tabule nenalezena',
canComment: 'Může komentovat',
canEditContentOfBoard: 'Může upravovat obsah tabule.',
canOnlyViewBoard: 'Může zobrazit pouze tabuli.',
cardActions_title: 'Akce na kartě', cardActions_title: 'Akce na kartě',
cardNotFound_title: 'Karta nenalezena', cardNotFound_title: 'Karta nenalezena',
cardOrActionAreDeleted: 'Karta nebo akce je smazána', cardOrActionAreDeleted: 'Karta nebo akce je smazána.',
color: 'Barva', color: 'Barva',
createBoard_title: 'Vytvořit tabuli', createBoard_title: 'Vytvořit tabuli',
createLabel_title: 'Vytvořit štítek', createLabel_title: 'Vytvořit štítek',
createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vyberte<br />již existující', createNewOneOrSelectExistingOne: 'Vytvořit nový nebo vyberte<br />již existující.',
createProject_title: 'Vytvořit projekt', createProject_title: 'Vytvořit projekt',
createTextFile_title: 'Vytvořit textový soubor', createTextFile_title: 'Vytvořit textový soubor',
currentPassword: 'Aktuální heslo', currentPassword: 'Aktuální heslo',
@@ -68,14 +72,18 @@ export default {
deleteTask_title: 'Smazat úkol', deleteTask_title: 'Smazat úkol',
deleteUser_title: 'Smazat uživatele', deleteUser_title: 'Smazat uživatele',
description: 'Popis', description: 'Popis',
detectAutomatically: 'Automatická detekce',
dropFileToUpload: 'Přetáhnutím nahraj soubor', dropFileToUpload: 'Přetáhnutím nahraj soubor',
editor: 'Editor',
editAttachment_title: 'Upravit přílohu', editAttachment_title: 'Upravit přílohu',
editAvatar_title: 'Upravit avatar', editAvatar_title: 'Upravit avatar',
editBoard_title: 'Upravit tabuli', editBoard_title: 'Upravit tabuli',
editDueDate_title: 'Upravit Termín do', editDueDate_title: 'Upravit Termín do',
editEmail_title: 'Upravit e-mail', editEmail_title: 'Upravit e-mail',
editInformation_title: 'Upravit informace',
editLabel_title: 'Upravit štítek', editLabel_title: 'Upravit štítek',
editPassword_title: 'Upravit heslo', editPassword_title: 'Upravit heslo',
editPermissions_title: 'Upravit oprávnění',
editStopwatch_title: 'Upravit časovač', editStopwatch_title: 'Upravit časovač',
editUsername_title: 'Upravit uživatelské jméno', editUsername_title: 'Upravit uživatelské jméno',
email: 'E-mail', email: 'E-mail',
@@ -89,10 +97,13 @@ export default {
filterByLabels_title: 'Filtruj podle štítku', filterByLabels_title: 'Filtruj podle štítku',
filterByMembers_title: 'Filtruj podle člena', filterByMembers_title: 'Filtruj podle člena',
fromComputer_title: 'Z počítače', fromComputer_title: 'Z počítače',
fromTrello: 'Z Trella',
general: 'Obecné', general: 'Obecné',
hours: 'Hodiny', hours: 'Hodiny',
importBoard_title: 'Importovat tabuli',
invalidCurrentPassword: 'Neplatné aktuální heslo', invalidCurrentPassword: 'Neplatné aktuální heslo',
labels: 'Štítky', labels: 'Štítky',
language: 'Jazyk',
leaveBoard_title: 'Opustit tabuli', leaveBoard_title: 'Opustit tabuli',
leaveProject_title: 'Opustit projekt', leaveProject_title: 'Opustit projekt',
list: 'Seznam', list: 'Seznam',
@@ -117,20 +128,25 @@ export default {
phone: 'Telefon', phone: 'Telefon',
preferences: 'Volby', preferences: 'Volby',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: dejte Ctrl-V (Cmd-V na Mac) pro vložení přílohy ze schránky', 'Tip: dejte Ctrl-V (Cmd-V na Mac) pro vložení přílohy ze schránky.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt nenalezen', projectNotFound_title: 'Projekt nenalezen',
removeManager_title: 'Odstranit vedoucího', removeManager_title: 'Odstranit vedoucího',
removeMember_title: 'Odstranit člena', removeMember_title: 'Odstranit člena',
searchLabels: 'Hledat štítky...',
searchMembers: 'Hledat členy...',
searchUsers: 'Hledat uživatele...',
seconds: 'Vteřin', seconds: 'Vteřin',
selectBoard: 'Vybrat tabuli', selectBoard: 'Vybrat tabuli',
selectList: 'Vybrat seznam', selectList: 'Vybrat seznam',
selectPermissions_title: 'Vybrat oprávnění',
selectProject: 'Vybrat projekt', selectProject: 'Vybrat projekt',
settings: 'Nastavení', settings: 'Nastavení',
stopwatch: 'Časovač', stopwatch: 'Časovač',
subscribeToMyOwnCardsByDefault: 'Ve výchozím nastavení odebírat vlastní karty', subscribeToMyOwnCardsByDefault: 'Ve výchozím nastavení odebírat vlastní karty',
taskActions_title: 'Akce na úkolu', taskActions_title: 'Akce na úkolu',
tasks: 'Úkoly', tasks: 'Úkoly',
thereIsNoPreviewAvailableForThisAttachment: 'Pro tuto přílohu není k dispozici žádný náhled.',
time: 'Čas', time: 'Čas',
title: 'Titulek', title: 'Titulek',
userActions_title: 'Akce na uživateli', userActions_title: 'Akce na uživateli',
@@ -142,6 +158,8 @@ export default {
username: 'Uživatelské jméno', username: 'Uživatelské jméno',
usernameAlreadyInUse: 'Uživatelské jméno se již používá', usernameAlreadyInUse: 'Uživatelské jméno se již používá',
users: 'Uživatelé', users: 'Uživatelé',
version: 'Verze',
viewer: 'Prohlížeč',
writeComment: 'Napsat komentář...', writeComment: 'Napsat komentář...',
}, },
@@ -153,6 +171,7 @@ export default {
addCard_title: 'Přidat kartu', addCard_title: 'Přidat kartu',
addComment: 'Přidat komentář', addComment: 'Přidat komentář',
addList: 'Přidat seznam', addList: 'Přidat seznam',
addMember: 'Přidat člena',
addMoreDetailedDescription: 'Přidat další detailní popis', addMoreDetailedDescription: 'Přidat další detailní popis',
addTask: 'Přidat úkol', addTask: 'Přidat úkol',
addToCard: 'Přidat na kartu', addToCard: 'Přidat na kartu',
@@ -182,10 +201,14 @@ export default {
editDueDate_title: 'Upravit termín do', editDueDate_title: 'Upravit termín do',
editDescription_title: 'Upravit popis', editDescription_title: 'Upravit popis',
editEmail_title: 'Upravit e-mail', editEmail_title: 'Upravit e-mail',
editInformation_title: 'Upravit informace',
editPassword_title: 'Upravit heslo', editPassword_title: 'Upravit heslo',
editPermissions: 'Upravit oprávnění',
editStopwatch_title: 'Upravit časovač', editStopwatch_title: 'Upravit časovač',
editTitle_title: 'Upravit titulek', editTitle_title: 'Upravit titulek',
editUsername_title: 'Upravit uživatelské jméno', editUsername_title: 'Upravit uživatelské jméno',
hideDetails: 'Skrýt detaily',
import: 'Import',
leaveBoard: 'Opustit tabuli', leaveBoard: 'Opustit tabuli',
leaveProject: 'Opustit projekt', leaveProject: 'Opustit projekt',
logOut_title: 'Odhlásit se', logOut_title: 'Odhlásit se',
@@ -202,6 +225,7 @@ export default {
save: 'Uložit', save: 'Uložit',
showAllAttachments: 'Zozbrazit všechny přílohy ({{hidden}} skryté)', showAllAttachments: 'Zozbrazit všechny přílohy ({{hidden}} skryté)',
showFewerAttachments: 'Zobrazit méně příloh', showFewerAttachments: 'Zobrazit méně příloh',
showDetails: 'Zobrazit detaily',
start: 'Start', start: 'Start',
stop: 'Stop', stop: 'Stop',
subscribe: 'Odebírat', subscribe: 'Odebírat',
+5 -5
View File
@@ -23,7 +23,7 @@ export default {
administrator: 'Administrator', administrator: 'Administrator',
all: 'Alle', all: 'Alle',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Alle ændringer vil automatisk blive gemt<br />ved genforbindelse', 'Alle ændringer vil automatisk blive gemt<br />ved genforbindelse.',
areYouSureYouWantToDeleteThisAttachment: 'Vil du slette den vedhæftede fil?', areYouSureYouWantToDeleteThisAttachment: 'Vil du slette den vedhæftede fil?',
areYouSureYouWantToDeleteThisBoard: 'Vil du slette dette bræt?', areYouSureYouWantToDeleteThisBoard: 'Vil du slette dette bræt?',
areYouSureYouWantToDeleteThisCard: 'Vil du slette dette kort?', areYouSureYouWantToDeleteThisCard: 'Vil du slette dette kort?',
@@ -46,11 +46,11 @@ export default {
boardNotFound_title: 'Bræt ikke fundet', boardNotFound_title: 'Bræt ikke fundet',
cardActions_title: 'Korthandlinger', cardActions_title: 'Korthandlinger',
cardNotFound_title: 'Kort ikke fundet', cardNotFound_title: 'Kort ikke fundet',
cardOrActionAreDeleted: 'Kort eller handling er slettet', cardOrActionAreDeleted: 'Kort eller handling er slettet.',
color: 'Farve', color: 'Farve',
createBoard_title: 'Opret bræt', createBoard_title: 'Opret bræt',
createLabel_title: 'Opret mærkat', createLabel_title: 'Opret mærkat',
createNewOneOrSelectExistingOne: 'Lav en ny eller marker<br />en eksisterende', createNewOneOrSelectExistingOne: 'Lav en ny eller marker<br />en eksisterende.',
createProject_title: 'Opret projekt', createProject_title: 'Opret projekt',
createTextFile_title: 'Opret tekstfil', createTextFile_title: 'Opret tekstfil',
currentPassword: 'Nuværende løsen', currentPassword: 'Nuværende løsen',
@@ -109,14 +109,14 @@ export default {
noLists: 'Ingen lister', noLists: 'Ingen lister',
noProjects: 'Ingen projekter', noProjects: 'Ingen projekter',
notifications: 'Notifikationer', notifications: 'Notifikationer',
noUnreadNotifications: 'Ingen ulæste notifikationer', noUnreadNotifications: 'Ingen ulæste notifikationer.',
openBoard_title: 'Åben bræt', openBoard_title: 'Åben bræt',
optional_inline: 'valgfri', optional_inline: 'valgfri',
organization: 'Organisation', organization: 'Organisation',
phone: 'Telefon', phone: 'Telefon',
preferences: 'Præferencer', preferences: 'Præferencer',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: Tryk Ctrl-V (Cmd-V på Mac) for at vedhæfte direkte fra udklipsholder', 'Tip: Tryk Ctrl-V (Cmd-V på Mac) for at vedhæfte direkte fra udklipsholder.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt ej fundet', projectNotFound_title: 'Projekt ej fundet',
removeManager_title: 'Fjern projektleder', removeManager_title: 'Fjern projektleder',
+3 -3
View File
@@ -51,7 +51,7 @@ export default {
boardNotFound_title: 'Board nicht gefunden', boardNotFound_title: 'Board nicht gefunden',
cardActions_title: 'Kartenaktionen', cardActions_title: 'Kartenaktionen',
cardNotFound_title: 'Karte nicht gefunden', cardNotFound_title: 'Karte nicht gefunden',
cardOrActionAreDeleted: 'Karte oder Aktion wurden gelöscht', cardOrActionAreDeleted: 'Karte oder Aktion wurden gelöscht.',
color: 'Farbe', color: 'Farbe',
createBoard_title: 'Board erstellen', createBoard_title: 'Board erstellen',
createLabel_title: 'Label erstellen', createLabel_title: 'Label erstellen',
@@ -117,14 +117,14 @@ export default {
noLists: 'Keine Listen', noLists: 'Keine Listen',
noProjects: 'Keine Projekte', noProjects: 'Keine Projekte',
notifications: 'Benachrichtigungen', notifications: 'Benachrichtigungen',
noUnreadNotifications: 'Keine ungelesenen Benachrichtigungen', noUnreadNotifications: 'Keine ungelesenen Benachrichtigungen.',
openBoard_title: 'Board öffnen', openBoard_title: 'Board öffnen',
optional_inline: 'Optional', optional_inline: 'Optional',
organization: 'Organisation', organization: 'Organisation',
phone: 'Telefon', phone: 'Telefon',
preferences: 'Voreinstellungen', preferences: 'Voreinstellungen',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tipp: Drücken Sie STRG-V (Cmd-V auf Mac), um einen Anhang aus der Zwischenablage hinzuzufügen', 'Tipp: Drücken Sie STRG-V (Cmd-V auf Mac), um einen Anhang aus der Zwischenablage hinzuzufügen.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt nicht gefunden', projectNotFound_title: 'Projekt nicht gefunden',
removeManager_title: 'Manager entfernen', removeManager_title: 'Manager entfernen',
+9 -9
View File
@@ -20,7 +20,7 @@ export default {
administrator: 'Administrator', administrator: 'Administrator',
all: 'All', all: 'All',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'All changes will be automatically saved<br />after connection restored', 'All changes will be automatically saved<br />after connection restored.',
areYouSureYouWantToDeleteThisAttachment: 'Are you sure you want to delete this attachment?', areYouSureYouWantToDeleteThisAttachment: 'Are you sure you want to delete this attachment?',
areYouSureYouWantToDeleteThisBoard: 'Are you sure you want to delete this board?', areYouSureYouWantToDeleteThisBoard: 'Are you sure you want to delete this board?',
areYouSureYouWantToDeleteThisCard: 'Are you sure you want to delete this card?', areYouSureYouWantToDeleteThisCard: 'Are you sure you want to delete this card?',
@@ -43,15 +43,15 @@ export default {
board: 'Board', board: 'Board',
boardNotFound_title: 'Board Not Found', boardNotFound_title: 'Board Not Found',
canComment: 'Can comment', canComment: 'Can comment',
canEditContentOfBoard: 'Can edit the content of the board', canEditContentOfBoard: 'Can edit the content of the board.',
canOnlyViewBoard: 'Can only view the board', canOnlyViewBoard: 'Can only view the board.',
cardActions_title: 'Card Actions', cardActions_title: 'Card Actions',
cardNotFound_title: 'Card Not Found', cardNotFound_title: 'Card Not Found',
cardOrActionAreDeleted: 'Card or action are deleted', cardOrActionAreDeleted: 'Card or action are deleted.',
color: 'Color', color: 'Color',
createBoard_title: 'Create Board', createBoard_title: 'Create Board',
createLabel_title: 'Create Label', createLabel_title: 'Create Label',
createNewOneOrSelectExistingOne: 'Create a new one or select<br />an existing one', createNewOneOrSelectExistingOne: 'Create a new one or select<br />an existing one.',
createProject_title: 'Create Project', createProject_title: 'Create Project',
createTextFile_title: 'Create Text File', createTextFile_title: 'Create Text File',
currentPassword: 'Current password', currentPassword: 'Current password',
@@ -84,7 +84,7 @@ export default {
editUsername_title: 'Edit Username', editUsername_title: 'Edit Username',
email: 'E-mail', email: 'E-mail',
emailAlreadyInUse: 'E-mail already in use', emailAlreadyInUse: 'E-mail already in use',
enterCardTitle: 'Enter card title... [Ctrl+Enter] to auto-open', enterCardTitle: 'Enter card title... [Ctrl+Enter] to auto-open.',
enterDescription: 'Enter description...', enterDescription: 'Enter description...',
enterFilename: 'Enter filename', enterFilename: 'Enter filename',
enterListTitle: 'Enter list title...', enterListTitle: 'Enter list title...',
@@ -117,14 +117,14 @@ export default {
noLists: 'No lists', noLists: 'No lists',
noProjects: 'No projects', noProjects: 'No projects',
notifications: 'Notifications', notifications: 'Notifications',
noUnreadNotifications: 'No unread notifications', noUnreadNotifications: 'No unread notifications.',
openBoard_title: 'Open Board', openBoard_title: 'Open Board',
optional_inline: 'optional', optional_inline: 'optional',
organization: 'Organization', organization: 'Organization',
phone: 'Phone', phone: 'Phone',
preferences: 'Preferences', preferences: 'Preferences',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: press Ctrl-V (Cmd-V on Mac) to add an attachment from the clipboard', 'Tip: press Ctrl-V (Cmd-V on Mac) to add an attachment from the clipboard.',
project: 'Project', project: 'Project',
projectNotFound_title: 'Project Not Found', projectNotFound_title: 'Project Not Found',
removeManager_title: 'Remove Manager', removeManager_title: 'Remove Manager',
@@ -143,7 +143,7 @@ export default {
taskActions_title: 'Task Actions', taskActions_title: 'Task Actions',
tasks: 'Tasks', tasks: 'Tasks',
thereIsNoPreviewAvailableForThisAttachment: thereIsNoPreviewAvailableForThisAttachment:
'There is no preview available for this attachment', 'There is no preview available for this attachment.',
time: 'Time', time: 'Time',
title: 'Title', title: 'Title',
userActions_title: 'User Actions', userActions_title: 'User Actions',
+2
View File
@@ -11,10 +11,12 @@ export default {
projectManagement: 'Project management', projectManagement: 'Project management',
serverConnectionFailed: 'Server connection failed', serverConnectionFailed: 'Server connection failed',
unknownError: 'Unknown error, try again later', unknownError: 'Unknown error, try again later',
useSingleSignOn: 'Use single sign-on',
}, },
action: { action: {
logIn: 'Log in', logIn: 'Log in',
logInWithSSO: 'Log in with SSO',
}, },
}, },
}; };
+4 -4
View File
@@ -22,7 +22,7 @@ export default {
administrator: 'Administrador', administrator: 'Administrador',
all: 'Todos', all: 'Todos',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Todos los cambios serán automáticamente guardados<br />después de que se restaure la conexión', 'Todos los cambios serán automáticamente guardados<br />después de que se restaure la conexión.',
areYouSureYouWantToDeleteThisAttachment: '¿Estás seguro de que quieres borrar este adjunto?', areYouSureYouWantToDeleteThisAttachment: '¿Estás seguro de que quieres borrar este adjunto?',
areYouSureYouWantToDeleteThisBoard: '¿Estás seguro de que quieres borrar este tablero?', areYouSureYouWantToDeleteThisBoard: '¿Estás seguro de que quieres borrar este tablero?',
areYouSureYouWantToDeleteThisCard: '¿Estás seguro de que quieres borrar esta tarjeta?', areYouSureYouWantToDeleteThisCard: '¿Estás seguro de que quieres borrar esta tarjeta?',
@@ -41,11 +41,11 @@ export default {
boardNotFound_title: 'Tablero no encontrado', boardNotFound_title: 'Tablero no encontrado',
cardActions_title: 'Acciones de las tarjetas', cardActions_title: 'Acciones de las tarjetas',
cardNotFound_title: 'tarjeta no encontrada', cardNotFound_title: 'tarjeta no encontrada',
cardOrActionAreDeleted: 'La tarjeta o la acción está eliminada', cardOrActionAreDeleted: 'La tarjeta o la acción está eliminada.',
color: 'Color', color: 'Color',
createBoard_title: 'Crear Tablero', createBoard_title: 'Crear Tablero',
createLabel_title: 'Crear Etiqueta', createLabel_title: 'Crear Etiqueta',
createNewOneOrSelectExistingOne: 'Crear uno nuevo o seleccionar<br /> uno existente', createNewOneOrSelectExistingOne: 'Crear uno nuevo o seleccionar<br />uno existente.',
createProject_title: 'Crear Proyecto', createProject_title: 'Crear Proyecto',
createTextFile_title: 'Crear archivo de Texto', createTextFile_title: 'Crear archivo de Texto',
currentPassword: 'Contraseña Actual', currentPassword: 'Contraseña Actual',
@@ -106,7 +106,7 @@ export default {
phone: 'Teléfono', phone: 'Teléfono',
preferences: 'Preferencias', preferences: 'Preferencias',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: presiona Ctrl-V (Cmd-V en Mac) para añadir adjuntos desde el portapapeles', 'Tip: presiona Ctrl-V (Cmd-V en Mac) para añadir adjuntos desde el portapapeles.',
project: 'Proyecto', project: 'Proyecto',
projectNotFound_title: 'Proyecto no encontrado', projectNotFound_title: 'Proyecto no encontrado',
removeMember_title: 'Remover Miembro', removeMember_title: 'Remover Miembro',
+8 -8
View File
@@ -22,7 +22,7 @@ export default {
administrator: 'Administrateur', administrator: 'Administrateur',
all: 'Tout', all: 'Tout',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Toutes les modifications seront automatiquement enregistrées <br /> une fois la connexion rétablie', 'Toutes les modifications seront automatiquement enregistrées<br />une fois la connexion rétablie.',
areYouSureYouWantToDeleteThisAttachment: 'Voulez-vous vraiment supprimer cette pièce jointe?', areYouSureYouWantToDeleteThisAttachment: 'Voulez-vous vraiment supprimer cette pièce jointe?',
areYouSureYouWantToDeleteThisBoard: 'Êtes-vous sûr de vouloir supprimer ce forum?', areYouSureYouWantToDeleteThisBoard: 'Êtes-vous sûr de vouloir supprimer ce forum?',
areYouSureYouWantToDeleteThisCard: 'Voulez-vous vraiment supprimer cette carte?', areYouSureYouWantToDeleteThisCard: 'Voulez-vous vraiment supprimer cette carte?',
@@ -41,11 +41,11 @@ export default {
boardNotFound_title: 'Carte non trouvée', boardNotFound_title: 'Carte non trouvée',
cardActions_title: 'Actions sur la carte', cardActions_title: 'Actions sur la carte',
cardNotFound_title: 'Carte non trouvée', cardNotFound_title: 'Carte non trouvée',
cardOrActionAreDeleted: "La carte ou l'action sont supprimées", cardOrActionAreDeleted: "La carte ou l'action sont supprimées.",
color: 'Couleur', color: 'Couleur',
createBoard_title: 'Créer un tableau', createBoard_title: 'Créer un tableau',
createLabel_title: 'Créer une étiquette', createLabel_title: 'Créer une étiquette',
createNewOneOrSelectExistingOne: 'Créez-en un nouveau ou sélectionnez <br /> un existant', createNewOneOrSelectExistingOne: 'Créez-en un nouveau ou sélectionnez<br />un existant.',
createProject_title: 'Créer un projet', createProject_title: 'Créer un projet',
createTextFile_title: 'Créer un fichier texte', createTextFile_title: 'Créer un fichier texte',
currentPassword: 'Mot de passe actuel', currentPassword: 'Mot de passe actuel',
@@ -73,12 +73,12 @@ export default {
editUsername_title: "Modifier le nom d'utilisateur", editUsername_title: "Modifier le nom d'utilisateur",
email: 'E-mail', email: 'E-mail',
emailAlreadyInUse: 'Email déjà utilisé', emailAlreadyInUse: 'Email déjà utilisé',
enterCardTitle: 'Entrer le titre de la carte ...', enterCardTitle: 'Entrer le titre de la carte...',
enterDescription: 'Entrez la description ...', enterDescription: 'Entrez la description...',
enterFilename: 'Entrez le nom du fichier', enterFilename: 'Entrez le nom du fichier',
enterListTitle: 'Entrer le titre de la liste ...', enterListTitle: 'Entrer le titre de la liste...',
enterProjectTitle: 'Saisir le titre du projet', enterProjectTitle: 'Saisir le titre du projet',
enterTaskDescription: 'Saisir la description de la tâche ...', enterTaskDescription: 'Saisir la description de la tâche...',
filterByLabels_title: 'Filtrer par libellés', filterByLabels_title: 'Filtrer par libellés',
filterByMembers_title: 'Filtrer par membres', filterByMembers_title: 'Filtrer par membres',
fromComputer_title: "Depuis l'ordinateur", fromComputer_title: "Depuis l'ordinateur",
@@ -99,7 +99,7 @@ export default {
noLists: 'Pas de listes', noLists: 'Pas de listes',
noProjects: 'Pas de projets', noProjects: 'Pas de projets',
notifications: 'Notifications', notifications: 'Notifications',
noUnreadNotifications: 'Aucune notification non lue', noUnreadNotifications: 'Aucune notification non lue.',
openBoard_title: 'Open Board', openBoard_title: 'Open Board',
optional_inline: 'optionnel', optional_inline: 'optionnel',
organization: 'Organisation', organization: 'Organisation',
+3 -1
View File
@@ -8,13 +8,15 @@ import it from './it';
import ja from './ja'; import ja from './ja';
import ko from './ko'; import ko from './ko';
import pl from './pl'; import pl from './pl';
import ro from './ro';
import ru from './ru'; import ru from './ru';
import sk from './sk'; import sk from './sk';
import sv from './sv'; import sv from './sv';
import tr from './tr';
import uz from './uz'; import uz from './uz';
import zh from './zh'; import zh from './zh';
const locales = [cs, da, de, en, es, fr, it, ja, ko, pl, ru, sk, sv, uz, zh]; const locales = [cs, da, de, en, es, fr, it, ja, ko, pl, ro, ru, sk, sv, tr, uz, zh];
export default locales; export default locales;
+8 -8
View File
@@ -19,7 +19,7 @@ export default {
administrator: 'Amministratore', administrator: 'Amministratore',
all: 'tutto', all: 'tutto',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'All changes will be automatically saved<br />after connection restored', 'All changes will be automatically saved<br />after connection restored.',
areYouSureYouWantToDeleteThisAttachment: 'Sei sicuro di voler eliminare questo allegato?', areYouSureYouWantToDeleteThisAttachment: 'Sei sicuro di voler eliminare questo allegato?',
areYouSureYouWantToDeleteThisBoard: 'Sei sicuro di voler eliminare questa bacheca?', areYouSureYouWantToDeleteThisBoard: 'Sei sicuro di voler eliminare questa bacheca?',
areYouSureYouWantToDeleteThisCard: 'Sei sicuro di voler eliminare questa card?', areYouSureYouWantToDeleteThisCard: 'Sei sicuro di voler eliminare questa card?',
@@ -42,15 +42,15 @@ export default {
board: 'Bacheca', board: 'Bacheca',
boardNotFound_title: 'Bacheca non trovata', boardNotFound_title: 'Bacheca non trovata',
canComment: 'Può commentare', canComment: 'Può commentare',
canEditContentOfBoard: 'Può modificare il contenuto della bacheca', canEditContentOfBoard: 'Può modificare il contenuto della bacheca.',
canOnlyViewBoard: 'Può solo vedere la bacheca', canOnlyViewBoard: 'Può solo vedere la bacheca.',
cardActions_title: 'Card Azioni', cardActions_title: 'Card Azioni',
cardNotFound_title: 'Card non trovata', cardNotFound_title: 'Card non trovata',
cardOrActionAreDeleted: "La card o l'azione vengono eliminate", cardOrActionAreDeleted: "La card o l'azione vengono eliminate.",
color: 'Colore', color: 'Colore',
createBoard_title: 'Crea Bacheca', createBoard_title: 'Crea Bacheca',
createLabel_title: 'Crea Etichetta', createLabel_title: 'Crea Etichetta',
createNewOneOrSelectExistingOne: 'Crea nuovo o seleziona <br /> esistente', createNewOneOrSelectExistingOne: 'Crea nuovo o seleziona<br />esistente.',
createProject_title: 'Crea Progetto', createProject_title: 'Crea Progetto',
createTextFile_title: 'Create File di Testo', createTextFile_title: 'Create File di Testo',
currentPassword: 'Password corrente', currentPassword: 'Password corrente',
@@ -114,14 +114,14 @@ export default {
noLists: 'No liste', noLists: 'No liste',
noProjects: 'No progetti', noProjects: 'No progetti',
notifications: 'Notifiche', notifications: 'Notifiche',
noUnreadNotifications: 'Nessuna notifica non letta', noUnreadNotifications: 'Nessuna notifica non letta.',
openBoard_title: 'Bacheca aperta', openBoard_title: 'Bacheca aperta',
optional_inline: 'opzionale', optional_inline: 'opzionale',
organization: 'Organizazzione', organization: 'Organizazzione',
phone: 'Telefono', phone: 'Telefono',
preferences: 'Preferenze', preferences: 'Preferenze',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: prmi Ctrl-V (Cmd-V on Mac) per aggiungere un allegato dalla clipboard', 'Tip: prmi Ctrl-V (Cmd-V on Mac) per aggiungere un allegato dalla clipboard.',
project: 'Progetto', project: 'Progetto',
projectNotFound_title: 'Progetto non trovato', projectNotFound_title: 'Progetto non trovato',
removeManager_title: 'Rimuovi Manager', removeManager_title: 'Rimuovi Manager',
@@ -140,7 +140,7 @@ export default {
taskActions_title: 'Task Azioni', taskActions_title: 'Task Azioni',
tasks: 'Tasks', tasks: 'Tasks',
thereIsNoPreviewAvailableForThisAttachment: thereIsNoPreviewAvailableForThisAttachment:
'Non è disponibile alcuna anteprima per questo allegato', 'Non è disponibile alcuna anteprima per questo allegato.',
time: 'Tempo', time: 'Tempo',
title: 'Titolo', title: 'Titolo',
userActions_title: 'Azioni Utente', userActions_title: 'Azioni Utente',
+40 -16
View File
@@ -8,11 +8,12 @@ export default {
time: 'HH:mm', time: 'HH:mm',
dateTime: '$t(format:date) $t(format:time)', dateTime: '$t(format:date) $t(format:time)',
longDate: 'MMMMd日', longDate: 'MMMMd日',
longDateTime: "MMMMd'日 ' HH:MM", longDateTime: "MMMMd'日 ' HH:mm",
}, },
translation: { translation: {
common: { common: {
aboutPlanka: 'Plankaについて',
account: 'アカウント', account: 'アカウント',
actions: 'アクション', actions: 'アクション',
addAttachment_title: '添付ファイルを追加', addAttachment_title: '添付ファイルを追加',
@@ -23,7 +24,7 @@ export default {
administrator: '管理者', administrator: '管理者',
all: 'すべて', all: 'すべて',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'全ての変更は接続回復後自動的に保存されます', '全ての変更は接続回復後自動的に保存されます。',
areYouSureYouWantToDeleteThisAttachment: 'この添付ファイルを削除してもよろしいですか?', areYouSureYouWantToDeleteThisAttachment: 'この添付ファイルを削除してもよろしいですか?',
areYouSureYouWantToDeleteThisBoard: 'このボードを削除してもよろしいですか?', areYouSureYouWantToDeleteThisBoard: 'このボードを削除してもよろしいですか?',
areYouSureYouWantToDeleteThisCard: 'このカードを削除してもよろしいですか?', areYouSureYouWantToDeleteThisCard: 'このカードを削除してもよろしいですか?',
@@ -45,13 +46,16 @@ export default {
background: '背景', background: '背景',
board: 'ボード', board: 'ボード',
boardNotFound_title: 'ボードが見つかりません', boardNotFound_title: 'ボードが見つかりません',
canComment: 'コメントを作成することができます',
canEditContentOfBoard: 'ボードコンテンツを修正することができます。',
canOnlyViewBoard: 'ボードの読み取りのみ可能です。',
cardActions_title: 'カードのアクション', cardActions_title: 'カードのアクション',
cardNotFound_title: 'カードが見つかりません', cardNotFound_title: 'カードが見つかりません',
cardOrActionAreDeleted: 'カードやアクションが削除されます', cardOrActionAreDeleted: 'カードやアクションが削除されます。',
color: '色', color: '色',
createBoard_title: 'ボードを作成', createBoard_title: 'ボードを作成',
createLabel_title: 'ラベルを作成', createLabel_title: 'ラベルを作成',
createNewOneOrSelectExistingOne: '新規作成もしくは既存のものから選択', createNewOneOrSelectExistingOne: '新規作成もしくは<br />既存のものから選択。',
createProject_title: 'プロジェクトを作成', createProject_title: 'プロジェクトを作成',
createTextFile_title: 'テキストファイルを作成', createTextFile_title: 'テキストファイルを作成',
currentPassword: '現在のパスワード', currentPassword: '現在のパスワード',
@@ -68,31 +72,38 @@ export default {
deleteTask_title: 'タスクを削除', deleteTask_title: 'タスクを削除',
deleteUser_title: 'ユーザーを削除', deleteUser_title: 'ユーザーを削除',
description: '説明', description: '説明',
detectAutomatically: '自動的に検知',
dropFileToUpload: 'ファイルをドロップしてアップロード', dropFileToUpload: 'ファイルをドロップしてアップロード',
editor: 'エディター',
editAttachment_title: '添付ファイルを編集', editAttachment_title: '添付ファイルを編集',
editAvatar_title: 'アバターを編集', editAvatar_title: 'アバターを編集',
editBoard_title: 'ボードを編集', editBoard_title: 'ボードを編集',
editDueDate_title: '期限を編集', editDueDate_title: '期限を編集',
editEmail_title: 'Eメールを編集', editEmail_title: 'Eメールを編集',
editInformation_title: '情報を編集',
editLabel_title: 'ラベルを編集', editLabel_title: 'ラベルを編集',
editPassword_title: 'パスワードを編集', editPassword_title: 'パスワードを編集',
editPermissions_title: '権限を編集',
editStopwatch_title: 'タイマーを編集', editStopwatch_title: 'タイマーを編集',
editUsername_title: 'ユーザー名を編集', editUsername_title: 'ユーザー名を編集',
email: 'Eメール', email: 'Eメール',
emailAlreadyInUse: 'Eメールは既に使われています', emailAlreadyInUse: 'Eメールは既に使われています',
enterCardTitle: 'カードのタイトルを入力...', enterCardTitle: 'カードのタイトルを入力… [Ctrl+Enter]で自動的に開く。',
enterDescription: '説明を入力...', enterDescription: '説明を入力…',
enterFilename: 'ファイル名を入力...', enterFilename: 'ファイル名を入力',
enterListTitle: 'リストのタイトルを入力...', enterListTitle: 'リストのタイトルを入力…',
enterProjectTitle: 'プロジェクトのタイトルを入力', enterProjectTitle: 'プロジェクトのタイトルを入力',
enterTaskDescription: 'タスクの説明を入力...', enterTaskDescription: 'タスクの説明を入力…',
filterByLabels_title: 'ラベルで絞り込む', filterByLabels_title: 'ラベルで絞り込む',
filterByMembers_title: 'メンバーで絞り込む', filterByMembers_title: 'メンバーで絞り込む',
fromComputer_title: 'コンピューターから', fromComputer_title: 'コンピューターから',
fromTrello: 'Trelloから',
general: '一般', general: '一般',
hours: '時間', hours: '時間',
importBoard_title: 'インポートボード',
invalidCurrentPassword: '現在のパスワードが無効', invalidCurrentPassword: '現在のパスワードが無効',
labels: 'ラベル', labels: 'ラベル',
language: '使用言語',
leaveBoard_title: 'ボードから退出', leaveBoard_title: 'ボードから退出',
leaveProject_title: 'プロジェクトから退出', leaveProject_title: 'プロジェクトから退出',
list: 'リスト', list: 'リスト',
@@ -110,41 +121,48 @@ export default {
noLists: 'リストがありません', noLists: 'リストがありません',
noProjects: 'プロジェクトがありません', noProjects: 'プロジェクトがありません',
notifications: '通知', notifications: '通知',
noUnreadNotifications: '未読の通知はありません', noUnreadNotifications: '未読の通知はありません。',
openBoard_title: 'ボードを開く', openBoard_title: 'ボードを開く',
optional_inline: '任意', optional_inline: '任意',
organization: '組織', organization: '組織',
phone: '電話番号', phone: '電話番号',
preferences: '環境設定', preferences: '環境設定',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'ヒント: Ctrl-V(MacではCmd-V)を押して、クリップボードから添付ファイルを追加します', 'ヒント: Ctrl-V(MacではCmd-V)を押して、クリップボードから添付ファイルを追加します。',
project: 'プロジェクト', project: 'プロジェクト',
projectNotFound_title: 'プロジェクトがありません', projectNotFound_title: 'プロジェクトがありません',
removeManager_title: 'マネージャーを削除', removeManager_title: 'マネージャーを削除',
removeMember_title: 'メンバーを削除', removeMember_title: 'メンバーを削除',
searchLabels: 'ラベルから探す…',
searchMembers: 'メンバーから探す…',
searchUsers: 'ユーザーから探す…',
seconds: '秒', seconds: '秒',
selectBoard: 'ボードを選択', selectBoard: 'ボードを選択',
selectList: 'リストを選択', selectList: 'リストを選択',
selectPermissions_title: '権限を選択',
selectProject: 'プロジェクトを選択', selectProject: 'プロジェクトを選択',
settings: '設定', settings: '設定',
stopwatch: 'タイマー', stopwatch: 'タイマー',
subscribeToMyOwnCardsByDefault: '自分のカードをデフォルトで購読する', subscribeToMyOwnCardsByDefault: '自分のカードをデフォルトで購読する',
taskActions_title: 'タスクのアクション', taskActions_title: 'タスクのアクション',
tasks: 'タスク', tasks: 'タスク',
thereIsNoPreviewAvailableForThisAttachment: 'この添付ファイルにはプレビューがありません。',
time: '時間', time: '時間',
title: 'タイトル', title: 'タイトル',
userActions_title: 'ユーザーのアクション', userActions_title: 'ユーザーのアクション',
userAddedThisCardToList: '<0>{{user}}</0> は <1>{{list}} をこのカードに追加しました</1>', userAddedThisCardToList: '<0>{{user}}</0> 様が <1>{{list}} をこのカードに追加しました</1>',
userLeftNewCommentToCard: userLeftNewCommentToCard:
'{{user}} は <2> {{card}} </2> に新しいコメント «{{comment}}» を残しました', '{{user}} 様が <2> {{card}} </2> に新しいコメント «{{comment}}» を残しました',
userMovedCardFromListToList: userMovedCardFromListToList:
'{{user}} は <2> {{card}} </2> を {{fromList}} から {{toList}} に移動しました', '{{user}} 様が <2> {{card}} </2> を {{fromList}} から {{toList}} に移動しました',
userMovedThisCardFromListToList: userMovedThisCardFromListToList:
'<0>{{user}}</0> <1>はこのカードを {{fromList}} から {{toList}} に移動しました</1>', '<0>{{user}}</0> <1>様がこのカードを {{fromList}} から {{toList}} に移動しました</1>',
username: 'ユーザー名', username: 'ユーザー名',
usernameAlreadyInUse: 'ユーザー名は既に使われています', usernameAlreadyInUse: 'ユーザー名は既に使われています',
users: 'ユーザー', users: 'ユーザー',
writeComment: 'コメントを書く...', version: 'バージョン',
viewer: 'ビューア',
writeComment: 'コメントを書く…',
}, },
action: { action: {
@@ -155,6 +173,7 @@ export default {
addCard_title: 'カードを追加', addCard_title: 'カードを追加',
addComment: 'コメントを追加', addComment: 'コメントを追加',
addList: 'リストを追加', addList: 'リストを追加',
addMember: 'メンバーを追加',
addMoreDetailedDescription: 'より詳細な説明を追加', addMoreDetailedDescription: 'より詳細な説明を追加',
addTask: 'タスクを追加', addTask: 'タスクを追加',
addToCard: 'カードに追加', addToCard: 'カードに追加',
@@ -184,10 +203,14 @@ export default {
editDueDate_title: '期限を編集', editDueDate_title: '期限を編集',
editDescription_title: '説明を編集', editDescription_title: '説明を編集',
editEmail_title: 'Eメールを編集', editEmail_title: 'Eメールを編集',
editInformation_title: '情報を編集',
editPassword_title: 'パスワードの編集', editPassword_title: 'パスワードの編集',
editPermissions: '権限を編集',
editStopwatch_title: 'タイマーの編集', editStopwatch_title: 'タイマーの編集',
editTitle_title: 'タイトルの編集', editTitle_title: 'タイトルの編集',
editUsername_title: 'ユーザー名の編集', editUsername_title: 'ユーザー名の編集',
hideDetails: '詳細を隠す',
import: 'インポート',
leaveBoard: 'ボードから退出', leaveBoard: 'ボードから退出',
leaveProject: 'プロジェクトから退出', leaveProject: 'プロジェクトから退出',
logOut_title: 'ログアウト', logOut_title: 'ログアウト',
@@ -203,6 +226,7 @@ export default {
removeMember: 'メンバーを削除', removeMember: 'メンバーを削除',
save: '保存', save: '保存',
showAllAttachments: '全ての添付ファイルを表示する({{hidden}} 非表示)', showAllAttachments: '全ての添付ファイルを表示する({{hidden}} 非表示)',
showDetails: '詳細を表示',
showFewerAttachments: 'テンプファイルの表示数を減らす', showFewerAttachments: 'テンプファイルの表示数を減らす',
start: 'スタート', start: 'スタート',
stop: 'ストップ', stop: 'ストップ',
+4 -2
View File
@@ -5,16 +5,18 @@ export default {
invalidEmailOrUsername: 'Eメールまたはユーザー名が無効', invalidEmailOrUsername: 'Eメールまたはユーザー名が無効',
invalidPassword: 'パスワードが無効', invalidPassword: 'パスワードが無効',
logInToPlanka: 'Planka にログインする', logInToPlanka: 'Planka にログインする',
noInternetConnection: 'インターネットに接続されていません。', noInternetConnection: 'インターネットに接続されていません',
pageNotFound_title: 'ページが見つかりません。', pageNotFound_title: 'ページが見つかりません',
password: 'パスワード', password: 'パスワード',
projectManagement: 'プロジェクト管理', projectManagement: 'プロジェクト管理',
serverConnectionFailed: 'サーバーの接続に失敗', serverConnectionFailed: 'サーバーの接続に失敗',
unknownError: '不明なエラーです。後でもう一度試してください。', unknownError: '不明なエラーです。後でもう一度試してください。',
useSingleSignOn: 'SSOを使用',
}, },
action: { action: {
logIn: 'ログイン', logIn: 'ログイン',
logInWithSSO: 'SSOでログイン',
}, },
}, },
}; };
+146 -128
View File
@@ -1,167 +1,181 @@
import dateFns from 'date-fns/locale/ko'; import dateFns from 'date-fns/locale/ko';
/* Translated by Park Seok Ho */
export default { export default {
dateFns, dateFns,
format: { format: {
date: 'yyyy/M/d', date: 'yyyy/M/d',
time: 'HH:mm', time: 'a hh시 mm분',
dateTime: '$t(format:date) $t(format:time)', dateTime: '$t(format:date) $t(format:time)',
longDate: 'MMMMd일', longDate: "MMMMd'일'",
longDateTime: "MMMMd'일 ' HH:MM", longDateTime: "MMMMd'일 ' a hh시 mm분",
}, },
translation: { translation: {
common: { common: {
aboutPlanka: 'Planka에 대해서',
account: '계정', account: '계정',
actions: '활동', actions: '활동',
addAttachment_title: '첨부파일 추가', addAttachment_title: '첨부 파일 추가',
addComment: '댓글', addComment: '댓글',
addManager_title: '관리자 추가', addManager_title: '매니저 추가',
addMember_title: '회원 추가', addMember_title: '멤버 추가',
addUser_title: '사용자 추가', addUser_title: '사용자 추가',
administrator: '시스템 관리자', administrator: '관리자',
all: 'All', all: '모두',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'모든 변경 사항은 연결이 복원된 후 자동으로 저장됩니다', '연결이 복원되면<br />모든 변경 사항이 자동으로 저장됩니다.',
areYouSureYouWantToDeleteThisAttachment: '첨부 파일을 삭제하시겠습니까?', areYouSureYouWantToDeleteThisAttachment: '해당하는 첨부 파일을 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisBoard: '보드를 삭제하시겠습니까?', areYouSureYouWantToDeleteThisBoard: '해당하는 보드를 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisCard: '항목카드를 삭제하시겠습니까?', areYouSureYouWantToDeleteThisCard: '해당하는 항목카드를 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisComment: '댓글을 삭제하시겠습니까?', areYouSureYouWantToDeleteThisComment: '해당하는 댓글을 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisLabel: '라벨을 삭제하시겠습니까?', areYouSureYouWantToDeleteThisLabel: '해당하는 라벨을 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisList: '리스트를 삭제하시겠습니까?', areYouSureYouWantToDeleteThisList: '해당하는 목록를 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisProject: '프로젝트를 삭제하시겠습니까?', areYouSureYouWantToDeleteThisProject: '해당하는 프로젝트를 삭제하시겠습니까?',
areYouSureYouWantToDeleteThisTask: '태스트를 삭제하겠습니까?', areYouSureYouWantToDeleteThisTask: '해당하는 업무를 삭제하겠습니까?',
areYouSureYouWantToDeleteThisUser: '이 유저를 삭제하겠습니까?', areYouSureYouWantToDeleteThisUser: '해당하는 사용자를 삭제하겠습니까?',
areYouSureYouWantToLeaveBoard: '이 보드에서 나가시겠습니까?', areYouSureYouWantToLeaveBoard: '이 보드에서 나가시겠습니까?',
areYouSureYouWantToLeaveProject: '이 프로젝트에서 나가시겠습니까?', areYouSureYouWantToLeaveProject: '이 프로젝트에서 나가시겠습니까?',
areYouSureYouWantToRemoveThisManagerFromProject: '프로젝트에서 관리자를 제거하시겠습니까?', areYouSureYouWantToRemoveThisManagerFromProject:
areYouSureYouWantToRemoveThisMemberFromBoard: '이 회원을 보드에서 탈퇴시키겠습니까?', '해당하는 프로젝트에서 매니저를 제거하시겠습니까?',
attachment: '첨부파일', areYouSureYouWantToRemoveThisMemberFromBoard: '해당하는 멤버를 보드에서 삭제하시겠습니까?',
attachments: '첨부파일', attachment: '첨부',
authentication: '계정 관리', attachments: '첨부 파일',
background: 'Background', authentication: '인증',
background: '배경',
board: '보드', board: '보드',
boardNotFound_title: '보드를 찾을 수 없습니다.', boardNotFound_title: '보드를 찾을 수 없습니다',
cardActions_title: 'Card Actions', canComment: '댓글을 작성할 수 있습니다',
cardNotFound_title: '항목카드를 찾을 수 없습니다.', canEditContentOfBoard: '보드 콘텐츠를 수정할 수 있습니다.',
cardOrActionAreDeleted: '항목카드 혹은 활동내역이 삭제되었습니다.', canOnlyViewBoard: '보드를 읽기만 할 수 있습니다.',
color: 'Color', cardActions_title: '카드 작업',
createBoard_title: '보드명칭을 입력하세요.', cardNotFound_title: '카드를 찾을 수 없습니다',
cardOrActionAreDeleted: '카드 또는 작업이 삭제되었습니다.',
color: '색상',
createBoard_title: '보드 생성',
createLabel_title: '라벨 생성', createLabel_title: '라벨 생성',
createNewOneOrSelectExistingOne: '새 항목을 만들거나<br />기존 항목을 선택하세요.', createNewOneOrSelectExistingOne: '새로 생성하거나<br />기존 항목을 선택하세요.',
createProject_title: '프로젝트 생성', createProject_title: '프로젝트 생성',
createTextFile_title: 'Text File 생성', createTextFile_title: '텍스트 파일 생성',
currentPassword: '현재 비밀번호', currentPassword: '현재 비밀번호',
dangerZone_title: 'Danger Zone', dangerZone_title: '위험 구역',
date: '날짜', date: '날짜',
dueDate_title: '완료일', dueDate_title: '마감일',
deleteAttachment_title: '첨부파일 삭제', deleteAttachment_title: '첨부 파일 삭제',
deleteBoard_title: '보드 삭제', deleteBoard_title: '보드 삭제',
deleteCard_title: '항목 카드 삭제', deleteCard_title: '카드 삭제',
deleteComment_title: '댓글 삭제', deleteComment_title: '댓글 삭제',
deleteLabel_title: '라벨 삭제', deleteLabel_title: '라벨 삭제',
deleteList_title: '리스트 삭제', deleteList_title: '목록 삭제',
deleteProject_title: '프로젝트 삭제', deleteProject_title: '프로젝트 삭제',
deleteTask_title: '태스크 삭제', deleteTask_title: '업무 삭제',
deleteUser_title: '사용자 삭제', deleteUser_title: '사용자 삭제',
description: '설명', description: '설명',
detectAutomatically: '자동으로 감지', detectAutomatically: '자동으로 감지',
dropFileToUpload: '업로드 하기 위해서 파일을 Drop 하세요.', dropFileToUpload: '업로드할 파일 놓기',
editor: '편집기',
editAttachment_title: '첨부 수정', editAttachment_title: '첨부 수정',
editAvatar_title: '프로필사진 수정', editAvatar_title: '아바타 수정',
editBoard_title: '보드 수정', editBoard_title: '보드 수정',
editDueDate_title: '완료일 수정', editDueDate_title: '마감일 수정',
editEmail_title: '메일 수정', editEmail_title: '이메일 수정',
editInformation_title: '정보 수정', editInformation_title: '정보 수정',
editLabel_title: '라벨 수정', editLabel_title: '라벨 수정',
editPassword_title: '비밀번호 수정', editPassword_title: '비밀번호 수정',
editStopwatch_title: '타이머 수정', editPermissions_title: '권한 수정',
editUsername_title: '사용자이름 수정', editStopwatch_title: '스톱워치 수정',
email: '메일', editUsername_title: '사용자 이름 수정',
emailAlreadyInUse: '기 가입된 이메일이 존재합니다.', email: '이메일',
enterCardTitle: '항목카드명을 입력하세요...', emailAlreadyInUse: '이미 사용 중인 이메일입니다',
enterDescription: '자세한 설명을 작성하세요...', enterCardTitle: '카드 제목 입력... [Ctrl+Enter]로 자동으로 열 수 있습니다.',
enterFilename: '파일이름을 입력하세요...', enterDescription: '설명 입력...',
enterListTitle: '리스트명을 입력 (예,todo,완료,이슈등...)', enterFilename: '파일 이름 입력',
enterProjectTitle: '프로젝트명칭을 입력하세요.', enterListTitle: '목록 제목 입력...',
enterTaskDescription: '태스크 설명을 입력하세요...', enterProjectTitle: '프로젝트 제목 입력',
filterByLabels_title: '라벨 검색', enterTaskDescription: '업무 설명 입력...',
filterByMembers_title: '회원으로 검색', filterByLabels_title: '라벨로 필터링',
fromComputer_title: 'PC로 부터', filterByMembers_title: '멤버로 필터링',
general: 'General', fromComputer_title: 'PC에서',
fromTrello: '트렐로에서',
general: '일반',
hours: '시', hours: '시',
invalidCurrentPassword: '현재 패스워드는 유효하지 않습니다.', importBoard_title: '보드 가져오기',
invalidCurrentPassword: '현재 비밀번호가 일치하지 않습니다',
labels: '라벨', labels: '라벨',
language: '언어 선택', language: '언어',
leaveBoard_title: '보드 탈퇴', leaveBoard_title: '보드 떠나기',
leaveProject_title: '프로젝트 탈퇴', leaveProject_title: '프로젝트 떠나기',
list: '내역', list: '목록',
listActions_title: '활용 내역', listActions_title: '목록 항목 조율',
managers: '관리자', managers: '매니저',
members: '팀원', members: '멤버',
minutes: '분', minutes: '분',
moveCard_title: '항목카드 이동', moveCard_title: '카드 옮기기',
name: '이름', name: '이름',
newEmail: '새로운 메일', newEmail: '새로운 이메일',
newPassword: '새로운 패스워드', newPassword: '새로운 비밀번호',
newUsername: '새로운 사용자 이름', newUsername: '새로운 사용자 이름',
noConnectionToServer: '서버에 연결할수 없습니다.', noConnectionToServer: '서버에 연결할 수 없습니다',
noBoards: '보드가 존재하지 않습니다.', noBoards: '보드가 존재하지 않습니다',
noLists: '리스트가 존재하지 않습니다.', noLists: '목록이 존재하지 않습니다',
noProjects: '프로젝트가 존재하지 않습니다.', noProjects: '프로젝트가 존재하지 않습니다',
notifications: '알림', notifications: '알림',
noUnreadNotifications: '알림을 모두 확인했습니다.', noUnreadNotifications: '확인하지 않은 알림이 없습니다.',
openBoard_title: '보드열기', openBoard_title: '보드 열기',
optional_inline: '옵션', optional_inline: '옵션',
organization: '조직', organization: '조직',
phone: '전화번호', phone: '전화번호',
preferences: '환경설정', preferences: '환경설정',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: 클립보드에서 첨부 파일을 추가하려면 Ctrl-V(Mac의 경우 Cmd-V) 입니다..', '팁: 클립보드에서 첨부 파일을 추가하려면 Ctrl-V (Mac의 경우 Cmd-V)를 누릅니다.',
project: '프로젝트', project: '프로젝트',
projectNotFound_title: '프로젝트가 존재하지 않습니다.', projectNotFound_title: '프로젝트를 찾을 수 없습니다',
removeManager_title: '관리자 삭제', removeManager_title: '매니저 삭제',
removeMember_title: '맴버 삭제', removeMember_title: '멤버 삭제',
searchLabels: '라벨 검색...',
searchMembers: '멤버 검색...',
searchUsers: '사용자 검색...',
seconds: '초', seconds: '초',
selectBoard: '보드 선택', selectBoard: '보드 선택',
selectList: '리스트 선택', selectList: '목록 선택',
selectPermissions_title: '권한 선택',
selectProject: '프로젝트 선택', selectProject: '프로젝트 선택',
settings: '설정', settings: '설정',
stopwatch: '활동시간', stopwatch: '스톱워치',
subscribeToMyOwnCardsByDefault: '내 항목카드는 기본으로 구독', subscribeToMyOwnCardsByDefault: '기본적으로 내 카드를 구독합니다',
taskActions_title: '태스크 활동', taskActions_title: '업무 조율',
tasks: '태스크', tasks: '업무',
thereIsNoPreviewAvailableForThisAttachment: thereIsNoPreviewAvailableForThisAttachment: '이 첨부 파일은 미리 보기를 사용할 수 없습니다.',
'이 첨부 파일에 사용할 수 있는 미리보기가 없습니다.',
time: '시간', time: '시간',
title: '제목', title: '제목',
userActions_title: '', userActions_title: '사용자 조율',
userAddedThisCardToList: '<0>{{user}}</0><1>이 카드를 {{list}}</1>에 추가했습니다.', userAddedThisCardToList: '<0>{{user}}</0>님이 <1>{{list}}에 카드를 추가했습니다</1>',
userLeftNewCommentToCard: userLeftNewCommentToCard:
'{{user}}이(가) <2>{{card}}</2>에 «{{comment}}»라는 댓글을 남겼습니다', '{{user}}님이 <2>{{card}}</2>에 «{{comment}}»라는 댓글을 남겼습니다',
userMovedCardFromListToList: '{{user}} moved <2>{{card}}</2> from {{fromList}} to {{toList}}', userMovedCardFromListToList:
'{{user}}님이 {{fromList}}에서 {{toList}}로 <2>{{card}}</2>를 옮겼습니다',
userMovedThisCardFromListToList: userMovedThisCardFromListToList:
'<0>{{user}}</0><1> 이 항목카드를 {{fromList}} 에서 {{toList}} 으로 이동했습니다. </1>', '<0>{{user}}</0><1> 님이 {{fromList}}에서 {{toList}}로 이 카드를 옮겼습니다</1>',
username: '아이디', username: '사용자 이름',
usernameAlreadyInUse: '이미 사용중인 사용자입니다.', usernameAlreadyInUse: '이미 사용중인 사용자 이름입니다',
users: '사용자', users: '사용자',
writeComment: '댓글 작성...', version: '버전',
viewer: '열람자',
writeComment: '댓글 쓰기...',
}, },
action: { action: {
addAnotherCard: '다른 항목카드 추가', addAnotherCard: '다른 카드 추가',
addAnotherList: '다른 리스트 추가', addAnotherList: '다른 목록 추가',
addAnotherTask: '다른 TASK 추가', addAnotherTask: '다른 업무 추가',
addCard: '항목카드 추가', addCard: '카드 추가',
addCard_title: '항목카드 추가', addCard_title: '카드 추가',
addComment: '댓글 추가', addComment: '댓글 추가',
addList: '리스트 추가', addList: '목록 추가',
addMember: '멤버 추가',
addMoreDetailedDescription: '자세한 설명 추가', addMoreDetailedDescription: '자세한 설명 추가',
addTask: '태스트 추가', addTask: '업무 추가',
addToCard: '항목카드 추가', addToCard: '카드에 추가',
addUser: '사용자 추가', addUser: '사용자 추가',
createBoard: '보드 생성', createBoard: '보드 생성',
createFile: '파일 생성', createFile: '파일 생성',
@@ -169,51 +183,55 @@ export default {
createNewLabel: '새로운 라벨 생성', createNewLabel: '새로운 라벨 생성',
createProject: '프로젝트 생성', createProject: '프로젝트 생성',
delete: '삭제', delete: '삭제',
deleteAttachment: '첨부삭제', deleteAttachment: '첨부 삭제',
deleteAvatar: '프로필 사진 삭제', deleteAvatar: '아바타 삭제',
deleteBoard: '보드 삭제', deleteBoard: '보드 삭제',
deleteCard: '항목카드 삭제', deleteCard: '카드 삭제',
deleteCard_title: '항목카드 삭제', deleteCard_title: '카드 삭제',
deleteComment: '댓글 삭제', deleteComment: '댓글 삭제',
deleteImage: '이미지 삭제', deleteImage: '이미지 삭제',
deleteLabel: '라벨 삭제', deleteLabel: '라벨 삭제',
deleteList: '리스트 삭제', deleteList: '목록 삭제',
deleteList_title: '리스트 삭제', deleteList_title: '목록 삭제',
deleteProject: '프로젝트 삭제', deleteProject: '프로젝트 삭제',
deleteProject_title: '프로젝트 삭제', deleteProject_title: '프로젝트 삭제',
deleteTask: '태스트 삭제', deleteTask: '업무 삭제',
deleteTask_title: '태스트 삭제', deleteTask_title: '업무 삭제',
deleteUser: '사용자 삭제', deleteUser: '사용자 삭제',
edit: '수정', edit: '수정',
editDueDate_title: '완료일 수정', editDueDate_title: '마감일 수정',
editDescription_title: '설명 수정', editDescription_title: '설명 수정',
editEmail_title: '메일 수정', editEmail_title: '이메일 수정',
editInformation_title: '정보 수정', editInformation_title: '정보 수정',
editPassword_title: '패스워드 수정', editPassword_title: '비밀번호 수정',
editStopwatch_title: '시간 수정', editPermissions: '권한 수정',
editStopwatch_title: '스톱워치 수정',
editTitle_title: '제목 수정', editTitle_title: '제목 수정',
editUsername_title: '이름 수정', editUsername_title: '사용자 이름 수정',
leaveBoard: '보드에서 나가기', hideDetails: '세부 사항 숨기기',
leaveProject: '프로젝트에서 나가기', import: '가져오기',
leaveBoard: '보드 나가기',
leaveProject: '프로젝트 나가기',
logOut_title: '로그아웃', logOut_title: '로그아웃',
makeCover_title: '커버 만들기', makeCover_title: '커버 만들기',
move: '이동', move: '이동',
moveCard_title: '항목카드 이동', moveCard_title: '카드 이동',
remove: '제거', remove: '제거',
removeBackground: '백그라운드 제거', removeBackground: '배경 제거',
removeCover_title: '커버 제거', removeCover_title: '커버 제거',
removeFromBoard: '보드에서 제거', removeFromBoard: '보드 제거',
removeFromProject: '프로젝트에서 제거', removeFromProject: '프로젝트 제거',
removeManager: '관리자 삭제', removeManager: '매니저 제거',
removeMember: '멤버 삭제', removeMember: '멤버 제거',
save: '저장', save: '저장',
showAllAttachments: '모든 첨부파일 표시 ({{hidden}} hidden)', showAllAttachments: '모든 첨부 파일 표시 ({{hidden}} 숨겨짐)',
showFewerAttachments: '일부 첨부파일만 표시', showDetails: '세부 사항 표시',
showFewerAttachments: '일부 첨부 파일만 표시',
start: '시작', start: '시작',
stop: '끝', stop: '종료',
subscribe: '구독하기', subscribe: '구독',
unsubscribe: '구독 취소', unsubscribe: '구독 취소',
uploadNewAvatar: '새로운 프로필 사진 업로드', uploadNewAvatar: '새로운 아바타 업로드',
uploadNewImage: '새로운 이미지 업로드', uploadNewImage: '새로운 이미지 업로드',
}, },
}, },
+10 -10
View File
@@ -1,22 +1,22 @@
/* Translated by Park Seok Ho */
export default { export default {
translation: { translation: {
common: { common: {
emailOrUsername: '이메일 혹은 아이디', emailOrUsername: '이메일 혹은 사용자 이름',
invalidEmailOrUsername: '이메일이나 사용자 이름이 유효하지 않습니다.', invalidEmailOrUsername: '이메일 혹은 사용자 이름이 유효하지 않습니다',
invalidPassword: '잘못된 비밀번호', invalidPassword: '유효하지 않은 비밀번호',
logInToPlanka: 'Planka에 로그인', logInToPlanka: 'Planka에 로그인',
noInternetConnection: '인터넷에 연결되지 않음', noInternetConnection: '인터넷 연결이 없음',
pageNotFound_title: '페이지를 찾을수 없습니다.', pageNotFound_title: '페이지를 찾을 수 없습니다',
password: '패스워드', password: '비밀번호',
projectManagement: '프로젝트 관리', projectManagement: '프로젝트 관리',
serverConnectionFailed: '서버 연결 실패', serverConnectionFailed: '서버 연결에 실패함',
unknownError: '알 수 없는 오류가 발생하였습니다, 나중에 다시 시도하세요.', unknownError: '알 수 없는 오류, 나중에 다시 시도하십시오',
useSingleSignOn: 'single sign-on(SSO) 사용',
}, },
action: { action: {
logIn: '로그인', logIn: '로그인',
logInWithSSO: 'single sign-on(SSO)으로 로그인',
}, },
}, },
}; };
+5 -5
View File
@@ -22,7 +22,7 @@ export default {
administrator: 'Administrator', administrator: 'Administrator',
all: 'Wszyscy', all: 'Wszyscy',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Wszystkie zmiany zostaną automatycznie zapisane<br />po przywróceniu połączenia', 'Wszystkie zmiany zostaną automatycznie zapisane<br />po przywróceniu połączenia.',
areYouSureYouWantToDeleteThisAttachment: 'Jesteś pewien że chcesz usunąć ten załącznik?', areYouSureYouWantToDeleteThisAttachment: 'Jesteś pewien że chcesz usunąć ten załącznik?',
areYouSureYouWantToDeleteThisBoard: 'Jesteś pewien że chcesz usunąć tę tablicę?', areYouSureYouWantToDeleteThisBoard: 'Jesteś pewien że chcesz usunąć tę tablicę?',
areYouSureYouWantToDeleteThisCard: 'Jesteś pewien że chcesz usunąć tę kartę?', areYouSureYouWantToDeleteThisCard: 'Jesteś pewien że chcesz usunąć tę kartę?',
@@ -41,11 +41,11 @@ export default {
boardNotFound_title: 'Tablica Nie Znaleziona', boardNotFound_title: 'Tablica Nie Znaleziona',
cardActions_title: 'Akcje Karty', cardActions_title: 'Akcje Karty',
cardNotFound_title: 'Karta Nie Znaleziona', cardNotFound_title: 'Karta Nie Znaleziona',
cardOrActionAreDeleted: 'Karta lub akcja została usunięta', cardOrActionAreDeleted: 'Karta lub akcja została usunięta.',
color: 'Kolor', color: 'Kolor',
createBoard_title: 'Utwórz Tablicę', createBoard_title: 'Utwórz Tablicę',
createLabel_title: 'Utwórz Oznaczenie', createLabel_title: 'Utwórz Oznaczenie',
createNewOneOrSelectExistingOne: 'Utwórz nowy lub wybierz<br />istniejący', createNewOneOrSelectExistingOne: 'Utwórz nowy lub wybierz<br />istniejący.',
createProject_title: 'Utwórz Projekt', createProject_title: 'Utwórz Projekt',
createTextFile_title: 'Utwórz Plik Tekstowy', createTextFile_title: 'Utwórz Plik Tekstowy',
currentPassword: 'Aktualne hasło', currentPassword: 'Aktualne hasło',
@@ -99,14 +99,14 @@ export default {
noLists: 'Brak list', noLists: 'Brak list',
noProjects: 'Brak projektów', noProjects: 'Brak projektów',
notifications: 'Powiadomienia', notifications: 'Powiadomienia',
noUnreadNotifications: 'Brak nieprzeczytanych powiadomień', noUnreadNotifications: 'Brak nieprzeczytanych powiadomień.',
openBoard_title: 'Otwórz Tablicę', openBoard_title: 'Otwórz Tablicę',
optional_inline: 'opcjonalny', optional_inline: 'opcjonalny',
organization: 'Organizacja', organization: 'Organizacja',
phone: 'Telefon', phone: 'Telefon',
preferences: 'Preferencje', preferences: 'Preferencje',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Podpowiedź: naciśnij Ctrl-V (Cmd-V na Macu) aby dodać załącznik ze schowka', 'Podpowiedź: naciśnij Ctrl-V (Cmd-V na Macu) aby dodać załącznik ze schowka.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt Nie Znaleziony', projectNotFound_title: 'Projekt Nie Znaleziony',
removeMember_title: 'Usuń Członka', removeMember_title: 'Usuń Członka',
+240
View File
@@ -0,0 +1,240 @@
import dateFns from 'date-fns/locale/ro';
export default {
dateFns,
format: {
date: 'P',
time: 'HH:mm',
dateTime: '$t(format:date) $t(format:time)',
longDate: 'd MMM',
longDateTime: "d MMMM 'в' p",
},
translation: {
common: {
aboutPlanka: 'Despre Planka',
account: 'Cont',
actions: 'Acțiuni',
addAttachment_title: 'Adauga atasament',
addComment: 'Adaugă comentariu',
addManager_title: 'Adaugă Manager',
addMember_title: 'Adaugă Membru',
addUser_title: 'Adaugă Utilizator',
administrator: 'Administrator',
all: 'Toate',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Toate modificarile vor fi salvate automat<br />dupa restabilirea conexiunii.',
areYouSureYouWantToDeleteThisAttachment: 'Sigur doriți să ștergeți acest atașament?',
areYouSureYouWantToDeleteThisBoard: 'Sigur doriți să ștergeți acest panou?',
areYouSureYouWantToDeleteThisCard: 'Sigur doriți să ștergeți acest card?',
areYouSureYouWantToDeleteThisComment: 'Sigur doriți să ștergeți acest comentariu?',
areYouSureYouWantToDeleteThisLabel: 'Sigur doriți să ștergeți această etichetă?',
areYouSureYouWantToDeleteThisList: 'Sigur doriți să ștergeți această listă?',
areYouSureYouWantToDeleteThisProject: 'Sigur doriți să ștergeți acest proiect?',
areYouSureYouWantToDeleteThisTask: 'Sigur doriți să ștergeți această sarcină?',
areYouSureYouWantToDeleteThisUser: 'Sigur doriți să ștergeți acest utilizator?',
areYouSureYouWantToLeaveBoard: 'Ești sigur că vrei să părăsești tabla?',
areYouSureYouWantToLeaveProject: 'Ești sigur că vrei să părăsești proiectul?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Sigur doriți să eliminați acest manager din proiect?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Sigur doriți să eliminați acest membru din consiliu?',
attachment: 'Atașament',
attachments: 'Atasamente',
authentication: 'Autentificare',
background: 'Fundal',
board: 'Tabla',
boardNotFound_title: 'Tabla nu a fost găsită',
canComment: 'Poate comenta',
canEditContentOfBoard: 'Poate edita conținutul tablei.',
canOnlyViewBoard: 'Poate doar vizualiza tabla.',
cardActions_title: 'Acțiuni cu carduri',
cardNotFound_title: 'Cardul nu a fost găsit',
cardOrActionAreDeleted: 'Cardul sau acțiunea sunt șterse.',
color: 'Culoarea',
createBoard_title: 'Creare Tabla',
createLabel_title: 'Creați etichetă',
createNewOneOrSelectExistingOne: 'Crează unu nou sau selectează<br />unu deja existent.',
createProject_title: 'Crează Proiect',
createTextFile_title: 'Crează un Fișier Text',
currentPassword: 'Parola Curentă',
dangerZone_title: 'Zona periculoasă',
date: 'Data',
dueDate_title: 'Data scadentă',
deleteAttachment_title: 'Ștergeți atașamentul',
deleteBoard_title: 'Ștergeți Tabla',
deleteCard_title: 'Ștergeți cardul',
deleteComment_title: 'Șterge comentariul',
deleteLabel_title: 'Ștergeți eticheta',
deleteList_title: 'Șterge lista',
deleteProject_title: 'Șterge proiectul',
deleteTask_title: 'Ștergeți sarcina',
deleteUser_title: 'Șterge utilizator',
description: 'Descriere',
detectAutomatically: 'Detectează automat',
dropFileToUpload: 'Aruncă fișierul pentru a încărca',
editor: 'Editor',
editAttachment_title: 'Editați atașamentul',
editAvatar_title: 'Editați avatarul',
editBoard_title: 'Editați tabla',
editDueDate_title: 'Editați data scadentă',
editEmail_title: 'Editați E-mail',
editInformation_title: 'Editați informații',
editLabel_title: 'Editați eticheta',
editPassword_title: 'Editați parola',
editPermissions_title: 'Editați permisiunile',
editStopwatch_title: 'Editați cronometrul',
editUsername_title: 'Editați numele de utilizator',
email: 'E-mail',
emailAlreadyInUse: 'E-mail deja utilizat',
enterCardTitle: 'Introduceți titlul cardului... [Ctrl+Enter] pentru a se deschide automat.',
enterDescription: 'Introduceți descrierea...',
enterFilename: 'Introduceți numele fișierului',
enterListTitle: 'Introduceți titlul listei...',
enterProjectTitle: 'Introduceți titlul proiectului',
enterTaskDescription: 'Introduceți descrierea sarcinii...',
filterByLabels_title: 'Filtrați după etichete',
filterByMembers_title: 'Filtrați după membri',
fromComputer_title: 'De pe computer',
fromTrello: 'De pe Trello',
general: 'General',
hours: 'Ore',
importBoard_title: 'Import Tabla',
invalidCurrentPassword: 'Parolă actuală nevalidă',
labels: 'Etichete',
language: 'Limba',
leaveBoard_title: 'Părăsiți Tabla',
leaveProject_title: 'Părăsiți proiectul',
list: 'Lista',
listActions_title: 'Listează acțiuni',
managers: 'Managerii',
members: 'Membri',
minutes: 'Minute',
moveCard_title: 'Mutați cardul',
name: 'Nume',
newEmail: 'Email nou',
newPassword: 'Parolă Nouă',
newUsername: 'Nume de utilizator nou',
noConnectionToServer: 'Nicio conexiune la server',
noBoards: 'Fără Table',
noLists: 'Fără Liste',
noProjects: 'Fără proiecte',
notifications: 'Notificări',
noUnreadNotifications: 'Fără notificări necitite.',
openBoard_title: 'Tablă deschisă',
optional_inline: 'optional',
organization: 'Organizatia',
phone: 'Telefon',
preferences: 'Preferințe',
pressPasteShortcutToAddAttachmentFromClipboard:
'Sfat: apăsați Ctrl-V (Cmd-V pe Mac) pentru a adăuga un atașament din clipboard.',
project: 'Proiect',
projectNotFound_title: 'Proiectul nu a fost găsit',
removeManager_title: 'Eliminați Manager',
removeMember_title: 'Eliminați membru',
searchLabels: 'Căutați etichete...',
searchMembers: 'Căutați membri...',
searchUsers: 'Căutați utilizatori...',
seconds: 'Secunde',
selectBoard: 'Selectați tabla',
selectList: 'Selectați lista',
selectPermissions_title: 'Selectați Permisiuni',
selectProject: 'Selectați proiectul',
settings: 'Setări',
stopwatch: 'Cronometru',
subscribeToMyOwnCardsByDefault: 'Abonați-vă la propriile carduri în mod implicit',
taskActions_title: 'Acțiuni de sarcină',
tasks: 'Sarcini',
thereIsNoPreviewAvailableForThisAttachment:
'Nu există nicio previzualizare disponibilă pentru acest atașament.',
time: 'Timp',
title: 'Titlu',
userActions_title: 'Acțiunile utilizatorului',
userAddedThisCardToList: '<0>{{user}}</0><1> a adăugat acest card în {{list}}</1>',
userLeftNewCommentToCard:
'{{user}} a lăsat un nou comentariu «{{comment}}» în <2>{{card}}</2>',
userMovedCardFromListToList:
'{{user}} a mutat <2>{{card}}</2> din {{fromList}} în {{toList}}',
userMovedThisCardFromListToList:
'<0>{{user}}</0><1> a mutat aceast card din {{fromList}} în {{toList}}</1>',
username: 'Nume utilizator',
usernameAlreadyInUse: 'Nume utilizator deja exista',
users: 'Utilizatori',
version: 'Versiunea',
viewer: 'Vizualizator',
writeComment: 'Scrie un comentariu...',
},
action: {
addAnotherCard: 'Adăugați un alt card',
addAnotherList: 'Adăugați o altă listă',
addAnotherTask: 'Adăugați o altă sarcină',
addCard: 'Adăugați card',
addCard_title: 'Adăugați card',
addComment: 'Adauga comentariu',
addList: 'Adăugați listă',
addMember: 'Adăugați membru',
addMoreDetailedDescription: 'Adăugați descrierea mai detaliata',
addTask: 'Adăugați sarcină',
addToCard: 'Adauga în card',
addUser: 'Adăugați utilizator',
createBoard: 'Creați tablă',
createFile: 'Creați fișier',
createLabel: 'Creați eticheta',
createNewLabel: 'Creați o nouă etichetă',
createProject: 'Creați proiect',
delete: 'Ștergeți',
deleteAttachment: 'Ștergeți atașamentul',
deleteAvatar: 'Ștergeți avatarul',
deleteBoard: 'Ștergeți tabla',
deleteCard: 'Ștergeți cardul',
deleteCard_title: 'Ștergeți Cardul',
deleteComment: 'Șterge comentariu',
deleteImage: 'Șterge imaginea',
deleteLabel: 'Ștergeți Eticheta',
deleteList: 'Ștergeți lista',
deleteList_title: 'Ștergeți Lista',
deleteProject: 'Ștergeți proiectul',
deleteProject_title: 'Ștergeți Proiectul',
deleteTask: 'Ștergeți sarcina',
deleteTask_title: 'Ștergeți Sarcina',
deleteUser: 'Ștergeți utilizatorul',
edit: 'Editați',
editDueDate_title: 'Editați data scadentă',
editDescription_title: 'Editați descrierea',
editEmail_title: 'Editați e-mailul',
editInformation_title: 'Editați informații',
editPassword_title: 'Editați parola',
editPermissions: 'Editați permisiunile',
editStopwatch_title: 'Editați cronometrul',
editTitle_title: 'Editați Titlul',
editUsername_title: 'Editați Numele Utilizator',
hideDetails: 'Ascunde detalii',
import: 'Import',
leaveBoard: 'Părăsiți bordul',
leaveProject: 'Părăsiți proiect',
logOut_title: 'Deconectați-vă',
makeCover_title: 'Faceți Coperta',
move: 'Mutați',
moveCard_title: 'Mutați cardul',
remove: 'Eliminați',
removeBackground: 'Eliminați fundalul',
removeCover_title: 'Eliminați Coperta',
removeFromBoard: 'Eliminați din Tabla',
removeFromProject: 'Eliminați din proiect',
removeManager: 'Eliminați managerul',
removeMember: 'Eliminați membrul',
save: 'Salveaza',
showAllAttachments: 'Afișați toate atașamentele ({{hidden}} ascunse)',
showDetails: 'Arată detalii',
showFewerAttachments: 'Afișați mai puține atașamente',
start: 'Start',
stop: 'Stop',
subscribe: 'Abonati-va',
unsubscribe: 'Dezabonați-vă',
uploadNewAvatar: 'Încărcați un avatar nou',
uploadNewImage: 'Încărcați o nouă imagine',
},
},
};
+8
View File
@@ -0,0 +1,8 @@
import login from './login';
export default {
language: 'ro',
country: 'ro',
name: 'Română',
embeddedLocale: login,
};
+22
View File
@@ -0,0 +1,22 @@
export default {
translation: {
common: {
emailOrUsername: 'E-mail sau nume de utilizator',
invalidEmailOrUsername: 'E-mail sau nume de utilizator introduse greșit',
invalidPassword: 'Parola greșita',
logInToPlanka: 'Autentificarea în Planka',
noInternetConnection: 'Lipsește conexiunea cu internet',
pageNotFound_title: 'Pagina n-a fost găsită',
password: 'Parola',
projectManagement: 'Gestionarea proiectului',
serverConnectionFailed: 'Conexiunea cu Server a eșuat',
unknownError: 'Eroarea necunoscuta, mai incercați',
useSingleSignOn: 'Folosiți autentificarea unica',
},
action: {
logIn: 'Autentificarea',
logInWithSSO: 'Autentificarea cu SSO',
},
},
};
+35 -12
View File
@@ -13,16 +13,18 @@ export default {
translation: { translation: {
common: { common: {
aboutPlanka: 'О проекте Planka',
account: 'Учетная запись', account: 'Учетная запись',
actions: 'Действия', actions: 'Действия',
addAttachment: 'Добавление вложения', addAttachment: 'Добавление вложения',
addComment: 'Добавление комментария', addComment: 'Добавление комментария',
addManager_title: 'Добавление менеджера',
addMember: 'Добавление участника', addMember: 'Добавление участника',
addUser: 'Добавление пользователя', addUser: 'Добавление пользователя',
administrator: 'Администратор', administrator: 'Администратор',
all: 'Все', all: 'Все',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Все изменения сохранятся автоматически,<br />как только подключение восстановится', 'Все изменения сохранятся автоматически,<br />как только подключение восстановится.',
areYouSureYouWantToDeleteThisAttachment: 'Вы уверены, что хотите удалить это вложение?', areYouSureYouWantToDeleteThisAttachment: 'Вы уверены, что хотите удалить это вложение?',
areYouSureYouWantToDeleteThisBoard: 'Вы уверены, что хотите удалить эту доску?', areYouSureYouWantToDeleteThisBoard: 'Вы уверены, что хотите удалить эту доску?',
areYouSureYouWantToDeleteThisCard: 'Вы уверены, что хотите удалить эту карточку?', areYouSureYouWantToDeleteThisCard: 'Вы уверены, что хотите удалить эту карточку?',
@@ -32,27 +34,33 @@ export default {
areYouSureYouWantToDeleteThisProject: 'Вы уверены, что хотите удалить этот проект?', areYouSureYouWantToDeleteThisProject: 'Вы уверены, что хотите удалить этот проект?',
areYouSureYouWantToDeleteThisTask: 'Вы уверены, что хотите удалить эту задачу?', areYouSureYouWantToDeleteThisTask: 'Вы уверены, что хотите удалить эту задачу?',
areYouSureYouWantToDeleteThisUser: 'Вы уверены, что хотите удалить этого пользователя?', areYouSureYouWantToDeleteThisUser: 'Вы уверены, что хотите удалить этого пользователя?',
areYouSureYouWantToRemoveThisMemberFromProject: areYouSureYouWantToLeaveBoard: 'Вы уверены, что хотите покинуть эту доску?',
'Вы уверены, что хотите удалить этого участника из проекта?', areYouSureYouWantToLeaveProject: 'Вы уверены, что хотите покинуть этот проект?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Вы уверены, что хотите удалить этого менеджера из проекта?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Вы уверены, что хотите удалить этого участника из доски?',
attachment: 'Вложение', attachment: 'Вложение',
attachments: 'Вложения', attachments: 'Вложения',
authentication: 'Аутентификация', authentication: 'Аутентификация',
background: 'Фон',
board: 'Доска', board: 'Доска',
boardNotFound: 'Доска не найдена', boardNotFound: 'Доска не найдена',
canComment: 'Может комментировать', canComment: 'Может комментировать',
canEditContentOfBoard: 'Может редактировать содержимое доски', canEditContentOfBoard: 'Может редактировать содержимое доски.',
canOnlyViewBoard: 'Может только просматривать доску', canOnlyViewBoard: 'Может только просматривать доску.',
cardActions: 'Действия с карточкой', cardActions: 'Действия с карточкой',
cardNotFound: 'Карточка не найдена', cardNotFound: 'Карточка не найдена',
cardOrActionAreDeleted: 'Карточка или действие удалены', cardOrActionAreDeleted: 'Карточка или действие удалены.',
color: 'Цвет', color: 'Цвет',
connectionRestored: 'Соединение восстановлено', connectionRestored: 'Соединение восстановлено',
createBoard: 'Создание доски', createBoard: 'Создание доски',
createLabel: 'Создание метки', createLabel: 'Создание метки',
createNewOneOrSelectExistingOne: 'Создайте новую или выберите<br />уже существующую', createNewOneOrSelectExistingOne: 'Создайте новую или выберите<br />уже существующую.',
createProject: 'Создание проекта', createProject: 'Создание проекта',
createTextFile: 'Создание текстового файла', createTextFile: 'Создание текстового файла',
currentPassword: 'Текущий пароль', currentPassword: 'Текущий пароль',
dangerZone_title: 'Опасная зона',
date: 'Дата', date: 'Дата',
dueDate: 'Срок', dueDate: 'Срок',
deleteAttachment: 'Удаление вложения', deleteAttachment: 'Удаление вложения',
@@ -74,7 +82,8 @@ export default {
editBackground: 'Изменение фона', editBackground: 'Изменение фона',
editDueDate: 'Изменение срока', editDueDate: 'Изменение срока',
editEmail: 'Изменение e-mail', editEmail: 'Изменение e-mail',
editLabel: 'Изменения метки', editInformation: 'Изменение информации',
editLabel: 'Изменение метки',
editPassword: 'Изменение пароля', editPassword: 'Изменение пароля',
editPermissions: 'Редактирование разрешений', editPermissions: 'Редактирование разрешений',
editStopwatch: 'Изменение секундомера', editStopwatch: 'Изменение секундомера',
@@ -91,12 +100,18 @@ export default {
filterByLabels: 'Фильтр по меткам', filterByLabels: 'Фильтр по меткам',
filterByMembers: 'Фильтр по участникам', filterByMembers: 'Фильтр по участникам',
fromComputer: 'С компьютера', fromComputer: 'С компьютера',
fromTrello: 'Из Trello',
general: 'Основные',
hours: 'Часы', hours: 'Часы',
importBoard: 'Импорт доски',
invalidCurrentPassword: 'Неверный текущий пароль', invalidCurrentPassword: 'Неверный текущий пароль',
labels: 'Метки', labels: 'Метки',
language: 'Язык', language: 'Язык',
leaveBoard: 'Покинуть доску',
leaveProject: 'Покинуть проект',
list: 'Список', list: 'Список',
listActions: 'Действия со списком', listActions: 'Действия со списком',
managers: 'Менеджеры',
members: 'Участники', members: 'Участники',
minutes: 'Минуты', minutes: 'Минуты',
moveCard: 'Перемещение карточки', moveCard: 'Перемещение карточки',
@@ -109,17 +124,18 @@ export default {
noLists: 'Списков нет', noLists: 'Списков нет',
noProjects: 'Проектов нет', noProjects: 'Проектов нет',
notifications: 'Уведомления', notifications: 'Уведомления',
noUnreadNotifications: 'Уведомлений нет', noUnreadNotifications: 'Уведомлений нет.',
openBoard: 'Откройте доску', openBoard: 'Откройте доску',
optional_inline: 'необязательно', optional_inline: 'необязательно',
organization: 'Организация', organization: 'Организация',
phone: 'Телефон', phone: 'Телефон',
preferences: 'Предпочтения', preferences: 'Предпочтения',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Совет: нажмите Ctrl-V (Cmd-V на Mac), чтобы добавить вложение из буфера обмена', 'Совет: нажмите Ctrl-V (Cmd-V на Mac), чтобы добавить вложение из буфера обмена.',
project: 'Проект', project: 'Проект',
projectActions: 'Действия с проектом', projectActions: 'Действия с проектом',
projectNotFound: 'Проект не найден', projectNotFound: 'Проект не найден',
removeManager: 'Удалить менеджера',
removeMember: 'Удаление участника', removeMember: 'Удаление участника',
searchLabels: 'Поиск меток...', searchLabels: 'Поиск меток...',
searchMembers: 'Поиск участников...', searchMembers: 'Поиск участников...',
@@ -131,10 +147,10 @@ export default {
selectProject: 'Выберите проект', selectProject: 'Выберите проект',
settings: 'Настройки', settings: 'Настройки',
stopwatch: 'Секундомер', stopwatch: 'Секундомер',
subscribeToMyOwnCardsByDefault: 'По умолчанию подписаться на мои собственные карточки', subscribeToMyOwnCardsByDefault: 'По умолчанию подписываться на мои собственные карточки',
taskActions: 'Действия с задачей', taskActions: 'Действия с задачей',
tasks: 'Задачи', tasks: 'Задачи',
thereIsNoPreviewAvailableForThisAttachment: 'Предпросмотр для этого вложения недоступен', thereIsNoPreviewAvailableForThisAttachment: 'Предпросмотр для этого вложения недоступен.',
time: 'Время', time: 'Время',
title: 'Название', title: 'Название',
userActions: 'Действия с пользователем', userActions: 'Действия с пользователем',
@@ -147,6 +163,7 @@ export default {
username: 'Имя пользователя', username: 'Имя пользователя',
usernameAlreadyInUse: 'Имя пользователя уже занято', usernameAlreadyInUse: 'Имя пользователя уже занято',
users: 'Пользователи', users: 'Пользователи',
version: 'Версия',
viewer: 'Читатель', viewer: 'Читатель',
writeComment: 'Напишите комментарий...', writeComment: 'Напишите комментарий...',
}, },
@@ -185,6 +202,7 @@ export default {
editDueDate: 'Изменить срок', editDueDate: 'Изменить срок',
editDescription: 'Изменить описание', editDescription: 'Изменить описание',
editEmail: 'Изменить e-mail', editEmail: 'Изменить e-mail',
editInformation: 'Изменить информацию',
editPassword: 'Изменить пароль', editPassword: 'Изменить пароль',
editPermissions: 'Изменить разрешения', editPermissions: 'Изменить разрешения',
editStopwatch: 'Изменить секундомер', editStopwatch: 'Изменить секундомер',
@@ -192,6 +210,9 @@ export default {
editTitle: 'Изменить название', editTitle: 'Изменить название',
editUsername: 'Изменить имя пользователя', editUsername: 'Изменить имя пользователя',
hideDetails: 'Скрыть подробности', hideDetails: 'Скрыть подробности',
import: 'Импорт',
leaveBoard: 'Покинуть доску',
leaveProject: 'Покинуть проект',
logOut: 'Выйти', logOut: 'Выйти',
makeCover: 'Сделать обложкой', makeCover: 'Сделать обложкой',
move: 'Переместить', move: 'Переместить',
@@ -199,7 +220,9 @@ export default {
remove: 'Убрать', remove: 'Убрать',
removeBackground: 'Убрать фон', removeBackground: 'Убрать фон',
removeCover: 'Убрать обложку', removeCover: 'Убрать обложку',
removeFromBoard: 'Удалить из доски',
removeFromProject: 'Удалить из проекта', removeFromProject: 'Удалить из проекта',
removeManager: 'Удалить менеджера',
removeMember: 'Удалить участника', removeMember: 'Удалить участника',
save: 'Сохранить', save: 'Сохранить',
showAllAttachments: 'Показать все вложения ({{hidden}} скрыто)', showAllAttachments: 'Показать все вложения ({{hidden}} скрыто)',
+5 -5
View File
@@ -23,7 +23,7 @@ export default {
administrator: 'Administrátor', administrator: 'Administrátor',
all: 'Všetko', all: 'Všetko',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Všetky zmeny budú automaticky uložené<br />po obnovení spojenia', 'Všetky zmeny budú automaticky uložené<br />po obnovení spojenia.',
areYouSureYouWantToDeleteThisAttachment: 'Naozaj chcete zmazať túto prílohu?', areYouSureYouWantToDeleteThisAttachment: 'Naozaj chcete zmazať túto prílohu?',
areYouSureYouWantToDeleteThisBoard: 'Naozaj chcete zmazať túto tabuľu?', areYouSureYouWantToDeleteThisBoard: 'Naozaj chcete zmazať túto tabuľu?',
areYouSureYouWantToDeleteThisCard: 'Naozaj chcete zmazať túto kartu?', areYouSureYouWantToDeleteThisCard: 'Naozaj chcete zmazať túto kartu?',
@@ -47,11 +47,11 @@ export default {
boardNotFound_title: 'Tabuľa neexistuje', boardNotFound_title: 'Tabuľa neexistuje',
cardActions_title: 'Akcie na karte', cardActions_title: 'Akcie na karte',
cardNotFound_title: 'Karta neexistuje', cardNotFound_title: 'Karta neexistuje',
cardOrActionAreDeleted: 'Karta alebo akcia sú zmazané', cardOrActionAreDeleted: 'Karta alebo akcia sú zmazané.',
color: 'Farba', color: 'Farba',
createBoard_title: 'Vytvoriť tabuľu', createBoard_title: 'Vytvoriť tabuľu',
createLabel_title: 'Vytvoriť štítok', createLabel_title: 'Vytvoriť štítok',
createNewOneOrSelectExistingOne: 'Vytvoriť nový alebo vyberte<br />už existujúci', createNewOneOrSelectExistingOne: 'Vytvoriť nový alebo vyberte<br />už existujúci.',
createProject_title: 'Vytvoriť projekt', createProject_title: 'Vytvoriť projekt',
createTextFile_title: 'Vytvoriť textový súbor', createTextFile_title: 'Vytvoriť textový súbor',
currentPassword: 'Aktuálne heslo', currentPassword: 'Aktuálne heslo',
@@ -111,14 +111,14 @@ export default {
noLists: 'Žiadne zoznamy', noLists: 'Žiadne zoznamy',
noProjects: 'Žiadne projekty', noProjects: 'Žiadne projekty',
notifications: 'Oznámenia', notifications: 'Oznámenia',
noUnreadNotifications: 'Žiadne neprečítané oznámenia', noUnreadNotifications: 'Žiadne neprečítané oznámenia.',
openBoard_title: 'Otvoriť tabuľu', openBoard_title: 'Otvoriť tabuľu',
optional_inline: 'voliteľné', optional_inline: 'voliteľné',
organization: 'Spoločnosť', organization: 'Spoločnosť',
phone: 'Telefón', phone: 'Telefón',
preferences: 'Voľby', preferences: 'Voľby',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tip: stlačte Ctrl-V (Cmd-V na Mac) pre vloženie prílohy zo schránky', 'Tip: stlačte Ctrl-V (Cmd-V na Mac) pre vloženie prílohy zo schránky.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt neexistuje', projectNotFound_title: 'Projekt neexistuje',
removeManager_title: 'Odstrániť správcu', removeManager_title: 'Odstrániť správcu',
+5 -5
View File
@@ -23,7 +23,7 @@ export default {
administrator: 'Administratör', administrator: 'Administratör',
all: 'Alla', all: 'Alla',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Alla ändringar kommer att sparas automatiskt<br />så fort anslutningen är återställd', 'Alla ändringar kommer att sparas automatiskt<br />så fort anslutningen är återställd.',
areYouSureYouWantToDeleteThisAttachment: areYouSureYouWantToDeleteThisAttachment:
'Är du säker på att du vill ta bort den här bilagan?', 'Är du säker på att du vill ta bort den här bilagan?',
areYouSureYouWantToDeleteThisBoard: 'Är du säker på att du vill ta bort den här tavlan?', areYouSureYouWantToDeleteThisBoard: 'Är du säker på att du vill ta bort den här tavlan?',
@@ -49,11 +49,11 @@ export default {
boardNotFound_title: 'Tavla Ej Funnen', boardNotFound_title: 'Tavla Ej Funnen',
cardActions_title: 'Kortåtgärder', cardActions_title: 'Kortåtgärder',
cardNotFound_title: 'Kort Ej Funnet', cardNotFound_title: 'Kort Ej Funnet',
cardOrActionAreDeleted: 'Kort eller åtgärd är borttagen', cardOrActionAreDeleted: 'Kort eller åtgärd är borttagen.',
color: 'Färg', color: 'Färg',
createBoard_title: 'Skapa Tavla', createBoard_title: 'Skapa Tavla',
createLabel_title: 'Skapa Etikett', createLabel_title: 'Skapa Etikett',
createNewOneOrSelectExistingOne: 'Skapa en ny eller välj<br />en redan existerande', createNewOneOrSelectExistingOne: 'Skapa en ny eller välj<br />en redan existerande.',
createProject_title: 'Skapa Projekt', createProject_title: 'Skapa Projekt',
createTextFile_title: 'Skapa Textfil', createTextFile_title: 'Skapa Textfil',
currentPassword: 'Nuvarande lösenord', currentPassword: 'Nuvarande lösenord',
@@ -112,14 +112,14 @@ export default {
noLists: 'Inga listor', noLists: 'Inga listor',
noProjects: 'Inga projekt', noProjects: 'Inga projekt',
notifications: 'Notifikationer', notifications: 'Notifikationer',
noUnreadNotifications: 'Inga olästa notifikationer', noUnreadNotifications: 'Inga olästa notifikationer.',
openBoard_title: 'Öppna Tavla', openBoard_title: 'Öppna Tavla',
optional_inline: 'valfri', optional_inline: 'valfri',
organization: 'Organisation', organization: 'Organisation',
phone: 'Telefon', phone: 'Telefon',
preferences: 'Preferenser', preferences: 'Preferenser',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'Tips: tryck på Ctrl-V (Cmd-V på Mac) för att lägga till en bilaga från urklipp', 'Tips: tryck på Ctrl-V (Cmd-V på Mac) för att lägga till en bilaga från urklipp.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt Ej Funnet', projectNotFound_title: 'Projekt Ej Funnet',
removeManager_title: 'Ta Bort Projektledare', removeManager_title: 'Ta Bort Projektledare',
+219
View File
@@ -0,0 +1,219 @@
import dateFns from 'date-fns/locale/tr';
export default {
dateFns,
format: {
date: 'd.MM.yyyy',
time: 'p',
dateTime: '$t(format:date) $t(format:time)',
longDate: 'd. MMM',
longDateTime: "d. MMMM 'Saat' p",
},
translation: {
common: {
account: 'Hesap',
actions: 'Eylemler',
addAttachment_title: 'Dosya ekle',
addComment: 'Yorum ekle',
addManager_title: 'Yönetici ekle',
addMember_title: 'Üye ekle',
addUser_title: 'Kullanıcı ekle',
administrator: 'Administrator',
all: 'Tümü',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Bağlantı yeniden kurulduğunda tüm değişiklikler kaydedilecektir.',
areYouSureYouWantToDeleteThisAttachment: 'Bu eki silmek istediğinize emin misiniz?',
areYouSureYouWantToDeleteThisBoard: 'Bu panoyu silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisCard: 'Bu kartı silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisComment: 'Bu yorumu silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisLabel: 'Bu etiketi silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisList: 'Bu listeyi silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisProject: 'Bu projeyi silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisTask: 'Bu görevi silmek istediğinizden emin misiniz?',
areYouSureYouWantToDeleteThisUser: 'Bu kullanıcıyı silmek istediğinizden emin misiniz?',
areYouSureYouWantToLeaveBoard: 'Panodan ayrılmak istediğinizden emin misiniz?',
areYouSureYouWantToLeaveProject: 'Projeden ayrılmak istediğinizden emin misiniz?',
areYouSureYouWantToRemoveThisManagerFromProject:
'Bu yöneticiyi projeden çıkarmak istediğinizden emin misiniz?',
areYouSureYouWantToRemoveThisMemberFromBoard:
'Bu üyeyi panodan çıkarmak istediğinizden emin misiniz?',
attachment: 'ek',
attachments: 'ekler',
authentication: 'kimlik doğrulama',
background: 'arka plan',
board: 'pano',
boardNotFound_title: 'Pano bulunamadı',
cardActions_title: 'Kart İşlemleri',
cardNotFound_title: 'Kart bulunamadı',
cardOrActionAreDeleted: 'Kart veya işlem silindi.',
color: 'renk',
createBoard_title: 'Pano Oluştur',
createLabel_title: 'Etiket Oluştur',
createNewOneOrSelectExistingOne: 'Yeni bir tane oluşturun veya mevcut bir tanesini seçin.',
createProject_title: 'Proje Oluştur',
createTextFile_title: 'Metin Dosyası Oluştur',
currentPassword: 'Geçerli şifre',
dangerZone_title: 'Tehlikeli Bölge',
date: 'tarih',
dueDate_title: 'Termin Tarihi',
deleteAttachment_title: 'Eki Sil',
deleteBoard_title: 'Panoyu Sil',
deleteCard_title: 'Kartı Sil',
deleteComment_title: 'Yorumu Sil',
deleteLabel_title: 'Etiketi Sil',
deleteList_title: 'Listeyi Sil',
deleteProject_title: 'Projeyi Sil',
deleteTask_title: 'Görevi Sil',
deleteUser_title: 'Kullanıcıyı Sil',
description: 'açıklama',
detectAutomaically: 'Otomatik olarak algıla',
dropFileToUpload: 'Yüklenecek dosyayı buraya bırakın',
editAttachment_title: 'Eki Düzenle',
editAvatar_title: 'Avatarı Düzenle',
editBoard_title: 'Panoyu Düzenle',
editDueDate_title: 'Son Tarihi Düzenle',
editEmail_title: 'E-posta Adresini Düzenle',
editLabel_title: 'Etiketi Düzenle',
editPassword_title: 'Şifreyi Değiştir',
editStopwatch_title: 'Kronometreyi Düzenle',
editUsername_title: 'Kullanıcı Adını Düzenle',
email: 'e-posta',
emailAlreadyInUse: 'E-posta adresi zaten kullanımda',
enterCardTitle: 'Kart başlığını girin...',
enterDescription: 'Açıklamayı girin...',
enterFilename: 'Dosya adını girin',
enterListTitle: 'Liste başlığını girin...',
enterProjectTitle: 'Proje başlığını girin',
enterTaskDescription: 'Görev açıklamasını girin...',
filterByLabels_title: 'Etikete Göre Filtrele',
filterByMembers_title: 'Üyelere göre filtrele',
fromComputer_title: 'Bilgisayardan',
general: 'Genel',
hours: 'saat',
invalidCurrentPassword: 'Mevcut şifre yanlış',
labels: 'etiketler',
language: 'dil',
leaveBoard_title: 'Panodan Ayrıl',
leaveProject_title: 'Projeden Ayrıl',
list: 'Listeler',
listActions_title: 'Görevleri Listele',
managers: 'Yöneticiler',
members: 'Üyeler',
minutes: 'dakika',
moveCard_title: 'Kartı Taşı',
name: 'isim',
newEmail: 'Yeni e-posta adresi',
newPassword: 'Yeni şifre',
newUsername: 'Yeni kullanıcı adı',
noConnectionToServer: 'Sunucuya bağlantı yok',
noBoards: 'Pano yok',
noLists: 'Liste yok',
noProjects: 'Proje yok',
notifications: 'Bildirimler',
noUnreadNotifications: 'Okunmamış bildirim yok.',
openBoard_title: 'Açık Pano',
optional_inline: 'İsteğe bağlı',
organization: 'Organizasyon',
phone: 'telefon',
preferences: 'Tercihler',
pressPasteShortcutToAddAttachmentFromClipboard:
'İpucu: Panodan bir ek eklemek için CTRL-V ye (Macte Cmd-V) basın.',
project: 'Proje',
projectNotFound_title: 'Proje bulunamadı',
removeManager_title: 'Yöneticiyi Kaldır',
removeMember_title: 'Üyeyi Kaldır',
seconds: 'saniye',
selectBoard: 'Pano Seç',
selectList: 'Liste seç',
selectProject: 'Proje seç',
settings: 'Ayarlar',
stopwatch: 'kronometre',
subscribeToMyOwnCardsByDefault: 'Varsayılan olarak kendi kartlarıma abone ol',
taskActions_title: 'Görev Eylemleri',
tasks: 'Görevler',
thereIsNoPreviewAvailableForThisAttachment: 'Bu ek için önizleme mevcut değil.',
time: 'zaman',
title: 'başlık',
userActions_title: 'Kullanıcı İşlemleri',
userAddedThisCardToList: '<0>{{user}}</0><1> bu kartı {{list}</1> listesine ekledi',
userLeftNewCommentToCard:
'{{user}} yeni bir yorum yazdı: <2>{{card}</2> kartına «{{comment}}»',
userMovedCardFromListToList:
'{{user}}, <2>{{card}></2> kartını {{fromList}} listesinden {{toList}} listesine taşıdı',
userMovedThisCardFromListToList:
'<0>{{user}}</0><1> bu kartı {{fromList}} konumundan {{toList}}</1> konumuna taşıdı',
username: 'kullanıcı adı',
usernameAlreadyInUse: 'Kullanıcı adı zaten kullanımda',
users: 'kullanıcı',
writeComment: 'Yorum yazın...',
},
action: {
addAnotherCard: 'Başka bir kart ekle',
addAnotherList: 'Başka bir liste ekle',
addAnotherTask: 'Başka bir görev ekle',
addCard: 'Kart ekle',
addCard_title: 'Kart Ekle',
addComment: 'Yorum ekle',
addList: 'Liste ekle',
addMoreDetailedDescription: 'Ayrıntılı bir açıklama ekleyin',
addTask: 'Görev ekle',
addToCard: 'Karta ekle',
addUser: 'Kullanıcı ekle',
createBoard: 'Pano oluştur',
createFile: 'Dosya oluştur',
createLabel: 'Etiket Oluştur',
createNewLabel: 'Yeni etiket oluştur',
createProject: 'Proje oluştur',
delete: 'Sil',
deleteAttachment: 'Eki sil',
deleteAvatar: 'Avatarı sil',
deleteBoard: 'Panoyu Sil',
deleteCard: 'Kartı sil',
deleteCard_title: 'Kartı Sil',
deleteComment: 'Yorumu sil',
deleteImage: 'Resmi sil',
deleteLabel: 'Etiketi sil',
deleteList: 'Listeyi sil',
deleteList_title: 'Listeyi Sil',
deleteProject: 'Projeyi sil',
deleteProject_title: 'Projeyi Sil',
deleteTask: 'Görevi sil',
deleteTask_title: 'Görevi Sil',
deleteUser: 'Kullanıcıyı sil',
edit: 'Düzenle',
editDueDate_title: 'Son Tarihi Düzenle',
editDescription_title: 'Açıklamayı Düzenle',
editEmail_title: 'E-posta Adresini Düzenle',
editPassword_title: 'Şifreyi Değiştir',
editStopwatch_title: 'Kronometreyi Düzenle',
editTitle_title: 'Başlığı düzenle',
editUsername_title: 'Kullanıcı Adını Düzenle',
hideDetails: 'Ayrıntıları gizle',
leaveBoard: 'Panodan Ayrıl',
leaveProject: 'Projeden ayrıl',
logOut_title: 'Çıkış',
makeCover_title: 'Önizleme olarak ayarla',
move: 'Taşı',
moveCard_title: 'Kartı Taşı',
remove: 'Sil',
removeBackground: 'Arka planı kaldır',
removeCover_title: 'Önizlemeyi Kaldır',
removeFromBoard: 'Panodan kaldır',
removeFromProject: 'Projeden kaldır',
removeManager: 'Yöneticiyi kaldır',
removeMember: 'Üyeyi kaldır',
save: 'Kaydet',
showAllAttachments: 'Tüm ekleri göster ({{hidden}} gizli)',
showDetails: 'Ayrıntıları göster',
showFewerAttachments: 'Daha az ek göster',
start: 'başlat',
stop: 'dur',
subscribe: 'Abone ol',
unsubscribe: 'Abonelikten çık',
uploadNewAvatar: 'Yeni avatar yükle',
uploadNewImage: 'Yeni resim yükle',
},
},
};
+8
View File
@@ -0,0 +1,8 @@
import login from './login';
export default {
language: 'tr',
country: 'tr',
name: 'Türkçe',
embeddedLocale: login,
};
+20
View File
@@ -0,0 +1,20 @@
export default {
translation: {
common: {
emailOrUsername: 'E-posta adresi veya Kullanıcı adı',
invalidEmailOrUsername: 'Geçersiz e-posta adresi veya kullanıcı adı',
invalidPassword: 'Hatalı Şifre',
logInToPlanka: 'Giriş Yap',
noInternetConnection: 'Internet bağlantısı yok',
pageNotFound_title: 'Sayfa bulunamadı',
password: 'Şifre',
projectManagement: 'Proje Yönetimi',
serverConnectionFailed: 'Sunucu bağlantı hatası',
unknownError: 'Bilinmeyen Hata, daha sonra tekrar deneyin',
},
action: {
logIn: 'Giriş Yap',
},
},
};
+5 -5
View File
@@ -19,7 +19,7 @@ export default {
administrator: 'Administrator', administrator: 'Administrator',
all: 'Barchasi', all: 'Barchasi',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
"Barcha o'zgarishlar tarmoq ulanishi tiklangandan so'ng<br /> avtomatik saqlanadi", "Barcha o'zgarishlar tarmoq ulanishi tiklangandan so'ng<br />avtomatik saqlanadi.",
areYouSureYouWantToDeleteThisAttachment: "Ushbu biriktirmani o'chirmoqchimisiz?", areYouSureYouWantToDeleteThisAttachment: "Ushbu biriktirmani o'chirmoqchimisiz?",
areYouSureYouWantToDeleteThisBoard: "Ushbu doskani o'chirmoqchimisiz?", areYouSureYouWantToDeleteThisBoard: "Ushbu doskani o'chirmoqchimisiz?",
areYouSureYouWantToDeleteThisCard: "Ushbu kartani o'chirmoqchimisiz?", areYouSureYouWantToDeleteThisCard: "Ushbu kartani o'chirmoqchimisiz?",
@@ -42,11 +42,11 @@ export default {
boardNotFound_title: 'Doska Topilmadi', boardNotFound_title: 'Doska Topilmadi',
cardActions_title: 'Karta Amallari', cardActions_title: 'Karta Amallari',
cardNotFound_title: 'Karta Topilmadi', cardNotFound_title: 'Karta Topilmadi',
cardOrActionAreDeleted: "Karta yoki amal o'chirilgan", cardOrActionAreDeleted: "Karta yoki amal o'chirilgan.",
color: 'Rang', color: 'Rang',
createBoard_title: 'Doska Yaratish', createBoard_title: 'Doska Yaratish',
createLabel_title: 'Yorliq Yaratish', createLabel_title: 'Yorliq Yaratish',
createNewOneOrSelectExistingOne: "Yangisini tanlash yoki<br /> mavjud bo'lganini tanlash", createNewOneOrSelectExistingOne: "Yangisini tanlash yoki<br />mavjud bo'lganini tanlash.",
createProject_title: 'Loyiha Yaratish', createProject_title: 'Loyiha Yaratish',
createTextFile_title: 'Matnli fayl yaratish', createTextFile_title: 'Matnli fayl yaratish',
currentPassword: 'Hozirgi parol', currentPassword: 'Hozirgi parol',
@@ -105,14 +105,14 @@ export default {
noLists: "Ro'yxatlar yo'q", noLists: "Ro'yxatlar yo'q",
noProjects: "Loyihalar yo'q", noProjects: "Loyihalar yo'q",
notifications: 'Bildirishnomalar', notifications: 'Bildirishnomalar',
noUnreadNotifications: "O'qilmagan bildirishnomalar yo'q", noUnreadNotifications: "O'qilmagan bildirishnomalar yo'q.",
openBoard_title: 'Doskani Ochish', openBoard_title: 'Doskani Ochish',
optional_inline: 'ixtiyoriy', optional_inline: 'ixtiyoriy',
organization: 'Tashkilot', organization: 'Tashkilot',
phone: 'Telefon', phone: 'Telefon',
preferences: 'Afzalliklar', preferences: 'Afzalliklar',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
"Tip: Buferdan ilova qo'shish uchun Ctrl-V (Mac da Cmd-V) ni bosing", "Tip: Buferdan ilova qo'shish uchun Ctrl-V (Mac da Cmd-V) ni bosing.",
project: 'Loyiha', project: 'Loyiha',
projectNotFound_title: 'Loyiha Topilmadi', projectNotFound_title: 'Loyiha Topilmadi',
removeManager_title: "Boshqaruvchini O'chirish", removeManager_title: "Boshqaruvchini O'chirish",
+6 -6
View File
@@ -53,7 +53,7 @@ export default {
dueDate_title: '截止日期', dueDate_title: '截止日期',
deleteAttachment_title: '删除附件', deleteAttachment_title: '删除附件',
deleteBoard_title: '删除面板', deleteBoard_title: '删除面板',
deleteCard_title: '删除擦片', deleteCard_title: '删除卡片',
deleteComment_title: '删除评论', deleteComment_title: '删除评论',
deleteLabel_title: '删除标签', deleteLabel_title: '删除标签',
deleteList_title: '删除列表', deleteList_title: '删除列表',
@@ -81,7 +81,7 @@ export default {
enterTaskDescription: '输入任务描述...', enterTaskDescription: '输入任务描述...',
filterByLabels_title: '通过标签筛选', filterByLabels_title: '通过标签筛选',
filterByMembers_title: '通过成员筛选', filterByMembers_title: '通过成员筛选',
fromComputer_title: '从电脑', fromComputer_title: '从本机',
general: '全体', general: '全体',
hours: '小时', hours: '小时',
invalidCurrentPassword: '当前密码错误', invalidCurrentPassword: '当前密码错误',
@@ -110,7 +110,7 @@ export default {
phone: '电话', phone: '电话',
preferences: '偏好', preferences: '偏好',
pressPasteShortcutToAddAttachmentFromClipboard: pressPasteShortcutToAddAttachmentFromClipboard:
'提示: 点击 Ctrl-V (Mac: Cmd-V) 从剪切板添加附件', '提示: 按下 Ctrl-V (Mac: Cmd-V) 从剪切板添加附件',
project: '项目', project: '项目',
projectNotFound_title: '项目未找到', projectNotFound_title: '项目未找到',
removeManager_title: '删除管理员', removeManager_title: '删除管理员',
@@ -134,7 +134,7 @@ export default {
userMovedThisCardFromListToList: userMovedThisCardFromListToList:
'<0>{{user}}</0><1> 将该卡片从 {{fromList}} 移动到 {{toList}}</1>', '<0>{{user}}</0><1> 将该卡片从 {{fromList}} 移动到 {{toList}}</1>',
username: '用户名', username: '用户名',
usernameAlreadyInUse: '用户名已占用', usernameAlreadyInUse: '用户名已被占用',
users: '用户', users: '用户',
writeComment: '编写评论...', writeComment: '编写评论...',
}, },
@@ -149,7 +149,7 @@ export default {
addList: '添加列表', addList: '添加列表',
addMoreDetailedDescription: '添加更多详细描述', addMoreDetailedDescription: '添加更多详细描述',
addTask: '添加任务', addTask: '添加任务',
addToCard: '添加擦篇', addToCard: '添加到卡片',
addUser: '添加用户', addUser: '添加用户',
createBoard: '创建面板', createBoard: '创建面板',
createFile: '创建文件', createFile: '创建文件',
@@ -177,7 +177,7 @@ export default {
editDescription_title: '编辑描述', editDescription_title: '编辑描述',
editEmail_title: '编辑邮箱', editEmail_title: '编辑邮箱',
editPassword_title: '编辑密码', editPassword_title: '编辑密码',
editStopwatch_title: '编辑实践', editStopwatch_title: '编辑时间',
editTitle_title: '编辑标题', editTitle_title: '编辑标题',
editUsername_title: '编辑用户名', editUsername_title: '编辑用户名',
leaveBoard: '离开面板', leaveBoard: '离开面板',
+3
View File
@@ -12,6 +12,9 @@ export default class extends BaseModel {
coverUrl: attr(), coverUrl: attr(),
image: attr(), image: attr(),
name: attr(), name: attr(),
createdAt: attr({
getDefault: () => new Date(),
}),
cardId: fk({ cardId: fk({
to: 'Card', to: 'Card',
as: 'card', as: 'card',
+1 -1
View File
@@ -172,7 +172,7 @@ export default class extends BaseModel {
} }
getOrderedMembershipsQuerySet() { getOrderedMembershipsQuerySet() {
return this.memberships.orderBy('id'); return this.memberships.orderBy('createdAt');
} }
getOrderedLabelsQuerySet() { getOrderedLabelsQuerySet() {
+3
View File
@@ -10,6 +10,9 @@ export default class extends BaseModel {
id: attr(), id: attr(),
role: attr(), role: attr(),
canComment: attr(), canComment: attr(),
createdAt: attr({
getDefault: () => new Date(),
}),
boardId: fk({ boardId: fk({
to: 'Board', to: 'Board',
as: 'board', as: 'board',
+2 -2
View File
@@ -244,7 +244,7 @@ export default class extends BaseModel {
} }
getOrderedAttachmentsQuerySet() { getOrderedAttachmentsQuerySet() {
return this.attachments.orderBy('id', false); return this.attachments.orderBy('createdAt', false);
} }
getFilteredOrderedInCardActivitiesQuerySet() { getFilteredOrderedInCardActivitiesQuerySet() {
@@ -256,7 +256,7 @@ export default class extends BaseModel {
filter.type = ActivityTypes.COMMENT_CARD; filter.type = ActivityTypes.COMMENT_CARD;
} }
return this.activities.filter(filter).orderBy('id', false); return this.activities.filter(filter).orderBy('createdAt', false);
} }
getUnreadNotificationsQuerySet() { getUnreadNotificationsQuerySet() {
+1 -1
View File
@@ -137,7 +137,7 @@ export default class extends BaseModel {
} }
getOrderedManagersQuerySet() { getOrderedManagersQuerySet() {
return this.managers.orderBy('id'); return this.managers.orderBy('createdAt');
} }
getOrderedBoardsQuerySet() { getOrderedBoardsQuerySet() {
+3
View File
@@ -8,6 +8,9 @@ export default class extends BaseModel {
static fields = { static fields = {
id: attr(), id: attr(),
createdAt: attr({
getDefault: () => new Date(),
}),
projectId: fk({ projectId: fk({
to: 'Project', to: 'Project',
as: 'project', as: 'project',
+10 -6
View File
@@ -43,9 +43,13 @@ export default class extends BaseModel {
organization: attr(), organization: attr(),
language: attr(), language: attr(),
subscribeToOwnCards: attr(), subscribeToOwnCards: attr(),
isAdmin: attr(),
isLocked: attr(),
isRoleLocked: attr(),
isDeletionLocked: attr(),
deletedAt: attr(), deletedAt: attr(),
isAdmin: attr({ createdAt: attr({
getDefault: () => false, getDefault: () => new Date(),
}), }),
isAvatarUpdating: attr({ isAvatarUpdating: attr({
getDefault: () => false, getDefault: () => false,
@@ -293,15 +297,15 @@ export default class extends BaseModel {
static getOrderedUndeletedQuerySet() { static getOrderedUndeletedQuerySet() {
return this.filter({ return this.filter({
deletedAt: null, deletedAt: null,
}).orderBy('id'); }).orderBy('createdAt');
} }
getOrderedProjectManagersQuerySet() { getOrderedProjectManagersQuerySet() {
return this.projectManagers.orderBy('id'); return this.projectManagers.orderBy('createdAt');
} }
getOrderedBoardMembershipsQuerySet() { getOrderedBoardMembershipsQuerySet() {
return this.boardMemberships.orderBy('id'); return this.boardMemberships.orderBy('createdAt');
} }
getOrderedUnreadNotificationsQuerySet() { getOrderedUnreadNotificationsQuerySet() {
@@ -309,7 +313,7 @@ export default class extends BaseModel {
.filter({ .filter({
isRead: false, isRead: false,
}) })
.orderBy('id', false); .orderBy('createdAt', false);
} }
getOrderedAvailableProjectsModelArray() { getOrderedAvailableProjectsModelArray() {
+1
View File
@@ -10,6 +10,7 @@ const initialState = {
export default (state = initialState, { type, payload }) => { export default (state = initialState, { type, payload }) => {
switch (type) { switch (type) {
case ActionTypes.AUTHENTICATE__SUCCESS: case ActionTypes.AUTHENTICATE__SUCCESS:
case ActionTypes.USING_OIDC_AUTHENTICATE__SUCCESS:
return { return {
...state, ...state,
accessToken: payload.accessToken, accessToken: payload.accessToken,

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