From df3d388d22d95fb4b8b062d9a0c1d3d085251eb1 Mon Sep 17 00:00:00 2001 From: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e Date: Thu, 16 Jul 2026 20:45:26 -0700 Subject: [PATCH] feat(desktop): disambiguate agent name collisions Co-authored-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e Signed-off-by: npub1ux8n2yfs8qfvgd75s7kyhar2mztac355v6vmrz4juc9l3msw4pgstums9e Co-authored-by: Codex Ai-assisted: true --- desktop/playwright.config.ts | 1 + .../features/channels/ui/MembersSidebar.tsx | 75 ++++++--- .../messages/ui/MentionAutocomplete.tsx | 33 ++-- .../messages/ui/NewMessageResultRow.tsx | 17 +- .../features/messages/ui/NewMessageScreen.tsx | 15 ++ .../features/profile/lib/identity.test.mjs | 56 ++++++- desktop/src/features/profile/lib/identity.ts | 45 ++++++ .../e2e/ambiguous-agent-owner-suffix.spec.ts | 151 ++++++++++++++++++ 8 files changed, 358 insertions(+), 35 deletions(-) create mode 100644 desktop/tests/e2e/ambiguous-agent-owner-suffix.spec.ts diff --git a/desktop/playwright.config.ts b/desktop/playwright.config.ts index b6296f0f3a..c0ecf0ba3d 100644 --- a/desktop/playwright.config.ts +++ b/desktop/playwright.config.ts @@ -47,6 +47,7 @@ export default defineConfig({ "**/edit-agent.spec.ts", "**/doctor-cta-screenshots.spec.ts", "**/pubkey-display-screenshots.spec.ts", + "**/ambiguous-agent-owner-suffix.spec.ts", "**/file-attachment.spec.ts", "**/image-attachment-gallery.spec.ts", "**/composer-image-draw.spec.ts", diff --git a/desktop/src/features/channels/ui/MembersSidebar.tsx b/desktop/src/features/channels/ui/MembersSidebar.tsx index 48a04b5918..44cf2f777b 100644 --- a/desktop/src/features/channels/ui/MembersSidebar.tsx +++ b/desktop/src/features/channels/ui/MembersSidebar.tsx @@ -20,7 +20,12 @@ import { useUserSearchFetchMoreOnScroll, useUsersBatchQuery, } from "@/features/profile/hooks"; -import { formatOwnerLabel } from "@/features/profile/lib/identity"; +import { + countVisibleDisplayNames, + formatDisambiguatedAgentName, + formatOwnerLabel, + hasVisibleDisplayNameCollision, +} from "@/features/profile/lib/identity"; import { rankUserCandidatesBySearch } from "@/features/profile/lib/userCandidateSearch"; import { usePresenceQuery } from "@/features/presence/hooks"; import { useIdentityQuery } from "@/shared/api/hooks"; @@ -374,6 +379,13 @@ export function MembersSidebar({ userSearchResults, rawMembers, ]); + const addSearchNameCounts = React.useMemo( + () => + countVisibleDisplayNames( + addSearchResults.map((user) => formatAddCandidateName(user)), + ), + [addSearchResults], + ); const isAddSearchLoading = userSearchQuery.isLoading || managedAgentsQuery.isLoading || @@ -708,23 +720,39 @@ export function MembersSidebar({ Not in this channel ) : null} - {addSearchResults.map((user) => ( - { - void handleAddSearchResult(selectedUser); - }} - ownerLabel={formatOwnerLabel( - user.ownerPubkey, - identityQuery.data?.pubkey, - addSearchOwnerProfilesQuery.data?.profiles, - )} - user={user} - /> - ))} + {addSearchResults.map((user) => { + const ownerLabel = formatOwnerLabel( + user.ownerPubkey, + identityQuery.data?.pubkey, + addSearchOwnerProfilesQuery.data?.profiles, + ); + const displayName = formatAddCandidateName(user); + + return ( + { + void handleAddSearchResult(selectedUser); + }} + ownerLabel={ownerLabel} + user={user} + /> + ); + })} {isAddSearchLoading ? (

Searching... @@ -851,11 +879,13 @@ function SearchResultSectionTitle({ function AddMemberSearchResultRow({ disabled, + displayName, onSelect, ownerLabel, user, }: { disabled: boolean; + displayName: string; onSelect: (user: UserSearchResult) => void; ownerLabel?: string | null; user: UserSearchResult; @@ -869,7 +899,7 @@ function AddMemberSearchResultRow({ data-testid={`channel-user-search-result-${user.pubkey}`} >