Skip to content

Commit f16a6bc

Browse files
authored
Aggregate relations regardless of whether event fits into the timeline (#3496)
1 parent f884c78 commit f16a6bc

File tree

3 files changed

+39
-29
lines changed

3 files changed

+39
-29
lines changed

Diff for: spec/unit/event-timeline-set.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ See the License for the specific language governing permissions and
1414
limitations under the License.
1515
*/
1616

17+
import { mocked } from "jest-mock";
18+
1719
import * as utils from "../test-utils/test-utils";
1820
import {
1921
DuplicateStrategy,
@@ -160,6 +162,33 @@ describe("EventTimelineSet", () => {
160162
eventTimelineSet.addEventToTimeline(messageEvent, liveTimeline, true, false);
161163
}).not.toThrow();
162164
});
165+
166+
it("should aggregate relations which belong to unknown timeline without adding them to any timeline", () => {
167+
// If threads are disabled all events go into the main timeline
168+
mocked(client.supportsThreads).mockReturnValue(true);
169+
const reactionEvent = utils.mkReaction(messageEvent, client, client.getSafeUserId(), roomId);
170+
171+
const liveTimeline = eventTimelineSet.getLiveTimeline();
172+
expect(liveTimeline.getEvents().length).toStrictEqual(0);
173+
eventTimelineSet.addEventToTimeline(reactionEvent, liveTimeline, {
174+
toStartOfTimeline: true,
175+
});
176+
expect(liveTimeline.getEvents().length).toStrictEqual(0);
177+
178+
eventTimelineSet.addEventToTimeline(messageEvent, liveTimeline, {
179+
toStartOfTimeline: true,
180+
});
181+
expect(liveTimeline.getEvents()).toHaveLength(1);
182+
const [event] = liveTimeline.getEvents();
183+
const reactions = eventTimelineSet.relations!.getChildEventsForEvent(
184+
event.getId()!,
185+
"m.annotation",
186+
"m.reaction",
187+
)!;
188+
const relations = reactions.getRelations();
189+
expect(relations).toHaveLength(1);
190+
expect(relations[0].getId()).toBe(reactionEvent.getId());
191+
});
163192
});
164193

