fix(email threads): linkify Email body so that URL links are properly formatted (#16415)

Closes #16396

Added [linkify-react](https://www.npmjs.com/package/linkify-react) and
[linkifyjs](https://www.npmjs.com/package/linkifyjs?activeTab=versions)
to dependancies.
Both are widely used libraries with millions of weekly downloads. 
Both of them have 0 dependancies on other packages, so should be safe to
use.

### Before
URLs were shown as plain text

<img width="395" height="699" alt="Screenshot 2025-12-09 at 12 25 03 PM"
src="https://github.com/user-attachments/assets/772e6d03-8c48-45a1-985c-f775bbd3465c"
/>


### After
URLs are shown as link and are clickable now.

<img width="367" height="641" alt="Screenshot 2025-12-09 at 2 50 29 PM"
src="https://github.com/user-attachments/assets/d15bf23a-7cae-4cd4-b9da-e99706c7db38"
/>

<img width="376" height="656" alt="Screenshot 2025-12-09 at 2 50 46 PM"
src="https://github.com/user-attachments/assets/ba112a65-7550-47e3-b42f-83b94c08bfa6"
/>

---------

Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
This commit is contained in:
Abhishek Kumar 2025-12-30 22:19:31 +05:30 committed by GitHub
parent 64d75d0b79
commit 61addf8b62
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 38 additions and 2 deletions

View file

@ -88,6 +88,8 @@
"json-2-csv": "^5.4.0",
"json-logic-js": "^2.0.5",
"jwt-decode": "^4.0.0",
"linkify-react": "^4.1.3",
"linkifyjs": "^4.1.3",
"qs": "^6.11.2",
"react-data-grid": "7.0.0-beta.13",
"react-datepicker": "^6.7.1",

View file

@ -1,5 +1,6 @@
import styled from '@emotion/styled';
import { motion } from 'framer-motion';
import Linkify from 'linkify-react';
import { AnimatedEaseInOut } from 'twenty-ui/utilities';
const StyledThreadMessageBody = styled(motion.div)`
@ -9,6 +10,18 @@ const StyledThreadMessageBody = styled(motion.div)`
margin-top: ${({ theme }) => theme.spacing(4)};
white-space: pre-line;
overflow-wrap: break-word;
a {
color: ${({ theme }) => theme.font.color.primary};
text-decoration: underline;
text-decoration-color: ${({ theme }) => theme.font.color.primary};
&:hover {
color: ${({ theme }) => theme.font.color.tertiary};
text-decoration-color: ${({ theme }) => theme.border.color.strong};
}
}
`;
type EmailThreadMessageBodyProps = {
@ -22,7 +35,16 @@ export const EmailThreadMessageBody = ({
}: EmailThreadMessageBodyProps) => {
return (
<AnimatedEaseInOut isOpen={isDisplayed} duration="fast">
<StyledThreadMessageBody>{body}</StyledThreadMessageBody>
<StyledThreadMessageBody>
<Linkify
options={{
target: '_blank',
rel: 'noopener noreferrer',
}}
>
{body}
</Linkify>
</StyledThreadMessageBody>
</AnimatedEaseInOut>
);
};

View file

@ -42669,7 +42669,17 @@ __metadata:
languageName: node
linkType: hard
"linkifyjs@npm:^4.2.0, linkifyjs@npm:^4.3.2":
"linkify-react@npm:^4.1.3":
version: 4.3.2
resolution: "linkify-react@npm:4.3.2"
peerDependencies:
linkifyjs: ^4.0.0
react: ">= 15.0.0"
checksum: 10c0/6f1e5fa28129bfa2c9fe7568a63c4cc8453cfa7de9f401a33b9bf6826b8d7ecccbb054cfe54c0b3f7c39d36b410189a9adcf438667c3e6443afda8bd2e4b36df
languageName: node
linkType: hard
"linkifyjs@npm:^4.1.3, linkifyjs@npm:^4.2.0, linkifyjs@npm:^4.3.2":
version: 4.3.2
resolution: "linkifyjs@npm:4.3.2"
checksum: 10c0/1a85e6b368304a4417567fe5e38651681e3e82465590836942d1b4f3c834cc35532898eb1e2479f6337d9144b297d418eb708b6be8ed0b3dc3954a3588e07971
@ -56708,6 +56718,8 @@ __metadata:
json-2-csv: "npm:^5.4.0"
json-logic-js: "npm:^2.0.5"
jwt-decode: "npm:^4.0.0"
linkify-react: "npm:^4.1.3"
linkifyjs: "npm:^4.1.3"
monaco-editor: "npm:^0.51.0"
monaco-editor-auto-typings: "npm:^0.4.5"
optionator: "npm:^0.9.1"