1
0
Fork 0
mirror of https://github.com/plankanban/planka.git synced 2025-07-24 07:39:44 +02:00

Merge branch 'master' into mobile-support

This commit is contained in:
Fayad 2024-07-22 15:08:07 +02:00 committed by GitHub
commit 9e1f4df120
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
203 changed files with 2210 additions and 670 deletions

53
.github/ISSUE_TEMPLATE/1-bug-report.yml vendored Normal file
View file

@ -0,0 +1,53 @@
name: "🐛 Bug Report"
description: Report a bug found while using Planka
title: "[Bug]: "
labels: ["Type: Bug", "Status: Triage"]
body:
- type: dropdown
id: issue-type
attributes:
label: Where is the problem occurring?
description: Select the part of the application where you encountered the issue.
options:
- "I encountered the problem while using the application (Frontend)"
- "I encountered the problem while interacting with the server (Backend)"
- "I'm not sure"
- type: dropdown
id: browsers
attributes:
label: What browsers are you seeing the problem on?
multiple: true
options:
- Brave
- Chrome
- Firefox
- Microsoft Edge
- Safari
- Other
- type: textarea
id: current-behavior
attributes:
label: Current behaviour
description: A description of what is currently happening, including screenshots and other useful information (**DO NOT INCLUDE PRIVATE INFORMATION**).
placeholder: Currently...
validations:
required: true
- type: textarea
id: desired-behavior
attributes:
label: Desired behaviour
description: A clear description of what you think should happen.
placeholder: In this situation, I expected ...
- type: textarea
id: reproduction
attributes:
label: Steps to reproduce
description: Clearly describe which steps or actions you have taken to arrive at the problem. If you have some experience with the code, please link to the specific pieces of code.
placeholder: I did X, then Y, before arriving at Z, when ERROR ...
validations:
required: true
- type: textarea
id: other
attributes:
label: Other information
description: Any other details?

View file

@ -0,0 +1,33 @@
name: "✨ Feature Request"
description: Suggest a feature or enhancement to improve Planka.
labels: ["Type: Idea"]
body:
- type: dropdown
id: idea-type
attributes:
label: Is this a feature for the backend or frontend?
multiple: true
options:
- Backend
- Frontend
validations:
required: true
- type: textarea
id: feature
attributes:
label: What would you like?
description: A clear description of the feature or enhancement wanted.
placeholder: I'd like to be able to...
validations:
required: true
- type: textarea
id: reason
attributes:
label: Why is this needed?
description: A clear description of why this would be useful to have.
placeholder: I want this because...
- type: textarea
id: other
attributes:
label: Other information
placeholder: Any other details?

View file

