mirror of
https://github.com/plankanban/planka.git
synced 2026-07-16 21:33:57 +03:00
Compare commits
14 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
91eb43f472 | ||
|
|
f47c188331 | ||
|
|
38a45c66e3 | ||
|
|
c342d2edd7 | ||
|
|
95e479cd3a | ||
|
|
d9ae02899d | ||
|
|
5e6195b252 | ||
|
|
61a3ff55cc | ||
|
|
af0cd79535 | ||
|
|
bb907d62e4 | ||
|
|
7604a31a74 | ||
|
|
2685e5d5fc | ||
|
|
5ebe320396 | ||
|
|
66ff3b65c6 |
@@ -11,7 +11,7 @@ server/test
|
||||
server/.tmp
|
||||
server/.venv
|
||||
|
||||
server/views/index.html
|
||||
server/views/index.ejs
|
||||
|
||||
server/data/*
|
||||
!server/data/.gitkeep
|
||||
|
||||
@@ -34,7 +34,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 +45,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:
|
||||
|
||||
@@ -22,7 +22,7 @@ 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
|
||||
@@ -41,12 +41,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
|
||||
|
||||
@@ -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.2
|
||||
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.2"
|
||||
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 }}
|
||||
@@ -77,6 +77,10 @@ spec:
|
||||
subPath: tmp
|
||||
name: emptydir
|
||||
{{- end }}
|
||||
{{- if .Values.terms.enabled }}
|
||||
- mountPath: /app/terms/custom
|
||||
name: planka-terms
|
||||
{{- end }}
|
||||
{{- /* Extra volume mounts */}}
|
||||
{{- range .Values.extraMounts }}
|
||||
- name: {{ .name }}
|
||||
@@ -222,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
|
||||
|
||||
2563
client/package-lock.json
generated
2563
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,10 +120,10 @@
|
||||
"highlightjs-zenscript": "^2.0.0",
|
||||
"hightlightjs-papyrus": "^0.0.4",
|
||||
"history": "^5.3.0",
|
||||
"i18next": "^25.8.1",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"i18next": "^25.8.18",
|
||||
"i18next-browser-languagedetector": "^8.2.1",
|
||||
"initials": "^3.1.2",
|
||||
"javascript-time-ago": "^2.6.2",
|
||||
"javascript-time-ago": "^2.6.4",
|
||||
"js-cookie": "^3.0.5",
|
||||
"jwt-decode": "^4.0.0",
|
||||
"linkify-react": "^4.3.2",
|
||||
@@ -134,7 +131,7 @@
|
||||
"lodash": "^4.17.23",
|
||||
"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,25 +140,25 @@
|
||||
"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",
|
||||
@@ -174,10 +171,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 +184,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,19 @@
|
||||
# [2.0.2] - 2026-02-23
|
||||
# [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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -166,6 +166,7 @@ export default {
|
||||
deletedUser_title: 'مستخدم محذوف',
|
||||
description: 'الوصف',
|
||||
display: 'عرض',
|
||||
displayCardAges: 'عرض أعمار البطاقات',
|
||||
dropFileToUpload: 'أفلت الملف لرفعه',
|
||||
dueDate_title: 'تاريخ الاستحقاق',
|
||||
dynamicAndUnevenlySpacedLayout: 'تخطيط ديناميكي وغير متساوي المسافات.',
|
||||
|
||||
@@ -178,6 +178,7 @@ export default {
|
||||
deletedUser_title: 'Изтрит потребител',
|
||||
description: 'Описание',
|
||||
display: 'Показване',
|
||||
displayCardAges: 'Показвай възрастта на картите',
|
||||
dropFileToUpload: 'Пуснете файл за качване',
|
||||
dueDate_title: 'Краен срок',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамично и неравномерно разположение.',
|
||||
|
||||
@@ -177,6 +177,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.',
|
||||
|
||||
@@ -169,6 +169,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í.',
|
||||
|
||||
@@ -173,6 +173,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.',
|
||||
|
||||
@@ -188,6 +188,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.',
|
||||
|
||||
@@ -186,6 +186,7 @@ export default {
|
||||
deletedUser_title: 'Διαγραμμένος χρήστης',
|
||||
description: 'Περιγραφή',
|
||||
display: 'Εμφάνιση',
|
||||
displayCardAges: 'Εμφάνιση ηλικίας καρτών',
|
||||
dropFileToUpload: 'Σύρετε το αρχείο για μεταφόρτωση',
|
||||
dueDate_title: 'Ημερομηνία λήξης',
|
||||
dynamicAndUnevenlySpacedLayout: 'Δυναμική και άνισα κατανεμημένη διάταξη.',
|
||||
|
||||
@@ -172,6 +172,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.',
|
||||
|
||||
@@ -167,6 +167,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.',
|
||||
|
||||
@@ -178,6 +178,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.',
|
||||
|
||||
@@ -173,6 +173,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.',
|
||||
|
||||
@@ -176,6 +176,7 @@ export default {
|
||||
deletedUser_title: 'کاربر حذف شده',
|
||||
description: 'توضیحات',
|
||||
display: 'نمایش',
|
||||
displayCardAges: 'نمایش سن کارتها',
|
||||
dropFileToUpload: 'فایل را برای آپلود بکشید',
|
||||
dueDate_title: 'تاریخ سررسید',
|
||||
dynamicAndUnevenlySpacedLayout: 'طرحبندی پویا و نامتقارن.',
|
||||
|
||||
@@ -169,6 +169,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.',
|
||||
|
||||
@@ -177,6 +177,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.',
|
||||
|
||||
@@ -167,6 +167,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.',
|
||||
|
||||
@@ -174,6 +174,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.',
|
||||
|
||||
@@ -174,6 +174,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.',
|
||||
|
||||
@@ -170,6 +170,7 @@ export default {
|
||||
deletedUser_title: '削除されたユーザー',
|
||||
description: '説明',
|
||||
display: '表示',
|
||||
displayCardAges: 'カードの経過時間を表示',
|
||||
dropFileToUpload: 'ファイルをドロップしてアップロード',
|
||||
dueDate_title: '期限',
|
||||
dynamicAndUnevenlySpacedLayout: '動的で不均等な間隔のレイアウト。',
|
||||
|
||||
@@ -164,6 +164,7 @@ export default {
|
||||
deletedUser_title: '삭제된 사용자',
|
||||
description: '설명',
|
||||
display: '표시',
|
||||
displayCardAges: '카드 경과 시간 표시',
|
||||
dropFileToUpload: '업로드할 파일을 드롭하세요',
|
||||
dueDate_title: '마감일',
|
||||
dynamicAndUnevenlySpacedLayout: '동적이고 불균등한 간격의 레이아웃.',
|
||||
|
||||
@@ -173,6 +173,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.',
|
||||
|
||||
@@ -172,6 +172,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.',
|
||||
|
||||
@@ -175,6 +175,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.',
|
||||
|
||||
@@ -177,6 +177,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.',
|
||||
|
||||
@@ -171,6 +171,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.',
|
||||
|
||||
@@ -174,6 +174,7 @@ export default {
|
||||
deletedUser_title: 'Удалённый пользователь',
|
||||
description: 'Описание',
|
||||
display: 'Отображение',
|
||||
displayCardAges: 'Отображать возраст карточек',
|
||||
dropFileToUpload: 'Перетяните файл, чтобы загрузить',
|
||||
dueDate_title: 'Срок исполнения',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамичное и неравномерно распределённое расположение.',
|
||||
|
||||
@@ -168,6 +168,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.',
|
||||
|
||||
@@ -171,6 +171,7 @@ export default {
|
||||
deletedUser_title: 'Обрисан корисник',
|
||||
description: 'Опис',
|
||||
display: 'Приказ',
|
||||
displayCardAges: 'Прикажи старост картица',
|
||||
dropFileToUpload: 'Превуци датотеку за слање',
|
||||
dueDate_title: 'Рок',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамички и неравномерно распоређен изглед.',
|
||||
|
||||
@@ -172,6 +172,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.',
|
||||
|
||||
@@ -178,6 +178,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.',
|
||||
|
||||
@@ -174,6 +174,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.',
|
||||
|
||||
@@ -173,6 +173,7 @@ export default {
|
||||
deletedUser_title: 'Видалений користувач',
|
||||
description: 'Опис',
|
||||
display: 'Дисплей',
|
||||
displayCardAges: 'Відображати вік карток',
|
||||
dropFileToUpload: 'Перетягніть файл для завантаження',
|
||||
dueDate_title: 'Крайній термін',
|
||||
dynamicAndUnevenlySpacedLayout: 'Динамічна та нерівномірна верстка.',
|
||||
|
||||
@@ -169,6 +169,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.',
|
||||
|
||||
@@ -173,6 +173,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.',
|
||||
|
||||
@@ -153,6 +153,7 @@ export default {
|
||||
deletedUser_title: '已删除用户',
|
||||
description: '描述',
|
||||
display: '显示',
|
||||
displayCardAges: '显示卡片创建时间',
|
||||
dropFileToUpload: '拖放文件以上传',
|
||||
dueDate_title: '截止日期',
|
||||
dynamicAndUnevenlySpacedLayout: '动态非均匀间隔布局。',
|
||||
|
||||
@@ -153,6 +153,7 @@ export default {
|
||||
deletedUser_title: '已刪除的使用者',
|
||||
description: '描述',
|
||||
display: '顯示',
|
||||
displayCardAges: '顯示卡片建立時間',
|
||||
dropFileToUpload: '拖放文件以上傳',
|
||||
dueDate_title: '截止日期',
|
||||
dynamicAndUnevenlySpacedLayout: '動態不均勻間距佈局。',
|
||||
|
||||
@@ -31,6 +31,7 @@ export default class extends BaseModel {
|
||||
defaultCardType: attr(),
|
||||
limitCardTypesToDefaultOne: attr(),
|
||||
alwaysDisplayCardCreator: attr(),
|
||||
displayCardAges: attr(),
|
||||
expandTaskListsByDefault: attr(),
|
||||
context: attr(),
|
||||
view: attr(),
|
||||
|
||||
@@ -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.2';
|
||||
export default '2.1.0';
|
||||
|
||||
@@ -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,42 @@
|
||||
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';
|
||||
|
||||
// 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 +44,7 @@ export default defineConfig({
|
||||
}),
|
||||
react(),
|
||||
svgr(),
|
||||
createEjsTemplate(),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
@@ -24,6 +54,10 @@ export default defineConfig({
|
||||
server: {
|
||||
port: 3000,
|
||||
open: true,
|
||||
proxy: {
|
||||
'/api': 'http://localhost:1337',
|
||||
'/socket.io': { target: 'http://localhost:1337', ws: true },
|
||||
},
|
||||
},
|
||||
build: {
|
||||
target: browserslistToEsbuild(['>0.2%', 'not dead', 'not op_mini all']),
|
||||
|
||||
@@ -51,6 +51,9 @@ 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=
|
||||
@@ -78,6 +81,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/)
|
||||
|
||||
@@ -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=
|
||||
@@ -96,6 +99,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/)
|
||||
|
||||
192
package-lock.json
generated
192
package-lock.json
generated
@@ -1,24 +1,24 @@
|
||||
{
|
||||
"name": "planka",
|
||||
"version": "2.0.2",
|
||||
"version": "2.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "planka",
|
||||
"version": "2.0.2",
|
||||
"version": "2.1.0",
|
||||
"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"
|
||||
@@ -78,18 +78,6 @@
|
||||
"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": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "planka",
|
||||
"version": "2.0.2",
|
||||
"version": "2.1.0",
|
||||
"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,6 +42,9 @@ 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=
|
||||
@@ -69,6 +72,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;
|
||||
},
|
||||
};
|
||||
@@ -15,7 +15,7 @@ module.exports = {
|
||||
|
||||
fn(inputs) {
|
||||
inputs.response.clearCookie('httpOnlyToken', {
|
||||
path: sails.config.custom.baseUrlPath,
|
||||
path: sails.config.custom.baseUrlPath || '/',
|
||||
});
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ module.exports = {
|
||||
fn(inputs) {
|
||||
inputs.response.cookie('httpOnlyToken', inputs.value, {
|
||||
expires: new Date(inputs.accessTokenPayload.exp * 1000),
|
||||
path: sails.config.custom.baseUrlPath,
|
||||
path: sails.config.custom.baseUrlPath || '/',
|
||||
secure: sails.config.custom.baseUrlSecure,
|
||||
httpOnly: true,
|
||||
sameSite: 'strict',
|
||||
|
||||
@@ -45,6 +45,12 @@ module.exports = function defineOidcHook(sails) {
|
||||
clientInitPromise = (async () => {
|
||||
sails.log.info('Initializing OIDC client');
|
||||
|
||||
if (sails.config.custom.oidcTimeout !== null) {
|
||||
openidClient.custom.setHttpOptionsDefaults({
|
||||
timeout: sails.config.custom.oidcTimeout,
|
||||
});
|
||||
}
|
||||
|
||||
let issuer;
|
||||
try {
|
||||
issuer = await openidClient.Issuer.discover(sails.config.custom.oidcIssuer);
|
||||
|
||||
@@ -32,7 +32,9 @@ module.exports = function defineTermsHook(sails) {
|
||||
});
|
||||
|
||||
return entries
|
||||
.filter((entry) => entry.isFile() && path.extname(entry.name) === '.md')
|
||||
.filter(
|
||||
(entry) => (entry.isFile() || entry.isSymbolicLink()) && path.extname(entry.name) === '.md',
|
||||
)
|
||||
.map((entry) => path.basename(entry.name, '.md'))
|
||||
.sort();
|
||||
};
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
* - defaultCardType
|
||||
* - limitCardTypesToDefaultOne
|
||||
* - alwaysDisplayCardCreator
|
||||
* - displayCardAges
|
||||
* - expandTaskListsByDefault
|
||||
* - createdAt
|
||||
* - updatedAt
|
||||
@@ -67,6 +68,11 @@
|
||||
* default: false
|
||||
* description: Whether to always display the card creator
|
||||
* example: false
|
||||
* displayCardAges:
|
||||
* type: boolean
|
||||
* default: false
|
||||
* description: Whether to display card ages
|
||||
* example: false
|
||||
* expandTaskListsByDefault:
|
||||
* type: boolean
|
||||
* default: false
|
||||
@@ -137,6 +143,11 @@ module.exports = {
|
||||
defaultsTo: false,
|
||||
columnName: 'always_display_card_creator',
|
||||
},
|
||||
displayCardAges: {
|
||||
type: 'boolean',
|
||||
defaultsTo: false,
|
||||
columnName: 'display_card_ages',
|
||||
},
|
||||
expandTaskListsByDefault: {
|
||||
type: 'boolean',
|
||||
defaultsTo: false,
|
||||
|
||||
@@ -2,6 +2,10 @@ const fs = require('fs');
|
||||
const path = require('path');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const ignore = require('ignore');
|
||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||
const swaggerJsdoc = require('swagger-jsdoc');
|
||||
|
||||
const swaggerConfig = require('./config/swagger');
|
||||
|
||||
const OUT_DIR = 'dist';
|
||||
|
||||
@@ -40,3 +44,6 @@ const build = (src, dest) => {
|
||||
};
|
||||
|
||||
build('./', OUT_DIR);
|
||||
|
||||
const specification = swaggerJsdoc(swaggerConfig);
|
||||
fs.writeFileSync(path.join(OUT_DIR, 'swagger.json'), JSON.stringify(specification, null, 2));
|
||||
|
||||
@@ -41,7 +41,7 @@ module.exports.custom = {
|
||||
version,
|
||||
|
||||
baseUrl,
|
||||
baseUrlPath: parsedBasedUrl.pathname,
|
||||
baseUrlPath: parsedBasedUrl.pathname.replace(/\/$/, ''), // Remove trailing slash
|
||||
baseUrlSecure: parsedBasedUrl.protocol === 'https:',
|
||||
|
||||
maxUploadFileSize: envToBytes(process.env.MAX_UPLOAD_FILE_SIZE),
|
||||
@@ -64,6 +64,7 @@ module.exports.custom = {
|
||||
|
||||
showDetailedAuthErrors: process.env.SHOW_DETAILED_AUTH_ERRORS === 'true',
|
||||
outgoingProxy: process.env.OUTGOING_PROXY,
|
||||
swaggerExposed: process.env.SWAGGER_EXPOSED === 'true',
|
||||
|
||||
s3Endpoint: process.env.S3_ENDPOINT,
|
||||
s3Region: process.env.S3_REGION,
|
||||
@@ -92,6 +93,7 @@ module.exports.custom = {
|
||||
oidcIgnoreUsername: process.env.OIDC_IGNORE_USERNAME === 'true',
|
||||
oidcIgnoreRoles: process.env.OIDC_IGNORE_ROLES === 'true',
|
||||
oidcEnforced: process.env.OIDC_ENFORCED === 'true',
|
||||
oidcTimeout: envToNumber(process.env.OIDC_TIMEOUT),
|
||||
oidcDebug: process.env.OIDC_DEBUG === 'true',
|
||||
|
||||
// TODO: move client base url to environment variable?
|
||||
|
||||
@@ -44,6 +44,8 @@ module.exports.policies = {
|
||||
|
||||
'_internal/update-config': ['is-authenticated', 'is-internal'],
|
||||
|
||||
index: true,
|
||||
'swagger/show': true,
|
||||
'bootstrap/show': true,
|
||||
'terms/show': true,
|
||||
'access-tokens/create': true,
|
||||
|
||||
@@ -235,6 +235,8 @@ module.exports.routes = {
|
||||
|
||||
'PATCH /api/_internal/config': '_internal/update-config',
|
||||
|
||||
'GET /swagger.json': 'swagger/show',
|
||||
|
||||
'GET /favicons/*': {
|
||||
fn: protectedStaticDirServer('/favicons', () => sails.config.custom.faviconsPathSegment),
|
||||
skipAssets: false,
|
||||
@@ -264,7 +266,7 @@ module.exports.routes = {
|
||||
},
|
||||
|
||||
'GET /*': {
|
||||
view: 'index',
|
||||
action: 'index',
|
||||
skipAssets: true,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -24,7 +24,7 @@ module.exports.views = {
|
||||
*
|
||||
*/
|
||||
|
||||
extension: 'html',
|
||||
// extension: 'ejs',
|
||||
|
||||
/**
|
||||
*
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*!
|
||||
* Copyright (c) 2024 PLANKA Software GmbH
|
||||
* Licensed under the Fair Use License: https://github.com/plankanban/planka/blob/master/LICENSE.md
|
||||
*/
|
||||
|
||||
module.exports.up = async (knex) => {
|
||||
await knex.schema.alterTable('board', (table) => {
|
||||
table.boolean('display_card_ages').notNullable().defaultTo(false);
|
||||
});
|
||||
|
||||
return knex.schema.alterTable('board', (table) => {
|
||||
table.boolean('display_card_ages').notNullable().alter();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports.down = (knex) =>
|
||||
knex.schema.alterTable('board', (table) => {
|
||||
table.dropColumn('display_card_ages');
|
||||
});
|
||||
1663
server/package-lock.json
generated
1663
server/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -49,8 +49,8 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@aws-sdk/client-s3": "^3.995.0",
|
||||
"@aws-sdk/lib-storage": "^3.995.0",
|
||||
"@aws-sdk/client-s3": "^3.1009.0",
|
||||
"@aws-sdk/lib-storage": "^3.1009.0",
|
||||
"bcrypt": "^6.0.0",
|
||||
"bytes": "^3.1.2",
|
||||
"cross-env": "^10.1.0",
|
||||
@@ -58,8 +58,8 @@
|
||||
"dotenv-cli": "^11.0.0",
|
||||
"escape-html": "^1.0.3",
|
||||
"escape-markdown": "^1.0.4",
|
||||
"file-type": "^21.3.0",
|
||||
"fs-extra": "^11.3.3",
|
||||
"file-type": "^21.3.2",
|
||||
"fs-extra": "^11.3.4",
|
||||
"i18n-2": "^0.7.3",
|
||||
"ico-to-png": "^0.2.2",
|
||||
"istextorbinary": "^9.5.0",
|
||||
@@ -71,7 +71,7 @@
|
||||
"nodemailer": "^7.0.13",
|
||||
"openid-client": "^5.7.1",
|
||||
"patch-package": "^8.0.1",
|
||||
"pg": "^8.18.0",
|
||||
"pg": "^8.20.0",
|
||||
"read": "^5.0.1",
|
||||
"rimraf": "^6.1.3",
|
||||
"sails": "^1.5.17",
|
||||
@@ -80,7 +80,7 @@
|
||||
"sails-postgresql": "^5.0.1",
|
||||
"serve-static": "^2.2.1",
|
||||
"sharp": "^0.34.5",
|
||||
"undici": "^7.22.0",
|
||||
"undici": "^7.24.0",
|
||||
"uuid": "^11.1.0",
|
||||
"validator": "^13.15.26",
|
||||
"winston": "^3.19.0",
|
||||
|
||||
@@ -41,7 +41,7 @@ start_outgoing_proxy_if_needed() {
|
||||
|
||||
# Basic settings
|
||||
echo "pid_filename $SQUID_PID" >> "$SQUID_CONF"
|
||||
echo "http_port 3128" >> "$SQUID_CONF"
|
||||
echo "http_port 127.0.0.1:3128" >> "$SQUID_CONF"
|
||||
echo "acl all src all" >> "$SQUID_CONF"
|
||||
|
||||
# Disable caching
|
||||
@@ -52,11 +52,11 @@ start_outgoing_proxy_if_needed() {
|
||||
echo "cache_swap_high 0" >> "$SQUID_CONF"
|
||||
|
||||
# Disable logs
|
||||
echo "access_log /tmp/test.log" >> "$SQUID_CONF"
|
||||
echo "access_log none" >> "$SQUID_CONF"
|
||||
echo "cache_store_log none" >> "$SQUID_CONF"
|
||||
echo "cache_log /dev/null" >> "$SQUID_CONF"
|
||||
echo "logfile_rotate 0" >> "$SQUID_CONF"
|
||||
echo "debug_options ALL,1" >> "$SQUID_CONF"
|
||||
echo "debug_options ALL,0" >> "$SQUID_CONF"
|
||||
|
||||
# Make it pass-through like
|
||||
echo "forwarded_for delete" >> "$SQUID_CONF"
|
||||
@@ -65,6 +65,10 @@ start_outgoing_proxy_if_needed() {
|
||||
echo "request_header_access Via deny all" >> "$SQUID_CONF"
|
||||
echo "request_header_access Cache-Control deny all" >> "$SQUID_CONF"
|
||||
|
||||
# Allow only local sources
|
||||
echo "acl localhost_src src 127.0.0.1" >> "$SQUID_CONF"
|
||||
echo "http_access deny !localhost_src" >> "$SQUID_CONF"
|
||||
|
||||
# Blocked IPs
|
||||
if [[ -n "${OUTGOING_BLOCKED_IPS:-}" ]]; then
|
||||
IFS=',' read -ra BLOCKED_IPS <<< "$OUTGOING_BLOCKED_IPS"
|
||||
|
||||
@@ -1 +1 @@
|
||||
module.exports = '2.0.2';
|
||||
module.exports = '2.1.0';
|
||||
|
||||
Reference in New Issue
Block a user