Skip to content

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

Merged
merged 9 commits into from
Jul 23, 2025

Conversation

omarNaifer12
Copy link
Contributor

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

Copy link
Contributor

@greptile-apps greptile-apps bot left a 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 to getActivityAttachmentPathsAndName.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

Comment on lines 16 to 25
const newActivityBody = JSON.stringify([
{
type: 'file',
props: { url: '/files/images/test.txt' },
},
{
type: 'file',
props: { url: '/files/images/test2.txt' },
},
]);
Copy link
Contributor

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.

Comment on lines 11 to 16
const oldActivityAttachments = [
{
id: '1',
fullPath: '/files/attachment/test.txt',
fullPath: '/files/images/test.txt',
},
] as Attachment[];
Copy link
Contributor

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

Comment on lines 38 to 40
const attachmentIdsToRestore = filterAttachmentsToRestore(
['attachment/test.txt'],
['images/test.txt'],
softDeletedAttachments,
Copy link
Contributor

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.


export const getActivityAttachmentIdsToDelete = (
newActivityBody: string,
oldActivityAttachments: Attachment[] = [],
oldActivityBody: string,
Copy link
Contributor

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

Comment on lines 17 to 27
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;
},
[],
Copy link
Contributor

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

Copy link
Contributor

github-actions bot commented Jul 10, 2025

🚀 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.

@lucasbordeau lucasbordeau self-requested a review July 16, 2025 13:53
Copy link
Contributor

@lucasbordeau lucasbordeau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM nice work

@lucasbordeau lucasbordeau enabled auto-merge (squash) July 16, 2025 15:31
@lucasbordeau lucasbordeau disabled auto-merge July 16, 2025 15:32
Copy link
Contributor

@lucasbordeau lucasbordeau left a 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.

@omarNaifer12 omarNaifer12 force-pushed the fix/attachment-deletion branch from 37e3e34 to 3b462c6 Compare July 17, 2025 12:48
@omarNaifer12
Copy link
Contributor Author

Thanks @lucasbordeau for catching this case. I added the compareUrls function to check if two URLs have the same domain and path.

@prastoin
Copy link
Contributor

Hey @lucasbordeau could you please re-review this PR when you have some free time please ?

@prastoin prastoin requested a review from lucasbordeau July 21, 2025 15:28
Copy link
Contributor

@lucasbordeau lucasbordeau left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@lucasbordeau lucasbordeau merged commit dd5ae66 into twentyhq:main Jul 23, 2025
51 checks passed
Copy link
Contributor

Thanks @omarNaifer12 for your contribution!
This marks your 12th PR on the repo. You're top 3% of all our contributors 🎉
See contributor page - Share on LinkedIn - Share on Twitter

Contributions

@omarNaifer12 omarNaifer12 deleted the fix/attachment-deletion branch July 24, 2025 11:39
prastoin pushed a commit that referenced this pull request Jul 24, 2025
…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>
@omarNaifer12
Copy link
Contributor Author

@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?

@lucasbordeau
Copy link
Contributor

lucasbordeau commented Jul 28, 2025

@omarNaifer12 Indeed we could also handle that the other way around, if that's not too complex with the existing utils ?

@omarNaifer12
Copy link
Contributor Author

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.

@lucasbordeau
Copy link
Contributor

Ok, from what I know, that seems a bit nice to have for now, you could certainly find something more important to contribute to.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Attachments in Task/Note should not be deleted from Files when onChange mode is triggered
5 participants