authorgravatar for 91240327+shivamhwp@users.noreply.github.comshivam <91240327+shivamhwp@users.noreply.github.com> 2026-03-24 05:40:23+05:30
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-03-23 17:10:23-07:00
loge11fb6e778456a98e0066894bfb572864f98bb20
tree5e1e52d10df53f87a245119be4e2c120aea7611a
parentd415558915f3a06e92ce7e46acc07fce69374ea6
signature Signed by PGP key B5690EEEBB952194

fix(web): avoid false draft attachment persistence warnings (#1153)


1 files changed, 48 insertions(+), 26 deletions(-)

apps/web/src/composerDraftStore.ts+48-26
...@@ -846,6 +846,53 @@ function readPersistedAttachmentIdsFromStorage(threadId: ThreadId): string[] {...@@ -846,6 +846,53 @@ function readPersistedAttachmentIdsFromStorage(threadId: ThreadId): string[] {
846 }846 }
847}847}
848848
849function verifyPersistedAttachments(
850 threadId: ThreadId,
851 attachments: PersistedComposerImageAttachment[],
852 set: (
853 partial:
854 | ComposerDraftStoreState
855 | Partial<ComposerDraftStoreState>
856 | ((
857 state: ComposerDraftStoreState,
858 ) => ComposerDraftStoreState | Partial<ComposerDraftStoreState>),
859 replace?: false,
860 ) => void,
861): void {
862 let persistedIdSet = new Set<string>();
863 try {
864 composerDebouncedStorage.flush();
865 persistedIdSet = new Set(readPersistedAttachmentIdsFromStorage(threadId));
866 } catch {
867 persistedIdSet = new Set();
868 }
869 set((state) => {
870 const current = state.draftsByThreadId[threadId];
871 if (!current) {
872 return state;
873 }
874 const imageIdSet = new Set(current.images.map((image) => image.id));
875 const persistedAttachments = attachments.filter(
876 (attachment) => imageIdSet.has(attachment.id) && persistedIdSet.has(attachment.id),
877 );
878 const nonPersistedImageIds = current.images
879 .map((image) => image.id)
880 .filter((imageId) => !persistedIdSet.has(imageId));
881 const nextDraft: ComposerThreadDraftState = {
882 ...current,
883 persistedAttachments,
884 nonPersistedImageIds,
885 };
886 const nextDraftsByThreadId = { ...state.draftsByThreadId };
887 if (shouldRemoveDraft(nextDraft)) {
888 delete nextDraftsByThreadId[threadId];
889 } else {
890 nextDraftsByThreadId[threadId] = nextDraft;
891 }
892 return { draftsByThreadId: nextDraftsByThreadId };
893 });
894}
895
849function hydreatePersistedComposerImageAttachment(896function hydreatePersistedComposerImageAttachment(
850 attachment: PersistedComposerImageAttachment,897 attachment: PersistedComposerImageAttachment,
851): File | null {898): File | null {
...@@ -1662,32 +1709,7 @@ export const useComposerDraftStore = create<ComposerDraftStoreState>()(...@@ -1662,32 +1709,7 @@ export const useComposerDraftStore = create<ComposerDraftStoreState>()(
1662 return { draftsByThreadId: nextDraftsByThreadId };1709 return { draftsByThreadId: nextDraftsByThreadId };
1663 });1710 });
1664 Promise.resolve().then(() => {1711 Promise.resolve().then(() => {
1665 const persistedIdSet = new Set(readPersistedAttachmentIdsFromStorage(threadId));1712 verifyPersistedAttachments(threadId, attachments, set);
1666 set((state) => {
1667 const current = state.draftsByThreadId[threadId];
1668 if (!current) {
1669 return state;
1670 }
1671 const imageIdSet = new Set(current.images.map((image) => image.id));
1672 const persistedAttachments = attachments.filter(
1673 (attachment) => imageIdSet.has(attachment.id) && persistedIdSet.has(attachment.id),
1674 );
1675 const nonPersistedImageIds = current.images
1676 .map((image) => image.id)
1677 .filter((imageId) => !persistedIdSet.has(imageId));
1678 const nextDraft: ComposerThreadDraftState = {
1679 ...current,
1680 persistedAttachments,
1681 nonPersistedImageIds,
1682 };
1683 const nextDraftsByThreadId = { ...state.draftsByThreadId };
1684 if (shouldRemoveDraft(nextDraft)) {
1685 delete nextDraftsByThreadId[threadId];
1686 } else {
1687 nextDraftsByThreadId[threadId] = nextDraft;
1688 }
1689 return { draftsByThreadId: nextDraftsByThreadId };
1690 });
1691 });1713 });
1692 },1714 },
1693 clearComposerContent: (threadId) => {1715 clearComposerContent: (threadId) => {