diff --git a/components/settings/delegates/__tests__/delegates-settings.test.tsx b/components/settings/delegates/__tests__/delegates-settings.test.tsx index 0bb642887..ca8b7db6b 100644 --- a/components/settings/delegates/__tests__/delegates-settings.test.tsx +++ b/components/settings/delegates/__tests__/delegates-settings.test.tsx @@ -27,9 +27,10 @@ function targets(withCarol = false): ShareTarget[] { const ok = (changes: ShareChange[]): ShareChangeResult[] => changes.map((change) => ({ change, ok: true })); -function makeClient(options: { withCarol?: boolean; directory?: PrincipalListing; apply?: (c: ShareChange[]) => ShareChangeResult[] } = {}) { +function makeClient(options: { withCarol?: boolean; directory?: PrincipalListing; apply?: (c: ShareChange[]) => ShareChangeResult[]; sharedAccounts?: Array<{ id: string; name: string }> } = {}) { return { getAccountId: () => 'ci', + getSharedAccounts: () => options.sharedAccounts ?? [], supportsPrincipals: () => true, getPrincipals: vi.fn(async () => (options.directory ?? DIRECTORY_OFF).principals), listPrincipals: vi.fn(async () => options.directory ?? DIRECTORY_OFF), @@ -89,6 +90,17 @@ describe('DelegatesSettings', () => { expect(screen.getAllByTestId('delegate-row')).toHaveLength(1); }); + it('names someone the directory does not list from the accounts they share with the user', async () => { + renderWith(makeClient({ + withCarol: true, + directory: { principals: [ALICE], status: 'restricted', directoryQueriesOff: true }, + sharedAccounts: [{ id: 'ck', name: 'org-carol@example.org' }], + })); + const row = await screen.findByTestId('delegate-row'); + expect(within(row).getByText('org-carol@example.org')).toBeInTheDocument(); + expect(within(row).queryByText('unknown_person')).toBeNull(); + }); + it('removes a person from every item, files included', async () => { const client = makeClient({ withCarol: true }); renderWith(client); diff --git a/components/settings/delegates/delegates-settings.tsx b/components/settings/delegates/delegates-settings.tsx index 4ca5ecc51..d33b3cb80 100644 --- a/components/settings/delegates/delegates-settings.tsx +++ b/components/settings/delegates/delegates-settings.tsx @@ -75,8 +75,16 @@ export function DelegatesSettings() { const ownIds = useMemo(() => (client ? [client.getAccountId()] : []), [client]); const summaries = useMemo(() => (targets ? summarizeDelegates(targets, ownIds) : []), [targets, ownIds]); - const principalFor = useCallback((id: string): Principal | null => - directory?.principals.find((p) => p.id === id) ?? remembered.get(id) ?? null, [directory, remembered]); + // Stalwart names a principal by its account id, and an account shared with + // the user is in the session under the owner's address: a last way to name + // someone the directory won't (Stalwart 1.0 with directory queries off). + const sessionAccounts = useMemo(() => new Map((client?.getSharedAccounts() ?? []).map((a) => [a.id, a.name])), [client]); + const principalFor = useCallback((id: string): Principal | null => { + const known = directory?.principals.find((p) => p.id === id) ?? remembered.get(id); + if (known) return known; + const accountName = sessionAccounts.get(id); + return accountName ? { id, name: accountName, email: accountName.includes('@') ? accountName : null, type: 'individual' } : null; + }, [directory, remembered, sessionAccounts]); if (delegation.hidden || !client) return null;