165194
describe("addEventToTimeline (thread timeline)", () => {

Diff for: src/models/event-timeline-set.ts

+10-10
Original file line numberDiff line numberDiff line change
@@ -721,13 +721,17 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
721721
"in timelineSet(threadId=${this.thread?.id})`);
722722
}
723723

724+
const eventId = event.getId()!;
725+
this.relations.aggregateParentEvent(event);
726+
this.relations.aggregateChildEvent(event, this);
727+
724728
// Make sure events don't get mixed in timelines they shouldn't be in (e.g. a
725729
// threaded message should not be in the main timeline).
726730
//
727731
// We can only run this check for timelines with a `room` because `canContain`
728732
// requires it
729733
if (this.room && !this.canContain(event)) {
730-
let eventDebugString = `event=${event.getId()}`;
734+
let eventDebugString = `event=${eventId}`;
731735
if (event.threadRootId) {
732736
eventDebugString += `(belongs to thread=${event.threadRootId})`;
733737
}
@@ -738,17 +742,13 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
738742
return;
739743
}
740744

741-
const eventId = event.getId()!;
742745
timeline.addEvent(event, {
743746
toStartOfTimeline,
744747
roomState,
745748
timelineWasEmpty,
746749
});
747750
this._eventIdToTimeline.set(eventId, timeline);
748751

749-
this.relations.aggregateParentEvent(event);
750-
this.relations.aggregateChildEvent(event, this);
751-
752752
const data: IRoomTimelineData = {
753753
timeline: timeline,
754754
liveEvent: !toStartOfTimeline && timeline == this.liveTimeline && !fromCache,
@@ -782,13 +782,17 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
782782
"in timelineSet(threadId=${this.thread?.id})`);
783783
}
784784

785+
const eventId = event.getId()!;
786+
this.relations.aggregateParentEvent(event);
787+
this.relations.aggregateChildEvent(event, this);
788+
785789
// Make sure events don't get mixed in timelines they shouldn't be in (e.g. a
786790
// threaded message should not be in the main timeline).
787791
//
788792
// We can only run this check for timelines with a `room` because `canContain`
789793
// requires it
790794
if (this.room && !this.canContain(event)) {
791-
let eventDebugString = `event=${event.getId()}`;
795+
let eventDebugString = `event=${eventId}`;
792796
if (event.threadRootId) {
793797
eventDebugString += `(belongs to thread=${event.threadRootId})`;
794798
}
@@ -830,13 +834,9 @@ export class EventTimelineSet extends TypedEventEmitter<EmittedEvents, EventTime
830834
// If we got to the end of the loop, insertIndex points at the end of
831835
// the list.
832836

833-
const eventId = event.getId()!;
834837
timeline.insertEvent(event, insertIndex, roomState);
835838
this._eventIdToTimeline.set(eventId, timeline);
836839

837-
this.relations.aggregateParentEvent(event);
838-
this.relations.aggregateChildEvent(event, this);
839-
840840
const data: IRoomTimelineData = {
841841
timeline: timeline,
842842
liveEvent: timeline == this.liveTimeline,

Diff for: src/models/room.ts

-19
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21032103
threadId?: string;
21042104
} {
21052105
if (!this.client?.supportsThreads()) {
2106-
logger.debug(`Room::eventShouldLiveIn: eventId=${event.getId()} client does not support threads`);
21072106
return {
21082107
shouldLiveInRoom: true,
21092108
shouldLiveInThread: false,
@@ -2112,11 +2111,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21122111

21132112
// A thread root is always shown in both timelines
21142113
if (event.isThreadRoot || roots?.has(event.getId()!)) {
2115-
if (event.isThreadRoot) {
2116-
logger.debug(`Room::eventShouldLiveIn: eventId=${event.getId()} isThreadRoot is true`);
2117-
} else {
2118-
logger.debug(`Room::eventShouldLiveIn: eventId=${event.getId()} is a known thread root`);
2119-
}
21202114
return {
21212115
shouldLiveInRoom: true,
21222116
shouldLiveInThread: true,
@@ -2127,9 +2121,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21272121
// A thread relation (1st and 2nd order) is always only shown in a thread
21282122
const threadRootId = event.threadRootId;
21292123
if (threadRootId != undefined) {
2130-
logger.debug(
2131-
`Room::eventShouldLiveIn: eventId=${event.getId()} threadRootId=${threadRootId} is part of a thread`,
2132-
);
21332124
return {
21342125
shouldLiveInRoom: false,
21352126
shouldLiveInThread: true,
@@ -2141,9 +2132,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21412132
let parentEvent: MatrixEvent | undefined;
21422133
if (parentEventId) {
21432134
parentEvent = this.findEventById(parentEventId) ?? events?.find((e) => e.getId() === parentEventId);
2144-
logger.debug(
2145-
`Room::eventShouldLiveIn: eventId=${event.getId()} parentEventId=${parentEventId} found=${!!parentEvent}`,
2146-
);
21472135
}
21482136

21492137
// Treat relations and redactions as extensions of their parents so evaluate parentEvent instead
@@ -2152,7 +2140,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21522140
}
21532141

21542142
if (!event.isRelation()) {
2155-
logger.debug(`Room::eventShouldLiveIn: eventId=${event.getId()} not a relation`);
21562143
return {
21572144
shouldLiveInRoom: true,
21582145
shouldLiveInThread: false,
@@ -2161,11 +2148,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21612148

21622149
// Edge case where we know the event is a relation but don't have the parentEvent
21632150
if (roots?.has(event.relationEventId!)) {
2164-
logger.debug(
2165-
`Room::eventShouldLiveIn: eventId=${event.getId()} relationEventId=${
2166-
event.relationEventId
2167-
} is a known root`,
2168-
);
21692151
return {
21702152
shouldLiveInRoom: true,
21712153
shouldLiveInThread: true,
@@ -2176,7 +2158,6 @@ export class Room extends ReadReceipt<RoomEmittedEvents, RoomEventHandlerMap> {
21762158
// We've exhausted all scenarios,
21772159
// we cannot assume that it lives in the main timeline as this may be a relation for an unknown thread
21782160
// adding the event in the wrong timeline causes stuck notifications and can break ability to send read receipts
2179-
logger.debug(`Room::eventShouldLiveIn: eventId=${event.getId()} belongs to an unknown timeline`);
21802161
return {
21812162
shouldLiveInRoom: false,
21822163
shouldLiveInThread: false,

0 commit comments

Comments
 (0)