@ -1,7 +1,7 @@
# 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/badge/docker_pulls-4M%2B-%23066da5) ![GitHub](https://img.shields.io/github/license/plankanban/planka)
![](https://raw.githubusercontent.com/plankanban/planka/master/demo.gif) ![](https://raw.githubusercontent.com/plankanban/planka/master/demo.gif)

View file

@ -15,13 +15,13 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes # 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. # to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/) # Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 0.1.33 version: 0.2.5
# This is the version number of the application being deployed. This version number should be # 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 # 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. # follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes. # It is recommended to use it with quotes.
appVersion: "1.17.5" appVersion: "1.20.1"
dependencies: dependencies:
- alias: postgresql - alias: postgresql

View file

@ -90,17 +90,37 @@ spec:
value: http://localhost:3000 value: http://localhost:3000
{{- end }} {{- end }}
- name: SECRET_KEY - name: SECRET_KEY
{{- if .Values.existingSecretkeySecret }}
valueFrom:
secretKeyRef:
name: {{ .Values.existingSecretkeySecret }}
key: key
{{- else }}
value: {{ required "A secret key needs to be generated using 'openssl rand -hex 64' and assigned to secretkey." .Values.secretkey }} value: {{ required "A secret key needs to be generated using 'openssl rand -hex 64' and assigned to secretkey." .Values.secretkey }}
{{- end }}
- name: TRUST_PROXY - name: TRUST_PROXY
value: "0" value: "0"
- name: DEFAULT_ADMIN_EMAIL - name: DEFAULT_ADMIN_EMAIL
value: {{ .Values.admin_email }} value: {{ .Values.admin_email }}
- name: DEFAULT_ADMIN_PASSWORD
value: {{ .Values.admin_password }}
- name: DEFAULT_ADMIN_NAME - name: DEFAULT_ADMIN_NAME
value: {{ .Values.admin_name }} value: {{ .Values.admin_name }}
{{- if .Values.existingAdminCredsSecret }}
- name: DEFAULT_ADMIN_USERNAME
valueFrom:
secretKeyRef:
name: {{ .Values.existingAdminCredsSecret }}
key: username
- name: DEFAULT_ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: {{ .Values.existingAdminCredsSecret }}
key: password
{{- else }}
- name: DEFAULT_ADMIN_USERNAME - name: DEFAULT_ADMIN_USERNAME
value: {{ .Values.admin_username }} value: {{ .Values.admin_username }}
- name: DEFAULT_ADMIN_PASSWORD
value: {{ .Values.admin_password }}
{{- end }}
{{ range $k, $v := .Values.env }} {{ range $k, $v := .Values.env }}
- name: {{ $k | quote }} - name: {{ $k | quote }}
value: {{ $v | quote }} value: {{ $v | quote }}

View file

@ -17,6 +17,16 @@ fullnameOverride: ""
# Generate a secret using openssl rand -base64 45 # Generate a secret using openssl rand -base64 45
secretkey: "" secretkey: ""
## @param existingSecretkeySecret Name of an existing secret containing the session key string
## NOTE: Must contain key `key`
## NOTE: When it's set, the secretkey parameter is ignored
existingSecretkeySecret: ""
## @param existingAdminCredsSecret Name of an existing secret containing the admin username and password
## NOTE: Must contain keys `username` and `password`
## NOTE: When it's set, the `admin_username` and `admin_password` parameters are ignored
existingAdminCredsSecret: ""
# Base url for Planka. Will override `ingress.hosts[0].host` # Base url for Planka. Will override `ingress.hosts[0].host`
# Defaults to `http://localhost:3000` if ingress is disabled. # Defaults to `http://localhost:3000` if ingress is disabled.
baseUrl: "" baseUrl: ""

View file

@ -1 +1,2 @@
REACT_APP_VERSION=1.18.1
REACT_APP_VERSION=1.20.1

View file

@ -12,7 +12,7 @@
"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": "^23.11.5", "i18next": "^23.12.2",
"i18next-browser-languagedetector": "^8.0.0", "i18next-browser-languagedetector": "^8.0.0",
"initials": "^3.1.2", "initials": "^3.1.2",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
@ -30,7 +30,7 @@
"react-datepicker": "^4.25.0", "react-datepicker": "^4.25.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-i18next": "^14.1.2", "react-i18next": "^15.0.0",
"react-input-mask": "^2.0.4", "react-input-mask": "^2.0.4",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-photoswipe-gallery": "^2.2.7", "react-photoswipe-gallery": "^2.2.7",
@ -2007,9 +2007,9 @@
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
}, },
"node_modules/@babel/runtime": { "node_modules/@babel/runtime": {
"version": "7.24.6", "version": "7.24.8",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.8.tgz",
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==", "integrity": "sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA==",
"dependencies": { "dependencies": {
"regenerator-runtime": "^0.14.0" "regenerator-runtime": "^0.14.0"
}, },
@ -11975,9 +11975,9 @@
} }
}, },
"node_modules/i18next": { "node_modules/i18next": {
"version": "23.11.5", "version": "23.12.2",
"resolved": "https://registry.npmjs.org/i18next/-/i18next-23.11.5.tgz", "resolved": "https://registry.npmjs.org/i18next/-/i18next-23.12.2.tgz",
"integrity": "sha512-41pvpVbW9rhZPk5xjCX2TPJi2861LEig/YRhUkY+1FQ2IQPS0bKUDYnEqY8XPPbB48h1uIwLnP9iiEfuSl20CA==", "integrity": "sha512-XIeh5V+bi8SJSWGL3jqbTEBW5oD6rbP5L+E7dVQh1MNTxxYef0x15rhJVcRb7oiuq4jLtgy2SD8eFlf6P2cmqg==",
"funding": [ "funding": [
{ {
"type": "individual", "type": "individual",
@ -22084,11 +22084,11 @@
"integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ==" "integrity": "sha512-nsO+KSNgo1SbJqJEYRE9ERzo7YtYbou/OqjSQKxV7jcKox7+usiUVZOAC+XnDOABXggQTno0Y1CpVnuWEc1boQ=="
}, },
"node_modules/react-i18next": { "node_modules/react-i18next": {
"version": "14.1.2", "version": "15.0.0",
"resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-14.1.2.tgz", "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.0.tgz",
"integrity": "sha512-FSIcJy6oauJbGEXfhUgVeLzvWBhIBIS+/9c6Lj4niwKZyGaGb4V4vUbATXSlsHJDXXB+ociNxqFNiFuV1gmoqg==", "integrity": "sha512-2O3IgF4zivg57Q6p6i+ChDgJ371IDcEWbuWC6gvoh5NbkDMs0Q+O7RPr4v61+Se32E0V+LmtwePAeqWZW0bi6g==",
"dependencies": { "dependencies": {
"@babel/runtime": "^7.23.9", "@babel/runtime": "^7.24.8",
"html-parse-stringify": "^3.0.1" "html-parse-stringify": "^3.0.1"
}, },
"peerDependencies": { "peerDependencies": {

View file

@ -65,7 +65,7 @@
"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": "^23.11.5", "i18next": "^23.12.2",
"i18next-browser-languagedetector": "^8.0.0", "i18next-browser-languagedetector": "^8.0.0",
"initials": "^3.1.2", "initials": "^3.1.2",
"js-cookie": "^3.0.5", "js-cookie": "^3.0.5",
@ -83,7 +83,7 @@
"react-datepicker": "^4.25.0", "react-datepicker": "^4.25.0",
"react-dom": "^18.2.0", "react-dom": "^18.2.0",
"react-dropzone": "^14.2.3", "react-dropzone": "^14.2.3",
"react-i18next": "^14.1.2", "react-i18next": "^15.0.0",
"react-input-mask": "^2.0.4", "react-input-mask": "^2.0.4",
"react-markdown": "^8.0.7", "react-markdown": "^8.0.7",
"react-photoswipe-gallery": "^2.2.7", "react-photoswipe-gallery": "^2.2.7",

View file

@ -57,10 +57,15 @@ updateCard.failure = (id, error) => ({
}, },
}); });
const handleCardUpdate = (card) => ({ const handleCardUpdate = (card, isFetched, cardMemberships, cardLabels, tasks, attachments) => ({
type: ActionTypes.CARD_UPDATE_HANDLE, type: ActionTypes.CARD_UPDATE_HANDLE,
payload: { payload: {
card, card,
isFetched,
cardMemberships,
cardLabels,
tasks,
attachments,
}, },
}); });

View file

@ -1,4 +1,4 @@
import React, { useCallback, useRef } from 'react'; import React, { useCallback, useRef, useState } 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';
@ -81,6 +81,7 @@ const CardModal = React.memo(
onClose, onClose,
}) => { }) => {
const [t] = useTranslation(); const [t] = useTranslation();
const [isLinkCopied, setIsLinkCopied] = useState(false);
const isGalleryOpened = useRef(false); const isGalleryOpened = useRef(false);
@ -146,6 +147,14 @@ const CardModal = React.memo(
onClose(); onClose();
}, [onDuplicate, onClose]); }, [onDuplicate, onClose]);
const handleCopyLinkClick = useCallback(() => {
navigator.clipboard.writeText(window.location.href);
setIsLinkCopied(true);
setTimeout(() => {
setIsLinkCopied(false);
}, 5000);
}, []);
const handleGalleryOpen = useCallback(() => { const handleGalleryOpen = useCallback(() => {
isGalleryOpened.current = true; isGalleryOpened.current = true;
}, []); }, []);
@ -506,6 +515,14 @@ const CardModal = React.memo(
<Icon name="copy outline" className={styles.actionIcon} /> <Icon name="copy outline" className={styles.actionIcon} />
{t('action.duplicate')} {t('action.duplicate')}
</Button> </Button>
<Button fluid className={styles.actionButton} onClick={handleCopyLinkClick}>
<Icon name={isLinkCopied ? 'linkify' : 'unlink'} className={styles.actionIcon} />
{isLinkCopied
? t('common.linkIsCopied')
: t('action.copyLink', {
context: 'title',
})}
</Button>
<DeletePopup <DeletePopup
title="common.deleteCard" title="common.deleteCard"
content="common.areYouSureYouWantToDeleteThisCard" content="common.areYouSureYouWantToDeleteThisCard"

View file

@ -20,7 +20,6 @@
.actionIcon { .actionIcon {
color: #17394d; color: #17394d;
display: inline;
margin-right: 8px; margin-right: 8px;
} }

View file

@ -195,9 +195,6 @@ export default {
CARD_UPDATE__SUCCESS: 'CARD_UPDATE__SUCCESS', CARD_UPDATE__SUCCESS: 'CARD_UPDATE__SUCCESS',
CARD_UPDATE__FAILURE: 'CARD_UPDATE__FAILURE', CARD_UPDATE__FAILURE: 'CARD_UPDATE__FAILURE',
CARD_UPDATE_HANDLE: 'CARD_UPDATE_HANDLE', CARD_UPDATE_HANDLE: 'CARD_UPDATE_HANDLE',
CARD_TRANSFER: 'CARD_TRANSFER',
CARD_TRANSFER__SUCCESS: 'CARD_TRANSFER__SUCCESS',
CARD_TRANSFER__FAILURE: 'CARD_TRANSFER__FAILURE',
CARD_DUPLICATE: 'CARD_DUPLICATE', CARD_DUPLICATE: 'CARD_DUPLICATE',
CARD_DUPLICATE__SUCCESS: 'CARD_DUPLICATE__SUCCESS', CARD_DUPLICATE__SUCCESS: 'CARD_DUPLICATE__SUCCESS',
CARD_DUPLICATE__FAILURE: 'CARD_DUPLICATE__FAILURE', CARD_DUPLICATE__FAILURE: 'CARD_DUPLICATE__FAILURE',

View file

@ -6,12 +6,13 @@ import entryActions from '../entry-actions';
import Projects from '../components/Projects'; import Projects from '../components/Projects';
const mapStateToProps = (state) => { const mapStateToProps = (state) => {
const { allowAllToCreateProjects } = selectors.selectConfig(state);
const { isAdmin } = selectors.selectCurrentUser(state); const { isAdmin } = selectors.selectCurrentUser(state);
const projects = selectors.selectProjectsForCurrentUser(state); const projects = selectors.selectProjectsForCurrentUser(state);
return { return {
items: projects, items: projects,
canAdd: isAdmin, canAdd: allowAllToCreateProjects || isAdmin,
}; };
}; };

View file

@ -58,9 +58,9 @@ i18n
.use(initReactI18next) .use(initReactI18next)
.init({ .init({
resources: embeddedLocales, resources: embeddedLocales,
fallbackLng: 'en', fallbackLng: 'en-US',
supportedLngs: languages, supportedLngs: languages,
load: 'languageOnly', load: 'currentOnly',
interpolation: { interpolation: {
escapeValue: false, escapeValue: false,
format(value, format, language) { format(value, format, language) {
@ -80,7 +80,7 @@ i18n
}); });
i18n.loadCoreLocale = async (language = i18n.resolvedLanguage) => { i18n.loadCoreLocale = async (language = i18n.resolvedLanguage) => {
if (language === 'en') { if (language === i18n.options.fallbackLng[0]) {
return; return;
} }

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'bg', language: 'bg-BG',
country: 'bg', country: 'bg',
name: 'Български', name: 'Български',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'cs', language: 'cs-CZ',
country: 'cz', country: 'cz',
name: 'Čeština', name: 'Čeština',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'da', language: 'da-DK',
country: 'dk', country: 'dk',
name: 'Dansk', name: 'Dansk',
embeddedLocale: login, embeddedLocale: login,

View file

@ -104,6 +104,7 @@ export default {
language: 'Sprache', language: 'Sprache',
leaveBoard_title: 'Board verlassen', leaveBoard_title: 'Board verlassen',
leaveProject_title: 'Projekt verlassen', leaveProject_title: 'Projekt verlassen',
linkIsCopied: 'Link kopiert',
list: 'Listen', list: 'Listen',
listActions_title: 'Aufgaben auflisten', listActions_title: 'Aufgaben auflisten',
managers: 'Manager', managers: 'Manager',
@ -169,6 +170,7 @@ export default {
addTask: 'Aufgabe hinzufügen', addTask: 'Aufgabe hinzufügen',
addToCard: 'Zu Karte hinzufügen', addToCard: 'Zu Karte hinzufügen',
addUser: 'Benutzer hinzufügen', addUser: 'Benutzer hinzufügen',
copyLink_title: 'Link kopieren',
createBoard: 'Board erstellen', createBoard: 'Board erstellen',
createFile: 'Datei erstellen', createFile: 'Datei erstellen',
createLabel: 'Label erstellen', createLabel: 'Label erstellen',
@ -190,6 +192,8 @@ export default {
deleteTask: 'Aufgabe löschen', deleteTask: 'Aufgabe löschen',
deleteTask_title: 'Aufgabe löschen', deleteTask_title: 'Aufgabe löschen',
deleteUser: 'Benutzer löschen', deleteUser: 'Benutzer löschen',
duplicate: 'Kopieren',
duplicateCard_title: 'Karte kopieren',
edit: 'Bearbeiten', edit: 'Bearbeiten',
editDueDate_title: 'Fälligkeitsdatum bearbeiten', editDueDate_title: 'Fälligkeitsdatum bearbeiten',
editDescription_title: 'Beschreibung ändern', editDescription_title: 'Beschreibung ändern',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'de', language: 'de-DE',
country: 'de', country: 'de',
name: 'Deutsch', name: 'Deutsch',
embeddedLocale: login, embeddedLocale: login,

View file

@ -106,6 +106,7 @@ export default {
language: 'Language', language: 'Language',
leaveBoard_title: 'Leave Board', leaveBoard_title: 'Leave Board',
leaveProject_title: 'Leave Project', leaveProject_title: 'Leave Project',
linkIsCopied: 'Link is copied',
list: 'List', list: 'List',
listActions_title: 'List Actions', listActions_title: 'List Actions',
managers: 'Managers', managers: 'Managers',
@ -183,6 +184,7 @@ export default {
addTask: 'Add task', addTask: 'Add task',
addToCard: 'Add to card', addToCard: 'Add to card',
addUser: 'Add user', addUser: 'Add user',
copyLink_title: 'Copy Link',
createBoard: 'Create board', createBoard: 'Create board',
createFile: 'Create file', createFile: 'Create file',
createLabel: 'Create label', createLabel: 'Create label',

View file

@ -4,8 +4,8 @@ import login from './login';
import core from './core'; import core from './core';
export default { export default {
language: 'en', language: 'en-US',
country: 'gb', country: 'us',
name: 'English', name: 'English',
embeddedLocale: merge(login, core), embeddedLocale: merge(login, core),
}; };

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'es', language: 'es-ES',
country: 'es', country: 'es',
name: 'Español', name: 'Español',
embeddedLocale: login, embeddedLocale: login,

View file

@ -0,0 +1,254 @@
import dateFns from 'date-fns/locale/fa-IR';
export default {
dateFns,
format: {
date: 'M/d/yyyy',
time: 'p',
dateTime: '$t(format:date) $t(format:time)',
longDate: 'MMM d',
longDateTime: "MMMM d 'at' p",
fullDate: 'MMM d, y',
fullDateTime: "MMMM d, y 'at' p",
},
translation: {
common: {
aboutPlanka: 'درباره Planka',
account: 'حساب کاربری',
actions: 'اقدامات',
addAttachment_title: 'اضافه کردن پیوست',
addComment: 'اضافه کردن نظر',
addManager_title: 'اضافه کردن مدیر',
addMember_title: 'اضافه کردن عضو',
addUser_title: 'اضافه کردن کاربر',
administrator: 'مدیر سیستم',
all: 'همه',
allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'تمام تغییرات به صورت خودکار ذخیره می‌شوند<br />بعد از بازیابی ارتباط.',
areYouSureYouWantToDeleteThisAttachment:
'آیا مطمئن هستید که می‌خواهید این پیوست را حذف کنید؟',
areYouSureYouWantToDeleteThisBoard: 'آیا مطمئن هستید که می‌خواهید این برد را حذف کنید؟',
areYouSureYouWantToDeleteThisCard: 'آیا مطمئن هستید که می‌خواهید این کارت را حذف کنید؟',
areYouSureYouWantToDeleteThisComment: 'آیا مطمئن هستید که می‌خواهید این نظر را حذف کنید؟',
areYouSureYouWantToDeleteThisLabel: 'آیا مطمئن هستید که می‌خواهید این برچسب را حذف کنید؟',
areYouSureYouWantToDeleteThisList: 'آیا مطمئن هستید که می‌خواهید این لیست را حذف کنید؟',
areYouSureYouWantToDeleteThisProject: 'آیا مطمئن هستید که می‌خواهید این پروژه را حذف کنید؟',
areYouSureYouWantToDeleteThisTask: 'آیا مطمئن هستید که می‌خواهید این وظیفه را حذف کنید؟',
areYouSureYouWantToDeleteThisUser: 'آیا مطمئن هستید که می‌خواهید این کاربر را حذف کنید؟',
areYouSureYouWantToLeaveBoard: 'آیا مطمئن هستید که می‌خواهید از برد خارج شوید؟',
areYouSureYouWantToLeaveProject: 'آیا مطمئن هستید که می‌خواهید از پروژه خارج شوید؟',
areYouSureYouWantToRemoveThisManagerFromProject:
'آیا مطمئن هستید که می‌خواهید این مدیر را از پروژه حذف کنید؟',
areYouSureYouWantToRemoveThisMemberFromBoard:
'آیا مطمئن هستید که می‌خواهید این عضو را از برد حذف کنید؟',
attachment: 'پیوست',
attachments: 'پیوست‌ها',
authentication: 'احراز هویت',
background: 'پس‌زمینه',
board: 'برد',
boardNotFound_title: 'برد یافت نشد',
canComment: 'می‌تواند نظر بدهد',
canEditContentOfBoard: 'می‌تواند محتوای برد را ویرایش کند.',
canOnlyViewBoard: 'فقط می‌تواند برد را مشاهده کند.',
cardActions_title: 'اقدامات کارت',
cardNotFound_title: 'کارت یافت نشد',
cardOrActionAreDeleted: 'کارت یا اقدام حذف شده‌اند.',
color: 'رنگ',
copy_inline: 'کپی',
createBoard_title: 'ایجاد برد',
createLabel_title: 'ایجاد برچسب',
createNewOneOrSelectExistingOne: 'یک جدید ایجاد کنید یا<br />یکی موجود را انتخاب کنید.',
createProject_title: 'ایجاد پروژه',
createTextFile_title: 'ایجاد فایل متنی',
currentPassword: 'رمز عبور فعلی',
dangerZone_title: 'منطقه خطر',
date: 'تاریخ',
dueDate: 'تاریخ سررسید',
dueDate_title: 'تاریخ سررسید',
deleteAttachment_title: 'حذف پیوست',
deleteBoard_title: 'حذف برد',
deleteCard_title: 'حذف کارت',
deleteComment_title: 'حذف نظر',
deleteLabel_title: 'حذف برچسب',
deleteList_title: 'حذف لیست',
deleteProject_title: 'حذف پروژه',
deleteTask_title: 'حذف وظیفه',
deleteUser_title: 'حذف کاربر',
description: 'توضیحات',
detectAutomatically: 'تشخیص خودکار',
dropFileToUpload: 'فایل را برای آپلود بکشید',
editor: 'ویرایشگر',
editAttachment_title: 'ویرایش پیوست',
editAvatar_title: 'ویرایش آواتار',
editBoard_title: 'ویرایش برد',
editDueDate_title: 'ویرایش تاریخ سررسید',
editEmail_title: 'ویرایش ایمیل',
editInformation_title: 'ویرایش اطلاعات',
editLabel_title: 'ویرایش برچسب',
editPassword_title: 'ویرایش رمز عبور',
editPermissions_title: 'ویرایش دسترسی‌ها',
editStopwatch_title: 'ویرایش کرنومتر',
editUsername_title: 'ویرایش نام کاربری',
email: 'ایمیل',
emailAlreadyInUse: 'ایمیل قبلا استفاده شده است',
enterCardTitle: 'عنوان کارت را وارد کنید... [Ctrl+Enter] برای باز شدن خودکار.',
enterDescription: 'توضیحات را وارد کنید...',
enterFilename: 'نام فایل را وارد کنید',
enterListTitle: 'عنوان لیست را وارد کنید...',
enterProjectTitle: 'عنوان پروژه را وارد کنید',
enterTaskDescription: 'توضیحات وظیفه را وارد کنید...',
filterByLabels_title: 'فیلتر بر اساس برچسب‌ها',
filterByMembers_title: 'فیلتر بر اساس اعضا',
fromComputer_title: 'از کامپیوتر',
fromTrello: 'از Trello',
general: 'عمومی',
hours: 'ساعت‌ها',
importBoard_title: 'وارد کردن برد',
invalidCurrentPassword: 'رمز عبور فعلی نامعتبر است',
labels: 'برچسب‌ها',
language: 'زبان',
leaveBoard_title: 'ترک برد',
leaveProject_title: 'ترک پروژه',
linkIsCopied: 'لینک کپی شد',
list: 'لیست',
listActions_title: 'اقدامات لیست',
managers: 'مدیران',
managerActions_title: 'اقدامات مدیر',
members: 'اعضا',
memberActions_title: 'اقدامات عضو',
minutes: 'دقیقه‌ها',
moveCard_title: 'انتقال کارت',
name: 'نام',
newestFirst: 'جدیدترین اول',
newEmail: 'ایمیل جدید',
newPassword: 'رمز عبور جدید',
newUsername: 'نام کاربری جدید',
noConnectionToServer: 'ارتباط با سرور قطع است',
noBoards: 'بردی وجود ندارد',
noLists: 'لیستی وجود ندارد',
noProjects: 'پروژه‌ای وجود ندارد',
notifications: 'اعلان‌ها',
noUnreadNotifications: 'اعلان خوانده نشده‌ای وجود ندارد.',
oldestFirst: 'قدیمی‌ترین اول',
openBoard_title: 'باز کردن برد',
optional_inline: 'اختیاری',
organization: 'سازمان',
phone: 'تلفن',
preferences: 'ترجیحات',
pressPasteShortcutToAddAttachmentFromClipboard:
'نکته: با فشردن Ctrl-V (Cmd-V در مک) می‌توانید پیوست را از کلیپ بورد اضافه کنید.',
project: 'پروژه',
projectNotFound_title: 'پروژه یافت نشد',
removeManager_title: 'حذف مدیر',
removeMember_title: 'حذف عضو',
searchLabels: 'جستجوی برچسب‌ها...',
searchMembers: 'جستجوی اعضا...',
searchUsers: 'جستجوی کاربران...',
searchCards: 'جستجوی کارت‌ها...',
seconds: 'ثانیه‌ها',
selectBoard: 'انتخاب برد',
selectList: 'انتخاب لیست',
selectPermissions_title: 'انتخاب دسترسی‌ها',
selectProject: 'انتخاب پروژه',
settings: 'تنظیمات',
sortList_title: 'مرتب‌سازی لیست',
stopwatch: 'کرنومتر',
subscribeToMyOwnCardsByDefault: 'به طور پیش‌فرض به کارت‌های خودم مشترک شوم',
taskActions_title: 'اقدامات وظیفه',
tasks: 'وظایف',
thereIsNoPreviewAvailableForThisAttachment: 'پیش نمایشی برای این پیوست موجود نیست.',
time: 'زمان',
title: 'عنوان',
userActions_title: 'اقدامات کاربر',
userAddedThisCardToList: '<0>{{user}}</0><1> این کارت را به {{list}} اضافه کرد</1>',
userLeftNewCommentToCard: '{{user}} نظر جدید «{{comment}}» را به <2>{{card}}</2> اضافه کرد',
userMovedCardFromListToList:
'{{user}} <2>{{card}}</2> را از {{fromList}} به {{toList}} منتقل کرد',
userMovedThisCardFromListToList:
'<0>{{user}}</0><1> این کارت را از {{fromList}} به {{toList}} منتقل کرد</1>',
username: 'نام کاربری',
usernameAlreadyInUse: 'نام کاربری قبلا استفاده شده است',
users: 'کاربران',
version: 'نسخه',
viewer: 'بیننده',
writeComment: 'نظر بنویسید...',
},
action: {
addAnotherCard: 'اضافه کردن کارت دیگر',
addAnotherList: 'اضافه کردن لیست دیگر',
addAnotherTask: 'اضافه کردن وظیفه دیگر',
addCard: 'اضافه کردن کارت',
addCard_title: 'اضافه کردن کارت',
addComment: 'اضافه کردن نظر',
addList: 'اضافه کردن لیست',
addMember: 'اضافه کردن عضو',
addMoreDetailedDescription: 'اضافه کردن توضیحات بیشتر',
addTask: 'اضافه کردن وظیفه',
addToCard: 'اضافه کردن به کارت',
addUser: 'اضافه کردن کاربر',
copyLink_title: 'کپی لینک',
createBoard: 'ایجاد برد',
createFile: 'ایجاد فایل',
createLabel: 'ایجاد برچسب',
createNewLabel: 'ایجاد برچسب جدید',
createProject: 'ایجاد پروژه',
delete: 'حذف',
deleteAttachment: 'حذف پیوست',
deleteAvatar: 'حذف آواتار',
deleteBoard: 'حذف برد',
deleteCard: 'حذف کارت',
deleteCard_title: 'حذف کارت',
deleteComment: 'حذف نظر',
deleteImage: 'حذف تصویر',
deleteLabel: 'حذف برچسب',
deleteList: 'حذف لیست',
deleteList_title: 'حذف لیست',
deleteProject: 'حذف پروژه',
deleteProject_title: 'حذف پروژه',
deleteTask: 'حذف وظیفه',
deleteTask_title: 'حذف وظیفه',
deleteUser: 'حذف کاربر',
duplicate: 'تکرار',
duplicateCard_title: 'تکرار کارت',
edit: 'ویرایش',
editDueDate_title: 'ویرایش تاریخ سررسید',
editDescription_title: 'ویرایش توضیحات',
editEmail_title: 'ویرایش ایمیل',
editInformation_title: 'ویرایش اطلاعات',
editPassword_title: 'ویرایش رمز عبور',
editPermissions: 'ویرایش دسترسی‌ها',
editStopwatch_title: 'ویرایش کرنومتر',
editTitle_title: 'ویرایش عنوان',
editUsername_title: 'ویرایش نام کاربری',
hideDetails: 'پنهان کردن جزئیات',
import: 'وارد کردن',
leaveBoard: 'ترک برد',
leaveProject: 'ترک پروژه',
logOut_title: 'خروج',
makeCover_title: 'ایجاد کاور',
move: 'انتقال',
moveCard_title: 'انتقال کارت',
remove: 'حذف',
removeBackground: 'حذف پس‌زمینه',
removeCover_title: 'حذف کاور',
removeFromBoard: 'حذف از برد',
removeFromProject: 'حذف از پروژه',
removeManager: 'حذف مدیر',
removeMember: 'حذف عضو',
save: 'ذخیره',
showAllAttachments: 'نمایش همه پیوست‌ها ({{hidden}} مخفی)',
showDetails: 'نمایش جزئیات',
showFewerAttachments: 'نمایش کمتر پیوست‌ها',
sortList_title: 'مرتب‌سازی لیست',
start: 'شروع',
stop: 'توقف',
subscribe: 'مشترک شدن',
unsubscribe: 'لغو اشتراک',
uploadNewAvatar: 'آپلود آواتار جدید',
uploadNewImage: 'آپلود تصویر جدید',
},
},
};

View file

@ -0,0 +1,8 @@
import login from './login';
export default {
language: 'fa-IR',
country: 'ir',
name: 'فارسی',
embeddedLocale: login,
};

View file

@ -0,0 +1,22 @@
export default {
translation: {
common: {
emailOrUsername: 'ایمیل یا نام کاربری',
invalidEmailOrUsername: 'ایمیل یا نام کاربری نامعتبر است',
invalidPassword: 'رمز عبور نامعتبر است',
logInToPlanka: 'ورود به Planka',
noInternetConnection: 'بدون اتصال به اینترنت',
pageNotFound_title: 'صفحه یافت نشد',
password: 'رمز عبور',
projectManagement: 'مدیریت پروژه',
serverConnectionFailed: 'اتصال به سرور ناموفق بود',
unknownError: 'خطای ناشناخته، بعداً دوباره تلاش کنید',
useSingleSignOn: 'استفاده از ورود یکپارچه',
},
action: {
logIn: 'ورود',
logInWithSSO: 'ورود با SSO',
},
},
};

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'fr', language: 'fr-FR',
country: 'fr', country: 'fr',
name: 'Français', name: 'Français',
embeddedLocale: login, embeddedLocale: login,

View file

@ -15,6 +15,16 @@ export default {
translation: { translation: {
common: { common: {
aboutPlanka: 'Plankáról',
account: 'Fiók',
actions: 'Műveletek',
addAttachment_title: 'Melléklet hozzáadása',
addComment: 'Megjegyzés hozzáadása',
addManager_title: 'Menedzser hozzáadása',
addMember_title: 'Tag létrehozása',
addUser_title: 'Felhasználó hozzáadása',
administrator: 'Rendszergazda',
all: 'Összes',
allChangesWillBeAutomaticallySavedAfterConnectionRestored: allChangesWillBeAutomaticallySavedAfterConnectionRestored:
'Az összes változás automatikusan mentésre kerül a kapcsolat helyreállása után.', 'Az összes változás automatikusan mentésre kerül a kapcsolat helyreállása után.',
areYouSureYouWantToDeleteThisAttachment: 'Biztosan törölni szeretné ezt a mellékletet?', areYouSureYouWantToDeleteThisAttachment: 'Biztosan törölni szeretné ezt a mellékletet?',
@ -29,7 +39,7 @@ export default {
areYouSureYouWantToLeaveBoard: 'Biztosan el akarja hagyni a táblát?', areYouSureYouWantToLeaveBoard: 'Biztosan el akarja hagyni a táblát?',
areYouSureYouWantToLeaveProject: 'Biztosan el akarja hagyni a projektet?', areYouSureYouWantToLeaveProject: 'Biztosan el akarja hagyni a projektet?',
areYouSureYouWantToRemoveThisManagerFromProject: areYouSureYouWantToRemoveThisManagerFromProject:
'Biztosan eltávolítja ezt a vezetőt a projektből?', 'Biztosan eltávolítja ezt a menedzsert a projektből?',
areYouSureYouWantToRemoveThisMemberFromBoard: 'Biztosan eltávolítja ezt a tagot a tábláról?', areYouSureYouWantToRemoveThisMemberFromBoard: 'Biztosan eltávolítja ezt a tagot a tábláról?',
attachment: 'Melléklet', attachment: 'Melléklet',
attachments: 'Mellékletek', attachments: 'Mellékletek',
@ -44,6 +54,7 @@ export default {
cardNotFound_title: 'Kártya nem található', cardNotFound_title: 'Kártya nem található',
cardOrActionAreDeleted: 'A kártya vagy művelet törölve lett.', cardOrActionAreDeleted: 'A kártya vagy művelet törölve lett.',
color: 'Szín', color: 'Szín',
copy_inline: 'másolás',
createBoard_title: 'Tábla létrehozása', createBoard_title: 'Tábla létrehozása',
createLabel_title: 'Címke létrehozása', createLabel_title: 'Címke létrehozása',
createNewOneOrSelectExistingOne: 'Hozzon létre egy újat, vagy válasszon ki egy meglévőt.', createNewOneOrSelectExistingOne: 'Hozzon létre egy újat, vagy válasszon ki egy meglévőt.',
@ -52,6 +63,7 @@ export default {
currentPassword: 'Jelenlegi jelszó', currentPassword: 'Jelenlegi jelszó',
dangerZone_title: 'Veszélyzóna', dangerZone_title: 'Veszélyzóna',
date: 'Dátum', date: 'Dátum',
dueDate: 'Határidő',
dueDate_title: 'Esedékesség dátuma', dueDate_title: 'Esedékesség dátuma',
deleteAttachment_title: 'Melléklet törlése', deleteAttachment_title: 'Melléklet törlése',
deleteBoard_title: 'Tábla törlése', deleteBoard_title: 'Tábla törlése',
@ -97,13 +109,17 @@ export default {
language: 'Nyelv', language: 'Nyelv',
leaveBoard_title: 'Tábla elhagyása', leaveBoard_title: 'Tábla elhagyása',
leaveProject_title: 'Projekt elhagyása', leaveProject_title: 'Projekt elhagyása',
linkIsCopied: 'Link másolva',
list: 'Lista', list: 'Lista',
listActions_title: 'Lista műveletek', listActions_title: 'Lista műveletek',
managers: 'Vezetők', managers: 'Menedzserek',
managerActions_title: 'Menedzseri műveletek',
members: 'Tagok', members: 'Tagok',
memberActions_title: 'Tag műveletek',
minutes: 'Percek', minutes: 'Percek',
moveCard_title: 'Kártya áthelyezése', moveCard_title: 'Kártya áthelyezése',
name: 'Név', name: 'Név',
newestFirst: 'Újabbak előre',
newEmail: 'Új e-mail', newEmail: 'Új e-mail',
newPassword: 'Új jelszó', newPassword: 'Új jelszó',
newUsername: 'Új felhasználónév', newUsername: 'Új felhasználónév',
@ -113,6 +129,7 @@ export default {
noProjects: 'Nincsenek projektek', noProjects: 'Nincsenek projektek',
notifications: 'Értesítések', notifications: 'Értesítések',
noUnreadNotifications: 'Nincsenek olvasatlan értesítések.', noUnreadNotifications: 'Nincsenek olvasatlan értesítések.',
oldestFirst: 'Régebbi előre',
openBoard_title: 'Tábla megnyitása', openBoard_title: 'Tábla megnyitása',
optional_inline: 'opcionális', optional_inline: 'opcionális',
organization: 'Szervezet', organization: 'Szervezet',
@ -122,17 +139,19 @@ export default {
'Tipp: nyomja meg a Ctrl-V (Cmd-V a Mac-en) billentyűkombinációt a vágólapról történő melléklet hozzáadásához.', 'Tipp: nyomja meg a Ctrl-V (Cmd-V a Mac-en) billentyűkombinációt a vágólapról történő melléklet hozzáadásához.',
project: 'Projekt', project: 'Projekt',
projectNotFound_title: 'Projekt nem található', projectNotFound_title: 'Projekt nem található',
removeManager_title: 'Vezető eltávolítása', removeManager_title: 'Menedzser eltávolítása',
removeMember_title: 'Tag eltávolítása', removeMember_title: 'Tag eltávolítása',
searchLabels: 'Címkék keresése...', searchLabels: 'Címkék keresése...',
searchMembers: 'Tagok keresése...', searchMembers: 'Tagok keresése...',
searchUsers: 'Felhasználók keresése...', searchUsers: 'Felhasználók keresése...',
searchCards: 'Kártyák keresése..',
seconds: 'Másodpercek', seconds: 'Másodpercek',
selectBoard: 'Válassza ki a táblát', selectBoard: 'Válassza ki a táblát',
selectList: 'Válassza ki a listát', selectList: 'Válassza ki a listát',
selectPermissions_title: 'Jogosultságok kiválasztása', selectPermissions_title: 'Jogosultságok kiválasztása',
selectProject: 'Válassza ki a projektet', selectProject: 'Válassza ki a projektet',
settings: 'Beállítások', settings: 'Beállítások',
sortList_title: 'Rendezés listában',
stopwatch: 'Stopper', stopwatch: 'Stopper',
subscribeToMyOwnCardsByDefault: 'Alapértelmezés szerint feliratkozás a saját kártyáimra', subscribeToMyOwnCardsByDefault: 'Alapértelmezés szerint feliratkozás a saját kártyáimra',
taskActions_title: 'Feladat műveletek', taskActions_title: 'Feladat műveletek',
@ -170,6 +189,7 @@ export default {
addTask: 'Feladat hozzáadása', addTask: 'Feladat hozzáadása',
addToCard: 'Kártyához hozzáadása', addToCard: 'Kártyához hozzáadása',
addUser: 'Felhasználó hozzáadása', addUser: 'Felhasználó hozzáadása',
copyLink_title: 'Link másolása',
createBoard: 'Tábla létrehozása', createBoard: 'Tábla létrehozása',
createFile: 'Fájl létrehozása', createFile: 'Fájl létrehozása',
createLabel: 'Címke létrehozása', createLabel: 'Címke létrehozása',
@ -191,6 +211,8 @@ export default {
deleteTask: 'Feladat törlése', deleteTask: 'Feladat törlése',
deleteTask_title: 'Feladat törlése', deleteTask_title: 'Feladat törlése',
deleteUser: 'Felhasználó törlése', deleteUser: 'Felhasználó törlése',
duplicate: 'Másolás',
duplicateCard_title: 'Kártya másolása',
edit: 'Szerkesztés', edit: 'Szerkesztés',
editDueDate_title: 'Esedékesség dátumának szerkesztése', editDueDate_title: 'Esedékesség dátumának szerkesztése',
editDescription_title: 'Leírás szerkesztése', editDescription_title: 'Leírás szerkesztése',
@ -214,12 +236,13 @@ export default {
removeCover_title: 'Borító eltávolítása', removeCover_title: 'Borító eltávolítása',
removeFromBoard: 'Eltávolítás a tábláról', removeFromBoard: 'Eltávolítás a tábláról',
removeFromProject: 'Eltávolítás a projektről', removeFromProject: 'Eltávolítás a projektről',
removeManager: 'Vezető eltávolítása', removeManager: 'Menedzser eltávolítása',
removeMember: 'Tag eltávolítása', removeMember: 'Tag eltávolítása',
save: 'Mentés', save: 'Mentés',
showAllAttachments: 'Összes melléklet megjelenítése ({{hidden}} rejtve)', showAllAttachments: 'Összes melléklet megjelenítése ({{hidden}} rejtve)',
showDetails: 'Részletek megjelenítése', showDetails: 'Részletek megjelenítése',
showFewerAttachments: 'Kevesebb melléklet megjelenítése', showFewerAttachments: 'Kevesebb melléklet megjelenítése',
sortList_title: 'Rendezés listában',
start: 'Indítás', start: 'Indítás',
stop: 'Megállítás', stop: 'Megállítás',
subscribe: 'Feliratkozás', subscribe: 'Feliratkozás',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'hu', language: 'hu-HU',
country: 'hu', country: 'hu',
name: 'Magyar', name: 'Magyar',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'id', language: 'id-ID',
country: 'id', country: 'id',
name: 'Bahasa Indonesia', name: 'Bahasa Indonesia',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,51 +1,53 @@
import bg from './bg'; import bgBG from './bg-BG';
import cs from './cs'; import csCZ from './cs-CZ';
import da from './da'; import daDK from './da-DK';
import de from './de'; import deDE from './de-DE';
import en from './en'; import enUS from './en-US';
import es from './es'; import esES from './es-ES';
import fr from './fr'; import faIR from './fa-IR';
import hu from './hu'; import frFR from './fr-FR';
import id from './id'; import huHU from './hu-HU';
import it from './it'; import idID from './id-ID';
import ja from './ja'; import itIT from './it-IT';
import ko from './ko'; import jaJP from './ja-JP';
import nl from './nl'; import koKR from './ko-KR';
import pl from './pl'; import nlNL from './nl-NL';
import pt from './pt'; import plPL from './pl-PL';
import ro from './ro'; import ptBR from './pt-BR';
import ru from './ru'; import roRO from './ro-RO';
import sk from './sk'; import ruRU from './ru-RU';
import sv from './sv'; import skSK from './sk-SK';
import tr from './tr'; import svSE from './sv-SE';
import ua from './ua'; import trTR from './tr-TR';
import uz from './uz'; import ukUA from './uk-UA';
import zh from './zh'; import uzUZ from './uz-UZ';
import zhCN from './zh-CN';
const locales = [ const locales = [
bg, bgBG,
cs, csCZ,
da, daDK,
de, deDE,
en, enUS,
es, esES,
fr, faIR,
hu, frFR,
id, huHU,
it, idID,
ja, itIT,
ko, jaJP,
nl, koKR,
pl, nlNL,
pt, plPL,
ro, ptBR,
ru, roRO,
sk, ruRU,
sv, skSK,
tr, svSE,
ua, trTR,
uz, ukUA,
zh, uzUZ,
zhCN,
]; ];
export default locales; export default locales;

View file

@ -1,4 +1,8 @@
import dateFns from 'date-fns/locale/it';
export default { export default {
dateFns,
format: { format: {
date: 'd/M/yyyy', date: 'd/M/yyyy',
time: 'p', time: 'p',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'it', language: 'it-IT',
country: 'it', country: 'it',
name: 'Italiano', name: 'Italiano',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'ja', language: 'ja-JP',
country: 'jp', country: 'jp',
name: '日本語', name: '日本語',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'ko', language: 'ko-KR',
country: 'kr', country: 'kr',
name: '한국어', name: '한국어',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'nl', language: 'nl-NL',
country: 'nl', country: 'nl',
name: 'Nederlands', name: 'Nederlands',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'pl', language: 'pl-PL',
country: 'pl', country: 'pl',
name: 'Polski', name: 'Polski',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'pt', language: 'pt-BR',
country: 'br', country: 'br',
name: 'Português', name: 'Português',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'ro', language: 'ro-RO',
country: 'ro', country: 'ro',
name: 'Română', name: 'Română',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'ru', language: 'ru-RU',
country: 'ru', country: 'ru',
name: 'Русский', name: 'Русский',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'sk', language: 'sk-SK',
country: 'sk', country: 'sk',
name: 'Slovenčina', name: 'Slovenčina',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'sv', language: 'sv-SE',
country: 'se', country: 'se',
name: 'Svenska', name: 'Svenska',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'tr', language: 'tr-TR',
country: 'tr', country: 'tr',
name: 'Türkçe', name: 'Türkçe',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,4 +1,8 @@
import dateFns from 'date-fns/locale/uk';
export default { export default {
dateFns,
format: { format: {
date: 'd/M/yyyy', date: 'd/M/yyyy',
time: 'p', time: 'p',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'ua', language: 'uk-UA',
country: 'ua', country: 'ua',
name: 'Українська', name: 'Українська',
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,4 +1,8 @@
import dateFns from 'date-fns/locale/uz';
export default { export default {
dateFns,
format: { format: {
date: 'M/d/yyyy', date: 'M/d/yyyy',
time: 'p', time: 'p',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'uz', language: 'uz-UZ',
country: 'uz', country: 'uz',
name: "O'zbek", name: "O'zbek",
embeddedLocale: login, embeddedLocale: login,

View file

@ -1,4 +1,8 @@
import dateFns from 'date-fns/locale/zh-CN';
export default { export default {
dateFns,
format: { format: {
date: 'M/d/yyyy', date: 'M/d/yyyy',
time: 'p', time: 'p',

View file

@ -1,7 +1,7 @@
import login from './login'; import login from './login';
export default { export default {
language: 'zh', language: 'zh-CN',
country: 'cn', country: 'cn',
name: '中文', name: '中文',
embeddedLocale: login, embeddedLocale: login,

View file

@ -28,6 +28,7 @@ export default class extends BaseModel {
case ActionTypes.CORE_INITIALIZE: case ActionTypes.CORE_INITIALIZE:
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE: case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE: case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
case ActionTypes.CARD_UPDATE_HANDLE:
if (payload.attachments) { if (payload.attachments) {
payload.attachments.forEach((attachment) => { payload.attachments.forEach((attachment) => {
Attachment.upsert(attachment); Attachment.upsert(attachment);

View file

@ -1,3 +1,4 @@
import orderBy from 'lodash/orderBy';
import { attr, fk, many } from 'redux-orm'; import { attr, fk, many } from 'redux-orm';
import BaseModel from './BaseModel'; import BaseModel from './BaseModel';
@ -218,10 +219,6 @@ export default class extends BaseModel {
} }
} }
getOrderedMembershipsQuerySet() {
return this.memberships.orderBy('createdAt');
}
getOrderedLabelsQuerySet() { getOrderedLabelsQuerySet() {
return this.labels.orderBy('position'); return this.labels.orderBy('position');
} }
@ -230,6 +227,12 @@ export default class extends BaseModel {
return this.lists.orderBy('position'); return this.lists.orderBy('position');
} }
getOrderedMembershipsModelArray() {
return orderBy(this.memberships.toModelArray(), (boardMembershipModel) =>
boardMembershipModel.user.name.toLocaleLowerCase(),
);
}
getMembershipModelForUser(userId) { getMembershipModelForUser(userId) {
return this.memberships return this.memberships
.filter({ .filter({

View file

@ -180,7 +180,6 @@ export default class extends BaseModel {
break; break;
case ActionTypes.CARD_CREATE: case ActionTypes.CARD_CREATE:
case ActionTypes.CARD_UPDATE__SUCCESS: case ActionTypes.CARD_UPDATE__SUCCESS:
case ActionTypes.CARD_UPDATE_HANDLE:
Card.upsert(payload.card); Card.upsert(payload.card);
break; break;
@ -202,8 +201,40 @@ export default class extends BaseModel {
break; break;
} }
case ActionTypes.CARD_UPDATE: case ActionTypes.CARD_UPDATE: {
Card.withId(payload.id).update(payload.data); const cardModel = Card.withId(payload.id);
// TODO: introduce separate action?
if (payload.data.boardId && payload.data.boardId !== cardModel.boardId) {
cardModel.deleteWithRelated();
} else {
cardModel.update(payload.data);
}
break;
}
case ActionTypes.CARD_UPDATE_HANDLE:
if (payload.isFetched) {
const cardModel = Card.withId(payload.card.id);
if (cardModel) {
cardModel.deleteWithRelated();
}
}
Card.upsert(payload.card);
if (payload.cardMemberships) {
payload.cardMemberships.forEach(({ cardId, userId }) => {
Card.withId(cardId).users.add(userId);
});
}
if (payload.cardLabels) {
payload.cardLabels.forEach(({ cardId, labelId }) => {
Card.withId(cardId).labels.add(labelId);
});
}
break; break;
case ActionTypes.CARD_DUPLICATE: { case ActionTypes.CARD_DUPLICATE: {

View file

@ -27,6 +27,7 @@ export default class extends BaseModel {
case ActionTypes.CORE_INITIALIZE: case ActionTypes.CORE_INITIALIZE:
case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE: case ActionTypes.PROJECT_MANAGER_CREATE_HANDLE:
case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE: case ActionTypes.BOARD_MEMBERSHIP_CREATE_HANDLE:
case ActionTypes.CARD_UPDATE_HANDLE:
if (payload.tasks) { if (payload.tasks) {
payload.tasks.forEach((task) => { payload.tasks.forEach((task) => {
Task.upsert(task); Task.upsert(task);

View file

@ -298,7 +298,7 @@ export default class extends BaseModel {
static getOrderedUndeletedQuerySet() { static getOrderedUndeletedQuerySet() {
return this.filter({ return this.filter({
deletedAt: null, deletedAt: null,
}).orderBy('createdAt'); }).orderBy((user) => user.name.toLocaleLowerCase());
} }
getOrderedProjectManagersQuerySet() { getOrderedProjectManagersQuerySet() {

View file

@ -81,9 +81,30 @@ export function* updateCurrentCard(data) {
yield call(updateCard, cardId, data); yield call(updateCard, cardId, data);
} }
// TODO: handle card transfer
export function* handleCardUpdate(card) { export function* handleCardUpdate(card) {
yield put(actions.handleCardUpdate(card)); let fetch = false;
if (card.boardId) {
const prevCard = yield select(selectors.selectCardById, card.id);
fetch = !prevCard || prevCard.boardId !== card.boardId;
}
let cardMemberships;
let cardLabels;
let tasks;
let attachments;
if (fetch) {
try {
({
item: card, // eslint-disable-line no-param-reassign
included: { cardMemberships, cardLabels, tasks, attachments },
} = yield call(request, api.getCard, card.id));
} catch (error) {
fetch = false;
}
}
yield put(actions.handleCardUpdate(card, fetch, cardMemberships, cardLabels, tasks, attachments));
} }
export function* moveCard(id, listId, index = 0) { export function* moveCard(id, listId, index = 0) {

View file

@ -55,17 +55,14 @@ export const selectMembershipsForCurrentBoard = createSelector(
return boardModel; return boardModel;
} }
return boardModel return boardModel.getOrderedMembershipsModelArray().map((boardMembershipModel) => ({
.getOrderedMembershipsQuerySet() ...boardMembershipModel.ref,
.toModelArray() isPersisted: !isLocalId(boardMembershipModel.id),
.map((boardMembershipModel) => ({ user: {
...boardMembershipModel.ref, ...boardMembershipModel.user.ref,
isPersisted: !isLocalId(boardMembershipModel.id), isCurrent: boardMembershipModel.user.id === currentUserId,
user: { },
...boardMembershipModel.user.ref, }));
isCurrent: boardMembershipModel.user.id === currentUserId,
},
}));
}, },
); );

View file

@ -1,7 +1,6 @@
version: '3.8' version: '3.8'
services: services:
server: server:
build: build:
context: ./server context: ./server
@ -13,6 +12,7 @@ services:
- NODE_ENV=development - NODE_ENV=development
- DATABASE_URL=postgresql://user:password@postgres:5432/planka_db - DATABASE_URL=postgresql://user:password@postgres:5432/planka_db
- SECRET_KEY=notsecretkey - SECRET_KEY=notsecretkey
# - TRUST_PROXY=0 # - TRUST_PROXY=0
# - TOKEN_EXPIRES_IN=365 # In days # - TOKEN_EXPIRES_IN=365 # In days
@ -23,10 +23,17 @@ services:
# Configure knex to accept SSL certificates # Configure knex to accept SSL certificates
# - KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE=false # - KNEX_REJECT_UNAUTHORIZED_SSL_CERTIFICATE=false
# - ALLOW_ALL_TO_CREATE_PROJECTS=true
# - OIDC_ISSUER= # - OIDC_ISSUER=
# - OIDC_CLIENT_ID= # - OIDC_CLIENT_ID=
# - OIDC_CLIENT_SECRET= # - OIDC_CLIENT_SECRET=
# - OIDC_ID_TOKEN_SIGNED_RESPONSE_ALG=
# - OIDC_USERINFO_SIGNED_RESPONSE_ALG=
# - OIDC_SCOPES=openid email profile # - OIDC_SCOPES=openid email profile
# - OIDC_RESPONSE_MODE=fragment
# - OIDC_USE_DEFAULT_RESPONSE_MODE=true
# - OIDC_ADMIN_ROLES=admin # - OIDC_ADMIN_ROLES=admin
# - OIDC_EMAIL_ATTRIBUTE=email # - OIDC_EMAIL_ATTRIBUTE=email
# - OIDC_NAME_ATTRIBUTE=name # - OIDC_NAME_ATTRIBUTE=name
@ -45,9 +52,17 @@ services:
# - SMTP_PASSWORD= # - SMTP_PASSWORD=
# - SMTP_FROM="Demo Demo" <demo@demo.demo> # - SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
# - SLACK_BOT_TOKEN= # - SLACK_BOT_TOKEN=
# - SLACK_CHANNEL_ID= # - SLACK_CHANNEL_ID=
working_dir: /app working_dir: /app
command: ["sh", "-c", "npm run start"] command: ["sh", "-c", "npm run start"]
depends_on: depends_on:
@ -76,11 +91,11 @@ services:
dockerfile: ../config/development/Dockerfile.server dockerfile: ../config/development/Dockerfile.server
environment: environment:
- DATABASE_URL=postgresql://user:password@postgres:5432/planka_db - DATABASE_URL=postgresql://user:password@postgres:5432/planka_db
# - DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted # - DEFAULT_ADMIN_EMAIL=demo@demo.demo # Do not remove if you want to prevent this user from being edited/deleted
# - DEFAULT_ADMIN_PASSWORD=demo # - DEFAULT_ADMIN_PASSWORD=demo
# - DEFAULT_ADMIN_NAME=Demo Demo # - DEFAULT_ADMIN_NAME=Demo Demo
# - DEFAULT_ADMIN_USERNAME=demo # - DEFAULT_ADMIN_USERNAME=demo
working_dir: /app working_dir: /app
command: ["sh", "-c", "npm run db:init"] command: ["sh", "-c", "npm run db:init"]
volumes: volumes:
@ -117,6 +132,5 @@ services:
- server - server
- client - client
volumes: volumes:
db-data: db-data:

View file

@ -31,10 +31,16 @@ services:
# - DEFAULT_ADMIN_NAME=Demo Demo # - DEFAULT_ADMIN_NAME=Demo Demo
# - DEFAULT_ADMIN_USERNAME=demo # - DEFAULT_ADMIN_USERNAME=demo
# - ALLOW_ALL_TO_CREATE_PROJECTS=true
# - OIDC_ISSUER= # - OIDC_ISSUER=
# - OIDC_CLIENT_ID= # - OIDC_CLIENT_ID=
# - OIDC_CLIENT_SECRET= # - OIDC_CLIENT_SECRET=
# - OIDC_ID_TOKEN_SIGNED_RESPONSE_ALG=
# - OIDC_USERINFO_SIGNED_RESPONSE_ALG=
# - OIDC_SCOPES=openid email profile # - OIDC_SCOPES=openid email profile
# - OIDC_RESPONSE_MODE=fragment
# - OIDC_USE_DEFAULT_RESPONSE_MODE=true
# - OIDC_ADMIN_ROLES=admin # - OIDC_ADMIN_ROLES=admin
# - OIDC_EMAIL_ATTRIBUTE=email # - OIDC_EMAIL_ATTRIBUTE=email
# - OIDC_NAME_ATTRIBUTE=name # - OIDC_NAME_ATTRIBUTE=name
@ -53,6 +59,15 @@ services:
# - SMTP_PASSWORD= # - SMTP_PASSWORD=
# - SMTP_FROM="Demo Demo" <demo@demo.demo> # - SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# - |
# WEBHOOKS=[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]
# - SLACK_BOT_TOKEN= # - SLACK_BOT_TOKEN=
# - SLACK_CHANNEL_ID= # - SLACK_CHANNEL_ID=
depends_on: depends_on:

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "planka", "name": "planka",
"version": "1.17.5", "version": "1.20.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "planka", "name": "planka",
"version": "1.17.5", "version": "1.20.1",
"hasInstallScript": true, "hasInstallScript": true,
"license": "AGPL-3.0", "license": "AGPL-3.0",
"dependencies": { "dependencies": {

View file

@ -1,6 +1,6 @@
{ {
"name": "planka", "name": "planka",
"version": "1.17.5", "version": "1.20.1",
"private": true, "private": true,
"homepage": "https://plankanban.github.io/planka", "homepage": "https://plankanban.github.io/planka",
"repository": { "repository": {

View file

@ -22,10 +22,16 @@ SECRET_KEY=notsecretkey
# DEFAULT_ADMIN_NAME=Demo Demo # DEFAULT_ADMIN_NAME=Demo Demo
# DEFAULT_ADMIN_USERNAME=demo # DEFAULT_ADMIN_USERNAME=demo
# ALLOW_ALL_TO_CREATE_PROJECTS=true
# OIDC_ISSUER= # OIDC_ISSUER=
# OIDC_CLIENT_ID= # OIDC_CLIENT_ID=
# OIDC_CLIENT_SECRET= # OIDC_CLIENT_SECRET=
# OIDC_ID_TOKEN_SIGNED_RESPONSE_ALG=
# OIDC_USERINFO_SIGNED_RESPONSE_ALG=
# OIDC_SCOPES=openid email profile # OIDC_SCOPES=openid email profile
# OIDC_RESPONSE_MODE=fragment
# OIDC_USE_DEFAULT_RESPONSE_MODE=true
# OIDC_ADMIN_ROLES=admin # OIDC_ADMIN_ROLES=admin
# OIDC_EMAIL_ATTRIBUTE=email # OIDC_EMAIL_ATTRIBUTE=email
# OIDC_NAME_ATTRIBUTE=name # OIDC_NAME_ATTRIBUTE=name
@ -43,12 +49,17 @@ SECRET_KEY=notsecretkey
# SMTP_PASSWORD= # SMTP_PASSWORD=
# SMTP_FROM="Demo Demo" <demo@demo.demo> # SMTP_FROM="Demo Demo" <demo@demo.demo>
# Optional fields: accessToken, events, excludedEvents
# WEBHOOKS='[{
# "url": "http://localhost:3001",
# "accessToken": "notaccesstoken",
# "events": ["cardCreate", "cardUpdate", "cardDelete"],
# "excludedEvents": ["notificationCreate", "notificationUpdate"]
# }]'
# SLACK_BOT_TOKEN= # SLACK_BOT_TOKEN=
# SLACK_CHANNEL_ID= # SLACK_CHANNEL_ID=
# WEBHOOK_URL=
# WEBHOOK_BEARER=
## Do not edit this ## Do not edit this
TZ=UTC TZ=UTC

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