Skip to content

Commit 8d8692d

Browse files
committed
fix: render redacted state events as deleted instead of hiding them
1 parent ae69b8b commit 8d8692d

2 files changed

Lines changed: 122 additions & 76 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
default: patch
3+
---
4+
5+
Display redacted state events (membership, room name/topic/avatar, pins and other state events) as a "deleted" tombstone in the timeline instead of rendering them with empty/redacted content or hiding them, so the reply-to of a redaction highlights the redacted event.

src/app/hooks/timeline/useTimelineEventRenderer.tsx

Lines changed: 117 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -1178,9 +1178,10 @@ export function useTimelineEventRenderer({
11781178
if (membershipChanged && hideMembershipEvents) return null;
11791179
if (!membershipChanged && hideNickAvatarEvents) return null;
11801180

1181+
const isRedacted = mEvent.isRedacted();
11811182
const highlighted = focusItem?.index === item && focusItem.highlight;
11821183
const marked = activeReplyId === mEventId && !suppressMark;
1183-
const parsed = parseMemberEvent(mEvent);
1184+
const parsed = isRedacted ? null : parseMemberEvent(mEvent);
11841185

11851186
const timeJSX = (
11861187
<Time
@@ -1259,19 +1260,24 @@ export function useTimelineEventRenderer({
12591260
<EventContent
12601261
messageLayout={messageLayout}
12611262
time={timeJSX}
1262-
icon={parsed.icon}
1263+
icon={parsed?.icon ?? timelineIcon(Trash)}
12631264
content={
1264-
<Text size="T300" priority="300">
1265-
<Box direction="Row" style={{ flexWrap: 'wrap', columnGap: toRem(6) }}>
1266-
{parsed.body}
1267-
</Box>
1268-
</Text>
1265+
isRedacted ? (
1266+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
1267+
) : (
1268+
<Text size="T300" priority="300">
1269+
<Box direction="Row" style={{ flexWrap: 'wrap', columnGap: toRem(6) }}>
1270+
{parsed?.body}
1271+
</Box>
1272+
</Text>
1273+
)
12691274
}
12701275
/>
12711276
</Message>
12721277
);
12731278
},
12741279
[EventType.RoomName]: (mEventId, mEvent, item, timelineSet, collapse) => {
1280+
const isRedacted = mEvent.isRedacted();
12751281
const highlighted = focusItem?.index === item && focusItem.highlight;
12761282
const marked = activeReplyId === mEventId && !suppressMark;
12771283
const senderId = mEvent.getSender() ?? '';
@@ -1353,20 +1359,25 @@ export function useTimelineEventRenderer({
13531359
<EventContent
13541360
messageLayout={messageLayout}
13551361
time={timeJSX}
1356-
icon={timelineIcon(Hash)}
1362+
icon={isRedacted ? timelineIcon(Trash) : timelineIcon(Hash)}
13571363
content={
1358-
<Box grow="Yes" direction="Column">
1359-
<Text size="T300" priority="300">
1360-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1361-
{t('Organisms.RoomCommon.changed_room_name')}
1362-
</Text>
1363-
</Box>
1364+
isRedacted ? (
1365+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
1366+
) : (
1367+
<Box grow="Yes" direction="Column">
1368+
<Text size="T300" priority="300">
1369+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1370+
{t('Organisms.RoomCommon.changed_room_name')}
1371+
</Text>
1372+
</Box>
1373+
)
13641374
}
13651375
/>
13661376
</Message>
13671377
);
13681378
},
13691379
[EventType.RoomTopic]: (mEventId, mEvent, item, timelineSet, collapse) => {
1380+
const isRedacted = mEvent.isRedacted();
13701381
const highlighted = focusItem?.index === item && focusItem.highlight;
13711382
const marked = activeReplyId === mEventId && !suppressMark;
13721383
const senderId = mEvent.getSender() ?? '';
@@ -1449,20 +1460,25 @@ export function useTimelineEventRenderer({
14491460
<EventContent
14501461
messageLayout={messageLayout}
14511462
time={timeJSX}
1452-
icon={timelineIcon(Hash)}
1463+
icon={isRedacted ? timelineIcon(Trash) : timelineIcon(Hash)}
14531464
content={
1454-
<Box grow="Yes" direction="Column">
1455-
<Text size="T300" priority="300">
1456-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1457-
{' changed room topic'}
1458-
</Text>
1459-
</Box>
1465+
isRedacted ? (
1466+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
1467+
) : (
1468+
<Box grow="Yes" direction="Column">
1469+
<Text size="T300" priority="300">
1470+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1471+
{' changed room topic'}
1472+
</Text>
1473+
</Box>
1474+
)
14601475
}
14611476
/>
14621477
</Message>
14631478
);
14641479
},
14651480
[EventType.RoomAvatar]: (mEventId, mEvent, item, timelineSet, collapse) => {
1481+
const isRedacted = mEvent.isRedacted();
14661482
const highlighted = focusItem?.index === item && focusItem.highlight;
14671483
const marked = activeReplyId === mEventId && !suppressMark;
14681484
const senderId = mEvent.getSender() ?? '';
@@ -1545,20 +1561,25 @@ export function useTimelineEventRenderer({
15451561
<EventContent
15461562
messageLayout={messageLayout}
15471563
time={timeJSX}
1548-
icon={timelineIcon(Hash)}
1564+
icon={isRedacted ? timelineIcon(Trash) : timelineIcon(Hash)}
15491565
content={
1550-
<Box grow="Yes" direction="Column">
1551-
<Text size="T300" priority="300">
1552-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1553-
{' changed room avatar'}
1554-
</Text>
1555-
</Box>
1566+
isRedacted ? (
1567+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
1568+
) : (
1569+
<Box grow="Yes" direction="Column">
1570+
<Text size="T300" priority="300">
1571+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1572+
{' changed room avatar'}
1573+
</Text>
1574+
</Box>
1575+
)
15561576
}
15571577
/>
15581578
</Message>
15591579
);
15601580
},
15611581
[EventType.GroupCallMemberPrefix]: (mEventId, mEvent, item, timelineSet, collapse) => {
1582+
const isRedacted = mEvent.isRedacted();
15621583
const highlighted = focusItem?.index === item && focusItem.highlight;
15631584
const marked = activeReplyId === mEventId && !suppressMark;
15641585
const senderId = mEvent.getSender() ?? '';
@@ -1648,14 +1669,24 @@ export function useTimelineEventRenderer({
16481669
<EventContent
16491670
messageLayout={messageLayout}
16501671
time={timeJSX}
1651-
icon={callJoined ? timelineIcon(Phone) : timelineIcon(PhoneDisconnect)}
1672+
icon={
1673+
isRedacted
1674+
? timelineIcon(Trash)
1675+
: callJoined
1676+
? timelineIcon(Phone)
1677+
: timelineIcon(PhoneDisconnect)
1678+
}
16521679
content={
1653-
<Box grow="Yes" direction="Column">
1654-
<Text size="T300" priority="300">
1655-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1656-
{callJoined ? ' joined the call' : ' ended the call'}
1657-
</Text>
1658-
</Box>
1680+
isRedacted ? (
1681+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
1682+
) : (
1683+
<Box grow="Yes" direction="Column">
1684+
<Text size="T300" priority="300">
1685+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
1686+
{callJoined ? ' joined the call' : ' ended the call'}
1687+
</Text>
1688+
</Box>
1689+
)
16591690
}
16601691
/>
16611692
</Message>
@@ -1990,6 +2021,7 @@ export function useTimelineEventRenderer({
19902021
},
19912022
[EventType.RoomPinnedEvents]: (mEventId, mEvent, item, timelineSet, collapse) => {
19922023
if (!hiddenEventOther) return null;
2024+
const isRedacted = mEvent.isRedacted();
19932025
const highlighted = focusItem?.index === item && focusItem.highlight;
19942026
const marked = activeReplyId === mEventId && !suppressMark;
19952027
const senderId = mEvent.getSender() ?? '';
@@ -2083,39 +2115,43 @@ export function useTimelineEventRenderer({
20832115
<EventContent
20842116
messageLayout={messageLayout}
20852117
time={timeJSX}
2086-
icon={timelineIcon(PushPin)}
2118+
icon={isRedacted ? timelineIcon(Trash) : timelineIcon(PushPin)}
20872119
content={
2088-
<Box grow="Yes" direction="Column">
2089-
<Text size="T300" priority="300">
2090-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
2091-
{(pinsAdded?.length > 0 &&
2092-
`pinned ${pinsAdded.length} message${pinsAdded.length > 1 ? 's' : ''}`) ||
2093-
''}
2094-
{(pinsAdded?.length > 0 && pinsRemoved?.length > 0 && ` and `) || ''}
2095-
{(pinsRemoved?.length > 0 &&
2096-
`unpinned ${pinsRemoved.length} message${
2097-
pinsRemoved.length > 1 ? 's' : ''
2098-
}`) ||
2099-
''}
2100-
{((!pinsAdded || pinsAdded.length <= 0) &&
2101-
(!pinsRemoved || pinsRemoved.length <= 0) &&
2102-
`has not changed the pins`) ||
2103-
`:`}
2104-
</Text>
2105-
{pinPreviewIds.length > 0 &&
2106-
pinPreviewIds
2107-
.slice(0, 4)
2108-
.map((x: string) => (
2109-
<Reply
2110-
key={x}
2111-
style={{ opacity: '80%' }}
2112-
room={room}
2113-
replyEventId={x}
2114-
onClick={handleOpenReply}
2115-
replyIcon={<>{menuIcon(pinnedSet.has(x) ? PushPin : PushPinSlash)}</>}
2116-
/>
2117-
))}
2118-
</Box>
2120+
isRedacted ? (
2121+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
2122+
) : (
2123+
<Box grow="Yes" direction="Column">
2124+
<Text size="T300" priority="300">
2125+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
2126+
{(pinsAdded?.length > 0 &&
2127+
`pinned ${pinsAdded.length} message${pinsAdded.length > 1 ? 's' : ''}`) ||
2128+
''}
2129+
{(pinsAdded?.length > 0 && pinsRemoved?.length > 0 && ` and `) || ''}
2130+
{(pinsRemoved?.length > 0 &&
2131+
`unpinned ${pinsRemoved.length} message${
2132+
pinsRemoved.length > 1 ? 's' : ''
2133+
}`) ||
2134+
''}
2135+
{((!pinsAdded || pinsAdded.length <= 0) &&
2136+
(!pinsRemoved || pinsRemoved.length <= 0) &&
2137+
`has not changed the pins`) ||
2138+
`:`}
2139+
</Text>
2140+
{pinPreviewIds.length > 0 &&
2141+
pinPreviewIds
2142+
.slice(0, 4)
2143+
.map((x: string) => (
2144+
<Reply
2145+
key={x}
2146+
style={{ opacity: '80%' }}
2147+
room={room}
2148+
replyEventId={x}
2149+
onClick={handleOpenReply}
2150+
replyIcon={<>{menuIcon(pinnedSet.has(x) ? PushPin : PushPinSlash)}</>}
2151+
/>
2152+
))}
2153+
</Box>
2154+
)
21192155
}
21202156
/>
21212157
</Message>
@@ -2124,6 +2160,7 @@ export function useTimelineEventRenderer({
21242160
},
21252161
(mEventId, mEvent, item, timelineSet, collapse) => {
21262162
if (!hiddenEventOther) return null;
2163+
const isRedacted = mEvent.isRedacted();
21272164
const highlighted = focusItem?.index === item && focusItem.highlight;
21282165
const marked = activeReplyId === mEventId && !suppressMark;
21292166
const senderId = mEvent.getSender() ?? '';
@@ -2205,16 +2242,20 @@ export function useTimelineEventRenderer({
22052242
<EventContent
22062243
messageLayout={messageLayout}
22072244
time={timeJSX}
2208-
icon={timelineIcon(Code)}
2245+
icon={isRedacted ? timelineIcon(Trash) : timelineIcon(Code)}
22092246
content={
2210-
<Box grow="Yes" direction="Column">
2211-
<Text size="T300" priority="300">
2212-
<DecoratedUser userId={senderId} userName={senderName} room={room} />
2213-
{' sent '}
2214-
<code className={customHtmlCss.Code}>{mEvent.getType()}</code>
2215-
{' state event'}
2216-
</Text>
2217-
</Box>
2247+
isRedacted ? (
2248+
<RedactedContent reason={mEvent.getUnsigned().redacted_because?.content.reason} />
2249+
) : (
2250+
<Box grow="Yes" direction="Column">
2251+
<Text size="T300" priority="300">
2252+
<DecoratedUser userId={senderId} userName={senderName} room={room} />
2253+
{' sent '}
2254+
<code className={customHtmlCss.Code}>{mEvent.getType()}</code>
2255+
{' state event'}
2256+
</Text>
2257+
</Box>
2258+
)
22182259
}
22192260
/>
22202261
</Message>

0 commit comments

Comments
 (0)