diff --git a/client/package-lock.json b/client/package-lock.json
index 62cebb94..b1e6907f 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 25cdce03..3f3c4e13 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 d76340fd..c5304749 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 508ac89f..8f8a7ec4 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 a34beb0d..8bb30462 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 00000000..71b01fdf
--- /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;