mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-10-31 00:12:39 +00:00
fix: give large attachment offloads time to finish and let cloud pickers write links into the text
This commit is contained in:
@@ -271,6 +271,15 @@ describe('composer-above-body and composer-below-body', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('let a cloud picker put share links into the text', () => {
|
||||
offerSlots('p1', ['composer-attachment-source']);
|
||||
render(<EmailComposer initialData={DRAFT} onClose={vi.fn()} />);
|
||||
|
||||
const props = lastSlotProps('composer-attachment-source');
|
||||
expect(typeof props.onAttach).toBe('function');
|
||||
expect(typeof props.insertText).toBe('function');
|
||||
});
|
||||
|
||||
it('draw nothing without a plugin', () => {
|
||||
const { container } = render(<EmailComposer initialData={DRAFT} onClose={vi.fn()} />);
|
||||
expect(container.querySelector('[data-plugin-slot="composer-above-body"]')).toBeNull();
|
||||
|
||||
@@ -2070,7 +2070,6 @@ export function EmailComposer({
|
||||
}, [composerClient, t]);
|
||||
// Stable props, so a re-render of the composer doesn't post them to the
|
||||
// plugin's iframe again.
|
||||
const pluginAttachmentSourceProps = useMemo(() => ({ onAttach: handlePluginAttachmentAdd }), [handlePluginAttachmentAdd]);
|
||||
const pluginToolbarOffers = usePluginSlotOffers('composer-toolbar');
|
||||
const pluginAttachmentSourceOffers = usePluginSlotOffers('composer-attachment-source');
|
||||
const hasAboveBodyOffers = usePluginSlotOffers('composer-above-body').length > 0;
|
||||
@@ -2469,6 +2468,11 @@ export function EmailComposer({
|
||||
() => ({ insertText: pluginInsertText, getSelectedText: pluginSelectedText }),
|
||||
[pluginInsertText, pluginSelectedText],
|
||||
);
|
||||
// A cloud picker attaches files, or puts share links in the text.
|
||||
const pluginAttachmentSourceProps = useMemo(
|
||||
() => ({ onAttach: handlePluginAttachmentAdd, insertText: pluginInsertText }),
|
||||
[handlePluginAttachmentAdd, pluginInsertText],
|
||||
);
|
||||
const sendMenuContext = useCallback(() => ({ draft: draftSnapshotRef.current() }), []);
|
||||
|
||||
// Trigger auto-save when content changes (only if user modified something)
|
||||
|
||||
+6
-5
@@ -63,11 +63,12 @@ const DEFAULT_TIMEOUT_MS = 5000;
|
||||
// reply-all, mailto, attachment upload), so they need a much longer budget
|
||||
// than observer / transform hooks.
|
||||
const INTERCEPT_TIMEOUT_MS = 60_000;
|
||||
// onBeforeBlobUpload handlers may push the attachment to an external store
|
||||
// before handing back a link (see ExternalAttachmentResult), which is a real
|
||||
// upload over the wire - 5s would kill every offload of a file worth
|
||||
// offloading, and three of those in a minute would auto-disable the plugin.
|
||||
const BLOB_UPLOAD_TIMEOUT_MS = 120_000;
|
||||
// onBeforeBlobUpload handlers may ask the user and then push the attachment
|
||||
// to an external store before handing back a link (see
|
||||
// ExternalAttachmentResult): a real upload of a file too big to mail, which
|
||||
// takes minutes on a slow line. Two minutes cut off large offloads and
|
||||
// counted them toward auto-disable.
|
||||
const BLOB_UPLOAD_TIMEOUT_MS = 15 * 60_000;
|
||||
|
||||
class HookTimeoutError extends Error {}
|
||||
|
||||
|
||||
@@ -490,7 +490,8 @@ function buildPluginApi(manifest: PluginManifest) {
|
||||
openExternalUrl: (url: string, target?: string) =>
|
||||
callApi('ui.openExternalUrl', [url, target]) as Promise<void>,
|
||||
/** Downloads a file generated by the plugin. Not a user's file or attachment. */
|
||||
downloadFile: (opts: { content: string; filename: string; contentType?: string }) =>
|
||||
/** `content` is text, or the file's bytes (ArrayBuffer / Uint8Array). */
|
||||
downloadFile: (opts: { content: string | ArrayBuffer | Uint8Array; filename: string; contentType?: string }) =>
|
||||
callApi('ui.downloadFile', [opts]) as Promise<void>,
|
||||
/**
|
||||
* Buttons or menu entries on an action surface (see the slot catalogue:
|
||||
|
||||
@@ -81,7 +81,7 @@ export const SLOT_CATALOG = {
|
||||
'composer-below-body': S('composer', 'frame', ['ui:composer-toolbar', 'ui:composer-sidebar'], { draft: 'email:send', insertText: 'compose:open', getSelectedText: 'email:send' }, 'below the message text, above the attachments'),
|
||||
'composer-sidebar': S('composer', 'frame', ['ui:composer-sidebar'], {}, 'a panel left of the composer'),
|
||||
'composer-sidebar-right': S('composer', 'frame', ['ui:composer-sidebar'], {}, 'a panel right of the composer'),
|
||||
'composer-attachment-source': S('composer', 'frame', ['ui:composer-toolbar', 'ui:composer-sidebar'], { onAttach: null }, 'the composer\'s attach menu, as a source of files', true),
|
||||
'composer-attachment-source': S('composer', 'frame', ['ui:composer-toolbar', 'ui:composer-sidebar'], { onAttach: null, insertText: 'compose:open' }, 'the composer\'s attach menu, as a source of files', true),
|
||||
'composer-send-menu': S('composer', 'action', ['ui:composer-toolbar'], { draft: 'email:send' }, 'entries in the menu next to Send'),
|
||||
'composer-attach-menu': S('composer', 'action', ['ui:composer-toolbar'], {}, 'entries in the attach menu (for example "From Nextcloud")'),
|
||||
|
||||
|
||||
Reference in New Issue
Block a user