diff --git a/charts/planka/Chart.yaml b/charts/planka/Chart.yaml
index 470f805..02158c7 100644
--- a/charts/planka/Chart.yaml
+++ b/charts/planka/Chart.yaml
@@ -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: 0.1.24
+version: 0.1.26
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
-appVersion: "1.16.2"
+appVersion: "1.16.4"
dependencies:
- alias: postgresql
diff --git a/client/.env b/client/.env
index e17aeb7..1b48387 100644
--- a/client/.env
+++ b/client/.env
@@ -1 +1 @@
-REACT_APP_VERSION=1.16.2
+REACT_APP_VERSION=1.16.4
diff --git a/client/package-lock.json b/client/package-lock.json
index 62cebb9..b1e6907 100644
--- a/client/package-lock.json
+++ b/client/package-lock.json
@@ -17,6 +17,8 @@
"initials": "^3.1.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
+ "linkify-react": "^4.1.3",
+ "linkifyjs": "^4.1.3",
"lodash": "^4.17.21",
"nanoid": "^5.0.3",
"node-sass": "^9.0.0",
@@ -11911,6 +11913,20 @@
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
"integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg=="
},
+ "node_modules/linkify-react": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/linkify-react/-/linkify-react-4.1.3.tgz",
+ "integrity": "sha512-rhI3zM/fxn5BfRPHfi4r9N7zgac4vOIxub1wHIWXLA5ENTMs+BGaIaFO1D1PhmxgwhIKmJz3H7uCP0Dg5JwSlA==",
+ "peerDependencies": {
+ "linkifyjs": "^4.0.0",
+ "react": ">= 15.0.0"
+ }
+ },
+ "node_modules/linkifyjs": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/linkifyjs/-/linkifyjs-4.1.3.tgz",
+ "integrity": "sha512-auMesunaJ8yfkHvK4gfg1K0SaKX/6Wn9g2Aac/NwX+l5VdmFZzo/hdPGxEOETj+ryRa4/fiOPjeeKURSAJx1sg=="
+ },
"node_modules/loader-runner": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.3.0.tgz",
diff --git a/client/package.json b/client/package.json
index 25cdce0..3f3c4e1 100755
--- a/client/package.json
+++ b/client/package.json
@@ -70,6 +70,8 @@
"initials": "^3.1.2",
"js-cookie": "^3.0.5",
"jwt-decode": "^4.0.0",
+ "linkify-react": "^4.1.3",
+ "linkifyjs": "^4.1.3",
"lodash": "^4.17.21",
"nanoid": "^5.0.3",
"node-sass": "^9.0.0",
diff --git a/client/src/components/Card/Tasks.jsx b/client/src/components/Card/Tasks.jsx
index d76340f..c530474 100644
--- a/client/src/components/Card/Tasks.jsx
+++ b/client/src/components/Card/Tasks.jsx
@@ -4,6 +4,8 @@ import classNames from 'classnames';
import { Progress } from 'semantic-ui-react';
import { useToggle } from '../../lib/hooks';
+import Linkify from '../Linkify';
+
import styles from './Tasks.module.scss';
const Tasks = React.memo(({ items }) => {
@@ -48,7 +50,7 @@ const Tasks = React.memo(({ items }) => {
key={item.id}
className={classNames(styles.task, item.isCompleted && styles.taskCompleted)}
>
- {item.name}
+ {item.name}
))}
diff --git a/client/src/components/Card/Tasks.module.scss b/client/src/components/Card/Tasks.module.scss
index 508ac89..8f8a7ec 100644
--- a/client/src/components/Card/Tasks.module.scss
+++ b/client/src/components/Card/Tasks.module.scss
@@ -55,8 +55,10 @@
display: block;
font-size: 12px;
line-height: 14px;
+ overflow: hidden;
padding-bottom: 6px;
padding-left: 14px;
+ text-overflow: ellipsis;
&:before {
content: "–";
diff --git a/client/src/components/CardModal/Tasks/Item.jsx b/client/src/components/CardModal/Tasks/Item.jsx
index a34beb0..8bb3046 100755
--- a/client/src/components/CardModal/Tasks/Item.jsx
+++ b/client/src/components/CardModal/Tasks/Item.jsx
@@ -8,6 +8,7 @@ import { usePopup } from '../../../lib/popup';
import NameEdit from './NameEdit';
import ActionsStep from './ActionsStep';
+import Linkify from '../../Linkify';
import styles from './Item.module.scss';
@@ -65,7 +66,7 @@ const Item = React.memo(
onClick={handleClick}
>
- {name}
+ {name}
{isPersisted && canEdit && (
diff --git a/client/src/components/Linkify.jsx b/client/src/components/Linkify.jsx
new file mode 100644
index 0000000..71b01fd
--- /dev/null
+++ b/client/src/components/Linkify.jsx
@@ -0,0 +1,68 @@
+import React, { useCallback } from 'react';
+import PropTypes from 'prop-types';
+import LinkifyReact from 'linkify-react';
+
+import history from '../history';
+
+const Linkify = React.memo(({ children, linkStopPropagation, ...props }) => {
+ const handleLinkClick = useCallback(
+ (event) => {
+ if (linkStopPropagation) {
+ event.stopPropagation();
+ }
+
+ if (!event.target.getAttribute('target')) {
+ event.preventDefault();
+ history.push(event.target.href);
+ }
+ },
+ [linkStopPropagation],
+ );
+
+ const linkRenderer = useCallback(
+ ({ attributes: { href, ...linkProps }, content }) => {
+ let url;
+ try {
+ url = new URL(href, window.location);
+ } catch (error) {} // eslint-disable-line no-empty
+
+ const isSameSite = !!url && url.origin === window.location.origin;
+
+ return (
+
+ {isSameSite ? url.pathname : content}
+
+ );
+ },
+ [handleLinkClick],
+ );
+
+ return (
+
+ {children}
+
+ );
+});
+
+Linkify.propTypes = {
+ children: PropTypes.string.isRequired,
+ linkStopPropagation: PropTypes.bool,
+};
+
+Linkify.defaultProps = {
+ linkStopPropagation: false,
+};
+
+export default Linkify;
diff --git a/client/src/containers/LoginContainer.js b/client/src/containers/LoginContainer.js
index 881b65b..1a16788 100755
--- a/client/src/containers/LoginContainer.js
+++ b/client/src/containers/LoginContainer.js
@@ -20,7 +20,7 @@ const mapStateToProps = (state) => {
isSubmittingUsingOidc,
error,
withOidc: !!oidcConfig,
- isOidcEnforced: oidcConfig && oidcConfig.isEnforced,
+ isOidcEnforced: !!oidcConfig && oidcConfig.isEnforced,
};
};
diff --git a/config/development/Dockerfile.client b/config/development/Dockerfile.client
new file mode 100644
index 0000000..8a5ed92
--- /dev/null
+++ b/config/development/Dockerfile.client
@@ -0,0 +1,18 @@
+FROM node:18-alpine as server-dependencies
+
+RUN apk -U upgrade \
+ && apk add build-base python3 \
+ --no-cache
+
+WORKDIR /app/client
+COPY package.json package-lock.json /app/client/
+RUN npm install npm@latest --global \
+ && npm install pnpm --global \
+ && pnpm import \
+ && pnpm install
+
+
+WORKDIR /app/
+COPY ../../package.json ../../package-lock.json /app/
+RUN pnpm import \
+ && pnpm install
diff --git a/config/development/Dockerfile.server b/config/development/Dockerfile.server
new file mode 100644
index 0000000..0f51abe
--- /dev/null
+++ b/config/development/Dockerfile.server
@@ -0,0 +1,14 @@
+FROM node:18-alpine as server-dependencies
+
+RUN apk -U upgrade \
+ && apk add build-base python3 \
+ --no-cache
+
+WORKDIR /app
+
+COPY package.json package-lock.json ./
+
+RUN npm install npm@latest --global \
+ && npm install pnpm --global \
+ && pnpm import \
+ && pnpm install
diff --git a/config/development/nginx.conf b/config/development/nginx.conf
new file mode 100644
index 0000000..94fc7d7
--- /dev/null
+++ b/config/development/nginx.conf
@@ -0,0 +1,47 @@
+user nginx;
+worker_processes 1;
+
+events {
+ worker_connections 1024;
+}
+
+http {
+ include /etc/nginx/mime.types;
+ default_type application/octet-stream;
+
+ sendfile on;
+ keepalive_timeout 65;
+
+ server {
+ listen 80;
+
+ location /api/ {
+ proxy_pass http://server:1337;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+
+ location /socket.io {
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection "upgrade";
+ proxy_http_version 1.1;
+ proxy_set_header Host $host;
+ proxy_set_header X-Real-IP $remote_addr;
+ proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Proto $scheme;
+ proxy_pass http://server:1337/socket.io;
+ }
+
+ location / {
+ proxy_pass http://client:3000;
+ proxy_http_version 1.1;
+ proxy_set_header Upgrade $http_upgrade;
+ proxy_set_header Connection 'upgrade';
+ proxy_set_header Host $host;
+ proxy_cache_bypass $http_upgrade;
+ }
+ }
+}
diff --git a/docker-compose-dev.yml b/docker-compose-dev.yml
index 9fe7085..b44da1b 100644
--- a/docker-compose-dev.yml
+++ b/docker-compose-dev.yml
@@ -1,20 +1,18 @@
-version: '3'
+version: '3.8'
services:
- planka:
- image: ghcr.io/plankanban/planka:master
- restart: on-failure
+
+ server:
+ build:
+ context: ./server
+ dockerfile: ../config/development/Dockerfile.server
volumes:
- - user-avatars:/app/public/user-avatars
- - project-background-images:/app/public/project-background-images
- - attachments:/app/private/attachments
- ports:
- - 3000:1337
+ - ./server:/app
+ - /app/node_modules
environment:
- - BASE_URL=http://localhost:3000
- - DATABASE_URL=postgresql://postgres@postgres/planka
+ - NODE_ENV=development
+ - DATABASE_URL=postgresql://user:password@postgres:5432/planka_db
- SECRET_KEY=notsecretkey
-
# - TRUST_PROXY=0
# - TOKEN_EXPIRES_IN=365 # In days
@@ -31,14 +29,6 @@ services:
# - DEFAULT_ADMIN_NAME=Demo Demo
# - DEFAULT_ADMIN_USERNAME=demo
- # Email Notifications (https://nodemailer.com/smtp/)
- # - SMTP_HOST=
- # - SMTP_PORT=587
- # - SMTP_SECURE=true
- # - SMTP_USER=
- # - SMTP_PASSWORD=
- # - SMTP_FROM="Demo Demo"
-
# - OIDC_ISSUER=
# - OIDC_CLIENT_ID=
# - OIDC_CLIENT_SECRET=
@@ -51,26 +41,82 @@ services:
# - OIDC_IGNORE_USERNAME=true
# - OIDC_IGNORE_ROLES=true
# - OIDC_ENFORCED=true
+
+ # Email Notifications (https://nodemailer.com/smtp/)
+ # - SMTP_HOST=
+ # - SMTP_PORT=587
+ # - SMTP_SECURE=true
+ # - SMTP_USER=
+ # - SMTP_PASSWORD=
+ # - SMTP_FROM="Demo Demo"
+
+ # - SLACK_BOT_TOKEN=
+ # - SLACK_CHANNEL_ID=
+
+ working_dir: /app
+ command: ["sh", "-c", "npm run start"]
+ depends_on:
+ - init-db
+
+ client:
+ build:
+ context: ./client
+ dockerfile: ../config/development/Dockerfile.client
+ volumes:
+ - ./client:/app/client
+ - /app/client/node_modules
+ - /app/node_modules
+ environment:
+ - NODE_ENV=development
+ - CHOKIDAR_USEPOLLING=true
+ - BASE_URL=http://localhost:3000
+ - REACT_APP_SERVER_BASE_URL=http://localhost:3000
+ working_dir: /app/client
+ command: npm start
+
+ init-db:
+ build:
+ context: ./server
+ dockerfile: ../config/development/Dockerfile.server
+ environment:
+ - DATABASE_URL=postgresql://user:password@postgres:5432/planka_db
+
+ working_dir: /app
+ command: ["sh", "-c", "npm run db:init"]
+ volumes:
+ - ./server:/app
+ - /app/node_modules
depends_on:
postgres:
condition: service_healthy
postgres:
- image: postgres:14-alpine
- restart: on-failure
+ image: postgres:latest
volumes:
- db-data:/var/lib/postgresql/data
environment:
- - POSTGRES_DB=planka
- - POSTGRES_HOST_AUTH_METHOD=trust
+ POSTGRES_DB: planka_db
+ POSTGRES_USER: user
+ POSTGRES_PASSWORD: password
+ ports:
+ - "5432:5432"
+ restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres -d planka"]
interval: 10s
timeout: 5s
retries: 5
+ proxy:
+ image: nginx:alpine
+ ports:
+ - "3000:80"
+ volumes:
+ - ./config/development/nginx.conf:/etc/nginx/nginx.conf
+ depends_on:
+ - server
+ - client
+
+
volumes:
- user-avatars:
- project-background-images:
- attachments:
db-data:
diff --git a/package-lock.json b/package-lock.json
index eee91c9..9c2bff2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "planka",
- "version": "1.16.2",
+ "version": "1.16.4",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "planka",
- "version": "1.16.2",
+ "version": "1.16.4",
"hasInstallScript": true,
"license": "AGPL-3.0",
"dependencies": {
diff --git a/package.json b/package.json
index 7e06e77..dab2865 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "planka",
- "version": "1.16.2",
+ "version": "1.16.4",
"private": true,
"homepage": "https://plankanban.github.io/planka",
"repository": {
diff --git a/server/api/helpers/utils/send-email.js b/server/api/helpers/utils/send-email.js
index 7b8d08b..02593f8 100644
--- a/server/api/helpers/utils/send-email.js
+++ b/server/api/helpers/utils/send-email.js
@@ -23,9 +23,9 @@ module.exports = {
from: sails.config.custom.smtpFrom,
});
- sails.log.info('Email sent: %s', info.messageId);
+ sails.log.info(`Email sent: ${info.messageId}`);
} catch (error) {
- sails.log.error(error); // TODO: provide description text?
+ sails.log.error(`Error sending email: ${error}`);
}
},
};
diff --git a/server/api/helpers/utils/send-slack-message.js b/server/api/helpers/utils/send-slack-message.js
index 573fcf8..510ae1b 100644
--- a/server/api/helpers/utils/send-slack-message.js
+++ b/server/api/helpers/utils/send-slack-message.js
@@ -35,19 +35,19 @@ module.exports = {
body: JSON.stringify(body),
});
} catch (error) {
- sails.log.error(error); // TODO: provide description text?
+ sails.log.error(`Error sending to Slack: ${error}`);
return;
}
if (!response.ok) {
- sails.log.error('Error sending to Slack: %s', response.error);
+ sails.log.error(`Error sending to Slack: ${response.error}`);
return;
}
const responseJson = await response.json();
if (!responseJson.ok) {
- sails.log.error('Error sending to Slack: %s', responseJson.error);
+ sails.log.error(`Error sending to Slack: ${responseJson.error}`);
}
},
};