-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Fix: deletion and name updates of attachments in body reflected in Files #13169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix: deletion and name updates of attachments in body reflected in Files #13169
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PR Summary
Fixes critical attachment handling issues in the activity rich text editor by improving path comparison and name update functionality.
- Fixed unintended attachment deletion in
ActivityRichTextEditor.tsx
by properly handling JWT tokens in file paths during onChange events - Implemented attachment name synchronization between rich text editor and Files through new
getActivityAttachmentIdsAndNameToUpdate.ts
utility - Added path restoration logic in
getActivityAttachmentPathsToRestore.ts
to prevent accidental deletions when editing content - Consolidated attachment handling by renaming
getActivityAttachmentPaths.ts
togetActivityAttachmentPathsAndName.ts
with enhanced functionality - Extended test coverage with new test files specifically for attachment path handling and name updates
13 files reviewed, 19 comments
Edit PR Review Bot Settings | Greptile
const newActivityBody = JSON.stringify([ | ||
{ | ||
type: 'file', | ||
props: { url: '/files/images/test.txt' }, | ||
}, | ||
{ | ||
type: 'file', | ||
props: { url: '/files/images/test2.txt' }, | ||
}, | ||
]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Test data construction could be moved to a shared test helper function since it's duplicated in both test cases.
const oldActivityAttachments = [ | ||
{ | ||
id: '1', | ||
fullPath: '/files/attachment/test.txt', | ||
fullPath: '/files/images/test.txt', | ||
}, | ||
] as Attachment[]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider making test data reusable by moving it to a test fixtures file since it's used in multiple test files
const attachmentIdsToRestore = filterAttachmentsToRestore( | ||
['attachment/test.txt'], | ||
['images/test.txt'], | ||
softDeletedAttachments, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
logic: Test path is inconsistent with initial fullPath. Using 'images/test.txt' vs '/files/images/test.txt' might cause path matching issues in production.
packages/twenty-front/src/modules/activities/components/ActivityRichTextEditor.tsx
Outdated
Show resolved
Hide resolved
|
||
export const getActivityAttachmentIdsToDelete = ( | ||
newActivityBody: string, | ||
oldActivityAttachments: Attachment[] = [], | ||
oldActivityBody: string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: New required parameter 'oldActivityBody' should have a type annotation for consistency
packages/twenty-front/src/modules/activities/utils/getAttachmentPath.ts
Outdated
Show resolved
Hide resolved
packages/twenty-front/src/modules/activities/utils/getActivityAttachmentIdsAndNameToUpdate.ts
Outdated
Show resolved
Hide resolved
packages/twenty-front/src/modules/activities/utils/getActivityAttachmentIdsAndNameToUpdate.ts
Outdated
Show resolved
Hide resolved
return activityAttchmentsNameAndPaths.reduce( | ||
(acc: Partial<Attachment>[], activity: AttachmentInfo) => { | ||
const foundActivity = oldActivityAttachments.find( | ||
(attchment) => getAttachmentPath(attchment.fullPath) === activity.path, | ||
); | ||
if (isDefined(foundActivity) && foundActivity.name !== activity.name) { | ||
acc.push({ id: foundActivity.id, name: activity.name }); | ||
} | ||
return acc; | ||
}, | ||
[], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
style: Consider extracting this reduce operation into a separate utility function to improve readability and maintainability
🚀 Preview Environment Ready! Your preview environment is available at: http://bore.pub:12190 This environment will automatically shut down when the PR is closed or after 5 hours. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM nice work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@omarNaifer12 Could you please handle the case of embedded media ? Also please split the utils, because the code would be more easy to maintain with small utils, one for parsing and Attachment fullPath, one for parsing a URL.
…on in Files and update related tests
37e3e34
to
3b462c6
Compare
Thanks @lucasbordeau for catching this case. I added the compareUrls function to check if two URLs have the same domain and path. |
Hey @lucasbordeau could you please re-review this PR when you have some free time please ? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
Thanks @omarNaifer12 for your contribution! |
…les (#13169) resolve #13168 , #8501 This PR fixes an issue where the onChange trigger was deleting all attachments by removing the JWT token from their paths (if it existed) and comparing the new body with the old body to identify deleted attachments. It ensures that only attachments actually removed from the body get deleted, preventing unintended deletion of attachments not added directly through the body. It also handles updating attachment names in the body so changes are reflected in Files, with related tests updated accordingly. https://github.com/user-attachments/assets/8d824a24-b257-4794-942e-3b2dceb9907d --------- Co-authored-by: Lucas Bordeau <bordeau.lucas@gmail.com>
@lucasbordeau I have a quick question: this PR syncs body changes to files. If we update or remove directly from files, does it also reflect in the body? |
@omarNaifer12 Indeed we could also handle that the other way around, if that's not too complex with the existing utils ? |
I did a small investigation, and I think we might only need to use the compareUrls utility and apply filtering to the entire block note body.We also need to extract the record (either task or note) that is opened on the record page or in the side panel. |
Ok, from what I know, that seems a bit nice to have for now, you could certainly find something more important to contribute to. |
resolve #13168 , #8501
This PR fixes an issue where the onChange trigger was deleting all attachments by removing the JWT token from their paths (if it existed) and comparing the new body with the old body to identify deleted attachments. It ensures that only attachments actually removed from the body get deleted, preventing unintended deletion of attachments not added directly through the body. It also handles updating attachment names in the body so changes are reflected in Files, with related tests updated accordingly.
ByStatus-Tasks-Personal-MicrosoftEdge2025-07-1022-29-26-ezgif.com-crop-video.mp4