mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-04 00:14:12 +00:00
feat: tell plugins when the open message's attachments can't be read from this login
This commit is contained in:
@@ -77,6 +77,22 @@ describe('the reader panel prop listSelection', () => {
|
||||
expect(seen.length).toBeGreaterThan(renders);
|
||||
});
|
||||
|
||||
it('tells the panel when this login can not read the open message\'s parts', () => {
|
||||
// An open message makes the viewer ask the login more; nothing of it matters here.
|
||||
const client = new Proxy({ getAccountId: () => 'acc1' } as Record<string | symbol, unknown>, {
|
||||
get: (target, key) => (key in target ? target[key] : key === 'then' ? undefined : () => undefined),
|
||||
}) as unknown as IJMAPClient;
|
||||
useAuthStore.setState({ client });
|
||||
const message = { ...row('m'), textBody: [], htmlBody: [], attachments: [], bodyValues: {} } as unknown as Email;
|
||||
const view = () => render(<EmailViewer email={message} isLoading={false} mailboxes={mailboxes} selectedMailbox="inbox" currentMailboxRole="inbox" onDelete={() => {}} blobSource={{ client: otherLogin, accountId: 'acc-2' }} />);
|
||||
const otherLogin = { getAccountId: () => 'acc-2' } as unknown as IJMAPClient;
|
||||
view();
|
||||
expect((seen.at(-1)?.email as { blobsReadable?: boolean }).blobsReadable).toBe(false);
|
||||
cleanup();
|
||||
render(<EmailViewer email={message} isLoading={false} mailboxes={mailboxes} selectedMailbox="inbox" currentMailboxRole="inbox" onDelete={() => {}} blobSource={{ client, accountId: undefined }} />);
|
||||
expect(seen.at(-1)?.email).not.toHaveProperty('blobsReadable');
|
||||
});
|
||||
|
||||
it('gives a panel outside the main list (a Pro tab) no ticks', () => {
|
||||
useAuthStore.setState({ client });
|
||||
useEmailStore.setState({ emails: [row('a'), row('b')], selectedEmailKeys: new Set(['a', 'b']), selectedMailbox: 'inbox', mailboxes });
|
||||
|
||||
@@ -136,6 +136,7 @@ import { useAuthStore } from "@/stores/auth-store";
|
||||
import { useAccountStore } from "@/stores/account-store";
|
||||
import { useEmailStore, resolveEmailBlobContext, emailWriteSource, type EmailBlobContext } from "@/stores/email-store";
|
||||
import { useListSelection } from "@/lib/plugin-sandbox/assistant/b.list-selection";
|
||||
import { readability } from "@/lib/plugin-sandbox/assistant/b.projection";
|
||||
import { useThemeStore } from "@/stores/theme-store";
|
||||
import { EmailIdentityBadge } from "./email-identity-badge";
|
||||
import { ExternalSenderChip } from "./external-sender-chip";
|
||||
@@ -1804,9 +1805,11 @@ export function EmailViewer({
|
||||
// each slot post its props to the plugin again and re-run shouldShow.
|
||||
const wantsPluginEmailView = hasDetailSidebar || hasDetailsSlotOffers || hasBannerOffers
|
||||
|| hasHeaderOffers || hasBelowSubjectOffers || hasAboveQuoteOffers;
|
||||
// A message of another connected login (unified view, Pro tab): the host
|
||||
// reads parts only through the signed-in login, so plugins hear they can't.
|
||||
const pluginEmailView = useMemo(
|
||||
() => (email && wantsPluginEmailView ? emailToReadView(email) : null),
|
||||
[email, wantsPluginEmailView],
|
||||
() => (email && wantsPluginEmailView ? { ...emailToReadView(email), ...readability(blobClient === client) } : null),
|
||||
[email, wantsPluginEmailView, blobClient, client],
|
||||
);
|
||||
// Reader frames learn the layout: the bar a plugin shows on phones has no
|
||||
// place next to a side panel on a desktop.
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// name a picture without looking at it.
|
||||
|
||||
import type { Email } from '@/lib/jmap/types';
|
||||
import type { AttachmentExtrasB } from './b.types';
|
||||
import type { AttachmentExtrasB, EmailReadViewExtrasB } from './b.types';
|
||||
|
||||
const ENTITIES: Record<string, string> = { amp: '&', lt: '<', gt: '>', quot: '"', apos: "'", nbsp: ' ' };
|
||||
|
||||
@@ -50,6 +50,11 @@ export function cidAltTexts(email: Pick<Email, 'htmlBody' | 'bodyValues'>): Map<
|
||||
return out;
|
||||
}
|
||||
|
||||
/** EmailReadView.blobsReadable: false when the signed-in login can't read the message's parts, else left out. */
|
||||
export function readability(readable: boolean): EmailReadViewExtrasB {
|
||||
return readable ? {} : { blobsReadable: false };
|
||||
}
|
||||
|
||||
/** `cid` and `alt` of one attachment, for EmailReadView.attachments (empty for a plain attachment). */
|
||||
export function attachmentExtras(part: { cid?: string | null }, alts: Map<string, string>): AttachmentExtrasB {
|
||||
if (!part.cid) return {};
|
||||
|
||||
@@ -16,6 +16,17 @@ export interface AreaHostFeaturesB {
|
||||
listSelection?: boolean;
|
||||
}
|
||||
|
||||
/** What EmailReadView adds for the assistant. */
|
||||
export interface EmailReadViewExtrasB {
|
||||
/**
|
||||
* false: this login can't read the message's attachments, text or
|
||||
* conversation through the host (it belongs to another connected login,
|
||||
* as in a unified view), so attachment, image and thread reads of it
|
||||
* fail; offer none. Left out when they can be read.
|
||||
*/
|
||||
blobsReadable?: boolean;
|
||||
}
|
||||
|
||||
/** What EmailReadView.attachments adds for an image the message shows inline. */
|
||||
export interface AttachmentExtrasB {
|
||||
/** The Content-ID the message's HTML refers to (`<img src="cid:…">`), without angle brackets. */
|
||||
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
import type { CredentialSpec } from './plugin-secrets/credentials';
|
||||
import type { CatalogSlotName } from './plugin-slot-catalog';
|
||||
import { ASSISTANT_PERMISSIONS, type AssistantHostFeatures } from './plugin-sandbox/assistant/types';
|
||||
import type { AttachmentExtrasB } from './plugin-sandbox/assistant/b.types';
|
||||
import type { AttachmentExtrasB, EmailReadViewExtrasB } from './plugin-sandbox/assistant/b.types';
|
||||
|
||||
// Plugin & Theme system types
|
||||
|
||||
@@ -397,7 +397,7 @@ export interface KeyboardShortcut {
|
||||
// ─── Read-Only View Types ────────────────────────────────────
|
||||
// Projected views exposed to plugins - no direct store references
|
||||
|
||||
export interface EmailReadView {
|
||||
export interface EmailReadView extends EmailReadViewExtrasB {
|
||||
id: string;
|
||||
/**
|
||||
* The JMAP account the message is in. Message ids repeat across accounts
|
||||
|
||||
Reference in New Issue
Block a user