mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-02 08:07:11 +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 { describe, it, expect } from 'vitest';
|
||||||
import fs from 'node:fs';
|
import fs from 'node:fs';
|
||||||
import path from 'node:path';
|
import path from 'node:path';
|
||||||
import { listAddressLabel } from '../list-sender';
|
import { listAddressLabel, rowShowsRecipient } from '../list-sender';
|
||||||
import { toUnicodeEmailOnOwnDomains } from '../idn';
|
import { toUnicodeEmailOnOwnDomains } from '../idn';
|
||||||
|
|
||||||
// A sender with no display name on one of the user's own IDN domains showed
|
// 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/);
|
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 {
|
): string {
|
||||||
return address?.name || (address?.email ? formatAddress(address.email) : '') || unknown;
|
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 { useOutboxStore } from '../stores/outbox-store';
|
||||||
import { toast } from '../stores/toast-store';
|
import { toast } from '../stores/toast-store';
|
||||||
import { getContactDisplayName } from '../lib/contact-utils';
|
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 { useOwnDomainAddress } from '../lib/use-own-domain-address';
|
||||||
import { formatListDate } from '../lib/date-format';
|
import { formatListDate } from '../lib/date-format';
|
||||||
import { singleLine } from '../lib/single-line';
|
import { singleLine } from '../lib/single-line';
|
||||||
import { cleanPreview } from '../lib/preview-text';
|
import { cleanPreview } from '../lib/preview-text';
|
||||||
import { SearchSnippetText } from '../components/email/SearchSnippetText';
|
import { SearchSnippetText } from '../components/email/SearchSnippetText';
|
||||||
import {
|
import {
|
||||||
findTrashMailbox, findArchiveMailbox, findJunkMailbox, mailboxesForSiblingOf, ownMailboxes,
|
findTrashMailbox, findArchiveMailbox, findJunkMailbox, mailboxesForSiblingOf, ownMailboxes, mailboxesOfAccount,
|
||||||
} from '../lib/mailbox-tree';
|
} from '../lib/mailbox-tree';
|
||||||
import { localizeMailboxName } from '../lib/mailbox-label';
|
import { localizeMailboxName } from '../lib/mailbox-label';
|
||||||
import {
|
import {
|
||||||
@@ -577,7 +577,18 @@ export default function EmailListScreen({
|
|||||||
}, [sharedTags, keywordDefs]);
|
}, [sharedTags, keywordDefs]);
|
||||||
const folderKeywordDefs = (currentOwnerAccountId && keywordDefsByAccount.get(currentOwnerAccountId)) || keywordDefs;
|
const folderKeywordDefs = (currentOwnerAccountId && keywordDefsByAccount.get(currentOwnerAccountId)) || keywordDefs;
|
||||||
const inJunk = currentRole === 'junk' || currentRole === 'spam';
|
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();
|
const formatAddress = useOwnDomainAddress();
|
||||||
|
|
||||||
// When threading is on, collapse same-thread emails so the list shows the
|
// When threading is on, collapse same-thread emails so the list shows the
|
||||||
@@ -896,7 +907,7 @@ export default function EmailListScreen({
|
|||||||
item={item}
|
item={item}
|
||||||
threadCount={threadCountFor(item)}
|
threadCount={threadCountFor(item)}
|
||||||
showPreview={showPreview}
|
showPreview={showPreview}
|
||||||
showRecipient={showRecipient}
|
showRecipient={showRecipientFor(item)}
|
||||||
formatAddress={formatAddress}
|
formatAddress={formatAddress}
|
||||||
tagIds={rowTagIds.get(key) ?? ''}
|
tagIds={rowTagIds.get(key) ?? ''}
|
||||||
keywordDefs={(item.jmapAccountId && keywordDefsByAccount.get(item.jmapAccountId)) || folderKeywordDefs}
|
keywordDefs={(item.jmapAccountId && keywordDefsByAccount.get(item.jmapAccountId)) || folderKeywordDefs}
|
||||||
@@ -916,7 +927,7 @@ export default function EmailListScreen({
|
|||||||
[
|
[
|
||||||
selectedIds, activeRowKey, selectionMode, handleRowPress, toggleSelect, swipeLeftAction, swipeRightAction,
|
selectedIds, activeRowKey, selectionMode, handleRowPress, toggleSelect, swipeLeftAction, swipeRightAction,
|
||||||
swipeMode, handleRowSwipe, disableThreading, rowFlags, rowTagIds, threadCountFor,
|
swipeMode, handleRowSwipe, disableThreading, rowFlags, rowTagIds, threadCountFor,
|
||||||
showPreview, showRecipient, formatAddress, keywordDefsByAccount, folderKeywordDefs, inJunk, showAvatarsInJunk,
|
showPreview, showRecipientFor, formatAddress, keywordDefsByAccount, folderKeywordDefs, inJunk, showAvatarsInJunk,
|
||||||
loadAttachments, openAttachment,
|
loadAttachments, openAttachment,
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user