fix(dm): surface dm.name on chat header/placeholder; collapse unnamed-group placeholder
Three layered bugs all manifesting as "the group name doesn't show / the
placeholder is a 40-character wall of names":
1. **WS ready payload was missing `name`/`icon`.** The handler serialized
DmChannel rows with only `id, federatedId, ownerId, createdAt, members,
lastMessage`. The optional metadata fields were silently dropped, so
the client store never received `dm.name` until a subsequent
`dm_channel_updated` event fired (i.e. only mid-session renames worked,
never the initial render). `ownerHomeUserId`, `ownerHomeInstance`, and
`metadataUpdatedAt` were also missing — added too because federated
routing depends on `ownerHomeInstance` (`getDmOwnerHomeInstance`).
2. **Header surfaces silently dropped `dm.name`.** `MainContent` (desktop
chat header) and `MobileChatScreen` always rendered the joined member
names, even when `dm.name` was set. Five other surfaces (`DmListItem`,
`MobileDmsScreen`, `MessageList` welcome hero, `MobileGroupDmInfo`,
`GroupDmSettings`) honored it correctly, so a renamed group showed
different titles depending on which surface you looked at.
3. **Message-input placeholder rendered joined names.** Once a group
has 4+ members "Message #Alice, Bob, Charlie, Dave" overflows the
textarea and obscures the call-to-action.
Consolidates the display-name logic behind two utilities in
`dmFormatters.ts`:
- `formatDmHeaderName(dm, currentUser)` — `dm.name` verbatim if set,
else joined names (excluding self); falls back to `'Group'` /
`'Direct Message'`. Used by all 5 header surfaces (was inlined
5 different ways).
- `formatDmInputLabel(dm, currentUser)` — `'#<name>'` if set,
`'the group'` for unnamed groups (collapses the unreadable
joined-names form), `'@<partner>'` for 1-on-1.
`MessageInput` accepts an optional `placeholder` prop that bypasses the
default `Message {#|@}<channelName>` derivation; DM call sites use it
to inject the `formatDmInputLabel`-based form. 1-on-1 DMs keep the
canonical-view lookup so replicated aliases still surface the home
account's displayName; the placeholder reuses the canonical `dmName`
so header + placeholder stay aligned even when raw partner ≠ canonical.
13 new unit tests covering `formatDmHeaderName` (8 cases: named, blank,
joined, federated-username base, empty group, 1-on-1, no-displayName,
no-partner) and `formatDmInputLabel` (4 cases: named, unnamed,
whitespace-only, 1-on-1). 365 → 377 web tests, 1053 server tests,
typecheck clean.
This commit is contained in:
@@ -4,7 +4,7 @@ import { AvatarStack } from '../ui/AvatarStack';
|
||||
import { Tooltip } from '../ui/Tooltip';
|
||||
import { parseFederatedUsername, isSelf, isFederationGlobeApplicable } from '../../utils/identity';
|
||||
import { useCanonicalUserView } from '../../utils/userViewLookup';
|
||||
import { formatDmTimestamp, formatDmSidebarPreview } from '../../utils/dmFormatters';
|
||||
import { formatDmTimestamp, formatDmSidebarPreview, formatDmHeaderName } from '../../utils/dmFormatters';
|
||||
import { getRejectedPeerOrigins, getAwaitingApprovalPeerOrigins } from '../../hooks/useWebSocket';
|
||||
|
||||
function isMemberUnreachable(homeInstance: string | null | undefined): boolean {
|
||||
@@ -44,10 +44,11 @@ export function DmListItem({ dm, isActive, isUnread, user, onSelect, onClose, on
|
||||
const firstOther = rawFirstOther ? firstOtherCanonical : null;
|
||||
|
||||
const { baseName } = parseFederatedUsername(firstOther?.username ?? '');
|
||||
// Groups → `formatDmHeaderName` (honors `dm.name`, falls back to joined
|
||||
// names — same path used by the chat header, welcome hero, and mobile).
|
||||
// 1-on-1 keeps the canonical-view name so replicated aliases stay correct.
|
||||
const displayName = isGroup
|
||||
? (dm.name ?? (otherMembers.length > 0
|
||||
? otherMembers.map(m => m.displayName ?? parseFederatedUsername(m.username).baseName).join(', ')
|
||||
: 'Empty Group'))
|
||||
? formatDmHeaderName(dm, user)
|
||||
: firstOther?.displayName ?? baseName;
|
||||
|
||||
// Group globe: at least one member is federated → render once with comma-joined tooltip.
|
||||
|
||||
Reference in New Issue
Block a user