mirror of
https://github.com/plankanban/planka.git
synced 2026-05-04 18:00:55 +03:00
Compare commits
72 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8dcd7cef3 | ||
|
|
6e2e6539d1 | ||
|
|
e429b478ca | ||
|
|
0e5dedd627 | ||
|
|
eb90b12b0e | ||
|
|
cd9ba8ff4f | ||
|
|
4e23f3c8a9 | ||
|
|
a9f28b45f4 | ||
|
|
d44e0dde93 | ||
|
|
20eb57de4c | ||
|
|
4ccc71419f | ||
|
|
0e93111e1b | ||
|
|
11f7814e87 | ||
|
|
9a4241e3d1 | ||
|
|
4fd164c81a | ||
|
|
5331f590a2 | ||
|
|
082b257a50 | ||
|
|
fd0981b5b3 | ||
|
|
9b68d3fc30 | ||
|
|
922d70e289 | ||
|
|
40a3e436ad | ||
|
|
227332768c | ||
|
|
555117912c | ||
|
|
9ba5f86073 | ||
|
|
3bf6e6fa19 | ||
|
|
8cc00ef2ef | ||
|
|
3d3c8f374c | ||
|
|
7a3873cbeb | ||
|
|
512b69080d | ||
|
|
5fa6fe825b | ||
|
|
f61299fde8 | ||
|
|
a55214e617 | ||
|
|
dbad8e976b | ||
|
|
3915536e72 | ||
|
|
3b7cc9c8a7 | ||
|
|
081d0cee1f | ||
|
|
60aaa4ad92 | ||
|
|
dbff5b2b1b | ||
|
|
f9102db1b2 | ||
|
|
9abad91b04 | ||
|
|
2b5921c30d | ||
|
|
03acecc43e | ||
|
|
06bedc1f7d | ||
|
|
e31eca2273 | ||
|
|
d3ff3e2db8 | ||
|
|
952a078aa1 | ||
|
|
4ea0322dc4 | ||
|
|
105b37ef57 | ||
|
|
4fb498667e | ||
|
|
b7d3602dcd | ||
|
|
91eb43f472 | ||
|
|
f47c188331 | ||
|
|
38a45c66e3 | ||
|
|
c342d2edd7 | ||
|
|
95e479cd3a | ||
|
|
d9ae02899d | ||
|
|
5e6195b252 | ||
|
|
61a3ff55cc | ||
|
|
af0cd79535 | ||
|
|
bb907d62e4 | ||
|
|
7604a31a74 | ||
|
|
2685e5d5fc | ||
|
|
5ebe320396 | ||
|
|
66ff3b65c6 | ||
|
|
8009fbacc6 | ||
|
|
d5d3f1de44 | ||
|
|
4e9e842e3d | ||
|
|
605dcace54 | ||
|
|
61753f08eb | ||
|
|
52c96c6c8f | ||
|
|
2a1760393f | ||
|
|
7758312e05 |
@@ -11,7 +11,7 @@ server/test
|
||||
server/.tmp
|
||||
server/.venv
|
||||
|
||||
server/views/index.html
|
||||
server/views/index.ejs
|
||||
|
||||
server/data/*
|
||||
!server/data/.gitkeep
|
||||
|
||||
@@ -18,9 +18,6 @@ jobs:
|
||||
node-version: '22'
|
||||
cache: 'npm'
|
||||
|
||||
- name: Update npm
|
||||
run: npm install npm --global
|
||||
|
||||
- name: Install server dependencies
|
||||
run: npm install --omit=prod --ignore-scripts
|
||||
working-directory: ./server
|
||||
@@ -34,7 +31,7 @@ jobs:
|
||||
working-directory: ./client
|
||||
|
||||
- name: Build client
|
||||
run: DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
run: INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
working-directory: ./client
|
||||
|
||||
- name: Include licenses into dist
|
||||
@@ -45,7 +42,7 @@ jobs:
|
||||
- name: Include built client into dist
|
||||
run: |
|
||||
mv ../../client/dist/* public
|
||||
cp public/index.html views
|
||||
mv public/index.ejs views
|
||||
working-directory: ./server/dist
|
||||
|
||||
- name: Create release package
|
||||
|
||||
@@ -24,13 +24,13 @@ jobs:
|
||||
|
||||
- name: Build client
|
||||
run: |
|
||||
DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
mv dist build
|
||||
working-directory: ./client
|
||||
|
||||
- name: Update Dockerfile to use prebuilt client
|
||||
run: |
|
||||
sed -i '/^FROM node:22 AS client/,/^ && DISABLE_ESLINT_PLUGIN=true npm run build$/c\
|
||||
sed -i '/^FROM node:22 AS client/,/^ && INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build$/c\
|
||||
FROM node:22 AS client\n\
|
||||
WORKDIR /app\n\
|
||||
COPY client/build /app/dist' Dockerfile
|
||||
|
||||
@@ -38,13 +38,13 @@ jobs:
|
||||
|
||||
- name: Build client
|
||||
run: |
|
||||
DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
mv dist build
|
||||
working-directory: ./client
|
||||
|
||||
- name: Update Dockerfile to use prebuilt client
|
||||
run: |
|
||||
sed -i '/^FROM node:22 AS client/,/^ && DISABLE_ESLINT_PLUGIN=true npm run build$/c\
|
||||
sed -i '/^FROM node:22 AS client/,/^ && INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build$/c\
|
||||
FROM node:22 AS client\n\
|
||||
WORKDIR /app\n\
|
||||
COPY client/build /app/dist' Dockerfile
|
||||
|
||||
2
.github/workflows/build-and-test.yml
vendored
2
.github/workflows/build-and-test.yml
vendored
@@ -46,7 +46,7 @@ jobs:
|
||||
run: |
|
||||
npm install
|
||||
cd client
|
||||
npm run build
|
||||
INDEX_FORMAT=ejs npm run build
|
||||
|
||||
- name: Set up and start server for testing
|
||||
env:
|
||||
|
||||
10
Dockerfile
10
Dockerfile
@@ -8,8 +8,7 @@ WORKDIR /app
|
||||
|
||||
COPY server .
|
||||
|
||||
RUN npm install npm --global \
|
||||
&& npm install \
|
||||
RUN npm install \
|
||||
&& npm run build \
|
||||
&& npm prune --production
|
||||
|
||||
@@ -22,14 +21,13 @@ COPY client .
|
||||
|
||||
RUN npm install npm --global \
|
||||
&& npm install --omit=dev \
|
||||
&& DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
&& INDEX_FORMAT=ejs DISABLE_ESLINT_PLUGIN=true npm run build
|
||||
|
||||
# Stage 3: Final image
|
||||
FROM node:22-alpine
|
||||
|
||||
RUN apk -U upgrade \
|
||||
&& apk add bash python3 squid --no-cache \
|
||||
&& npm install npm --global
|
||||
&& apk add bash python3 squid --no-cache
|
||||
|
||||
USER node
|
||||
WORKDIR /app
|
||||
@@ -41,12 +39,12 @@ COPY --from=server --chown=node:node /app/node_modules node_modules
|
||||
COPY --from=server --chown=node:node /app/dist .
|
||||
|
||||
COPY --from=client --chown=node:node /app/dist public
|
||||
COPY --from=client --chown=node:node /app/dist/index.html views
|
||||
|
||||
RUN python3 -m venv .venv \
|
||||
&& .venv/bin/pip3 install --upgrade pip \
|
||||
&& .venv/bin/pip3 install -r requirements.txt --no-cache-dir \
|
||||
&& mv .env.sample .env \
|
||||
&& mv public/index.ejs views \
|
||||
&& npm config set update-notifier false
|
||||
|
||||
VOLUME /app/data
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
FROM node:22-alpine
|
||||
|
||||
RUN apk -U upgrade \
|
||||
&& apk add bash build-base python3 xdg-utils --no-cache \
|
||||
&& npm install npm --global
|
||||
&& apk add bash build-base python3 xdg-utils --no-cache
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@@ -15,13 +15,13 @@ type: application
|
||||
# This is the chart version. This version number should be incremented each time you make changes
|
||||
# to the chart and its templates, including the app version.
|
||||
# Versions are expected to follow Semantic Versioning (https://semver.org/)
|
||||
version: 2.0.1
|
||||
version: 2.1.0
|
||||
|
||||
# This is the version number of the application being deployed. This version number should be
|
||||
# incremented each time you make changes to the application. Versions are not expected to
|
||||
# follow Semantic Versioning. They should reflect the version the application is using.
|
||||
# It is recommended to use it with quotes.
|
||||
appVersion: "2.0.1"
|
||||
appVersion: "2.1.0"
|
||||
|
||||
dependencies:
|
||||
- alias: postgresql
|
||||
|
||||
@@ -227,6 +227,28 @@ extraEnv:
|
||||
key: api-key
|
||||
```
|
||||
|
||||
### Custom Terms of Service
|
||||
|
||||
You can provide your own End User Terms of Service by passing the markdown files directly via `values.yaml` in the `terms` configuration block. This automates the creation of a corresponding ConfigMap and volume mount.
|
||||
|
||||
```yaml
|
||||
terms:
|
||||
enabled: true
|
||||
customFiles:
|
||||
en-US.md: |
|
||||
# End User Terms of Service
|
||||
...
|
||||
[confirmations]::
|
||||
---
|
||||
✔️ **I have read and accept these End User Terms of Service**
|
||||
de-DE.md: |
|
||||
# Nutzungsbedingungen
|
||||
...
|
||||
[confirmations]::
|
||||
---
|
||||
✔️ **Ich habe diese Nutzungsbedingungen gelesen und akzeptiere sie**
|
||||
```
|
||||
|
||||
### Image Digest Pinning
|
||||
|
||||
For enhanced security and reproducibility, you can pin the container image using its SHA256 digest instead of relying solely on tags. This ensures you always deploy the exact same image, preventing tag mutations or accidental updates.
|
||||
@@ -291,3 +313,4 @@ image:
|
||||
### Complete Example
|
||||
|
||||
See `values-example.yaml` for a comprehensive example that demonstrates all the advanced features including OIDC configuration with custom CA certificates.
|
||||
````
|
||||
|
||||
13
charts/planka/templates/configmap-terms.yaml
Normal file
13
charts/planka/templates/configmap-terms.yaml
Normal file
@@ -0,0 +1,13 @@
|
||||
{{- if .Values.terms.enabled }}
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "planka.fullname" . }}-terms
|
||||
labels:
|
||||
{{- include "planka.labels" . | nindent 4 }}
|
||||
data:
|
||||
{{- range $key, $value := .Values.terms.customFiles }}
|
||||
{{ $key }}: |
|
||||
{{- $value | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -70,6 +70,16 @@ spec:
|
||||
- mountPath: /app/logs
|
||||
subPath: app-logs
|
||||
name: emptydir
|
||||
- mountPath: /app/.tmp
|
||||
subPath: app-tmp
|
||||
name: emptydir
|
||||
- mountPath: /tmp
|
||||
subPath: tmp
|
||||
name: emptydir
|
||||
{{- end }}
|
||||
{{- if .Values.terms.enabled }}
|
||||
- mountPath: /app/terms/custom
|
||||
name: planka-terms
|
||||
{{- end }}
|
||||
{{- /* Extra volume mounts */}}
|
||||
{{- range .Values.extraMounts }}
|
||||
@@ -216,6 +226,11 @@ spec:
|
||||
{{- if .Values.securityContext.readOnlyRootFilesystem }}
|
||||
- name: emptydir
|
||||
emptyDir: {}
|
||||
{{- end }}
|
||||
{{- if .Values.terms.enabled }}
|
||||
- name: planka-terms
|
||||
configMap:
|
||||
name: {{ include "planka.fullname" . }}-terms
|
||||
{{- end }}
|
||||
{{- /* Extra volumes */}}
|
||||
{{- range .Values.extraMounts }}
|
||||
|
||||
@@ -248,6 +248,22 @@ extraEnv: []
|
||||
## - name: SMTP_FROM
|
||||
## value: "your_email@example.com"
|
||||
|
||||
## End User Terms of Service configuration
|
||||
## Mount custom terms of service markdown files into the Planka deployment
|
||||
##
|
||||
terms:
|
||||
enabled: false
|
||||
# Provide individual language files as key-value pairs
|
||||
# e.g.,
|
||||
# customFiles:
|
||||
# en-US.md: |
|
||||
# # End User Terms of Service
|
||||
# ...
|
||||
# de-DE.md: |
|
||||
# # Nutzungsbedingungen
|
||||
# ...
|
||||
customFiles: {}
|
||||
|
||||
## Extra volume mounts configuration
|
||||
## Mount ConfigMaps, Secrets, and arbitrary volumes to the PLANKA container
|
||||
## This allows mounting any pre-existing ConfigMaps, Secrets, or other volume types
|
||||
|
||||
2598
client/package-lock.json
generated
2598
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -79,9 +79,6 @@
|
||||
}
|
||||
},
|
||||
"overrides": {
|
||||
"@diplodoc/transform": {
|
||||
"lodash": "^4.17.23"
|
||||
},
|
||||
"react-mentions": {
|
||||
"@babel/runtime": "^7.28.6"
|
||||
}
|
||||
@@ -89,12 +86,12 @@
|
||||
"dependencies": {
|
||||
"@ballerina/highlightjs-ballerina": "^1.0.1",
|
||||
"@diplodoc/cut-extension": "^1.1.1",
|
||||
"@diplodoc/transform": "^4.64.1",
|
||||
"@diplodoc/transform": "^4.70.2",
|
||||
"@gravity-ui/components": "^4.18.0",
|
||||
"@gravity-ui/markdown-editor": "^15.31.0",
|
||||
"@gravity-ui/uikit": "^7.31.1",
|
||||
"@gravity-ui/markdown-editor": "^15.35.1",
|
||||
"@gravity-ui/uikit": "^7.34.0",
|
||||
"@juggle/resize-observer": "^3.4.0",
|
||||
"@vitejs/plugin-react": "^5.1.3",
|
||||
"@vitejs/plugin-react": "^5.2.0",
|
||||
"browserslist-to-esbuild": "^2.1.1",
|
||||
"classnames": "^2.5.1",
|
||||
"date-fns": "^4.1.0",
|
||||
@@ -123,18 +120,17 @@
|
||||
"highlightjs-zenscript": "^2.0.0",
|
||||
"hightlightjs-papyrus": "^0.0.4",
|
||||
"history": "^5.3.0",
|
||||
"i18next": "^25.8.1",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"initials": "^3.1.2",
|
||||
"javascript-time-ago": "^2.6.2",
|
||||
"i18next": "^25.8.18",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"javascript-time-ago": "^2.6.4",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"linkify-react": "^4.3.2",
|
||||
"linkifyjs": "^4.3.2",
|
||||
"lodash": "^4.17.23",
|
||||
"lodash": "^4.18.1",
|
||||
"lowlight": "^3.3.0",
|
||||
"markdown-it": "^13.0.2",
|
||||
"nanoid": "^5.1.6",
|
||||
"nanoid": "^5.1.7",
|
||||
"papaparse": "^5.5.3",
|
||||
"patch-package": "^8.0.1",
|
||||
"photoswipe": "^5.4.4",
|
||||
@@ -143,29 +139,29 @@
|
||||
"react-beautiful-dnd": "^13.1.1",
|
||||
"react-datepicker": "^9.1.0",
|
||||
"react-dom": "18.2.0",
|
||||
"react-dropzone": "^14.4.0",
|
||||
"react-dropzone": "^15.0.0",
|
||||
"react-frame-component": "^5.2.7",
|
||||
"react-hot-toast": "^2.6.0",
|
||||
"react-i18next": "^16.5.4",
|
||||
"react-i18next": "^16.5.8",
|
||||
"react-input-mask": "^2.0.4",
|
||||
"react-intersection-observer": "^10.0.2",
|
||||
"react-intersection-observer": "^10.0.3",
|
||||
"react-mentions": "^4.4.10",
|
||||
"react-photoswipe-gallery": "^4.0.0",
|
||||
"react-redux": "^9.2.0",
|
||||
"react-router": "^7.13.0",
|
||||
"react-router": "^7.13.1",
|
||||
"react-textarea-autosize": "^8.5.9",
|
||||
"react-time-ago": "^7.4.1",
|
||||
"react-time-ago": "^7.4.4",
|
||||
"redux": "^5.0.1",
|
||||
"redux-logger": "^3.0.6",
|
||||
"redux-orm": "^0.16.2",
|
||||
"redux-saga": "^1.4.2",
|
||||
"reselect": "^5.1.1",
|
||||
"sails.io.js": "^1.2.1",
|
||||
"sass-embedded": "^1.97.3",
|
||||
"sass-embedded": "^1.98.0",
|
||||
"semantic-ui-react": "^2.1.5",
|
||||
"socket.io-client": "^4.8.3",
|
||||
"validator": "^13.15.26",
|
||||
"vite": "^7.3.1",
|
||||
"vite": "^7.3.2",
|
||||
"vite-plugin-commonjs": "^0.10.4",
|
||||
"vite-plugin-node-polyfills": "^0.25.0",
|
||||
"vite-plugin-svgr": "^4.5.0",
|
||||
@@ -174,10 +170,10 @@
|
||||
"devDependencies": {
|
||||
"@babel/eslint-parser": "^7.28.6",
|
||||
"@babel/preset-env": "^7.29.0",
|
||||
"@cucumber/cucumber": "^12.6.0",
|
||||
"@cucumber/pretty-formatter": "^3.0.0",
|
||||
"@playwright/test": "^1.58.1",
|
||||
"babel-jest": "^30.2.0",
|
||||
"@cucumber/cucumber": "^12.7.0",
|
||||
"@cucumber/pretty-formatter": "^3.2.0",
|
||||
"@playwright/test": "^1.58.2",
|
||||
"babel-jest": "^30.3.0",
|
||||
"babel-preset-airbnb": "^5.0.0",
|
||||
"eslint": "^8.57.1",
|
||||
"eslint-config-airbnb": "^19.0.4",
|
||||
@@ -187,8 +183,8 @@
|
||||
"eslint-plugin-prettier": "^5.5.5",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^4.6.2",
|
||||
"jest": "^30.2.0",
|
||||
"playwright": "^1.58.0",
|
||||
"jest": "^30.3.0",
|
||||
"playwright": "^1.58.2",
|
||||
"prettier": "3.8.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/@diplodoc/transform/lib/md.js b/node_modules/@diplodoc/transform/lib/md.js
|
||||
index a2d222e..8d1377e 100644
|
||||
index c9faa96..e4bef9b 100644
|
||||
--- a/node_modules/@diplodoc/transform/lib/md.js
|
||||
+++ b/node_modules/@diplodoc/transform/lib/md.js
|
||||
@@ -101,8 +101,12 @@ function initPlugins(md, options, pluginOptions) {
|
||||
@@ -107,8 +107,12 @@ function initPlugins(md, options, pluginOptions) {
|
||||
}
|
||||
md.use(ol_attr_conversion_1.olAttrConversion);
|
||||
plugins.forEach((plugin) => md.use(plugin, pluginOptions));
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js b/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
|
||||
index dec01f0..a80b857 100644
|
||||
index c0d13c3..4c6e4e9 100644
|
||||
--- a/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
|
||||
+++ b/node_modules/@gravity-ui/markdown-editor/build/esm/bundle/wysiwyg-preset.js
|
||||
@@ -102,7 +102,6 @@ export const BundlePreset = (builder, opts) => {
|
||||
@@ -107,7 +107,6 @@ export const BundlePreset = (builder, opts) => {
|
||||
enableNewImageSizeCalculation: opts.enableNewImageSizeCalculation,
|
||||
...opts.imgSize,
|
||||
},
|
||||
@@ -10,7 +10,7 @@ index dec01f0..a80b857 100644
|
||||
deflist: {
|
||||
deflistTermPlaceholder: () => i18nPlaceholder('deflist_term'),
|
||||
deflistDescPlaceholder: () => i18nPlaceholder('deflist_desc'),
|
||||
@@ -123,11 +122,6 @@ export const BundlePreset = (builder, opts) => {
|
||||
@@ -128,11 +127,6 @@ export const BundlePreset = (builder, opts) => {
|
||||
...opts.yfmTable,
|
||||
controls: opts.mobile ? false : opts.yfmTable?.controls,
|
||||
},
|
||||
@@ -36,6 +36,23 @@ index 8aefe20..99e59e3 100644
|
||||
}
|
||||
if (options.pmTransformers) {
|
||||
this.#pmTransformers = options.pmTransformers;
|
||||
diff --git a/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/TooltipPlugin/index.js b/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/TooltipPlugin/index.js
|
||||
index 5eec9bb..3abd31a 100644
|
||||
--- a/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/TooltipPlugin/index.js
|
||||
+++ b/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/markdown/CodeBlock/CodeBlockHighlight/TooltipPlugin/index.js
|
||||
@@ -75,12 +75,6 @@ export const codeLangSelectTooltipViewCreator = (view, langItems, mapping = {},
|
||||
dispatch: view.dispatch,
|
||||
}),
|
||||
},
|
||||
- {
|
||||
- id: 'code-block-copy',
|
||||
- type: ToolbarDataType.ReactNodeFn,
|
||||
- width: 28,
|
||||
- content: () => _jsx(ClipboardButton, { text: node.textContent }),
|
||||
- },
|
||||
].filter(isTruthy),
|
||||
[
|
||||
{
|
||||
diff --git a/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/yfm/YfmNote/YfmNoteSpecs/index.js b/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/yfm/YfmNote/YfmNoteSpecs/index.js
|
||||
index 212c583..b709383 100644
|
||||
--- a/node_modules/@gravity-ui/markdown-editor/build/esm/extensions/yfm/YfmNote/YfmNoteSpecs/index.js
|
||||
@@ -18,7 +18,7 @@ const http = {};
|
||||
return result;
|
||||
}, new FormData());
|
||||
|
||||
return fetch(`${Config.SERVER_BASE_URL}/api${url}`, {
|
||||
return fetch(`${Config.BASE_PATH}/api${url}`, {
|
||||
method,
|
||||
headers,
|
||||
body: formData,
|
||||
|
||||
@@ -10,7 +10,7 @@ import Config from '../constants/Config';
|
||||
|
||||
const io = sailsIOClient(socketIOClient);
|
||||
|
||||
io.sails.url = Config.SERVER_BASE_URL;
|
||||
io.sails.path = `${Config.BASE_PATH}/socket.io`;
|
||||
io.sails.autoConnect = false;
|
||||
io.sails.reconnection = true;
|
||||
io.sails.useCORSRouteToGetCookie = false;
|
||||
|
||||
@@ -1,4 +1,46 @@
|
||||
# [2.0.1] - 2026-02-17
|
||||
# [2.1.1] - 2026-04-18
|
||||
|
||||
### Added
|
||||
|
||||
* Allow admins to edit user avatars
|
||||
* Add Pro features discovery banner
|
||||
|
||||
### Changed
|
||||
|
||||
* Remove global npm installation from Dockerfiles
|
||||
|
||||
### Fixed
|
||||
|
||||
* Fix Unicode and emoji characters in user avatar initials
|
||||
* Fix S3 request checksum calculation
|
||||
* Limit proxy file descriptors to prevent excessive memory allocation
|
||||
* Improve security by fixing multiple dependency vulnerabilities
|
||||
|
||||
## [2.1.0] - 2026-03-19
|
||||
|
||||
### Added
|
||||
|
||||
* Support running under subpath
|
||||
* Add ability to display card ages
|
||||
* Allow exposing Swagger specification
|
||||
* Configurable HTTP timeout for OIDC
|
||||
|
||||
## [2.0.3] - 2026-03-01
|
||||
|
||||
### Fixed
|
||||
|
||||
* Improve security by ensuring the outgoing proxy is not accessible from outside
|
||||
|
||||
## [2.0.2] - 2026-02-23
|
||||
|
||||
### Fixed
|
||||
|
||||
* Prevent dropzone from overflowing content
|
||||
* Update Gravatar hash algorithm
|
||||
* Improve backup and restore scripts
|
||||
* Improve installation on Windows and containerized environments
|
||||
|
||||
## [2.0.1] - 2026-02-17
|
||||
|
||||
### Fixed
|
||||
|
||||
|
||||
@@ -43,6 +43,14 @@ const Others = React.memo(() => {
|
||||
className={styles.radio}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Radio
|
||||
toggle
|
||||
name="displayCardAges"
|
||||
checked={board.displayCardAges}
|
||||
label={t('common.displayCardAges')}
|
||||
className={styles.radio}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
<Radio
|
||||
toggle
|
||||
name="expandTaskListsByDefault"
|
||||
|
||||
@@ -17,6 +17,7 @@ import { BoardMembershipRoles, BoardViews } from '../../../constants/Enums';
|
||||
import TaskList from './TaskList';
|
||||
import DueDateChip from '../DueDateChip';
|
||||
import StopwatchChip from '../StopwatchChip';
|
||||
import TimeAgo from '../../common/TimeAgo';
|
||||
import UserAvatar from '../../users/UserAvatar';
|
||||
import LabelChip from '../../labels/LabelChip';
|
||||
import CustomFieldValueChip from '../../custom-field-values/CustomFieldValueChip';
|
||||
@@ -75,12 +76,13 @@ const ProjectContent = React.memo(({ cardId }) => {
|
||||
return attachment && attachment.data.thumbnailUrls.outside360;
|
||||
});
|
||||
|
||||
const { listName, withCreator } = useSelector((state) => {
|
||||
const { listName, withCreator, withAge } = useSelector((state) => {
|
||||
const board = selectors.selectCurrentBoard(state);
|
||||
|
||||
return {
|
||||
listName: list.name && (board.view === BoardViews.KANBAN ? null : list.name),
|
||||
withCreator: board.alwaysDisplayCardCreator,
|
||||
withAge: board.displayCardAges,
|
||||
};
|
||||
}, shallowEqual);
|
||||
|
||||
@@ -115,6 +117,7 @@ const ProjectContent = React.memo(({ cardId }) => {
|
||||
card.dueDate ||
|
||||
card.stopwatch ||
|
||||
card.commentsTotal > 0 ||
|
||||
withAge ||
|
||||
attachmentsTotal > 0 ||
|
||||
notificationsTotal > 0 ||
|
||||
listName;
|
||||
@@ -236,6 +239,14 @@ const ProjectContent = React.memo(({ cardId }) => {
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
{withAge && card.createdAt && (
|
||||
<span className={classNames(styles.attachment, styles.attachmentLeft)}>
|
||||
<span className={styles.attachmentContent}>
|
||||
<Icon name="history" />
|
||||
<TimeAgo date={card.createdAt} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
{!isCompact && usersNode}
|
||||
|
||||
@@ -6,12 +6,13 @@
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { shallowEqual, useSelector } from 'react-redux';
|
||||
import { Icon } from 'semantic-ui-react';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import markdownToText from '../../../utils/markdown-to-text';
|
||||
import { BoardViews } from '../../../constants/Enums';
|
||||
import TimeAgo from '../../common/TimeAgo';
|
||||
import LabelChip from '../../labels/LabelChip';
|
||||
import CustomFieldValueChip from '../../custom-field-values/CustomFieldValueChip';
|
||||
|
||||
@@ -52,19 +53,14 @@ const StoryContent = React.memo(({ cardId }) => {
|
||||
selectNotificationsTotalByCardId(state, cardId),
|
||||
);
|
||||
|
||||
const listName = useSelector((state) => {
|
||||
if (!list.name) {
|
||||
return null;
|
||||
}
|
||||
const { listName, withAge } = useSelector((state) => {
|
||||
const board = selectors.selectCurrentBoard(state);
|
||||
|
||||
const { view } = selectors.selectCurrentBoard(state);
|
||||
|
||||
if (view === BoardViews.KANBAN) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return list.name;
|
||||
});
|
||||
return {
|
||||
listName: list.name && (board.view === BoardViews.KANBAN ? null : list.name),
|
||||
withAge: board.displayCardAges,
|
||||
};
|
||||
}, shallowEqual);
|
||||
|
||||
const coverUrl = useSelector((state) => {
|
||||
const attachment = selectAttachmentById(state, card.coverAttachmentId);
|
||||
@@ -109,7 +105,7 @@ const StoryContent = React.memo(({ cardId }) => {
|
||||
{card.name}
|
||||
</div>
|
||||
{card.description && <div className={styles.descriptionText}>{descriptionText}</div>}
|
||||
{(attachmentsTotal > 0 || notificationsTotal > 0 || listName) && (
|
||||
{(withAge || attachmentsTotal > 0 || notificationsTotal > 0 || listName) && (
|
||||
<span className={styles.attachments}>
|
||||
{notificationsTotal > 0 && (
|
||||
<span
|
||||
@@ -138,6 +134,14 @@ const StoryContent = React.memo(({ cardId }) => {
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
{withAge && card.createdAt && (
|
||||
<span className={classNames(styles.attachment, styles.attachmentLeft)}>
|
||||
<span className={styles.attachmentContent}>
|
||||
<Icon name="history" />
|
||||
<TimeAgo date={card.createdAt} />
|
||||
</span>
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -132,7 +132,11 @@ const AddAttachmentZone = React.memo(({ children }) => {
|
||||
<>
|
||||
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
||||
<div {...getRootProps()}>
|
||||
{isDragActive && <div className={styles.dropzone}>{t('common.dropFileToUpload')}</div>}
|
||||
{isDragActive && (
|
||||
<div className={styles.dropzone}>
|
||||
<div className={styles.dropzoneText}>{t('common.dropFileToUpload')}</div>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
||||
<input {...getInputProps()} />
|
||||
|
||||
@@ -8,13 +8,18 @@
|
||||
background: white;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
height: 100%;
|
||||
inset: 0;
|
||||
line-height: 30px;
|
||||
opacity: 0.7;
|
||||
padding: 200px 50px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 2001;
|
||||
}
|
||||
|
||||
.dropzoneText {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: min(200px, 50%);
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ import SelectRoleStep from './SelectRoleStep';
|
||||
import ApiKeyStep from './ApiKeyStep';
|
||||
import ConfirmationStep from '../../ConfirmationStep';
|
||||
import EditUserInformationStep from '../../../users/EditUserInformationStep';
|
||||
import EditUserAvatarStep from '../../../users/EditUserAvatarStep';
|
||||
import EditUserUsernameStep from '../../../users/EditUserUsernameStep';
|
||||
import EditUserEmailStep from '../../../users/EditUserEmailStep';
|
||||
import EditUserPasswordStep from '../../../users/EditUserPasswordStep';
|
||||
@@ -25,6 +26,7 @@ import styles from './ActionsStep.module.scss';
|
||||
|
||||
const StepTypes = {
|
||||
EDIT_INFORMATION: 'EDIT_INFORMATION',
|
||||
EDIT_AVATAR: 'EDIT_AVATAR',
|
||||
EDIT_USERNAME: 'EDIT_USERNAME',
|
||||
EDIT_EMAIL: 'EDIT_EMAIL',
|
||||
EDIT_PASSWORD: 'EDIT_PASSWORD',
|
||||
@@ -97,6 +99,10 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
|
||||
openStep(StepTypes.EDIT_INFORMATION);
|
||||
}, [openStep]);
|
||||
|
||||
const handleEditAvatarClick = useCallback(() => {
|
||||
openStep(StepTypes.EDIT_AVATAR);
|
||||
}, [openStep]);
|
||||
|
||||
const handleEditUsernameClick = useCallback(() => {
|
||||
openStep(StepTypes.EDIT_USERNAME);
|
||||
}, [openStep]);
|
||||
@@ -137,6 +143,8 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
|
||||
switch (step.type) {
|
||||
case StepTypes.EDIT_INFORMATION:
|
||||
return <EditUserInformationStep id={userId} onBack={handleBack} onClose={onClose} />;
|
||||
case StepTypes.EDIT_AVATAR:
|
||||
return <EditUserAvatarStep id={userId} onBack={handleBack} onClose={onClose} />;
|
||||
case StepTypes.EDIT_USERNAME:
|
||||
return <EditUserUsernameStep id={userId} onBack={handleBack} onClose={onClose} />;
|
||||
case StepTypes.EDIT_EMAIL:
|
||||
@@ -219,6 +227,12 @@ const ActionsStep = React.memo(({ userId, onClose }) => {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditAvatarClick}>
|
||||
<Icon name="image outline" className={styles.menuItemIcon} />
|
||||
{t('action.editAvatar', {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
{!user.lockedFieldNames.includes('username') && (
|
||||
<Menu.Item className={styles.menuItem} onClick={handleEditUsernameClick}>
|
||||
<Icon name="at" className={styles.menuItemIcon} />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
@@ -8,6 +8,7 @@ import { useSelector } from 'react-redux';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
import Header from '../Header';
|
||||
import PromoBanner from '../PromoBanner/PromoBanner';
|
||||
import Favorites from '../Favorites';
|
||||
import HomeActions from '../HomeActions';
|
||||
import Project from '../../projects/Project';
|
||||
@@ -22,6 +23,7 @@ const Fixed = React.memo(() => {
|
||||
return (
|
||||
<div className={styles.wrapper}>
|
||||
<Header />
|
||||
<PromoBanner />
|
||||
<Favorites />
|
||||
{projectId === undefined && <HomeActions />}
|
||||
{projectId && <Project />}
|
||||
|
||||
@@ -10,6 +10,7 @@ import { useSelector } from 'react-redux';
|
||||
import history from '../../../history';
|
||||
import selectors from '../../../selectors';
|
||||
import matchPaths from '../../../utils/match-paths';
|
||||
import Config from '../../../constants/Config';
|
||||
import Paths from '../../../constants/Paths';
|
||||
|
||||
const Link = React.memo(({ href, content, stopPropagation, ...props }) => {
|
||||
@@ -23,7 +24,8 @@ const Link = React.memo(({ href, content, stopPropagation, ...props }) => {
|
||||
}
|
||||
}, [href]);
|
||||
|
||||
const isSameSite = !!url && url.origin === window.location.origin;
|
||||
const isSameSite =
|
||||
!!url && url.origin === window.location.origin && url.pathname.startsWith(Config.BASE_PATH);
|
||||
|
||||
const cardsPathMatch = useMemo(() => {
|
||||
if (!isSameSite) {
|
||||
|
||||
111
client/src/components/common/PromoBanner/PromoBanner.jsx
Normal file
111
client/src/components/common/PromoBanner/PromoBanner.jsx
Normal file
@@ -0,0 +1,111 @@
|
||||
/*!
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import selectors from '../../../selectors';
|
||||
|
||||
import styles from './PromoBanner.module.scss';
|
||||
|
||||
const PRO_URL = 'https://planka.app/pro?ref=app-banner';
|
||||
const DISMISS_DURATION_MS = 30 * 24 * 60 * 60 * 1000;
|
||||
const CYCLE_INTERVAL_MS = 8000;
|
||||
const CSS_VAR = '--promo-banner-height';
|
||||
|
||||
const FEATURES = ['proFeatureCalendar', 'proFeatureRecurringCards', 'proFeatureGuestRoles'];
|
||||
|
||||
// Alternates: main, sub1, main, sub2, main, sub3
|
||||
const TEXTS = [
|
||||
'discoverPlankaPro',
|
||||
FEATURES[0],
|
||||
'discoverPlankaPro',
|
||||
FEATURES[1],
|
||||
'discoverPlankaPro',
|
||||
FEATURES[2],
|
||||
];
|
||||
|
||||
function getDismissKey(userId) {
|
||||
return `planka_proBannerDismissed_${userId}`;
|
||||
}
|
||||
|
||||
function isBannerDismissed(userId) {
|
||||
const stored = localStorage.getItem(getDismissKey(userId));
|
||||
if (!stored) return false;
|
||||
return Date.now() - Date.parse(stored) < DISMISS_DURATION_MS;
|
||||
}
|
||||
|
||||
const PromoBanner = React.memo(() => {
|
||||
const userId = useSelector(selectors.selectCurrentUserId);
|
||||
|
||||
const [dismissed, setDismissed] = useState(() => isBannerDismissed(userId));
|
||||
const [textIndex, setTextIndex] = useState(0);
|
||||
const [visible, setVisible] = useState(true);
|
||||
|
||||
const wrapperRef = useRef(null);
|
||||
const [t] = useTranslation();
|
||||
|
||||
useEffect(() => {
|
||||
if (dismissed) {
|
||||
document.documentElement.style.removeProperty(CSS_VAR);
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const height = wrapperRef.current ? wrapperRef.current.offsetHeight : 0;
|
||||
document.documentElement.style.setProperty(CSS_VAR, `${height}px`);
|
||||
|
||||
return () => document.documentElement.style.removeProperty(CSS_VAR);
|
||||
}, [dismissed]);
|
||||
|
||||
useEffect(() => {
|
||||
if (dismissed) return undefined;
|
||||
|
||||
const interval = setInterval(() => {
|
||||
setVisible(false);
|
||||
setTimeout(() => {
|
||||
setTextIndex((i) => (i + 1) % TEXTS.length);
|
||||
setVisible(true);
|
||||
}, 400);
|
||||
}, CYCLE_INTERVAL_MS);
|
||||
|
||||
return () => clearInterval(interval);
|
||||
}, [dismissed]);
|
||||
|
||||
const handleDismiss = useCallback(
|
||||
(e) => {
|
||||
e.preventDefault();
|
||||
localStorage.setItem(getDismissKey(userId), new Date().toISOString());
|
||||
setDismissed(true);
|
||||
},
|
||||
[userId],
|
||||
);
|
||||
|
||||
if (dismissed) return null;
|
||||
|
||||
return (
|
||||
<div ref={wrapperRef} className={styles.wrapper}>
|
||||
<a
|
||||
href={PRO_URL}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={`${styles.textLink} ${visible ? styles.textVisible : styles.textHidden}`}
|
||||
>
|
||||
{t(`common.${TEXTS[textIndex]}`)}
|
||||
<span className={styles.externalIcon}>↗</span>
|
||||
</a>
|
||||
<button
|
||||
type="button"
|
||||
title={t('common.dismissProBannerFor30Days')}
|
||||
className={styles.closeButton}
|
||||
onClick={handleDismiss}
|
||||
>
|
||||
×
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
export default PromoBanner;
|
||||
@@ -0,0 +1,60 @@
|
||||
/*!
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
:global(#app) {
|
||||
.wrapper {
|
||||
align-items: center;
|
||||
background: rgba(0, 0, 0, 0.18);
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
justify-content: center;
|
||||
padding: 5px 16px;
|
||||
}
|
||||
|
||||
.textLink {
|
||||
color: #fff;
|
||||
cursor: pointer;
|
||||
flex: 1 1 auto;
|
||||
font-size: 13px;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
|
||||
&:hover {
|
||||
color: #bdff22;
|
||||
}
|
||||
}
|
||||
|
||||
.externalIcon {
|
||||
font-size: 11px;
|
||||
margin-left: 4px;
|
||||
opacity: 0.7;
|
||||
vertical-align: super;
|
||||
}
|
||||
|
||||
.textVisible {
|
||||
opacity: 1;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.textHidden {
|
||||
opacity: 0;
|
||||
transition: opacity 0.4s ease;
|
||||
}
|
||||
|
||||
.closeButton {
|
||||
background: transparent;
|
||||
border: none;
|
||||
color: rgba(255, 255, 255, 0.45);
|
||||
cursor: pointer;
|
||||
flex: 0 0 auto;
|
||||
font-size: 18px;
|
||||
line-height: 1;
|
||||
padding: 0 2px;
|
||||
}
|
||||
|
||||
.closeButton:hover {
|
||||
color: rgba(255, 255, 255, 0.9);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
@@ -37,15 +37,15 @@
|
||||
|
||||
.wrapper {
|
||||
height: 100%;
|
||||
margin-top: 116px;
|
||||
margin-top: calc(116px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
|
||||
.wrapperBoard {
|
||||
margin-top: 174px;
|
||||
margin-top: calc(174px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
|
||||
.wrapperBoardWithFavorites {
|
||||
margin-top: 264px;
|
||||
margin-top: calc(264px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
|
||||
.wrapperFlex {
|
||||
@@ -57,11 +57,11 @@
|
||||
}
|
||||
|
||||
.wrapperProject {
|
||||
margin-top: 98px;
|
||||
margin-top: calc(98px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
|
||||
.wrapperProjectWithFavorites {
|
||||
margin-top: 188px;
|
||||
margin-top: calc(188px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
|
||||
.wrapperTransitioning {
|
||||
@@ -73,6 +73,6 @@
|
||||
}
|
||||
|
||||
.wrapperWithFavorites {
|
||||
margin-top: 206px;
|
||||
margin-top: calc(206px + var(--promo-banner-height, 0px));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,11 @@ const AddImageZone = React.memo(({ children, onCreate }) => {
|
||||
return (
|
||||
/* eslint-disable-next-line react/jsx-props-no-spreading */
|
||||
<div {...getRootProps()}>
|
||||
{isDragActive && <div className={styles.dropzone}>{t('common.dropFileToUpload')}</div>}
|
||||
{isDragActive && (
|
||||
<div className={styles.dropzone}>
|
||||
<div className={styles.dropzoneText}>{t('common.dropFileToUpload')}</div>
|
||||
</div>
|
||||
)}
|
||||
{children}
|
||||
{/* eslint-disable-next-line react/jsx-props-no-spreading */}
|
||||
<input {...getInputProps()} />
|
||||
|
||||
@@ -8,13 +8,18 @@
|
||||
background: white;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
height: 100%;
|
||||
inset: 0;
|
||||
line-height: 30px;
|
||||
opacity: 0.7;
|
||||
padding-top: 200px;
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
z-index: 2001;
|
||||
}
|
||||
|
||||
.dropzoneText {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: min(200px, 50%);
|
||||
transform: translateX(-50%) translateY(-50%);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,20 +3,22 @@
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import React, { useCallback, useEffect, useRef } from 'react';
|
||||
import React, { useCallback, useEffect, useMemo, useRef } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button } from 'semantic-ui-react';
|
||||
import { FilePicker, Popup } from '../../../../lib/custom-ui';
|
||||
import { FilePicker, Popup } from '../../../lib/custom-ui';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import entryActions from '../../../../entry-actions';
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
|
||||
import styles from './EditAvatarStep.module.scss';
|
||||
import styles from './EditUserAvatarStep.module.scss';
|
||||
|
||||
const EditAvatarStep = React.memo(({ onClose }) => {
|
||||
const defaultValue = useSelector((state) => selectors.selectCurrentUser(state).avatar);
|
||||
const EditUserAvatarStep = React.memo(({ id, onBack, onClose }) => {
|
||||
const selectUserById = useMemo(() => selectors.makeSelectUserById(), []);
|
||||
|
||||
const avatar = useSelector((state) => selectUserById(state, id).avatar);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const [t] = useTranslation();
|
||||
@@ -26,33 +28,33 @@ const EditAvatarStep = React.memo(({ onClose }) => {
|
||||
const handleFileSelect = useCallback(
|
||||
(file) => {
|
||||
dispatch(
|
||||
entryActions.updateCurrentUserAvatar({
|
||||
entryActions.updateUserAvatar(id, {
|
||||
file,
|
||||
}),
|
||||
);
|
||||
|
||||
onClose();
|
||||
},
|
||||
[onClose, dispatch],
|
||||
[dispatch, id, onClose],
|
||||
);
|
||||
|
||||
const handleDeleteClick = useCallback(() => {
|
||||
dispatch(
|
||||
entryActions.updateCurrentUser({
|
||||
entryActions.updateUser(id, {
|
||||
avatar: null,
|
||||
}),
|
||||
);
|
||||
|
||||
onClose();
|
||||
}, [onClose, dispatch]);
|
||||
}, [dispatch, id, onClose]);
|
||||
|
||||
useEffect(() => {
|
||||
fieldRef.current.focus();
|
||||
fieldRef.current?.focus?.();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Popup.Header>
|
||||
<Popup.Header onBack={onBack}>
|
||||
{t('common.editAvatar', {
|
||||
context: 'title',
|
||||
})}
|
||||
@@ -67,7 +69,7 @@ const EditAvatarStep = React.memo(({ onClose }) => {
|
||||
/>
|
||||
</FilePicker>
|
||||
</div>
|
||||
{defaultValue && (
|
||||
{avatar && (
|
||||
<Button negative content={t('action.deleteAvatar')} onClick={handleDeleteClick} />
|
||||
)}
|
||||
</Popup.Content>
|
||||
@@ -75,8 +77,14 @@ const EditAvatarStep = React.memo(({ onClose }) => {
|
||||
);
|
||||
});
|
||||
|
||||
EditAvatarStep.propTypes = {
|
||||
EditUserAvatarStep.propTypes = {
|
||||
id: PropTypes.string.isRequired,
|
||||
onBack: PropTypes.func,
|
||||
onClose: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
export default EditAvatarStep;
|
||||
EditUserAvatarStep.defaultProps = {
|
||||
onBack: undefined,
|
||||
};
|
||||
|
||||
export default EditUserAvatarStep;
|
||||
@@ -3,6 +3,6 @@
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
import AccountPane from './AccountPane';
|
||||
import EditUserAvatarStep from './EditUserAvatarStep';
|
||||
|
||||
export default AccountPane;
|
||||
export default EditUserAvatarStep;
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
@@ -104,6 +104,17 @@ const UserActionsStep = React.memo(({ onClose }) => {
|
||||
context: 'title',
|
||||
})}
|
||||
</Menu.Item>
|
||||
<Menu.Item
|
||||
href="https://planka.app/pro?ref=app-menu"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={styles.proMenuItem}
|
||||
>
|
||||
<Icon name="gem" className={styles.proMenuItemIcon} />
|
||||
{withAdministration
|
||||
? t('common.upgradeTeamToPro', { context: 'title' })
|
||||
: t('common.discoverPlankaPro', { context: 'title' })}
|
||||
</Menu.Item>
|
||||
<hr className={styles.divider} />
|
||||
<Menu.Item
|
||||
{...logoutMenuItemProps} // eslint-disable-line react/jsx-props-no-spreading
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Copyright (c) 2026 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
@@ -25,4 +25,14 @@
|
||||
float: left;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
.proMenuItem {
|
||||
margin: 0;
|
||||
padding-left: 14px;
|
||||
}
|
||||
|
||||
.proMenuItemIcon {
|
||||
float: left;
|
||||
margin: 0 0.5em 0 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
import upperFirst from 'lodash/upperFirst';
|
||||
import camelCase from 'lodash/camelCase';
|
||||
import initials from 'initials';
|
||||
import React, { useMemo } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import classNames from 'classnames';
|
||||
@@ -35,6 +34,19 @@ const COLORS = [
|
||||
'midnight-blue',
|
||||
];
|
||||
|
||||
const getInitials = (name) => {
|
||||
const words = name
|
||||
.trim()
|
||||
.split(/[\s-]+/)
|
||||
.filter(Boolean);
|
||||
if (words.length === 0) return '';
|
||||
if (words.length === 1) return [...words[0]].slice(0, 2).join('');
|
||||
return words
|
||||
.slice(0, 2)
|
||||
.map((word) => [...word][0])
|
||||
.join('');
|
||||
};
|
||||
|
||||
const getColor = (name) => {
|
||||
let sum = 0;
|
||||
for (let i = 0; i < name.length; i += 1) {
|
||||
@@ -78,7 +90,7 @@ const UserAvatar = React.memo(
|
||||
background: avatarUrl && `url("${avatarUrl}") center / cover`,
|
||||
}}
|
||||
>
|
||||
{!avatarUrl && <span className={styles.initials}>{initials(user.name).slice(0, 2)}</span>}
|
||||
{!avatarUrl && <span className={styles.initials}>{getInitials(user.name)}</span>}
|
||||
{withCreatorIndicator && <span className={styles.creatorIndicator}>+</span>}
|
||||
</span>
|
||||
);
|
||||
|
||||
@@ -8,16 +8,16 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Button, Divider, Dropdown, Header, Tab } from 'semantic-ui-react';
|
||||
|
||||
import selectors from '../../../../selectors';
|
||||
import entryActions from '../../../../entry-actions';
|
||||
import { usePopupInClosableContext } from '../../../../hooks';
|
||||
import locales from '../../../../locales';
|
||||
import EditAvatarStep from './EditAvatarStep';
|
||||
import EditUserInformation from '../../EditUserInformation';
|
||||
import EditUserUsernameStep from '../../EditUserUsernameStep';
|
||||
import EditUserEmailStep from '../../EditUserEmailStep';
|
||||
import EditUserPasswordStep from '../../EditUserPasswordStep';
|
||||
import UserAvatar from '../../UserAvatar';
|
||||
import selectors from '../../../selectors';
|
||||
import entryActions from '../../../entry-actions';
|
||||
import { usePopupInClosableContext } from '../../../hooks';
|
||||
import locales from '../../../locales';
|
||||
import EditUserInformation from '../EditUserInformation';
|
||||
import EditUserAvatarStep from '../EditUserAvatarStep';
|
||||
import EditUserUsernameStep from '../EditUserUsernameStep';
|
||||
import EditUserEmailStep from '../EditUserEmailStep';
|
||||
import EditUserPasswordStep from '../EditUserPasswordStep';
|
||||
import UserAvatar from '../UserAvatar';
|
||||
|
||||
import styles from './AccountPane.module.scss';
|
||||
|
||||
@@ -34,7 +34,7 @@ const AccountPane = React.memo(() => {
|
||||
[dispatch],
|
||||
);
|
||||
|
||||
const EditAvatarPopup = usePopupInClosableContext(EditAvatarStep);
|
||||
const EditUserAvatarPopup = usePopupInClosableContext(EditUserAvatarStep);
|
||||
const EditUserUsernamePopup = usePopupInClosableContext(EditUserUsernameStep);
|
||||
const EditUserEmailPopup = usePopupInClosableContext(EditUserEmailStep);
|
||||
const EditUserPasswordPopup = usePopupInClosableContext(EditUserPasswordStep);
|
||||
@@ -45,9 +45,9 @@ const AccountPane = React.memo(() => {
|
||||
|
||||
return (
|
||||
<Tab.Pane attached={false} className={styles.wrapper}>
|
||||
<EditAvatarPopup>
|
||||
<EditUserAvatarPopup id={user.id}>
|
||||
<UserAvatar id={user.id} size="massive" isDisabled={user.isAvatarUpdating} />
|
||||
</EditAvatarPopup>
|
||||
</EditUserAvatarPopup>
|
||||
<br />
|
||||
<br />
|
||||
<EditUserInformation id={user.id} />
|
||||
@@ -4,6 +4,7 @@
|
||||
*/
|
||||
|
||||
import history from '../../history';
|
||||
import Config from '../../constants/Config';
|
||||
|
||||
const SAME_SITE_CLASS = 'same-site';
|
||||
|
||||
@@ -30,7 +31,9 @@ function process(token, nextToken) {
|
||||
return;
|
||||
}
|
||||
|
||||
const isSameSite = url.origin === window.location.origin;
|
||||
const isSameSite =
|
||||
url.origin === window.location.origin && url.pathname.startsWith(Config.BASE_PATH);
|
||||
|
||||
const trimOrigin = isSameSite && nextToken.type === 'text' && nextToken.content === href;
|
||||
|
||||
if (isSameSite) {
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
const SERVER_BASE_URL =
|
||||
import.meta.env.VITE_SERVER_BASE_URL || (import.meta.env.DEV ? 'http://localhost:1337' : '');
|
||||
const BASE_PATH = window.BASE_PATH || '';
|
||||
|
||||
const ACCESS_TOKEN_KEY = 'accessToken';
|
||||
const ACCESS_TOKEN_VERSION_KEY = 'accessTokenVersion';
|
||||
@@ -20,7 +19,7 @@ const MAX_SIZE_TO_DISPLAY_CONTENT = 256 * 1024;
|
||||
const IS_MAC = navigator.platform.startsWith('Mac');
|
||||
|
||||
export default {
|
||||
SERVER_BASE_URL,
|
||||
BASE_PATH,
|
||||
ACCESS_TOKEN_KEY,
|
||||
ACCESS_TOKEN_VERSION_KEY,
|
||||
ACCESS_TOKEN_VERSION,
|
||||
|
||||
@@ -75,6 +75,7 @@ export default {
|
||||
CURRENT_USER_USERNAME_UPDATE: `${PREFIX}/CURRENT_USER_USERNAME_UPDATE`,
|
||||
USER_USERNAME_UPDATE_ERROR_CLEAR: `${PREFIX}/USER_USERNAME_UPDATE_ERROR_CLEAR`,
|
||||
CURRENT_USER_USERNAME_UPDATE_ERROR_CLEAR: `${PREFIX}/CURRENT_USER_USERNAME_UPDATE_ERROR_CLEAR`,
|
||||
USER_AVATAR_UPDATE: `${PREFIX}/USER_AVATAR_UPDATE`,
|
||||
CURRENT_USER_AVATAR_UPDATE: `${PREFIX}/CURRENT_USER_AVATAR_UPDATE`,
|
||||
USER_API_KEY_CREATE: `${PREFIX}/USER_API_KEY_CREATE`,
|
||||
USER_API_KEY_DELETE: `${PREFIX}/USER_API_KEY_DELETE`,
|
||||
|
||||
@@ -3,12 +3,14 @@
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
const ROOT = '/';
|
||||
const LOGIN = '/login';
|
||||
const OIDC_CALLBACK = '/oidc-callback';
|
||||
const PROJECTS = '/projects/:id';
|
||||
const BOARDS = '/boards/:id';
|
||||
const CARDS = '/cards/:id';
|
||||
import Config from './Config';
|
||||
|
||||
const ROOT = `${Config.BASE_PATH}/`;
|
||||
const LOGIN = `${Config.BASE_PATH}/login`;
|
||||
const OIDC_CALLBACK = `${Config.BASE_PATH}/oidc-callback`;
|
||||
const PROJECTS = `${Config.BASE_PATH}/projects/:id`;
|
||||
const BOARDS = `${Config.BASE_PATH}/boards/:id`;
|
||||
const CARDS = `${Config.BASE_PATH}/cards/:id`;
|
||||
|
||||
export default {
|
||||
ROOT,
|
||||
|
||||
@@ -139,6 +139,14 @@ const clearCurrentUserUsernameUpdateError = () => ({
|
||||
payload: {},
|
||||
});
|
||||
|
||||
const updateUserAvatar = (id, data) => ({
|
||||
type: EntryActionTypes.USER_AVATAR_UPDATE,
|
||||
payload: {
|
||||
id,
|
||||
data,
|
||||
},
|
||||
});
|
||||
|
||||
const updateCurrentUserAvatar = (data) => ({
|
||||
type: EntryActionTypes.CURRENT_USER_AVATAR_UPDATE,
|
||||
payload: {
|
||||
@@ -271,6 +279,7 @@ export default {
|
||||
updateCurrentUserUsername,
|
||||
clearUserUsernameUpdateError,
|
||||
clearCurrentUserUsernameUpdateError,
|
||||
updateUserAvatar,
|
||||
updateCurrentUserAvatar,
|
||||
createUserApiKey,
|
||||
deleteUserApiKey,
|
||||
|
||||
@@ -138,6 +138,13 @@ export default {
|
||||
customFieldGroups_title: 'مجموعات الحقول المخصصة',
|
||||
customField_title: 'الحقل المخصص',
|
||||
customFields_title: 'الحقول المخصصة',
|
||||
discoverPlankaPro: '✨ المزيد من الميزات لألواحك: اكتشف PLANKA Pro',
|
||||
discoverPlankaPro_title: 'اكتشف PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'ترقية الفريق إلى Pro',
|
||||
proFeatureCalendar: '✨ عرض التقويم للوحاتك',
|
||||
proFeatureRecurringCards: '✨ البطاقات المتكررة والأتمتة',
|
||||
proFeatureGuestRoles: '✨ أدوار الضيف والتعاون الخارجي',
|
||||
dismissProBannerFor30Days: 'إغلاق لمدة 30 يومًا',
|
||||
customerPanel_title: 'لوحة العملاء',
|
||||
dangerZone_title: 'منطقة الخطر',
|
||||
date: 'تاريخ',
|
||||
@@ -166,6 +173,7 @@ export default {
|
||||
deletedUser_title: 'مستخدم محذوف',
|
||||
description: 'الوصف',
|
||||
display: 'عرض',
|
||||
displayCardAges: 'عرض أعمار البطاقات',
|
||||
dropFileToUpload: 'أفلت الملف لرفعه',
|
||||
dueDate_title: 'تاريخ الاستحقاق',
|
||||
dynamicAndUnevenlySpacedLayout: 'تخطيط ديناميكي وغير متساوي المسافات.',
|
||||
@@ -435,6 +443,7 @@ export default {
|
||||
download: 'تحميل',
|
||||
duplicateCard_title: 'تكرار البطاقة',
|
||||
edit: 'تعديل',
|
||||
editAvatar_title: 'تعديل الصورة الرمزية',
|
||||
editColor_title: 'تعديل اللون',
|
||||
editDescription_title: 'تعديل الوصف',
|
||||
editDueDate_title: 'تعديل تاريخ الاستحقاق',
|
||||
|
||||
@@ -149,6 +149,13 @@ export default {
|
||||
customFieldGroups_title: 'Групи персонализирани полета',
|
||||
customField_title: 'Персонализирано поле',
|
||||
customFields_title: 'Персонализирани полета',
|
||||
discoverPlankaPro: '✨ Повече функции за вашите дъски: Открийте PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Открийте PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Надградете екипа до Pro',
|
||||
proFeatureCalendar: '✨ Изглед Календар за вашите дъски',
|
||||
proFeatureRecurringCards: '✨ Повтарящи се карти и автоматизация',
|
||||
proFeatureGuestRoles: '✨ Роли за гости и външно сътрудничество',
|
||||
dismissProBannerFor30Days: 'Скрий за 30 дни',
|
||||
customerPanel_title: 'Панел на клиента',
|
||||
dangerZone_title: 'Опасна зона',
|
||||
date: 'Дата',
|
||||
@@ -178,6 +185,7 @@ export default {
|
||||
deletedUser_title: 'Изтрит потребител',
|
||||
description: 'Описание',
|
||||
display: 'Показване',
|
||||
displayCardAges: 'Показвай възрастта на картите',
|
||||
dropFileToUpload: 'Пуснете файл за качване',
|
||||
dueDate_title: 'Краен срок',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамично и неравномерно разположение.',
|
||||
@@ -450,6 +458,7 @@ export default {
|
||||
download: 'Изтегляне',
|
||||
duplicateCard_title: 'Дублирана карта',
|
||||
edit: 'Редактиране',
|
||||
editAvatar_title: 'Редактиране на аватар',
|
||||
editColor_title: 'Редактиране на цвят',
|
||||
editDescription_title: 'Редактиране на описание',
|
||||
editDueDate_title: 'Редактиране на краен срок',
|
||||
|
||||
@@ -148,6 +148,13 @@ export default {
|
||||
customFieldGroups_title: 'Grups de camps personalitzats',
|
||||
customField_title: 'Camp personalitzat',
|
||||
customFields_title: 'Camps personalitzats',
|
||||
discoverPlankaPro: '✨ Més funcions per als vostres taulers: Descobriu PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Descobriu PLANKA Pro',
|
||||
upgradeTeamToPro_title: "Actualitzeu l'equip a Pro",
|
||||
proFeatureCalendar: '✨ Vista de calendari per als vostres taulers',
|
||||
proFeatureRecurringCards: '✨ Targetes recurrents i automatització',
|
||||
proFeatureGuestRoles: '✨ Rols de convidat i col·laboració externa',
|
||||
dismissProBannerFor30Days: 'Tanca durant 30 dies',
|
||||
customerPanel_title: 'Panell del client',
|
||||
dangerZone_title: 'Zona de perill',
|
||||
date: 'Data',
|
||||
@@ -177,6 +184,7 @@ export default {
|
||||
deletedUser_title: 'Usuari eliminat',
|
||||
description: 'Descripció',
|
||||
display: 'Mostrar',
|
||||
displayCardAges: "Mostrar l'antiguitat de les targetes",
|
||||
dropFileToUpload: 'Arrossega fitxer per pujar-lo',
|
||||
dueDate_title: 'Data de venciment',
|
||||
dynamicAndUnevenlySpacedLayout: 'Disseny dinàmic i amb espaiat irregular.',
|
||||
@@ -452,6 +460,7 @@ export default {
|
||||
download: 'Descarregar',
|
||||
duplicateCard_title: 'Duplicar targeta',
|
||||
edit: 'Editar',
|
||||
editAvatar_title: 'Editar avatar',
|
||||
editColor_title: 'Editar color',
|
||||
editDescription_title: 'Editar descripció',
|
||||
editDueDate_title: 'Editar data de venciment',
|
||||
|
||||
@@ -140,6 +140,13 @@ export default {
|
||||
customFieldGroups_title: 'Skupina vlastních polí',
|
||||
customField_title: 'Vlastní pole',
|
||||
customFields_title: 'Vlastní pole',
|
||||
discoverPlankaPro: '✨ Více funkcí pro vaše tabule: Objevte PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Objevte PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Upgradovat tým na Pro',
|
||||
proFeatureCalendar: '✨ Zobrazení kalendáře pro vaše tabule',
|
||||
proFeatureRecurringCards: '✨ Opakující se karty a automatizace',
|
||||
proFeatureGuestRoles: '✨ Role hosta a externí spolupráce',
|
||||
dismissProBannerFor30Days: 'Zavřít na 30 dní',
|
||||
customerPanel_title: 'Panel zákazníka',
|
||||
dangerZone_title: 'Nebezpečná zóna',
|
||||
date: 'Datum',
|
||||
@@ -169,6 +176,7 @@ export default {
|
||||
deletedUser_title: 'Smazaný uživatel',
|
||||
description: 'Popis',
|
||||
display: 'Zobrazit',
|
||||
displayCardAges: 'Zobrazit stáří karet',
|
||||
dropFileToUpload: 'Přetažením nahrát soubor',
|
||||
dueDate_title: 'Termín',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamické a nerovnoměrné rozložení.',
|
||||
@@ -440,6 +448,7 @@ export default {
|
||||
download: 'Stáhnout',
|
||||
duplicateCard_title: 'Duplikovat kartu',
|
||||
edit: 'Upravit',
|
||||
editAvatar_title: 'Upravit avatar',
|
||||
editColor_title: 'Upravit barvu',
|
||||
editDescription_title: 'Upravit popis',
|
||||
editDueDate_title: 'Upravit termín',
|
||||
|
||||
@@ -144,6 +144,13 @@ export default {
|
||||
customFieldGroups_title: 'Brugerdefinerede feltgrupper',
|
||||
customField_title: 'Brugerdefineret felt',
|
||||
customFields_title: 'Brugerdefinerede felter',
|
||||
discoverPlankaPro: '✨ Flere funktioner til dine boards: Opdag PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Opdag PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Opgrader team til Pro',
|
||||
proFeatureCalendar: '✨ Kalendervisning til dine boards',
|
||||
proFeatureRecurringCards: '✨ Tilbagevendende kort og automatisering',
|
||||
proFeatureGuestRoles: '✨ Gæsteroller og eksternt samarbejde',
|
||||
dismissProBannerFor30Days: 'Luk i 30 dage',
|
||||
customerPanel_title: 'Kundepanel',
|
||||
dangerZone_title: 'Farezone',
|
||||
date: 'Dato',
|
||||
@@ -173,6 +180,7 @@ export default {
|
||||
deletedUser_title: 'Slettet bruger',
|
||||
description: 'Beskrivelse',
|
||||
display: 'Vis',
|
||||
displayCardAges: 'Vis kortalder',
|
||||
dropFileToUpload: 'Slip fil for at uploade',
|
||||
dueDate_title: 'Frist',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamisk og ujævnt fordelt layout.',
|
||||
@@ -446,6 +454,7 @@ export default {
|
||||
download: 'Download',
|
||||
duplicateCard_title: 'Duplikér kort',
|
||||
edit: 'Rediger',
|
||||
editAvatar_title: 'Rediger profilbillede',
|
||||
editColor_title: 'Rediger farve',
|
||||
editDescription_title: 'Rediger beskrivelse',
|
||||
editDueDate_title: 'Rediger frist',
|
||||
|
||||
@@ -161,6 +161,13 @@ export default {
|
||||
customFields_title: 'Feldgruppen',
|
||||
customerPanel_title: 'Kundenpanel',
|
||||
dangerZone_title: 'Gefahrenbereich',
|
||||
discoverPlankaPro: '✨ Mehr Features für eure Boards: PLANKA Pro entdecken',
|
||||
discoverPlankaPro_title: 'PLANKA Pro entdecken',
|
||||
dismissProBannerFor30Days: 'Für 30 Tage schließen',
|
||||
upgradeTeamToPro_title: 'Team auf Pro upgraden',
|
||||
proFeatureCalendar: '✨ Kalenderansicht für eure Boards',
|
||||
proFeatureRecurringCards: '✨ Wiederkehrende Karten',
|
||||
proFeatureGuestRoles: '✨ Gastrollen & externe Zusammenarbeit',
|
||||
date: 'Datum',
|
||||
deactivateUser_title: 'Benutzer deaktivieren',
|
||||
defaultCardType_title: 'Standard-Kartentyp',
|
||||
@@ -188,6 +195,7 @@ export default {
|
||||
deletedUser_title: 'Gelöschter Benutzer',
|
||||
description: 'Beschreibung',
|
||||
display: 'Anzeige',
|
||||
displayCardAges: 'Kartenalter anzeigen',
|
||||
dropFileToUpload: 'Datei für Upload ablegen',
|
||||
dueDate_title: 'Fälligkeitsdatum',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamisches und ungleichmäßig verteiltes Layout.',
|
||||
@@ -462,6 +470,7 @@ export default {
|
||||
download: 'Herunterladen',
|
||||
duplicateCard_title: 'Karte duplizieren',
|
||||
edit: 'Bearbeiten',
|
||||
editAvatar_title: 'Profilbild bearbeiten',
|
||||
editColor_title: 'Farbe bearbeiten',
|
||||
editDescription_title: 'Beschreibung ändern',
|
||||
editDueDate_title: 'Fälligkeitsdatum bearbeiten',
|
||||
|
||||
@@ -157,6 +157,14 @@ export default {
|
||||
customFieldGroups_title: 'Ομάδες προσαρμοσμένων πεδίων',
|
||||
customField_title: 'Προσαρμοσμένο πεδίο',
|
||||
customFields_title: 'Προσαρμοσμένα πεδία',
|
||||
discoverPlankaPro:
|
||||
'✨ Περισσότερες λειτουργίες για τους πίνακές σας: Ανακαλύψτε το PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Ανακαλύψτε το PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Αναβαθμίστε την ομάδα σε Pro',
|
||||
proFeatureCalendar: '✨ Προβολή ημερολογίου για τους πίνακές σας',
|
||||
proFeatureRecurringCards: '✨ Επαναλαμβανόμενες κάρτες και αυτοματισμός',
|
||||
proFeatureGuestRoles: '✨ Ρόλοι επισκεπτών και εξωτερική συνεργασία',
|
||||
dismissProBannerFor30Days: 'Κλείσιμο για 30 ημέρες',
|
||||
customerPanel_title: 'Πίνακας πελάτη',
|
||||
dangerZone_title: 'Επικίνδυνη ζώνη',
|
||||
date: 'Ημερομηνία',
|
||||
@@ -186,6 +194,7 @@ export default {
|
||||
deletedUser_title: 'Διαγραμμένος χρήστης',
|
||||
description: 'Περιγραφή',
|
||||
display: 'Εμφάνιση',
|
||||
displayCardAges: 'Εμφάνιση ηλικίας καρτών',
|
||||
dropFileToUpload: 'Σύρετε το αρχείο για μεταφόρτωση',
|
||||
dueDate_title: 'Ημερομηνία λήξης',
|
||||
dynamicAndUnevenlySpacedLayout: 'Δυναμική και άνισα κατανεμημένη διάταξη.',
|
||||
@@ -466,6 +475,7 @@ export default {
|
||||
download: 'Λήψη',
|
||||
duplicateCard_title: 'Διπλασιασμός κάρτας',
|
||||
edit: 'Επεξεργασία',
|
||||
editAvatar_title: 'Επεξεργασία avatar',
|
||||
editColor_title: 'Επεξεργασία χρώματος',
|
||||
editDescription_title: 'Επεξεργασία περιγραφής',
|
||||
editDueDate_title: 'Επεξεργασία ημερομηνίας λήξης',
|
||||
|
||||
@@ -143,6 +143,13 @@ export default {
|
||||
customFieldGroups_title: 'Custom Field Groups',
|
||||
customField_title: 'Custom Field',
|
||||
customFields_title: 'Custom Fields',
|
||||
discoverPlankaPro: '✨ More features for your boards: Discover PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Discover PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Upgrade Team to Pro',
|
||||
proFeatureCalendar: '✨ Calendar View for your boards',
|
||||
proFeatureRecurringCards: '✨ Recurring Cards & Automation',
|
||||
proFeatureGuestRoles: '✨ Guest Roles & External Collaboration',
|
||||
dismissProBannerFor30Days: 'Dismiss for 30 days',
|
||||
customerPanel_title: 'Customer Panel',
|
||||
dangerZone_title: 'Danger Zone',
|
||||
date: 'Date',
|
||||
@@ -172,6 +179,7 @@ export default {
|
||||
deletedUser_title: 'Deleted User',
|
||||
description: 'Description',
|
||||
display: 'Display',
|
||||
displayCardAges: 'Display card ages',
|
||||
dropFileToUpload: 'Drop file to upload',
|
||||
dueDate_title: 'Due Date',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamic and unevenly spaced layout.',
|
||||
@@ -442,6 +450,7 @@ export default {
|
||||
download: 'Download',
|
||||
duplicateCard_title: 'Duplicate Card',
|
||||
edit: 'Edit',
|
||||
editAvatar_title: 'Edit Avatar',
|
||||
editColor_title: 'Edit Color',
|
||||
editDescription_title: 'Edit Description',
|
||||
editDueDate_title: 'Edit Due Date',
|
||||
|
||||
@@ -140,6 +140,13 @@ export default {
|
||||
customFields_title: 'Custom Fields',
|
||||
customerPanel_title: 'Customer Panel',
|
||||
dangerZone_title: 'Danger Zone',
|
||||
discoverPlankaPro: '✨ More features for your boards: Discover PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Discover PLANKA Pro',
|
||||
dismissProBannerFor30Days: 'Dismiss for 30 days',
|
||||
upgradeTeamToPro_title: 'Upgrade Team to Pro',
|
||||
proFeatureCalendar: '✨ Calendar View for your boards',
|
||||
proFeatureRecurringCards: '✨ Recurring Cards',
|
||||
proFeatureGuestRoles: '✨ Guest Roles & External Collaboration',
|
||||
date: 'Date',
|
||||
deactivateUser_title: 'Deactivate User',
|
||||
defaultCardType_title: 'Default Card Type',
|
||||
@@ -167,6 +174,7 @@ export default {
|
||||
deletedUser_title: 'Deleted User',
|
||||
description: 'Description',
|
||||
display: 'Display',
|
||||
displayCardAges: 'Display card ages',
|
||||
dropFileToUpload: 'Drop file to upload',
|
||||
dueDate_title: 'Due Date',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamic and unevenly spaced layout.',
|
||||
@@ -437,6 +445,7 @@ export default {
|
||||
download: 'Download',
|
||||
duplicateCard_title: 'Duplicate Card',
|
||||
edit: 'Edit',
|
||||
editAvatar_title: 'Edit Avatar',
|
||||
editColor_title: 'Edit Color',
|
||||
editDescription_title: 'Edit Description',
|
||||
editDueDate_title: 'Edit Due Date',
|
||||
|
||||
@@ -149,6 +149,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupos de campos personalizados',
|
||||
customField_title: 'Campo personalizado',
|
||||
customFields_title: 'Campos personalizados',
|
||||
discoverPlankaPro: '✨ Más funciones para tus tableros: Descubre PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Descubre PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Actualizar equipo a Pro',
|
||||
proFeatureCalendar: '✨ Vista de calendario para tus tableros',
|
||||
proFeatureRecurringCards: '✨ Tarjetas recurrentes y automatización',
|
||||
proFeatureGuestRoles: '✨ Roles de invitado y colaboración externa',
|
||||
dismissProBannerFor30Days: 'Cerrar durante 30 días',
|
||||
customerPanel_title: 'Panel del cliente',
|
||||
dangerZone_title: 'Zona de peligro',
|
||||
date: 'Fecha',
|
||||
@@ -178,6 +185,7 @@ export default {
|
||||
deletedUser_title: 'Usuario eliminado',
|
||||
description: 'Descripción',
|
||||
display: 'Mostrar',
|
||||
displayCardAges: 'Mostrar antigüedad de las tarjetas',
|
||||
dropFileToUpload: 'Arrastra archivo para subir',
|
||||
dueDate_title: 'Fecha de vencimiento',
|
||||
dynamicAndUnevenlySpacedLayout: 'Diseño dinámico y con espaciado irregular.',
|
||||
@@ -452,6 +460,7 @@ export default {
|
||||
download: 'Descargar',
|
||||
duplicateCard_title: 'Duplicar tarjeta',
|
||||
edit: 'Editar',
|
||||
editAvatar_title: 'Editar avatar',
|
||||
editColor_title: 'Editar color',
|
||||
editDescription_title: 'Editar descripción',
|
||||
editDueDate_title: 'Editar fecha de vencimiento',
|
||||
|
||||
@@ -144,6 +144,13 @@ export default {
|
||||
customFieldGroups_title: 'Kohandatud väljade grupid',
|
||||
customField_title: 'Kohandatud väli',
|
||||
customFields_title: 'Kohandatud väljad',
|
||||
discoverPlankaPro: '✨ Rohkem funktsioone oma tahvlite jaoks: Avasta PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Avasta PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Uuenda meeskond Pro-ks',
|
||||
proFeatureCalendar: '✨ Kalendervaade oma tahvlite jaoks',
|
||||
proFeatureRecurringCards: '✨ Korduvad kaardid ja automatiseerimine',
|
||||
proFeatureGuestRoles: '✨ Külalisrollid ja väline koostöö',
|
||||
dismissProBannerFor30Days: 'Sulge 30 päevaks',
|
||||
customerPanel_title: 'Kliendi paneel',
|
||||
dangerZone_title: 'Ohtliku ala',
|
||||
date: 'Kuupäev',
|
||||
@@ -173,6 +180,7 @@ export default {
|
||||
deletedUser_title: 'Kustutatud kasutaja',
|
||||
description: 'Kirjeldus',
|
||||
display: 'Kuva',
|
||||
displayCardAges: 'Näita kaartide vanust',
|
||||
dropFileToUpload: 'Lase faili üleslaadida',
|
||||
dueDate_title: 'Tähtaeg',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dünaamiline ja eirastega kujundus.',
|
||||
@@ -444,6 +452,7 @@ export default {
|
||||
download: 'Laadi alla',
|
||||
duplicateCard_title: 'Duplikaardi loomine',
|
||||
edit: 'Muuda',
|
||||
editAvatar_title: 'Muuda avatar',
|
||||
editColor_title: 'Muuda värvi',
|
||||
editDescription_title: 'Muuda kirjeldust',
|
||||
editDueDate_title: 'Muuda tähtaega',
|
||||
|
||||
@@ -147,6 +147,13 @@ export default {
|
||||
customFieldGroups_title: 'گروههای فیلد سفارشی',
|
||||
customField_title: 'فیلد سفارشی',
|
||||
customFields_title: 'فیلدهای سفارشی',
|
||||
discoverPlankaPro: '✨ ویژگیهای بیشتر برای تابلوهای شما: PLANKA Pro را کشف کنید',
|
||||
discoverPlankaPro_title: 'PLANKA Pro را کشف کنید',
|
||||
upgradeTeamToPro_title: 'ارتقای تیم به Pro',
|
||||
proFeatureCalendar: '✨ نمای تقویم برای تابلوهای شما',
|
||||
proFeatureRecurringCards: '✨ کارتهای تکرارشونده و خودکارسازی',
|
||||
proFeatureGuestRoles: '✨ نقشهای مهمان و همکاری خارجی',
|
||||
dismissProBannerFor30Days: 'بستن برای ۳۰ روز',
|
||||
customerPanel_title: 'پنل مشتری',
|
||||
dangerZone_title: 'منطقه خطر',
|
||||
date: 'تاریخ',
|
||||
@@ -176,6 +183,7 @@ export default {
|
||||
deletedUser_title: 'کاربر حذف شده',
|
||||
description: 'توضیحات',
|
||||
display: 'نمایش',
|
||||
displayCardAges: 'نمایش سن کارتها',
|
||||
dropFileToUpload: 'فایل را برای آپلود بکشید',
|
||||
dueDate_title: 'تاریخ سررسید',
|
||||
dynamicAndUnevenlySpacedLayout: 'طرحبندی پویا و نامتقارن.',
|
||||
@@ -446,6 +454,7 @@ export default {
|
||||
download: 'دانلود',
|
||||
duplicateCard_title: 'تکرار کارت',
|
||||
edit: 'ویرایش',
|
||||
editAvatar_title: 'ویرایش آواتار',
|
||||
editColor_title: 'ویرایش رنگ',
|
||||
editDescription_title: 'ویرایش توضیحات',
|
||||
editDueDate_title: 'ویرایش تاریخ سررسید',
|
||||
|
||||
@@ -140,6 +140,13 @@ export default {
|
||||
customFieldGroups_title: 'Mukautettujen kenttien ryhmät',
|
||||
customField_title: 'Mukautettu kenttä',
|
||||
customFields_title: 'Mukautetut kentät',
|
||||
discoverPlankaPro: '✨ Lisää ominaisuuksia tauluillesi: Tutustu PLANKA Pro:hon',
|
||||
discoverPlankaPro_title: 'Tutustu PLANKA Pro:hon',
|
||||
upgradeTeamToPro_title: 'Päivitä tiimi Pro-versioon',
|
||||
proFeatureCalendar: '✨ Kalenterinäkymä tauluillesi',
|
||||
proFeatureRecurringCards: '✨ Toistuvat kortit ja automaatio',
|
||||
proFeatureGuestRoles: '✨ Vierasroolit ja ulkoinen yhteistyö',
|
||||
dismissProBannerFor30Days: 'Sulje 30 päiväksi',
|
||||
customerPanel_title: 'Asiakaspaneeli',
|
||||
dangerZone_title: 'Vaaravyöhyke',
|
||||
date: 'Päivämäärä',
|
||||
@@ -169,6 +176,7 @@ export default {
|
||||
deletedUser_title: 'Poistettu käyttäjä',
|
||||
description: 'Kuvaus',
|
||||
display: 'Näyttö',
|
||||
displayCardAges: 'Näytä korttien ikä',
|
||||
dropFileToUpload: 'Pudota tiedosto ladattavaksi',
|
||||
dueDate_title: 'Määräpäivä',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynaaminen ja epätasaisesti jaettu asettelu.',
|
||||
@@ -445,6 +453,7 @@ export default {
|
||||
download: 'Lataa',
|
||||
duplicateCard_title: 'Monista kortti',
|
||||
edit: 'Muokkaa',
|
||||
editAvatar_title: 'Muokkaa avatar',
|
||||
editColor_title: 'Muokkaa väriä',
|
||||
editDescription_title: 'Muokkaa kuvausta',
|
||||
editDueDate_title: 'Muokkaa määräpäivää',
|
||||
|
||||
@@ -148,6 +148,13 @@ export default {
|
||||
customFieldGroups_title: 'Groupes de champs personnalisés',
|
||||
customField_title: 'Champ personnalisé',
|
||||
customFields_title: 'Champs personnalisés',
|
||||
discoverPlankaPro: '✨ Plus de fonctionnalités pour vos tableaux : Découvrez PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Découvrez PLANKA Pro',
|
||||
upgradeTeamToPro_title: "Passer l'équipe à Pro",
|
||||
proFeatureCalendar: '✨ Vue calendrier pour vos tableaux',
|
||||
proFeatureRecurringCards: '✨ Cartes récurrentes et automatisation',
|
||||
proFeatureGuestRoles: '✨ Rôles invités et collaboration externe',
|
||||
dismissProBannerFor30Days: 'Fermer pendant 30 jours',
|
||||
customerPanel_title: 'Panneau client',
|
||||
dangerZone_title: 'Zone dangereuse',
|
||||
date: 'Date',
|
||||
@@ -177,6 +184,7 @@ export default {
|
||||
deletedUser_title: 'Utilisateur supprimé',
|
||||
description: 'Description',
|
||||
display: 'Affichage',
|
||||
displayCardAges: "Afficher l'âge des cartes",
|
||||
dropFileToUpload: 'Déposer le fichier à télécharger',
|
||||
dueDate_title: "Date d'échéance",
|
||||
dynamicAndUnevenlySpacedLayout: 'Mise en page dynamique et inégalement espacée.',
|
||||
@@ -450,6 +458,7 @@ export default {
|
||||
download: 'Télécharger',
|
||||
duplicateCard_title: 'Dupliquer la carte',
|
||||
edit: 'Modifier',
|
||||
editAvatar_title: "Modifier l'avatar",
|
||||
editColor_title: 'Modifier la couleur',
|
||||
editDescription_title: 'Modifier la description',
|
||||
editDueDate_title: "Modifier la date d'échéance",
|
||||
|
||||
@@ -138,6 +138,13 @@ export default {
|
||||
customFieldGroups_title: 'Egyedi mezőcsoportok',
|
||||
customField_title: 'Egyedi mező',
|
||||
customFields_title: 'Egyedi mezők',
|
||||
discoverPlankaPro: '✨ Több funkció a tábláidhoz: Fedezd fel a PLANKA Pro-t',
|
||||
discoverPlankaPro_title: 'Fedezd fel a PLANKA Pro-t',
|
||||
upgradeTeamToPro_title: 'Csapat frissítése Pro-ra',
|
||||
proFeatureCalendar: '✨ Naptár nézet a tábláidhoz',
|
||||
proFeatureRecurringCards: '✨ Ismétlődő kártyák és automatizálás',
|
||||
proFeatureGuestRoles: '✨ Vendég szerepkörök és külső együttműködés',
|
||||
dismissProBannerFor30Days: 'Bezárás 30 napra',
|
||||
customerPanel_title: 'Ügyfélpanel',
|
||||
dangerZone_title: 'Veszélyzóna',
|
||||
date: 'Dátum',
|
||||
@@ -167,6 +174,7 @@ export default {
|
||||
deletedUser_title: 'Törölt felhasználó',
|
||||
description: 'Leírás',
|
||||
display: 'Megjelenítés',
|
||||
displayCardAges: 'Kártyák korának megjelenítése',
|
||||
dropFileToUpload: 'Dobja ide a fájlt a feltöltéshez',
|
||||
dueDate_title: 'Esedékesség dátuma',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dinamikus és asszimetrikus kiosztás.',
|
||||
@@ -444,6 +452,7 @@ export default {
|
||||
download: 'Letöltés',
|
||||
duplicateCard_title: 'Kártya másolása',
|
||||
edit: 'Szerkesztés',
|
||||
editAvatar_title: 'Avatar szerkesztése',
|
||||
editColor_title: 'Szín szerkesztése',
|
||||
editDescription_title: 'Leírás szerkesztése',
|
||||
editDueDate_title: 'Esedékesség dátumának szerkesztése',
|
||||
|
||||
@@ -145,6 +145,13 @@ export default {
|
||||
customFieldGroups_title: 'Grup bidang kustom',
|
||||
customField_title: 'Bidang kustom',
|
||||
customFields_title: 'Bidang kustom',
|
||||
discoverPlankaPro: '✨ Lebih banyak fitur untuk papan Anda: Temukan PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Temukan PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Tingkatkan tim ke Pro',
|
||||
proFeatureCalendar: '✨ Tampilan Kalender untuk papan Anda',
|
||||
proFeatureRecurringCards: '✨ Kartu Berulang & Otomatisasi',
|
||||
proFeatureGuestRoles: '✨ Peran Tamu & Kolaborasi Eksternal',
|
||||
dismissProBannerFor30Days: 'Tutup selama 30 hari',
|
||||
customerPanel_title: 'Panel pelanggan',
|
||||
dangerZone_title: 'Zona berbahaya',
|
||||
date: 'Tanggal',
|
||||
@@ -174,6 +181,7 @@ export default {
|
||||
deletedUser_title: 'Pengguna yang dihapus',
|
||||
description: 'Deskripsi',
|
||||
display: 'Tampilan',
|
||||
displayCardAges: 'Tampilkan usia kartu',
|
||||
dropFileToUpload: 'Tarik berkas untuk menggungah',
|
||||
dueDate_title: 'Tenggat waktu',
|
||||
dynamicAndUnevenlySpacedLayout: 'Tata letak dinamis dan tidak merata.',
|
||||
@@ -445,6 +453,7 @@ export default {
|
||||
download: 'Unduh',
|
||||
duplicateCard_title: 'Duplikat kartu',
|
||||
edit: 'Ubah',
|
||||
editAvatar_title: 'Ubah avatar',
|
||||
editColor_title: 'Ubah warna',
|
||||
editDescription_title: 'Ubah deskripsi',
|
||||
editDueDate_title: 'Ubah tenggat waktu',
|
||||
|
||||
@@ -145,6 +145,13 @@ export default {
|
||||
customFieldGroups_title: 'Campi personalizzati',
|
||||
customField_title: 'Campo personalizzato',
|
||||
customFields_title: 'Campi personalizzati',
|
||||
discoverPlankaPro: '✨ Più funzionalità per le tue bacheche: Scopri PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Scopri PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Aggiorna il team a Pro',
|
||||
proFeatureCalendar: '✨ Vista calendario per le tue bacheche',
|
||||
proFeatureRecurringCards: '✨ Schede ricorrenti e automazione',
|
||||
proFeatureGuestRoles: '✨ Ruoli ospite e collaborazione esterna',
|
||||
dismissProBannerFor30Days: 'Chiudi per 30 giorni',
|
||||
customerPanel_title: 'Pannello cliente',
|
||||
dangerZone_title: 'Zona pericolosa',
|
||||
date: 'Data',
|
||||
@@ -174,6 +181,7 @@ export default {
|
||||
deletedUser_title: 'Utente eliminato',
|
||||
description: 'Descrizione',
|
||||
display: 'Mostra',
|
||||
displayCardAges: 'Mostra età delle schede',
|
||||
dropFileToUpload: 'Trascina il file da caricare',
|
||||
dueDate_title: 'Data di scadenza',
|
||||
dynamicAndUnevenlySpacedLayout: 'Layout dinamico e irregolarmente distribuito.',
|
||||
@@ -448,6 +456,7 @@ export default {
|
||||
download: 'Scarica',
|
||||
duplicateCard_title: 'Duplica scheda',
|
||||
edit: 'Modifica',
|
||||
editAvatar_title: 'Modifica avatar',
|
||||
editColor_title: 'Modifica colore',
|
||||
editDescription_title: 'Modifica descrizione',
|
||||
editDueDate_title: 'Modifica data di scadenza',
|
||||
|
||||
@@ -141,6 +141,13 @@ export default {
|
||||
customFieldGroups_title: 'カスタムフィールドグループ',
|
||||
customField_title: 'カスタムフィールド',
|
||||
customFields_title: 'カスタムフィールド',
|
||||
discoverPlankaPro: '✨ ボードのさらなる機能: PLANKA Proを発見',
|
||||
discoverPlankaPro_title: 'PLANKA Proを発見',
|
||||
upgradeTeamToPro_title: 'チームをProにアップグレード',
|
||||
proFeatureCalendar: '✨ ボード用カレンダービュー',
|
||||
proFeatureRecurringCards: '✨ 繰り返しカードと自動化',
|
||||
proFeatureGuestRoles: '✨ ゲストロールと外部コラボレーション',
|
||||
dismissProBannerFor30Days: '30日間閉じる',
|
||||
customerPanel_title: '顧客パネル',
|
||||
dangerZone_title: '危険ゾーン',
|
||||
date: '日付',
|
||||
@@ -170,6 +177,7 @@ export default {
|
||||
deletedUser_title: '削除されたユーザー',
|
||||
description: '説明',
|
||||
display: '表示',
|
||||
displayCardAges: 'カードの経過時間を表示',
|
||||
dropFileToUpload: 'ファイルをドロップしてアップロード',
|
||||
dueDate_title: '期限',
|
||||
dynamicAndUnevenlySpacedLayout: '動的で不均等な間隔のレイアウト。',
|
||||
@@ -442,6 +450,7 @@ export default {
|
||||
download: 'ダウンロード',
|
||||
duplicateCard_title: 'カードを複製',
|
||||
edit: '編集',
|
||||
editAvatar_title: 'アバターを編集',
|
||||
editColor_title: '色を編集',
|
||||
editDescription_title: '説明を編集',
|
||||
editDueDate_title: '期限を編集',
|
||||
|
||||
@@ -136,6 +136,13 @@ export default {
|
||||
customFieldGroups_title: '사용자 정의 필드 그룹들',
|
||||
customField_title: '사용자 정의 필드',
|
||||
customFields_title: '사용자 정의 필드들',
|
||||
discoverPlankaPro: '✨ 보드를 위한 더 많은 기능: PLANKA Pro 알아보기',
|
||||
discoverPlankaPro_title: 'PLANKA Pro 알아보기',
|
||||
upgradeTeamToPro_title: '팀을 Pro로 업그레이드',
|
||||
proFeatureCalendar: '✨ 보드용 캘린더 뷰',
|
||||
proFeatureRecurringCards: '✨ 반복 카드 및 자동화',
|
||||
proFeatureGuestRoles: '✨ 게스트 역할 및 외부 협업',
|
||||
dismissProBannerFor30Days: '30일 동안 닫기',
|
||||
customerPanel_title: '고객 패널',
|
||||
dangerZone_title: '위험 구역',
|
||||
date: '날짜',
|
||||
@@ -164,6 +171,7 @@ export default {
|
||||
deletedUser_title: '삭제된 사용자',
|
||||
description: '설명',
|
||||
display: '표시',
|
||||
displayCardAges: '카드 경과 시간 표시',
|
||||
dropFileToUpload: '업로드할 파일을 드롭하세요',
|
||||
dueDate_title: '마감일',
|
||||
dynamicAndUnevenlySpacedLayout: '동적이고 불균등한 간격의 레이아웃.',
|
||||
@@ -439,6 +447,7 @@ export default {
|
||||
download: '다운로드',
|
||||
duplicateCard_title: '카드 복제',
|
||||
edit: '편집',
|
||||
editAvatar_title: '아바타 편집',
|
||||
editColor_title: '색상 편집',
|
||||
editDescription_title: '설명 편집',
|
||||
editDueDate_title: '마감일 편집',
|
||||
|
||||
@@ -144,6 +144,13 @@ export default {
|
||||
customFieldGroups_title: 'Aangepaste veldgroepen',
|
||||
customField_title: 'Aangepast veld',
|
||||
customFields_title: 'Aangepaste velden',
|
||||
discoverPlankaPro: '✨ Meer functies voor uw borden: Ontdek PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Ontdek PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Team upgraden naar Pro',
|
||||
proFeatureCalendar: '✨ Kalenderweergave voor uw borden',
|
||||
proFeatureRecurringCards: '✨ Terugkerende kaarten en automatisering',
|
||||
proFeatureGuestRoles: '✨ Gastrol en externe samenwerking',
|
||||
dismissProBannerFor30Days: 'Sluiten voor 30 dagen',
|
||||
customerPanel_title: 'Klantenpaneel',
|
||||
dangerZone_title: 'Gevaarlijke zone',
|
||||
date: 'Datum',
|
||||
@@ -173,6 +180,7 @@ export default {
|
||||
deletedUser_title: 'Verwijderde gebruiker',
|
||||
description: 'Beschrijving',
|
||||
display: 'Weergave',
|
||||
displayCardAges: 'Kaartleeftijd weergeven',
|
||||
dropFileToUpload: 'Sleep bestand om te uploaden',
|
||||
dueDate_title: 'Vervaldatum',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamische en ongelijk verdeelde indeling.',
|
||||
@@ -448,6 +456,7 @@ export default {
|
||||
download: 'Downloaden',
|
||||
duplicateCard_title: 'Kaart dupliceren',
|
||||
edit: 'Bewerken',
|
||||
editAvatar_title: 'Avatar bewerken',
|
||||
editColor_title: 'Kleur bewerken',
|
||||
editDescription_title: 'Beschrijving bewerken',
|
||||
editDueDate_title: 'Vervaldatum bewerken',
|
||||
|
||||
@@ -143,6 +143,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupy pól własnych',
|
||||
customField_title: 'Własne pole',
|
||||
customFields_title: 'Własne pola',
|
||||
discoverPlankaPro: '✨ Więcej funkcji dla Twoich tablic: Odkryj PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Odkryj PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Uaktualnij zespół do Pro',
|
||||
proFeatureCalendar: '✨ Widok kalendarza dla Twoich tablic',
|
||||
proFeatureRecurringCards: '✨ Powtarzające się karty i automatyzacja',
|
||||
proFeatureGuestRoles: '✨ Role gościa i zewnętrzna współpraca',
|
||||
dismissProBannerFor30Days: 'Zamknij na 30 dni',
|
||||
customerPanel_title: 'Panel klienta',
|
||||
dangerZone_title: 'Strefa niebezpieczeństwa',
|
||||
date: 'Data',
|
||||
@@ -172,6 +179,7 @@ export default {
|
||||
deletedUser_title: 'Usunięty użytkownik',
|
||||
description: 'Opis',
|
||||
display: 'Wyświetlanie',
|
||||
displayCardAges: 'Pokazuj wiek kart',
|
||||
dropFileToUpload: 'Upuść plik aby wgrać',
|
||||
dueDate_title: 'Termin',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamiczny i nierówny układ.',
|
||||
@@ -445,6 +453,7 @@ export default {
|
||||
download: 'Pobierz',
|
||||
duplicateCard_title: 'Duplikuj kartę',
|
||||
edit: 'Edytuj',
|
||||
editAvatar_title: 'Edytuj awatar',
|
||||
editColor_title: 'Edytuj kolor',
|
||||
editDescription_title: 'Edytuj opis',
|
||||
editDueDate_title: 'Edytuj termin',
|
||||
|
||||
@@ -146,6 +146,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupos de campo personalizado',
|
||||
customField_title: 'Campo personalizado',
|
||||
customFields_title: 'Campos personalizados',
|
||||
discoverPlankaPro: '✨ Mais recursos para seus quadros: Descubra o PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Descubra o PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Atualizar equipe para Pro',
|
||||
proFeatureCalendar: '✨ Visualização de calendário para seus quadros',
|
||||
proFeatureRecurringCards: '✨ Cartões recorrentes e automação',
|
||||
proFeatureGuestRoles: '✨ Funções de convidado e colaboração externa',
|
||||
dismissProBannerFor30Days: 'Fechar por 30 dias',
|
||||
customerPanel_title: 'Painel do cliente',
|
||||
dangerZone_title: 'Zona de perigo',
|
||||
date: 'Data',
|
||||
@@ -175,6 +182,7 @@ export default {
|
||||
deletedUser_title: 'Usuário excluído',
|
||||
description: 'Descrição',
|
||||
display: 'Exibir',
|
||||
displayCardAges: 'Exibir idade dos cartões',
|
||||
dropFileToUpload: 'Solte o arquivo para enviar',
|
||||
dueDate_title: 'Data de vencimento',
|
||||
dynamicAndUnevenlySpacedLayout: 'Layout dinâmico e desigualmente espaçado.',
|
||||
@@ -448,6 +456,7 @@ export default {
|
||||
download: 'Baixar',
|
||||
duplicateCard_title: 'Duplicar cartão',
|
||||
edit: 'Editar',
|
||||
editAvatar_title: 'Editar avatar',
|
||||
editColor_title: 'Editar cor',
|
||||
editDescription_title: 'Editar descrição',
|
||||
editDueDate_title: 'Editar data de vencimento',
|
||||
|
||||
@@ -148,6 +148,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupos de campos personalizados',
|
||||
customField_title: 'Campo personalizado',
|
||||
customFields_title: 'Campos personalizados',
|
||||
discoverPlankaPro: '✨ Mais funcionalidades para os seus quadros: Descubra o PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Descubra o PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Atualizar equipa para Pro',
|
||||
proFeatureCalendar: '✨ Vista de calendário para os seus quadros',
|
||||
proFeatureRecurringCards: '✨ Cartões recorrentes e automatização',
|
||||
proFeatureGuestRoles: '✨ Funções de convidado e colaboração externa',
|
||||
dismissProBannerFor30Days: 'Fechar durante 30 dias',
|
||||
customerPanel_title: 'Painel do cliente',
|
||||
dangerZone_title: 'Zona perigosa',
|
||||
date: 'Data',
|
||||
@@ -177,6 +184,7 @@ export default {
|
||||
deletedUser_title: 'Utilizador eliminado',
|
||||
description: 'Descrição',
|
||||
display: 'Exibir',
|
||||
displayCardAges: 'Mostrar idade dos cartões',
|
||||
dropFileToUpload: 'Largue o ficheiro para carregar',
|
||||
dueDate_title: 'Data de vencimento',
|
||||
dynamicAndUnevenlySpacedLayout: 'Layout dinâmico e espaçamento irregular.',
|
||||
@@ -451,6 +459,7 @@ export default {
|
||||
download: 'Transferir',
|
||||
duplicateCard_title: 'Duplicar cartão',
|
||||
edit: 'Editar',
|
||||
editAvatar_title: 'Editar avatar',
|
||||
editColor_title: 'Editar cor',
|
||||
editDescription_title: 'Editar descrição',
|
||||
editDueDate_title: 'Editar data de vencimento',
|
||||
|
||||
@@ -142,6 +142,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupuri de câmpuri personalizate',
|
||||
customField_title: 'Câmp personalizat',
|
||||
customFields_title: 'Câmpuri personalizate',
|
||||
discoverPlankaPro: '✨ Mai multe funcții pentru panourile tale: Descoperă PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Descoperă PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Actualizează echipa la Pro',
|
||||
proFeatureCalendar: '✨ Vizualizare calendar pentru panourile tale',
|
||||
proFeatureRecurringCards: '✨ Carduri recurente și automatizare',
|
||||
proFeatureGuestRoles: '✨ Roluri invitat și colaborare externă',
|
||||
dismissProBannerFor30Days: 'Închide pentru 30 de zile',
|
||||
customerPanel_title: 'Panoul clientului',
|
||||
dangerZone_title: 'Zona periculoasă',
|
||||
date: 'Data',
|
||||
@@ -171,6 +178,7 @@ export default {
|
||||
deletedUser_title: 'Utilizator șters',
|
||||
description: 'Descriere',
|
||||
display: 'Afișare',
|
||||
displayCardAges: 'Afișează vârsta cardurilor',
|
||||
dropFileToUpload: 'Aruncă fișierul pentru a încărca',
|
||||
dueDate_title: 'Data scadentă',
|
||||
dynamicAndUnevenlySpacedLayout: 'Aspect dinamic și spațiat neuniform.',
|
||||
@@ -445,6 +453,7 @@ export default {
|
||||
download: 'Descărcați',
|
||||
duplicateCard_title: 'Duplicați cardul',
|
||||
edit: 'Editați',
|
||||
editAvatar_title: 'Editați avatarul',
|
||||
editColor_title: 'Editați culoarea',
|
||||
editDescription_title: 'Editați descrierea',
|
||||
editDueDate_title: 'Editați data scadentă',
|
||||
|
||||
@@ -145,6 +145,13 @@ export default {
|
||||
customFieldGroups_title: 'Группы настраиваемых полей',
|
||||
customField_title: 'Настраиваемое поле',
|
||||
customFields_title: 'Настраиваемые поля',
|
||||
discoverPlankaPro: '✨ Больше возможностей для ваших досок: Откройте PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Откройте PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Улучшить команду до Pro',
|
||||
proFeatureCalendar: '✨ Вид календаря для ваших досок',
|
||||
proFeatureRecurringCards: '✨ Повторяющиеся карточки и автоматизация',
|
||||
proFeatureGuestRoles: '✨ Роли гостей и внешнее сотрудничество',
|
||||
dismissProBannerFor30Days: 'Закрыть на 30 дней',
|
||||
customerPanel_title: 'Панель клиента',
|
||||
dangerZone_title: 'Опасная зона',
|
||||
date: 'Дата',
|
||||
@@ -174,6 +181,7 @@ export default {
|
||||
deletedUser_title: 'Удалённый пользователь',
|
||||
description: 'Описание',
|
||||
display: 'Отображение',
|
||||
displayCardAges: 'Отображать возраст карточек',
|
||||
dropFileToUpload: 'Перетяните файл, чтобы загрузить',
|
||||
dueDate_title: 'Срок исполнения',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамичное и неравномерно распределённое расположение.',
|
||||
@@ -447,6 +455,7 @@ export default {
|
||||
download: 'Скачать',
|
||||
duplicateCard_title: 'Дублировать карточку',
|
||||
edit: 'Изменить',
|
||||
editAvatar_title: 'Изменить аватар',
|
||||
editColor_title: 'Изменить цвет',
|
||||
editDescription_title: 'Изменить описание',
|
||||
editDueDate_title: 'Изменить срок',
|
||||
|
||||
@@ -139,6 +139,13 @@ export default {
|
||||
customFieldGroups_title: 'Skupiny vlastných polí',
|
||||
customField_title: 'Vlastné pole',
|
||||
customFields_title: 'Vlastné polia',
|
||||
discoverPlankaPro: '✨ Viac funkcií pre vaše tabule: Objavte PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Objavte PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Inovovať tím na Pro',
|
||||
proFeatureCalendar: '✨ Zobrazenie kalendára pre vaše tabule',
|
||||
proFeatureRecurringCards: '✨ Opakujúce sa karty a automatizácia',
|
||||
proFeatureGuestRoles: '✨ Roly hosťa a externá spolupráca',
|
||||
dismissProBannerFor30Days: 'Zavrieť na 30 dní',
|
||||
customerPanel_title: 'Panel zákazníka',
|
||||
dangerZone_title: 'Nebezpečná zóna',
|
||||
date: 'Dátum',
|
||||
@@ -168,6 +175,7 @@ export default {
|
||||
deletedUser_title: 'Zmazaný používateľ',
|
||||
description: 'Popis',
|
||||
display: 'Zobraziť',
|
||||
displayCardAges: 'Zobraziť vek kariet',
|
||||
dropFileToUpload: 'Potiahnutím nahraj súbor',
|
||||
dueDate_title: 'Termín do',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamické a nerovnomerne rozložené usporiadanie.',
|
||||
@@ -438,6 +446,7 @@ export default {
|
||||
download: 'Stiahnuť',
|
||||
duplicateCard_title: 'Duplikovať kartu',
|
||||
edit: 'Upraviť',
|
||||
editAvatar_title: 'Upraviť avatar',
|
||||
editColor_title: 'Upraviť farbu',
|
||||
editDescription_title: 'Upraviť popis',
|
||||
editDueDate_title: 'Upraviť termín do',
|
||||
|
||||
@@ -142,6 +142,13 @@ export default {
|
||||
customFieldGroups_title: 'Групе прилагођених поља',
|
||||
customField_title: 'Прилагођено поље',
|
||||
customFields_title: 'Прилагођена поља',
|
||||
discoverPlankaPro: '✨ Више функција за ваше табле: Откријте PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Откријте PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Надоградите тим на Pro',
|
||||
proFeatureCalendar: '✨ Приказ календара за ваше табле',
|
||||
proFeatureRecurringCards: '✨ Понављајуће картице и аутоматизација',
|
||||
proFeatureGuestRoles: '✨ Гостујуће улоге и спољна сарадња',
|
||||
dismissProBannerFor30Days: 'Затвори на 30 дана',
|
||||
customerPanel_title: 'Панел купца',
|
||||
dangerZone_title: 'Опасна зона',
|
||||
date: 'Датум',
|
||||
@@ -171,6 +178,7 @@ export default {
|
||||
deletedUser_title: 'Обрисан корисник',
|
||||
description: 'Опис',
|
||||
display: 'Приказ',
|
||||
displayCardAges: 'Прикажи старост картица',
|
||||
dropFileToUpload: 'Превуци датотеку за слање',
|
||||
dueDate_title: 'Рок',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамички и неравномерно распоређен изглед.',
|
||||
@@ -441,6 +449,7 @@ export default {
|
||||
download: 'Преузми',
|
||||
duplicateCard_title: 'Клонирај картицу',
|
||||
edit: 'Измени',
|
||||
editAvatar_title: 'Уреди аватара',
|
||||
editColor_title: 'Уреди боју',
|
||||
editDescription_title: 'Измени опис',
|
||||
editDueDate_title: 'Измени рок',
|
||||
|
||||
@@ -143,6 +143,13 @@ export default {
|
||||
customFieldGroups_title: 'Grupe prilagođenih polja',
|
||||
customField_title: 'Prilagođeno polje',
|
||||
customFields_title: 'Prilagođena polja',
|
||||
discoverPlankaPro: '✨ Više funkcija za vaše table: Otkrijte PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Otkrijte PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Nadogradite tim na Pro',
|
||||
proFeatureCalendar: '✨ Prikaz kalendara za vaše table',
|
||||
proFeatureRecurringCards: '✨ Ponavljajuće kartice i automatizacija',
|
||||
proFeatureGuestRoles: '✨ Gostujuće uloge i spoljna saradnja',
|
||||
dismissProBannerFor30Days: 'Zatvori na 30 dana',
|
||||
customerPanel_title: 'Panel kupca',
|
||||
dangerZone_title: 'Opasna zona',
|
||||
date: 'Datum',
|
||||
@@ -172,6 +179,7 @@ export default {
|
||||
deletedUser_title: 'Obrisan korisnik',
|
||||
description: 'Opis',
|
||||
display: 'Prikaz',
|
||||
displayCardAges: 'Prikaži starost kartica',
|
||||
dropFileToUpload: 'Prevuci datoteku za slanje',
|
||||
dueDate_title: 'Rok',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dinamički i neravnomerno raspoređen izgled.',
|
||||
@@ -443,6 +451,7 @@ export default {
|
||||
download: 'Preuzmi',
|
||||
duplicateCard_title: 'Kloniraj karticu',
|
||||
edit: 'Izmeni',
|
||||
editAvatar_title: 'Uredi avatara',
|
||||
editColor_title: 'Uredi boju',
|
||||
editDescription_title: 'Izmeni opis',
|
||||
editDueDate_title: 'Izmeni rok',
|
||||
|
||||
@@ -149,6 +149,13 @@ export default {
|
||||
customFieldGroups_title: 'Anpassade fältgrupper',
|
||||
customField_title: 'Anpassat fält',
|
||||
customFields_title: 'Anpassade fält',
|
||||
discoverPlankaPro: '✨ Fler funktioner för dina bräden: Upptäck PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Upptäck PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Uppgradera teamet till Pro',
|
||||
proFeatureCalendar: '✨ Kalendervy för dina bräden',
|
||||
proFeatureRecurringCards: '✨ Återkommande kort och automatisering',
|
||||
proFeatureGuestRoles: '✨ Gästroller och externt samarbete',
|
||||
dismissProBannerFor30Days: 'Stäng i 30 dagar',
|
||||
customerPanel_title: 'Kundpanel',
|
||||
dangerZone_title: 'Farozon',
|
||||
date: 'Datum',
|
||||
@@ -178,6 +185,7 @@ export default {
|
||||
deletedUser_title: 'Borttagen användare',
|
||||
description: 'Beskrivning',
|
||||
display: 'Visa',
|
||||
displayCardAges: 'Visa kortålder',
|
||||
dropFileToUpload: 'Släpp en fil för att ladda upp',
|
||||
dueDate_title: 'Förfallodatum',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dynamisk och ojämnt fördelad layout.',
|
||||
@@ -452,6 +460,7 @@ export default {
|
||||
download: 'Ladda ner',
|
||||
duplicateCard_title: 'Duplicera kort',
|
||||
edit: 'Redigera',
|
||||
editAvatar_title: 'Redigera avatar',
|
||||
editColor_title: 'Redigera färg',
|
||||
editDescription_title: 'Redigera beskrivning',
|
||||
editDueDate_title: 'Redigera förfallodatum',
|
||||
|
||||
@@ -146,6 +146,13 @@ export default {
|
||||
customFieldGroups_title: 'özel alan grupları',
|
||||
customField_title: 'Özel alan',
|
||||
customFields_title: 'Özel alanlar',
|
||||
discoverPlankaPro: "✨ Panolarınız için daha fazla özellik: PLANKA Pro'yu keşfedin",
|
||||
discoverPlankaPro_title: "PLANKA Pro'yu keşfedin",
|
||||
upgradeTeamToPro_title: "Ekibi Pro'ya yükseltin",
|
||||
proFeatureCalendar: '✨ Panolarınız için takvim görünümü',
|
||||
proFeatureRecurringCards: '✨ Yinelenen kartlar ve otomasyon',
|
||||
proFeatureGuestRoles: '✨ Misafir rolleri ve harici iş birliği',
|
||||
dismissProBannerFor30Days: '30 gün için kapat',
|
||||
customerPanel_title: 'Müşteri paneli',
|
||||
dangerZone_title: 'Tehlikeli bölge',
|
||||
date: 'tarih',
|
||||
@@ -174,6 +181,7 @@ export default {
|
||||
deletedUser_title: 'Silinmiş kullanıcı',
|
||||
description: 'açıklama',
|
||||
display: 'Görüntüle',
|
||||
displayCardAges: 'Kart yaşlarını göster',
|
||||
dropFileToUpload: 'Yüklenecek dosyayı buraya bırakın',
|
||||
dueDate_title: 'Termin tarihi',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dinamik ve düzensiz aralıklı düzen.',
|
||||
@@ -448,6 +456,7 @@ export default {
|
||||
download: 'İndir',
|
||||
duplicateCard_title: 'Kartı kopyala',
|
||||
edit: 'Düzenle',
|
||||
editAvatar_title: 'Avatarı düzenle',
|
||||
editColor_title: 'Rengi düzenle',
|
||||
editDescription_title: 'Açıklamayı düzenle',
|
||||
editDueDate_title: 'Son tarihi düzenle',
|
||||
|
||||
@@ -144,6 +144,13 @@ export default {
|
||||
customFieldGroups_title: 'Користувацькі групи полів',
|
||||
customField_title: 'Користувацьке поле',
|
||||
customFields_title: 'Користувацькі поля',
|
||||
discoverPlankaPro: '✨ Більше можливостей для ваших дощок: Відкрийте PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Відкрийте PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Оновити команду до Pro',
|
||||
proFeatureCalendar: '✨ Вигляд календаря для ваших дощок',
|
||||
proFeatureRecurringCards: '✨ Повторювані картки та автоматизація',
|
||||
proFeatureGuestRoles: '✨ Ролі гостей та зовнішня співпраця',
|
||||
dismissProBannerFor30Days: 'Закрити на 30 днів',
|
||||
customerPanel_title: 'Панель клієнта',
|
||||
dangerZone_title: 'Небезпечна зона',
|
||||
date: 'Дата',
|
||||
@@ -173,6 +180,7 @@ export default {
|
||||
deletedUser_title: 'Видалений користувач',
|
||||
description: 'Опис',
|
||||
display: 'Дисплей',
|
||||
displayCardAges: 'Відображати вік карток',
|
||||
dropFileToUpload: 'Перетягніть файл для завантаження',
|
||||
dueDate_title: 'Крайній термін',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамічна та нерівномірна верстка.',
|
||||
@@ -443,6 +451,7 @@ export default {
|
||||
download: 'Завантажити',
|
||||
duplicateCard_title: 'Дублювати картку',
|
||||
edit: 'Редагувати',
|
||||
editAvatar_title: 'Редагувати аватар',
|
||||
editColor_title: 'Редагувати колір',
|
||||
editDescription_title: 'Редагувати опис',
|
||||
editDueDate_title: 'Редагувати термін виконання',
|
||||
|
||||
@@ -140,6 +140,13 @@ export default {
|
||||
customFieldGroups_title: 'Maxsus maydon guruhlari',
|
||||
customField_title: 'Maxsus maydon',
|
||||
customFields_title: 'Maxsus maydonlar',
|
||||
discoverPlankaPro: "✨ Doskalaringiz uchun ko'proq imkoniyatlar: PLANKA Pro ni kashf eting",
|
||||
discoverPlankaPro_title: 'PLANKA Pro ni kashf eting',
|
||||
upgradeTeamToPro_title: 'Jamoani Pro ga yangilash',
|
||||
proFeatureCalendar: "✨ Doskalaringiz uchun kalendar ko'rinishi",
|
||||
proFeatureRecurringCards: '✨ Takrorlanuvchi kartalar va avtomatlashtirish',
|
||||
proFeatureGuestRoles: '✨ Mehmon rollari va tashqi hamkorlik',
|
||||
dismissProBannerFor30Days: '30 kunga yopish',
|
||||
customerPanel_title: 'Mijoz paneli',
|
||||
dangerZone_title: 'Xavfli hudud',
|
||||
date: 'Sana',
|
||||
@@ -169,6 +176,7 @@ export default {
|
||||
deletedUser_title: "O'chirilgan foydalanuvchi",
|
||||
description: 'Tavsif',
|
||||
display: "Ko'rsatish",
|
||||
displayCardAges: "Kartalar yoshini ko'rsatish",
|
||||
dropFileToUpload: 'Faylni yuklash uchun qoldiring',
|
||||
dueDate_title: 'Muddati',
|
||||
dynamicAndUnevenlySpacedLayout: 'Dinamik va notekis joylashtirilgan tartib.',
|
||||
@@ -441,6 +449,7 @@ export default {
|
||||
download: 'Yuklab olish',
|
||||
duplicateCard_title: 'Kartani nusxalash',
|
||||
edit: 'Tahrirlash',
|
||||
editAvatar_title: 'Avatarni tahrirlash',
|
||||
editColor_title: 'Rangni tahrirlash',
|
||||
editDescription_title: 'Izohni tahrirlash',
|
||||
editDueDate_title: 'Muddatni tahrirlash',
|
||||
|
||||
@@ -145,6 +145,13 @@ export default {
|
||||
customFieldGroups_title: 'Các nhóm trường tùy chỉnh',
|
||||
customField_title: 'Trường tùy chỉnh',
|
||||
customFields_title: 'Các trường tùy chỉnh',
|
||||
discoverPlankaPro: '✨ Nhiều tính năng hơn cho bảng của bạn: Khám phá PLANKA Pro',
|
||||
discoverPlankaPro_title: 'Khám phá PLANKA Pro',
|
||||
upgradeTeamToPro_title: 'Nâng cấp nhóm lên Pro',
|
||||
proFeatureCalendar: '✨ Chế độ xem lịch cho bảng của bạn',
|
||||
proFeatureRecurringCards: '✨ Thẻ định kỳ và tự động hóa',
|
||||
proFeatureGuestRoles: '✨ Vai trò khách và cộng tác bên ngoài',
|
||||
dismissProBannerFor30Days: 'Đóng trong 30 ngày',
|
||||
customerPanel_title: 'Bảng điều khiển khách hàng',
|
||||
dangerZone_title: 'Khu vực nguy hiểm',
|
||||
date: 'Ngày',
|
||||
@@ -173,6 +180,7 @@ export default {
|
||||
deletedUser_title: 'Người dùng đã bị xóa',
|
||||
description: 'Mô tả',
|
||||
display: 'Hiển thị',
|
||||
displayCardAges: 'Hiển thị tuổi thẻ',
|
||||
dropFileToUpload: 'Thả tệp vào đây để tải lên',
|
||||
dueDate_title: 'Hạn chót',
|
||||
dynamicAndUnevenlySpacedLayout: 'Bố cục động và khoảng cách không đều.',
|
||||
@@ -443,6 +451,7 @@ export default {
|
||||
download: 'Tải xuống',
|
||||
duplicateCard_title: 'Nhân bản Thẻ',
|
||||
edit: 'Chỉnh sửa',
|
||||
editAvatar_title: 'Chỉnh sửa ảnh đại diện',
|
||||
editColor_title: 'Chỉnh sửa Màu sắc',
|
||||
editDescription_title: 'Chỉnh sửa Mô tả',
|
||||
editDueDate_title: 'Chỉnh sửa Hạn chót',
|
||||
|
||||
@@ -125,6 +125,13 @@ export default {
|
||||
customFieldGroups_title: '自定义字段组',
|
||||
customField_title: '自定义字段',
|
||||
customFields_title: '自定义字段',
|
||||
discoverPlankaPro: '✨ 为您的看板提供更多功能:探索 PLANKA Pro',
|
||||
discoverPlankaPro_title: '探索 PLANKA Pro',
|
||||
upgradeTeamToPro_title: '将团队升级到 Pro',
|
||||
proFeatureCalendar: '✨ 看板的日历视图',
|
||||
proFeatureRecurringCards: '✨ 重复卡片与自动化',
|
||||
proFeatureGuestRoles: '✨ 访客角色与外部协作',
|
||||
dismissProBannerFor30Days: '关闭 30 天',
|
||||
customerPanel_title: '客户面板',
|
||||
dangerZone_title: '危险区域',
|
||||
date: '日期',
|
||||
@@ -153,6 +160,7 @@ export default {
|
||||
deletedUser_title: '已删除用户',
|
||||
description: '描述',
|
||||
display: '显示',
|
||||
displayCardAges: '显示卡片创建时间',
|
||||
dropFileToUpload: '拖放文件以上传',
|
||||
dueDate_title: '截止日期',
|
||||
dynamicAndUnevenlySpacedLayout: '动态非均匀间隔布局。',
|
||||
@@ -418,6 +426,7 @@ export default {
|
||||
download: '下载',
|
||||
duplicateCard_title: '复制卡片',
|
||||
edit: '编辑',
|
||||
editAvatar_title: '编辑头像',
|
||||
editColor_title: '编辑颜色',
|
||||
editDescription_title: '编辑描述',
|
||||
editDueDate_title: '编辑到期时间',
|
||||
|
||||
@@ -125,6 +125,13 @@ export default {
|
||||
customFieldGroups_title: '自定義欄位群組',
|
||||
customField_title: '自定義欄位',
|
||||
customFields_title: '自定義欄位',
|
||||
discoverPlankaPro: '✨ 為您的看板提供更多功能:探索 PLANKA Pro',
|
||||
discoverPlankaPro_title: '探索 PLANKA Pro',
|
||||
upgradeTeamToPro_title: '將團隊升級至 Pro',
|
||||
proFeatureCalendar: '✨ 看板的日曆檢視',
|
||||
proFeatureRecurringCards: '✨ 重複卡片與自動化',
|
||||
proFeatureGuestRoles: '✨ 訪客角色與外部協作',
|
||||
dismissProBannerFor30Days: '關閉 30 天',
|
||||
customerPanel_title: '客戶面板',
|
||||
dangerZone_title: '危險區域',
|
||||
date: '日期',
|
||||
@@ -153,6 +160,7 @@ export default {
|
||||
deletedUser_title: '已刪除的使用者',
|
||||
description: '描述',
|
||||
display: '顯示',
|
||||
displayCardAges: '顯示卡片建立時間',
|
||||
dropFileToUpload: '拖放文件以上傳',
|
||||
dueDate_title: '截止日期',
|
||||
dynamicAndUnevenlySpacedLayout: '動態不均勻間距佈局。',
|
||||
@@ -418,6 +426,7 @@ export default {
|
||||
download: '下載',
|
||||
duplicateCard_title: '複製卡片',
|
||||
edit: '編輯',
|
||||
editAvatar_title: '編輯頭像',
|
||||
editColor_title: '編輯顏色',
|
||||
editDescription_title: '編輯描述',
|
||||
editDueDate_title: '編輯截止時間',
|
||||
|
||||
@@ -31,6 +31,7 @@ export default class extends BaseModel {
|
||||
defaultCardType: attr(),
|
||||
limitCardTypesToDefaultOne: attr(),
|
||||
alwaysDisplayCardCreator: attr(),
|
||||
displayCardAges: attr(),
|
||||
expandTaskListsByDefault: attr(),
|
||||
context: attr(),
|
||||
view: attr(),
|
||||
|
||||
@@ -64,6 +64,9 @@ export default function* usersWatchers() {
|
||||
takeEvery(EntryActionTypes.CURRENT_USER_USERNAME_UPDATE_ERROR_CLEAR, () =>
|
||||
services.clearCurrentUserUsernameUpdateError(),
|
||||
),
|
||||
takeEvery(EntryActionTypes.USER_AVATAR_UPDATE, ({ payload: { id, data } }) =>
|
||||
services.updateUserAvatar(id, data),
|
||||
),
|
||||
takeEvery(EntryActionTypes.CURRENT_USER_AVATAR_UPDATE, ({ payload: { data } }) =>
|
||||
services.updateCurrentUserAvatar(data),
|
||||
),
|
||||
|
||||
@@ -8,24 +8,28 @@ import { jwtDecode } from 'jwt-decode';
|
||||
|
||||
import Config from '../constants/Config';
|
||||
|
||||
const PATH = Config.BASE_PATH || '/';
|
||||
|
||||
export const setAccessToken = (accessToken) => {
|
||||
const { exp } = jwtDecode(accessToken);
|
||||
const expires = new Date(exp * 1000);
|
||||
|
||||
Cookies.set(Config.ACCESS_TOKEN_KEY, accessToken, {
|
||||
expires,
|
||||
path: PATH,
|
||||
secure: window.location.protocol === 'https:',
|
||||
sameSite: 'strict',
|
||||
});
|
||||
|
||||
Cookies.set(Config.ACCESS_TOKEN_VERSION_KEY, Config.ACCESS_TOKEN_VERSION, {
|
||||
expires,
|
||||
path: PATH,
|
||||
});
|
||||
};
|
||||
|
||||
export const removeAccessToken = () => {
|
||||
Cookies.remove(Config.ACCESS_TOKEN_KEY);
|
||||
Cookies.remove(Config.ACCESS_TOKEN_VERSION_KEY);
|
||||
Cookies.remove(Config.ACCESS_TOKEN_KEY, { path: PATH });
|
||||
Cookies.remove(Config.ACCESS_TOKEN_VERSION_KEY, { path: PATH });
|
||||
};
|
||||
|
||||
export const getAccessToken = () => {
|
||||
|
||||
@@ -1 +1 @@
|
||||
export default '2.0.1';
|
||||
export default '2.1.1';
|
||||
|
||||
@@ -17,6 +17,6 @@ ln -s ${CLIENT_PATH}/logo512.png ${SERVER_PUBLIC_PATH}/logo512.png && echo "Link
|
||||
ln -s ${CLIENT_PATH}/manifest.json ${SERVER_PUBLIC_PATH}/manifest.json && echo "Linked manifest.json successfully"
|
||||
ln -s ${CLIENT_PATH}/robots.txt ${SERVER_PUBLIC_PATH}/robots.txt && echo "Linked robots.txt successfully"
|
||||
ln -s ${CLIENT_PATH}/assets ${SERVER_PUBLIC_PATH}/assets && echo "Linked assets folder successfully"
|
||||
ln -s ${CLIENT_PATH}/index.html ${SERVER_VIEWS_PATH}/index.html && echo "Linked index.html successfully"
|
||||
ln -s ${CLIENT_PATH}/index.ejs ${SERVER_VIEWS_PATH}/index.ejs && echo "Linked index.ejs successfully"
|
||||
|
||||
echo "Setup symbolic links completed successfully."
|
||||
|
||||
@@ -1,13 +1,44 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import { defineConfig } from 'vite';
|
||||
import commonjs from 'vite-plugin-commonjs';
|
||||
import { nodePolyfills } from 'vite-plugin-node-polyfills';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import react from '@vitejs/plugin-react';
|
||||
import svgr from 'vite-plugin-svgr';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import browserslistToEsbuild from 'browserslist-to-esbuild';
|
||||
|
||||
const PROXY_TARGET = process.env.PROXY_TARGET || 'http://localhost:1337';
|
||||
|
||||
// eslint-disable-next-line no-underscore-dangle
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const createEjsTemplate = () => ({
|
||||
name: 'create-ejs-template',
|
||||
closeBundle() {
|
||||
if (process.env.INDEX_FORMAT !== 'ejs') return;
|
||||
|
||||
const distPath = path.resolve(__dirname, 'dist');
|
||||
const htmlPath = path.join(distPath, 'index.html');
|
||||
|
||||
if (!fs.existsSync(htmlPath)) return;
|
||||
|
||||
const html = fs.readFileSync(htmlPath, 'utf8');
|
||||
|
||||
const ejs = html
|
||||
.replace(/(href|src)="\.\/([^"]+)"/g, '$1="<%- basePath %>/$2"')
|
||||
.replace('</head>', " <script>window.BASE_PATH = '<%- basePath %>';</script>\n </head>");
|
||||
|
||||
fs.writeFileSync(path.join(distPath, 'index.ejs'), ejs);
|
||||
fs.unlinkSync(htmlPath);
|
||||
},
|
||||
});
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
export default defineConfig({
|
||||
base: './',
|
||||
plugins: [
|
||||
commonjs(),
|
||||
nodePolyfills({
|
||||
@@ -15,6 +46,7 @@ export default defineConfig({
|
||||
}),
|
||||
react(),
|
||||
svgr(),
|
||||
createEjsTemplate(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -24,6 +56,10 @@ export default defineConfig({
|
||||
server: {
|
||||
port: 3000,
|
||||
open: true,
|
||||
proxy: {
|
||||
'/api': PROXY_TARGET,
|
||||
'/socket.io': { target: PROXY_TARGET, ws: true },
|
||||
},
|
||||
},
|
||||
build: {
|
||||
target: browserslistToEsbuild(['>0.2%', 'not dead', 'not op_mini all']),
|
||||
|
||||
@@ -1,13 +1,22 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Stop on Error
|
||||
# Stop on error
|
||||
set -e
|
||||
|
||||
# Configure those to match your PLANKA Docker container names
|
||||
PLANKA_DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
|
||||
PLANKA_DOCKER_CONTAINER_PLANKA="planka-planka-1"
|
||||
# Configure those to match your Docker container names
|
||||
DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
|
||||
DOCKER_CONTAINER_PLANKA="planka-planka-1"
|
||||
|
||||
# Use provided directory or default to current directory
|
||||
BACKUP_DIR="${1:-$(pwd)}"
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "No backup directory specified, backing up to current directory: $BACKUP_DIR"
|
||||
else
|
||||
echo "Backing up to: $BACKUP_DIR"
|
||||
fi
|
||||
echo
|
||||
|
||||
# Create Temporary folder
|
||||
if date --version >/dev/null 2>&1; then
|
||||
# GNU date (Linux)
|
||||
BACKUP_DATETIME=$(date --utc +%FT%H-%M-%SZ)
|
||||
@@ -15,28 +24,30 @@ else
|
||||
# BSD date (macOS)
|
||||
BACKUP_DATETIME=$(date -u +%FT%H-%M-%SZ)
|
||||
fi
|
||||
mkdir -p "$BACKUP_DATETIME-backup"
|
||||
|
||||
# Dump DB into SQL File
|
||||
BACKUP_TEMP="$BACKUP_DIR/$BACKUP_DATETIME-backup"
|
||||
|
||||
# Create temporary directory
|
||||
mkdir -p "$BACKUP_TEMP"
|
||||
|
||||
echo -n "Exporting postgres database ... "
|
||||
docker exec -t "$PLANKA_DOCKER_CONTAINER_POSTGRES" pg_dumpall -c -U postgres > "$BACKUP_DATETIME-backup/postgres.sql"
|
||||
docker exec -t "$DOCKER_CONTAINER_POSTGRES" pg_dumpall -c -U postgres > "$BACKUP_TEMP/postgres.sql"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
# Export Docker Volume
|
||||
echo -n "Exporting data volume ... "
|
||||
docker run --rm --volumes-from "$PLANKA_DOCKER_CONTAINER_PLANKA" -v "$(pwd)/$BACKUP_DATETIME-backup:/backup" ubuntu cp -r /app/data /backup/data
|
||||
docker run --rm --volumes-from "$DOCKER_CONTAINER_PLANKA" -v "$BACKUP_TEMP:/backup" node:22-alpine cp -r /app/data /backup/data
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
# Create tgz
|
||||
echo -n "Creating final tarball $BACKUP_DATETIME-backup.tgz ... "
|
||||
tar -czf "$BACKUP_DATETIME-backup.tgz" \
|
||||
"$BACKUP_DATETIME-backup/postgres.sql" \
|
||||
"$BACKUP_DATETIME-backup/data"
|
||||
tar -C "$BACKUP_DIR" -czf "$BACKUP_TEMP.tgz" "$BACKUP_DATETIME-backup"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
# Remove source files
|
||||
echo -n "Cleaning up temporary files and folders ... "
|
||||
rm -rf "$BACKUP_DATETIME-backup"
|
||||
echo -n "Cleaning up temporary files and directories ... "
|
||||
rm -rf "$BACKUP_TEMP"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
echo "Backup Complete!"
|
||||
|
||||
@@ -51,12 +51,16 @@ services:
|
||||
# will be sent through this proxy if set.
|
||||
# - OUTGOING_PROXY=http://proxy:3128
|
||||
|
||||
# Set to true to expose the Swagger specification at /swagger.json
|
||||
# - SWAGGER_EXPOSED=false
|
||||
|
||||
# - S3_ENDPOINT=
|
||||
# - S3_REGION=
|
||||
# - S3_ACCESS_KEY_ID=
|
||||
# - S3_SECRET_ACCESS_KEY=
|
||||
# - S3_BUCKET=
|
||||
# - S3_FORCE_PATH_STYLE=true
|
||||
# - S3_REQUEST_CHECKSUM_CALCULATION=
|
||||
|
||||
# - OIDC_ISSUER=
|
||||
# - OIDC_CLIENT_ID=
|
||||
@@ -78,6 +82,7 @@ services:
|
||||
# - OIDC_IGNORE_USERNAME=true
|
||||
# - OIDC_IGNORE_ROLES=true
|
||||
# - OIDC_ENFORCED=true
|
||||
# - OIDC_TIMEOUT=3500
|
||||
# - OIDC_DEBUG=true
|
||||
|
||||
# Email Notifications (https://nodemailer.com/smtp/)
|
||||
@@ -107,6 +112,8 @@ services:
|
||||
- ./client:/app
|
||||
ports:
|
||||
- 3000:3000
|
||||
environment:
|
||||
- PROXY_TARGET=http://planka-server:1337
|
||||
|
||||
postgres:
|
||||
image: postgres:16-alpine
|
||||
|
||||
@@ -65,6 +65,9 @@ services:
|
||||
# which you can control via OUTGOING_BLOCKED_* and OUTGOING_ALLOWED_* below.
|
||||
# - OUTGOING_PROXY=http://proxy:3128
|
||||
|
||||
# Set to true to expose the Swagger specification at /swagger.json
|
||||
# - SWAGGER_EXPOSED=false
|
||||
|
||||
# - S3_ENDPOINT=
|
||||
# - S3_REGION=
|
||||
# - S3_ACCESS_KEY_ID=
|
||||
@@ -73,6 +76,7 @@ services:
|
||||
# - S3_SECRET_ACCESS_KEY__FILE=/run/secrets/s3_secret_access_key
|
||||
# - S3_BUCKET=
|
||||
# - S3_FORCE_PATH_STYLE=true
|
||||
# - S3_REQUEST_CHECKSUM_CALCULATION=
|
||||
|
||||
# - OIDC_ISSUER=
|
||||
# - OIDC_CLIENT_ID=
|
||||
@@ -96,6 +100,7 @@ services:
|
||||
# - OIDC_IGNORE_USERNAME=true
|
||||
# - OIDC_IGNORE_ROLES=true
|
||||
# - OIDC_ENFORCED=true
|
||||
# - OIDC_TIMEOUT=3500
|
||||
# - OIDC_DEBUG=true
|
||||
|
||||
# Email Notifications (https://nodemailer.com/smtp/)
|
||||
|
||||
@@ -1,31 +1,41 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Stop on Error
|
||||
# Stop on error
|
||||
set -e
|
||||
|
||||
# Configure those to match your PLANKA Docker container names
|
||||
PLANKA_DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
|
||||
PLANKA_DOCKER_CONTAINER_PLANKA="planka-planka-1"
|
||||
# Configure those to match your Docker container names
|
||||
DOCKER_CONTAINER_POSTGRES="planka-postgres-1"
|
||||
DOCKER_CONTAINER_PLANKA="planka-planka-1"
|
||||
|
||||
# Extract tgz archive
|
||||
PLANKA_BACKUP_ARCHIVE_TGZ=$1
|
||||
PLANKA_BACKUP_ARCHIVE=$(basename "$PLANKA_BACKUP_ARCHIVE_TGZ" .tgz)
|
||||
echo -n "Extracting tarball $PLANKA_BACKUP_ARCHIVE_TGZ ... "
|
||||
tar -xzf "$PLANKA_BACKUP_ARCHIVE_TGZ"
|
||||
# Use provided archive
|
||||
BACKUP_ARCHIVE="$1"
|
||||
|
||||
if [ -z "$BACKUP_ARCHIVE" ]; then
|
||||
echo "Usage: $0 <backup-archive.tgz>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BACKUP_DIR=$(dirname "$BACKUP_ARCHIVE")
|
||||
BACKUP_TEMP="$BACKUP_DIR/$(basename "$BACKUP_ARCHIVE" .tgz)"
|
||||
|
||||
echo -n "Extracting tarball $BACKUP_ARCHIVE ... "
|
||||
tar -C "$BACKUP_DIR" -xzf "$BACKUP_ARCHIVE"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
# Import Database
|
||||
echo -n "Importing postgres database ... "
|
||||
cat "$PLANKA_BACKUP_ARCHIVE/postgres.sql" | docker exec -i "$PLANKA_DOCKER_CONTAINER_POSTGRES" psql -U postgres
|
||||
cat "$BACKUP_TEMP/postgres.sql" | docker exec -i "$DOCKER_CONTAINER_POSTGRES" psql -U postgres
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
# Restore Docker Volume
|
||||
echo -n "Importing data volume ... "
|
||||
docker run --rm --volumes-from "$PLANKA_DOCKER_CONTAINER_PLANKA" -v "$(pwd)/$PLANKA_BACKUP_ARCHIVE:/backup" ubuntu cp -rf /backup/data/. /app/data
|
||||
docker run --rm --user root --volumes-from "$DOCKER_CONTAINER_PLANKA" -v "$BACKUP_TEMP:/backup" node:22-alpine sh -c "cp -rf /backup/data/. /app/data && chown -R node:node /app/data/*"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
echo -n "Cleaning up temporary files and folders ... "
|
||||
rm -r "$PLANKA_BACKUP_ARCHIVE"
|
||||
echo -n "Cleaning up temporary files and directories ... "
|
||||
rm -r "$BACKUP_TEMP"
|
||||
echo "Success!"
|
||||
echo
|
||||
|
||||
echo "Restore complete!"
|
||||
|
||||
204
package-lock.json
generated
204
package-lock.json
generated
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"name": "planka",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "planka",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.1",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"concurrently": "^9.2.1",
|
||||
"genversion": "^3.2.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7"
|
||||
"lint-staged": "^16.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-escapes": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.2.0.tgz",
|
||||
"integrity": "sha512-g6LhBsl+GBPRWGWsBtutpzBYuIIdBkLEvad5C/va/74Db018+5TZiyA26cZJAr3Rft5lprVqOIPxf5Vid6tqAw==",
|
||||
"version": "7.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz",
|
||||
"integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"environment": "^1.0.0"
|
||||
@@ -70,26 +70,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/brace-expansion": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
|
||||
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
|
||||
"integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/braces": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
|
||||
"integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fill-range": "^7.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/chalk": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||
@@ -134,13 +122,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/cli-truncate": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.1.1.tgz",
|
||||
"integrity": "sha512-SroPvNHxUnk+vIW/dOSfNqdy1sPEFkrTk6TUtqLCnBlo3N7TNYYkzzN7uSD6+jVjrdO4+p8nH7JzH6cIvUem6A==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-5.2.0.tgz",
|
||||
"integrity": "sha512-xRwvIOMGrfOAnM1JYtqQImuaNtDEv9v6oIYAs4LIHwTiKee8uwvIi363igssOC0O5U04i4AlENs79LQLu9tEMw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"slice-ansi": "^7.1.0",
|
||||
"string-width": "^8.0.0"
|
||||
"slice-ansi": "^8.0.0",
|
||||
"string-width": "^8.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
@@ -330,26 +318,14 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/filelist": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz",
|
||||
"integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==",
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.6.tgz",
|
||||
"integrity": "sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"minimatch": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fill-range": {
|
||||
"version": "7.1.1",
|
||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
|
||||
"integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"to-regex-range": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/find-package": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-package/-/find-package-1.0.0.tgz",
|
||||
@@ -386,9 +362,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/get-east-asian-width": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.4.0.tgz",
|
||||
"integrity": "sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==",
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz",
|
||||
"integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
@@ -436,15 +412,6 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-number": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
|
||||
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/jake": {
|
||||
"version": "10.9.4",
|
||||
"resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz",
|
||||
@@ -463,18 +430,17 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lint-staged": {
|
||||
"version": "16.2.7",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.2.7.tgz",
|
||||
"integrity": "sha512-lDIj4RnYmK7/kXMya+qJsmkRFkGolciXjrsZ6PC25GdTfWOAWetR0ZbsNXRAj1EHHImRSalc+whZFg56F5DVow==",
|
||||
"version": "16.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-16.4.0.tgz",
|
||||
"integrity": "sha512-lBWt8hujh/Cjysw5GYVmZpFHXDCgZzhrOm8vbcUdobADZNOK/bRshr2kM3DfgrrtR1DQhfupW9gnIXOfiFi+bw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"commander": "^14.0.2",
|
||||
"commander": "^14.0.3",
|
||||
"listr2": "^9.0.5",
|
||||
"micromatch": "^4.0.8",
|
||||
"nano-spawn": "^2.0.0",
|
||||
"pidtree": "^0.6.0",
|
||||
"picomatch": "^4.0.3",
|
||||
"string-argv": "^0.3.2",
|
||||
"yaml": "^2.8.1"
|
||||
"tinyexec": "^1.0.4",
|
||||
"yaml": "^2.8.2"
|
||||
},
|
||||
"bin": {
|
||||
"lint-staged": "bin/lint-staged.js"
|
||||
@@ -531,17 +497,32 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||
"node_modules/log-update/node_modules/ansi-styles": {
|
||||
"version": "6.2.3",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
|
||||
"integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/log-update/node_modules/slice-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
||||
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"braces": "^3.0.3",
|
||||
"picomatch": "^2.3.1"
|
||||
"ansi-styles": "^6.2.1",
|
||||
"is-fullwidth-code-point": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
"node": ">=18"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/mimic-function": {
|
||||
@@ -557,9 +538,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "5.1.6",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
|
||||
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
|
||||
"version": "5.1.9",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz",
|
||||
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@@ -568,18 +549,6 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/nano-spawn": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nano-spawn/-/nano-spawn-2.0.0.tgz",
|
||||
"integrity": "sha512-tacvGzUY5o2D8CBh2rrwxyNojUsZNU2zjNTzKQrkgGJQTbGAfArVWXSKMBokBeeg6C7OLRGUEyoFlYbfeWQIqw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=20.17"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sindresorhus/nano-spawn?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/onetime": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz",
|
||||
@@ -620,29 +589,17 @@
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
|
||||
"integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.6"
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/pidtree": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.0.tgz",
|
||||
"integrity": "sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"pidtree": "bin/pidtree.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
@@ -708,16 +665,16 @@
|
||||
}
|
||||
},
|
||||
"node_modules/slice-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz",
|
||||
"integrity": "sha512-iOBWFgUX7caIZiuutICxVgX1SdxwAVFFKwt1EvMYYec/NWO5meOJ6K5uQxhrYBdQJne4KxiqZc+KptFOWFSI9w==",
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz",
|
||||
"integrity": "sha512-stxByr12oeeOyY2BlviTNQlYV5xOj47GirPr4yA1hE9JCtxfQN0+tVbkxwCtYDQWhEKWFHsEK48ORg5jrouCAg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^6.2.1",
|
||||
"is-fullwidth-code-point": "^5.0.0"
|
||||
"ansi-styles": "^6.2.3",
|
||||
"is-fullwidth-code-point": "^5.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
"node": ">=20"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/slice-ansi?sponsor=1"
|
||||
@@ -745,13 +702,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "8.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.1.1.tgz",
|
||||
"integrity": "sha512-KpqHIdDL9KwYk22wEOg/VIqYbrnLeSApsKT/bSj6Ez7pn3CftUiLAv2Lccpq1ALcpLV9UX1Ppn92npZWu2w/aw==",
|
||||
"version": "8.2.0",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.0.tgz",
|
||||
"integrity": "sha512-6hJPQ8N0V0P3SNmP6h2J99RLuzrWz2gvT7VnK5tKvrNqJoyS9W4/Fb8mo31UiPvy00z7DQXkP2hnKBVav76thw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "^1.3.0",
|
||||
"strip-ansi": "^7.1.0"
|
||||
"get-east-asian-width": "^1.5.0",
|
||||
"strip-ansi": "^7.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20"
|
||||
@@ -761,12 +718,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "7.1.2",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.2.tgz",
|
||||
"integrity": "sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==",
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
|
||||
"integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^6.0.1"
|
||||
"ansi-regex": "^6.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
@@ -790,16 +747,13 @@
|
||||
"url": "https://github.com/chalk/supports-color?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
"integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
|
||||
"node_modules/tinyexec": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.0.4.tgz",
|
||||
"integrity": "sha512-u9r3uZC0bdpGOXtlxUIdwf9pkmvhqJdrVCH9fapQtgy/OeTTMZ1nqH7agtvEfmGui6e1XxjcdrlxvxJvc3sMqw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"is-number": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0"
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/tree-kill": {
|
||||
@@ -879,9 +833,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/yaml": {
|
||||
"version": "2.8.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
|
||||
"integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
|
||||
"integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"yaml": "bin.mjs"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planka",
|
||||
"version": "2.0.1",
|
||||
"version": "2.1.1",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"client:build": "npm run build --prefix client",
|
||||
@@ -39,6 +39,6 @@
|
||||
"concurrently": "^9.2.1",
|
||||
"genversion": "^3.2.0",
|
||||
"husky": "^9.1.7",
|
||||
"lint-staged": "^16.2.7"
|
||||
"lint-staged": "^16.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ test
|
||||
.tmp
|
||||
.venv
|
||||
|
||||
views/index.html
|
||||
views/index.ejs
|
||||
|
||||
data/*
|
||||
|
||||
|
||||
@@ -42,12 +42,16 @@ SECRET_KEY=notsecretkey
|
||||
# will be sent through this proxy if set.
|
||||
# OUTGOING_PROXY=http://proxy:3128
|
||||
|
||||
# Set to true to expose the Swagger specification at /swagger.json
|
||||
# SWAGGER_EXPOSED=false
|
||||
|
||||
# S3_ENDPOINT=
|
||||
# S3_REGION=
|
||||
# S3_ACCESS_KEY_ID=
|
||||
# S3_SECRET_ACCESS_KEY=
|
||||
# S3_BUCKET=
|
||||
# S3_FORCE_PATH_STYLE=true
|
||||
# S3_REQUEST_CHECKSUM_CALCULATION=
|
||||
|
||||
# OIDC_ISSUER=
|
||||
# OIDC_CLIENT_ID=
|
||||
@@ -69,6 +73,7 @@ SECRET_KEY=notsecretkey
|
||||
# OIDC_IGNORE_USERNAME=true
|
||||
# OIDC_IGNORE_ROLES=true
|
||||
# OIDC_ENFORCED=true
|
||||
# OIDC_TIMEOUT=3500
|
||||
# OIDC_DEBUG=true
|
||||
|
||||
# Email Notifications (https://nodemailer.com/smtp/)
|
||||
|
||||
2
server/.gitignore
vendored
2
server/.gitignore
vendored
@@ -134,7 +134,7 @@ swagger.json
|
||||
dist
|
||||
logs
|
||||
|
||||
views/index.html
|
||||
views/index.ejs
|
||||
|
||||
data/*
|
||||
!data/.gitkeep
|
||||
|
||||
@@ -55,6 +55,10 @@
|
||||
* type: boolean
|
||||
* description: Whether to always display card creators
|
||||
* example: false
|
||||
* displayCardAges:
|
||||
* type: boolean
|
||||
* description: Whether to display card ages
|
||||
* example: false
|
||||
* expandTaskListsByDefault:
|
||||
* type: boolean
|
||||
* description: Whether to expand task lists by default
|
||||
@@ -120,6 +124,9 @@ module.exports = {
|
||||
alwaysDisplayCardCreator: {
|
||||
type: 'boolean',
|
||||
},
|
||||
displayCardAges: {
|
||||
type: 'boolean',
|
||||
},
|
||||
expandTaskListsByDefault: {
|
||||
type: 'boolean',
|
||||
},
|
||||
@@ -160,6 +167,7 @@ module.exports = {
|
||||
'defaultCardType',
|
||||
'limitCardTypesToDefaultOne',
|
||||
'alwaysDisplayCardCreator',
|
||||
'displayCardAges',
|
||||
'expandTaskListsByDefault',
|
||||
);
|
||||
}
|
||||
@@ -178,6 +186,7 @@ module.exports = {
|
||||
'defaultCardType',
|
||||
'limitCardTypesToDefaultOne',
|
||||
'alwaysDisplayCardCreator',
|
||||
'displayCardAges',
|
||||
'expandTaskListsByDefault',
|
||||
'isSubscribed',
|
||||
]);
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /cards/{cardId}/custom-field-values/customFieldGroupId:{customFieldGroupId}:customFieldId:${customFieldId}:
|
||||
* /cards/{cardId}/custom-field-values/customFieldGroupId:{customFieldGroupId}:customFieldId:{customFieldId}:
|
||||
* patch:
|
||||
* summary: Create or update custom field value
|
||||
* description: Creates or updates a custom field value for a card. Requires board editor permissions.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
/**
|
||||
* @swagger
|
||||
* /cards/{cardId}/custom-field-value/customFieldGroupId:{customFieldGroupId}:customFieldId:${customFieldId}:
|
||||
* /cards/{cardId}/custom-field-value/customFieldGroupId:{customFieldGroupId}:customFieldId:{customFieldId}:
|
||||
* delete:
|
||||
* summary: Delete custom field value
|
||||
* description: Deletes a custom field value for a specific card. Requires board editor permissions.
|
||||
|
||||
19
server/api/controllers/index.js
Normal file
19
server/api/controllers/index.js
Normal file
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* Copyright (c) 2025 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
module.exports = {
|
||||
exits: {
|
||||
success: {
|
||||
responseType: 'view',
|
||||
viewTemplatePath: 'index',
|
||||
},
|
||||
},
|
||||
|
||||
fn() {
|
||||
return {
|
||||
basePath: sails.config.custom.baseUrlPath,
|
||||
};
|
||||
},
|
||||
};
|
||||
28
server/api/controllers/swagger/show.js
Normal file
28
server/api/controllers/swagger/show.js
Normal file
@@ -0,0 +1,28 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const SWAGGER_PATH = path.join(sails.config.appPath, 'swagger.json');
|
||||
|
||||
module.exports = {
|
||||
async fn() {
|
||||
if (!sails.config.custom.swaggerExposed) {
|
||||
return this.res.notFound();
|
||||
}
|
||||
|
||||
let specification;
|
||||
try {
|
||||
const content = fs.readFileSync(SWAGGER_PATH, 'utf8');
|
||||
specification = JSON.parse(content);
|
||||
} catch (error) {
|
||||
sails.log.warn('swagger.json not found, run "npm run swagger:generate" to create it');
|
||||
return this.res.notFound();
|
||||
}
|
||||
|
||||
return specification;
|
||||
},
|
||||
};
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user