diff --git a/components/email/__tests__/composer-account-switch.test.tsx b/components/email/__tests__/composer-account-switch.test.tsx index 9914ff30b..a5dfc270e 100644 --- a/components/email/__tests__/composer-account-switch.test.tsx +++ b/components/email/__tests__/composer-account-switch.test.tsx @@ -140,6 +140,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-attach-from-files.test.tsx b/components/email/__tests__/composer-attach-from-files.test.tsx index db41fe94f..475634773 100644 --- a/components/email/__tests__/composer-attach-from-files.test.tsx +++ b/components/email/__tests__/composer-attach-from-files.test.tsx @@ -151,6 +151,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-attachment-list-scroll.test.tsx b/components/email/__tests__/composer-attachment-list-scroll.test.tsx index 76b508546..af1d5673f 100644 --- a/components/email/__tests__/composer-attachment-list-scroll.test.tsx +++ b/components/email/__tests__/composer-attachment-list-scroll.test.tsx @@ -133,6 +133,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-close-guard.test.tsx b/components/email/__tests__/composer-close-guard.test.tsx index 7c0b892ff..e934e97ee 100644 --- a/components/email/__tests__/composer-close-guard.test.tsx +++ b/components/email/__tests__/composer-close-guard.test.tsx @@ -134,6 +134,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-discard.test.tsx b/components/email/__tests__/composer-discard.test.tsx index 9fa0f28dd..ae7e06c9d 100644 --- a/components/email/__tests__/composer-discard.test.tsx +++ b/components/email/__tests__/composer-discard.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-draft-attachments.test.tsx b/components/email/__tests__/composer-draft-attachments.test.tsx index d14cf789a..460acd1de 100644 --- a/components/email/__tests__/composer-draft-attachments.test.tsx +++ b/components/email/__tests__/composer-draft-attachments.test.tsx @@ -132,6 +132,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-format-toggle.test.tsx b/components/email/__tests__/composer-format-toggle.test.tsx index b70d7bbac..28f3f029c 100644 --- a/components/email/__tests__/composer-format-toggle.test.tsx +++ b/components/email/__tests__/composer-format-toggle.test.tsx @@ -137,6 +137,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-forward-other-account.test.tsx b/components/email/__tests__/composer-forward-other-account.test.tsx index a0957a0b0..087f5cf34 100644 --- a/components/email/__tests__/composer-forward-other-account.test.tsx +++ b/components/email/__tests__/composer-forward-other-account.test.tsx @@ -143,6 +143,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-from-override-envelope.test.tsx b/components/email/__tests__/composer-from-override-envelope.test.tsx index b203296ed..778a2c1c3 100644 --- a/components/email/__tests__/composer-from-override-envelope.test.tsx +++ b/components/email/__tests__/composer-from-override-envelope.test.tsx @@ -136,6 +136,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-mention.test.tsx b/components/email/__tests__/composer-mention.test.tsx index 7b0c84ae1..c79d871a0 100644 --- a/components/email/__tests__/composer-mention.test.tsx +++ b/components/email/__tests__/composer-mention.test.tsx @@ -138,6 +138,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-mobile-formatting.test.tsx b/components/email/__tests__/composer-mobile-formatting.test.tsx index bc58092c1..241a18bfb 100644 --- a/components/email/__tests__/composer-mobile-formatting.test.tsx +++ b/components/email/__tests__/composer-mobile-formatting.test.tsx @@ -138,6 +138,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-mv-window.test.tsx b/components/email/__tests__/composer-mv-window.test.tsx index 9039805f8..739d76da7 100644 --- a/components/email/__tests__/composer-mv-window.test.tsx +++ b/components/email/__tests__/composer-mv-window.test.tsx @@ -139,6 +139,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-plugin-attachment-source.test.tsx b/components/email/__tests__/composer-plugin-attachment-source.test.tsx index 03af74276..7128bf0b9 100644 --- a/components/email/__tests__/composer-plugin-attachment-source.test.tsx +++ b/components/email/__tests__/composer-plugin-attachment-source.test.tsx @@ -162,6 +162,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-plugin-send.test.tsx b/components/email/__tests__/composer-plugin-send.test.tsx index bd9b1fbf8..308d766b7 100644 --- a/components/email/__tests__/composer-plugin-send.test.tsx +++ b/components/email/__tests__/composer-plugin-send.test.tsx @@ -141,6 +141,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-recipient-validation.test.tsx b/components/email/__tests__/composer-recipient-validation.test.tsx index a9bb763f3..de2414ee6 100644 --- a/components/email/__tests__/composer-recipient-validation.test.tsx +++ b/components/email/__tests__/composer-recipient-validation.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-reopened-draft-signature.test.tsx b/components/email/__tests__/composer-reopened-draft-signature.test.tsx index 97f25953e..3ddd45a2f 100644 --- a/components/email/__tests__/composer-reopened-draft-signature.test.tsx +++ b/components/email/__tests__/composer-reopened-draft-signature.test.tsx @@ -138,6 +138,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-reply-draft-threading.test.tsx b/components/email/__tests__/composer-reply-draft-threading.test.tsx index 3ba0edceb..2e34434c0 100644 --- a/components/email/__tests__/composer-reply-draft-threading.test.tsx +++ b/components/email/__tests__/composer-reply-draft-threading.test.tsx @@ -138,6 +138,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-reply-focus.test.tsx b/components/email/__tests__/composer-reply-focus.test.tsx index b7d4ccacc..62bb0752e 100644 --- a/components/email/__tests__/composer-reply-focus.test.tsx +++ b/components/email/__tests__/composer-reply-focus.test.tsx @@ -145,6 +145,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-schedule-presets.test.tsx b/components/email/__tests__/composer-schedule-presets.test.tsx index 07bcc2f0b..954f7507c 100644 --- a/components/email/__tests__/composer-schedule-presets.test.tsx +++ b/components/email/__tests__/composer-schedule-presets.test.tsx @@ -143,6 +143,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-send-errors.test.tsx b/components/email/__tests__/composer-send-errors.test.tsx index 13e53fd23..5e791f620 100644 --- a/components/email/__tests__/composer-send-errors.test.tsx +++ b/components/email/__tests__/composer-send-errors.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-send-unmount.test.tsx b/components/email/__tests__/composer-send-unmount.test.tsx index 2aac397d1..2bd02d5e7 100644 --- a/components/email/__tests__/composer-send-unmount.test.tsx +++ b/components/email/__tests__/composer-send-unmount.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-short-pane.test.tsx b/components/email/__tests__/composer-short-pane.test.tsx index 243415f75..db39437d4 100644 --- a/components/email/__tests__/composer-short-pane.test.tsx +++ b/components/email/__tests__/composer-short-pane.test.tsx @@ -133,6 +133,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-title.test.tsx b/components/email/__tests__/composer-title.test.tsx index 78fbcbd1d..8f5e80ee9 100644 --- a/components/email/__tests__/composer-title.test.tsx +++ b/components/email/__tests__/composer-title.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/composer-upload-account.test.tsx b/components/email/__tests__/composer-upload-account.test.tsx index 229912d63..d5a9ab085 100644 --- a/components/email/__tests__/composer-upload-account.test.tsx +++ b/components/email/__tests__/composer-upload-account.test.tsx @@ -144,6 +144,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/empty-subject-warning.test.tsx b/components/email/__tests__/empty-subject-warning.test.tsx index a62b67891..4908bc2b9 100644 --- a/components/email/__tests__/empty-subject-warning.test.tsx +++ b/components/email/__tests__/empty-subject-warning.test.tsx @@ -142,6 +142,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/recipient-autocomplete.test.tsx b/components/email/__tests__/recipient-autocomplete.test.tsx index 97c1eb937..af1feb66d 100644 --- a/components/email/__tests__/recipient-autocomplete.test.tsx +++ b/components/email/__tests__/recipient-autocomplete.test.tsx @@ -137,6 +137,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/recipient-chip-drag.test.tsx b/components/email/__tests__/recipient-chip-drag.test.tsx index bfdac74c7..058916079 100644 --- a/components/email/__tests__/recipient-chip-drag.test.tsx +++ b/components/email/__tests__/recipient-chip-drag.test.tsx @@ -130,6 +130,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/recipient-paste.test.tsx b/components/email/__tests__/recipient-paste.test.tsx index 5863db954..3d8a80ca9 100644 --- a/components/email/__tests__/recipient-paste.test.tsx +++ b/components/email/__tests__/recipient-paste.test.tsx @@ -129,6 +129,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/__tests__/reply-addressing.test.tsx b/components/email/__tests__/reply-addressing.test.tsx index bec2f195b..86330916b 100644 --- a/components/email/__tests__/reply-addressing.test.tsx +++ b/components/email/__tests__/reply-addressing.test.tsx @@ -158,6 +158,14 @@ vi.mock('@/stores/toast-store', () => ({ })); vi.mock('@/lib/plugin-hooks', () => ({ + identityHooks: { + onSignatureRender: { size: 0, transform: async (value: unknown) => value }, + onIdentitySelect: { size: 0, emit: async () => {} }, + }, + templateHooks: { + onTemplateRender: { size: 0, transform: async (value: unknown) => value }, + onTemplateApply: { size: 0, emit: async () => {} }, + }, emailHooks: { onComposerOpen: { call: async () => [] }, onRecipientChange: { call: async () => [] }, diff --git a/components/email/email-composer.tsx b/components/email/email-composer.tsx index cb045cb38..9c7e2cc38 100644 --- a/components/email/email-composer.tsx +++ b/components/email/email-composer.tsx @@ -70,6 +70,8 @@ import type { IJMAPClient } from "@/lib/jmap/client-interface"; import type { FileNode } from "@/lib/jmap/types"; import { useContactStore, getContactDisplayName, getContactPrimaryEmail } from "@/stores/contact-store"; import { useTemplateStore } from "@/stores/template-store"; +import { notifyIdentitySelected } from "@/stores/identity-store"; +import { usePluginSignature } from "@/hooks/use-plugin-signature"; import { SubAddressHelper } from "@/components/identity/sub-address-helper"; import { generateSubAddress } from "@/lib/sub-addressing"; import { substitutePlaceholders, spliceTemplateAboveSignature, composeBodyHasUserContent } from "@/lib/template-utils"; @@ -886,9 +888,11 @@ export function EmailComposer({ // Alias identities often lack a configured signature - fall back to the primary // identity's signature so replies (which auto-select a matching alias) still // populate the user's signature. - const signatureIdentity = (currentIdentity?.htmlSignature || currentIdentity?.textSignature) + const ownSignatureIdentity = (currentIdentity?.htmlSignature || currentIdentity?.textSignature) ? currentIdentity : primaryIdentity; + // Plugins may rewrite the signature (onSignatureRender). + const { identity: signatureIdentity, revision: pluginSignatureRevision } = usePluginSignature(ownSignatureIdentity); // Hold the TipTap editor instance so we can swap the embedded signature // when the user switches identity in "above quote" mode without rebuilding @@ -899,15 +903,18 @@ export function EmailComposer({ const replyFocusedRef = useRef(false); const prevSignatureIdentityIdRef = useRef(signatureIdentity?.id); const prevSignatureSeparatorRef = useRef(signatureSeparatorEnabled); + const prevPluginSignatureRevisionRef = useRef(pluginSignatureRevision); useEffect(() => { const editor = editorRef.current; const identityChanged = prevSignatureIdentityIdRef.current !== signatureIdentity?.id; const separatorChanged = prevSignatureSeparatorRef.current !== signatureSeparatorEnabled; + const pluginSignatureChanged = prevPluginSignatureRevisionRef.current !== pluginSignatureRevision; prevSignatureIdentityIdRef.current = signatureIdentity?.id; prevSignatureSeparatorRef.current = signatureSeparatorEnabled; + prevPluginSignatureRevisionRef.current = pluginSignatureRevision; if (!editor) return; - if (!identityChanged && !separatorChanged) return; + if (!identityChanged && !separatorChanged && !pluginSignatureChanged) return; if (plainTextMode) return; // Replies/forwards only embed when configured for "above quote". Compose // always embeds (see getInitialBody), so swap on identity change there too. @@ -945,7 +952,7 @@ export function EmailComposer({ // would re-run on unrelated identity-field changes and re-splice the // signature into the live editor. // eslint-disable-next-line react-hooks/exhaustive-deps - }, [signatureIdentity?.id, signatureIdentity?.htmlSignature, signatureIdentity?.textSignature, signatureSeparatorEnabled, signaturePosition, mode, plainTextMode]); + }, [signatureIdentity?.id, signatureIdentity?.htmlSignature, signatureIdentity?.textSignature, signatureSeparatorEnabled, signaturePosition, mode, plainTextMode, pluginSignatureRevision]); useEffect(() => { const handleClickOutsideSendMenu = (event: MouseEvent) => { @@ -3248,7 +3255,10 @@ export function EmailComposer({