mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 08:06:13 +00:00
fix: show the sender on search hits from other folders when searching from Sent
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { describe, it, expect } from 'vitest';
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { listAddressLabel } from '../list-sender';
|
||||
import { listAddressLabel, rowShowsRecipient } from '../list-sender';
|
||||
import { toUnicodeEmailOnOwnDomains } from '../idn';
|
||||
|
||||
// A sender with no display name on one of the user's own IDN domains showed
|
||||
@@ -42,3 +42,40 @@ describe('list rows', () => {
|
||||
expect(unified).not.toMatch(/\.name \|\| [\w.?[\]]*\.email/);
|
||||
});
|
||||
});
|
||||
|
||||
// A search started in Sent spans every folder: Inbox hits showed their
|
||||
// recipient (the user) instead of their sender.
|
||||
describe('rowShowsRecipient', () => {
|
||||
const OWN = [
|
||||
{ id: 'inb', role: 'inbox' },
|
||||
{ id: 'snt', role: 'sent' },
|
||||
{ id: 'drf', role: 'drafts' },
|
||||
];
|
||||
const SHARED = [
|
||||
{ id: 'grp-1:inb', originalId: 'inb', role: 'inbox' },
|
||||
{ id: 'grp-1:snt', originalId: 'snt', role: 'sent' },
|
||||
];
|
||||
|
||||
it('follows the open folder for its own list', () => {
|
||||
expect(rowShowsRecipient({ inb: true }, [], 'sent', 'current')).toBe(true);
|
||||
expect(rowShowsRecipient({ snt: true }, [], 'inbox', 'current')).toBe(false);
|
||||
});
|
||||
|
||||
it("follows each row's own folders in a search over every folder", () => {
|
||||
expect(rowShowsRecipient({ inb: true }, OWN, 'sent', 'all')).toBe(false);
|
||||
expect(rowShowsRecipient({ snt: true }, OWN, 'sent', 'all')).toBe(true);
|
||||
expect(rowShowsRecipient({ drf: true }, OWN, 'inbox', 'all')).toBe(true);
|
||||
expect(rowShowsRecipient({ inb: true }, OWN, 'sent', 'inb')).toBe(false);
|
||||
});
|
||||
|
||||
it("matches a shared account's folders on their raw ids", () => {
|
||||
expect(rowShowsRecipient({ snt: true }, SHARED, 'sent', 'all')).toBe(true);
|
||||
expect(rowShowsRecipient({ inb: true }, SHARED, 'sent', 'all')).toBe(false);
|
||||
});
|
||||
|
||||
it('is wired into the list rows', () => {
|
||||
const list = fs.readFileSync(path.resolve(__dirname, '..', '..', 'screens/EmailListScreen.tsx'), 'utf8');
|
||||
expect(list).toMatch(/showRecipient=\{showRecipientFor\(item\)\}/);
|
||||
expect(list).not.toMatch(/const showRecipient = currentRole === 'sent'/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -11,3 +11,21 @@ export function listAddressLabel(
|
||||
): string {
|
||||
return address?.name || (address?.email ? formatAddress(address.email) : '') || unknown;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a list row names its recipient instead of its sender. Sent and
|
||||
* Drafts name the recipient (webmail 1.4.12). A search started there runs
|
||||
* over every folder unless it is narrowed (`folderScope` other than
|
||||
* 'current'), so the open folder says nothing about a row: the row's own
|
||||
* folders decide, matched on each folder's raw id. `rowMailboxes` are the
|
||||
* folders of the row's account.
|
||||
*/
|
||||
export function rowShowsRecipient(
|
||||
mailboxIds: Record<string, boolean> | undefined,
|
||||
rowMailboxes: ReadonlyArray<{ id: string; originalId?: string; role?: string | null }>,
|
||||
listRole: string | null | undefined,
|
||||
folderScope: string,
|
||||
): boolean {
|
||||
if (folderScope === 'current') return listRole === 'sent' || listRole === 'drafts';
|
||||
return rowMailboxes.some((m) => (m.role === 'sent' || m.role === 'drafts') && !!mailboxIds?.[m.originalId ?? m.id]);
|
||||
}
|
||||
|
||||
@@ -53,14 +53,14 @@ import { useContactsStore } from '../stores/contacts-store';
|
||||
import { useOutboxStore } from '../stores/outbox-store';
|
||||
import { toast } from '../stores/toast-store';
|
||||
import { getContactDisplayName } from '../lib/contact-utils';
|
||||
import { listAddressLabel } from '../lib/list-sender';
|
||||
import { listAddressLabel, rowShowsRecipient } from '../lib/list-sender';
|
||||
import { useOwnDomainAddress } from '../lib/use-own-domain-address';
|
||||
import { formatListDate } from '../lib/date-format';
|
||||
import { singleLine } from '../lib/single-line';
|
||||
import { cleanPreview } from '../lib/preview-text';
|
||||
import { SearchSnippetText } from '../components/email/SearchSnippetText';
|
||||
import {
|
||||
findTrashMailbox, findArchiveMailbox, findJunkMailbox, mailboxesForSiblingOf, ownMailboxes,
|
||||
findTrashMailbox, findArchiveMailbox, findJunkMailbox, mailboxesForSiblingOf, ownMailboxes, mailboxesOfAccount,
|
||||
} from '../lib/mailbox-tree';
|
||||
import { localizeMailboxName } from '../lib/mailbox-label';
|
||||
import {
|
||||
@@ -577,7 +577,18 @@ export default function EmailListScreen({
|
||||
}, [sharedTags, keywordDefs]);
|
||||
const folderKeywordDefs = (currentOwnerAccountId && keywordDefsByAccount.get(currentOwnerAccountId)) || keywordDefs;
|
||||
const inJunk = currentRole === 'junk' || currentRole === 'spam';
|
||||
const showRecipient = currentRole === 'sent' || currentRole === 'drafts';
|
||||
// A search started in Sent runs over every folder: each row names its
|
||||
// recipient only when it is in Sent or Drafts itself.
|
||||
const rowScope = effectiveFolderScope(storeSearchQuery, filters, currentRole);
|
||||
const showRecipientFor = React.useCallback(
|
||||
(item: Email) => rowShowsRecipient(
|
||||
item.mailboxIds,
|
||||
rowScope === 'current' ? [] : mailboxesOfAccount(mailboxes, accountIdOfRow(item)),
|
||||
currentRole,
|
||||
rowScope,
|
||||
),
|
||||
[rowScope, mailboxes, currentRole],
|
||||
);
|
||||
const formatAddress = useOwnDomainAddress();
|
||||
|
||||
// When threading is on, collapse same-thread emails so the list shows the
|
||||
@@ -896,7 +907,7 @@ export default function EmailListScreen({
|
||||
item={item}
|
||||
threadCount={threadCountFor(item)}
|
||||
showPreview={showPreview}
|
||||
showRecipient={showRecipient}
|
||||
showRecipient={showRecipientFor(item)}
|
||||
formatAddress={formatAddress}
|
||||
tagIds={rowTagIds.get(key) ?? ''}
|
||||
keywordDefs={(item.jmapAccountId && keywordDefsByAccount.get(item.jmapAccountId)) || folderKeywordDefs}
|
||||
@@ -916,7 +927,7 @@ export default function EmailListScreen({
|
||||
[
|
||||
selectedIds, activeRowKey, selectionMode, handleRowPress, toggleSelect, swipeLeftAction, swipeRightAction,
|
||||
swipeMode, handleRowSwipe, disableThreading, rowFlags, rowTagIds, threadCountFor,
|
||||
showPreview, showRecipient, formatAddress, keywordDefsByAccount, folderKeywordDefs, inJunk, showAvatarsInJunk,
|
||||
showPreview, showRecipientFor, formatAddress, keywordDefsByAccount, folderKeywordDefs, inJunk, showAvatarsInJunk,
|
||||
loadAttachments, openAttachment,
|
||||
],
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user