delete attachment when file is removed from activity body (#11952)

Using useEffect triggered at ActivityRichTextEditor unmount, to delete
attachments only when note is closed (and not when file block is deleted
during note update to keep command + z shortcut)

closes : https://github.com/twentyhq/twenty/issues/11229
This commit is contained in:
Etienne
2025-05-13 19:18:38 +02:00
committed by GitHub
parent 3fe9c79967
commit c0a0214879
13 changed files with 347 additions and 13 deletions

View File

@ -20,9 +20,16 @@ import { useDebouncedCallback } from 'use-debounce';
import { BLOCK_SCHEMA } from '@/activities/blocks/constants/Schema';
import { ActivityRichTextEditorChangeOnActivityIdEffect } from '@/activities/components/ActivityRichTextEditorChangeOnActivityIdEffect';
import { Attachment } from '@/activities/files/types/Attachment';
import { Note } from '@/activities/types/Note';
import { Task } from '@/activities/types/Task';
import { filterAttachmentsToRestore } from '@/activities/utils/filterAttachmentsToRestore';
import { getActivityAttachmentIdsToDelete } from '@/activities/utils/getActivityAttachmentIdsToDelete';
import { getActivityAttachmentPathsToRestore } from '@/activities/utils/getActivityAttachmentPathsToRestore';
import { CommandMenuHotkeyScope } from '@/command-menu/types/CommandMenuHotkeyScope';
import { useDeleteManyRecords } from '@/object-record/hooks/useDeleteManyRecords';
import { useLazyFetchAllRecords } from '@/object-record/hooks/useLazyFetchAllRecords';
import { useRestoreManyRecords } from '@/object-record/hooks/useRestoreManyRecords';
import { useIsRecordReadOnly } from '@/object-record/record-field/hooks/useIsRecordReadOnly';
import { BlockEditor } from '@/ui/input/editor/components/BlockEditor';
import { PartialBlock } from '@blocknote/core';
@ -40,6 +47,10 @@ type ActivityRichTextEditorProps = {
| CoreObjectNameSingular.Note;
};
type Activity = (Task | Note) & {
attachments: Attachment[];
};
export const ActivityRichTextEditor = ({
activityId,
activityObjectNameSingular,
@ -61,6 +72,24 @@ export const ActivityRichTextEditor = ({
isRecordReadOnly,
});
const { deleteManyRecords: deleteAttachments } = useDeleteManyRecords({
objectNameSingular: CoreObjectNameSingular.Attachment,
});
const { restoreManyRecords: restoreAttachments } = useRestoreManyRecords({
objectNameSingular: CoreObjectNameSingular.Attachment,
});
const { fetchAllRecords: findSoftDeletedAttachments } =
useLazyFetchAllRecords({
objectNameSingular: CoreObjectNameSingular.Attachment,
filter: {
deletedAt: {
is: 'NOT_NULL',
},
},
});
const {
goBackToPreviousHotkeyScope,
setHotkeyScopeAndMemorizePreviousScope,
@ -137,8 +166,12 @@ export const ActivityRichTextEditor = ({
);
const handleBodyChange = useRecoilCallback(
({ set }) =>
(newStringifiedBody: string) => {
({ set, snapshot }) =>
async (newStringifiedBody: string) => {
const oldActivity = snapshot
.getLoadable(recordStoreFamilyState(activityId))
.getValue() as Activity;
set(recordStoreFamilyState(activityId), (oldActivity) => {
return {
...oldActivity,
@ -166,8 +199,46 @@ export const ActivityRichTextEditor = ({
});
handlePersistBody(newStringifiedBody);
const attachmentIdsToDelete = getActivityAttachmentIdsToDelete(
newStringifiedBody,
oldActivity.attachments,
);
if (attachmentIdsToDelete.length > 0) {
await deleteAttachments({
recordIdsToDelete: attachmentIdsToDelete,
});
}
const attachmentPathsToRestore = getActivityAttachmentPathsToRestore(
newStringifiedBody,
oldActivity.attachments,
);
if (attachmentPathsToRestore.length > 0) {
const softDeletedAttachments =
(await findSoftDeletedAttachments()) as Attachment[];
const attachmentIdsToRestore = filterAttachmentsToRestore(
attachmentPathsToRestore,
softDeletedAttachments,
);
await restoreAttachments({
idsToRestore: attachmentIdsToRestore,
});
}
},
[activityId, cache, objectMetadataItemActivity, handlePersistBody],
[
activityId,
cache,
objectMetadataItemActivity,
handlePersistBody,
deleteAttachments,
restoreAttachments,
findSoftDeletedAttachments,
],
);
const handleBodyChangeDebounced = useDebouncedCallback(handleBodyChange, 500);