Skip to content

Commit 75674d9

Browse files
author
Germain
authored
Create threads event timeline set in the room model (#2244)
1 parent 779afbc commit 75674d9

File tree

2 files changed

+94
-2
lines changed

2 files changed

+94
-2
lines changed

src/models/room.ts

Lines changed: 89 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,9 +35,16 @@ import {
3535
} from "../@types/event";
3636
import { IRoomVersionsCapability, MatrixClient, PendingEventOrdering, RoomVersionStability } from "../client";
3737
import { GuestAccess, HistoryVisibility, JoinRule, ResizeMethod } from "../@types/partials";
38-
import { Filter } from "../filter";
38+
import { Filter, IFilterDefinition } from "../filter";
3939
import { RoomState } from "./room-state";
40-
import { Thread, ThreadEvent, EventHandlerMap as ThreadHandlerMap } from "./thread";
40+
import {
41+
Thread,
42+
ThreadEvent,
43+
EventHandlerMap as ThreadHandlerMap,
44+
FILTER_RELATED_BY_REL_TYPES, THREAD_RELATION_TYPE,
45+
FILTER_RELATED_BY_SENDERS,
46+
ThreadFilterType,
47+
} from "./thread";
4148
import { Method } from "../http-api";
4249
import { TypedEventEmitter } from "./typed-event-emitter";
4350

@@ -191,6 +198,7 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
191198
private receiptCacheByEventId: ReceiptCache = {}; // { event_id: ICachedReceipt[] }
192199
private notificationCounts: Partial<Record<NotificationCountType, number>> = {};
193200
private readonly timelineSets: EventTimelineSet[];
201+
public readonly threadsTimelineSets: EventTimelineSet[] = [];
194202
// any filtered timeline sets we're maintaining for this room
195203
private readonly filteredTimelineSets: Record<string, EventTimelineSet> = {}; // filter_id: timelineSet
196204
private readonly pendingEventList?: MatrixEvent[];
@@ -338,6 +346,15 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
338346
RoomEvent.TimelineReset,
339347
]);
340348

349+
if (this.client?.supportsExperimentalThreads) {
350+
Promise.all([
351+
this.createThreadTimelineSet(),
352+
this.createThreadTimelineSet(ThreadFilterType.My),
353+
]).then((timelineSets) => {
354+
this.threadsTimelineSets.push(...timelineSets);
355+
});
356+
}
357+
341358
this.fixUpLegacyTimelineFields();
342359

343360
if (this.opts.pendingEventOrdering === PendingEventOrdering.Detached) {
@@ -1377,6 +1394,61 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
13771394
return timelineSet;
13781395
}
13791396

1397+
private async createThreadTimelineSet(filterType?: ThreadFilterType): Promise<EventTimelineSet> {
1398+
let timelineSet: EventTimelineSet;
1399+
if (Thread.hasServerSideSupport) {
1400+
const myUserId = this.client.getUserId();
1401+
const filter = new Filter(myUserId);
1402+
1403+
const definition: IFilterDefinition = {
1404+
"room": {
1405+
"timeline": {
1406+
[FILTER_RELATED_BY_REL_TYPES.name]: [THREAD_RELATION_TYPE.name],
1407+
},
1408+
},
1409+
};
1410+
1411+
if (filterType === ThreadFilterType.My) {
1412+
definition.room.timeline[FILTER_RELATED_BY_SENDERS.name] = [myUserId];
1413+
}
1414+
1415+
filter.setDefinition(definition);
1416+
const filterId = await this.client.getOrCreateFilter(
1417+
`THREAD_PANEL_${this.roomId}_${filterType}`,
1418+
filter,
1419+
);
1420+
filter.filterId = filterId;
1421+
timelineSet = this.getOrCreateFilteredTimelineSet(
1422+
filter,
1423+
{
1424+
prepopulateTimeline: false,
1425+
pendingEvents: false,
1426+
},
1427+
);
1428+
1429+
// An empty pagination token allows to paginate from the very bottom of
1430+
// the timeline set.
1431+
timelineSet.getLiveTimeline().setPaginationToken("", EventTimeline.BACKWARDS);
1432+
} else {
1433+
timelineSet = new EventTimelineSet(this, {
1434+
pendingEvents: false,
1435+
});
1436+
1437+
Array.from(this.threads)
1438+
.forEach(([, thread]) => {
1439+
if (thread.length === 0) return;
1440+
const currentUserParticipated = thread.events.some(event => {
1441+
return event.getSender() === this.client.getUserId();
1442+
});
1443+
if (filterType !== ThreadFilterType.My || currentUserParticipated) {
1444+
timelineSet.getLiveTimeline().addEvent(thread.rootEvent, false);
1445+
}
1446+
});
1447+
}
1448+
1449+
return timelineSet;
1450+
}
1451+
13801452
/**
13811453
* Forget the timelineSet for this room with the given filter
13821454
*
@@ -1476,6 +1548,21 @@ export class Room extends TypedEventEmitter<EmittedEvents, RoomEventHandlerMap>
14761548
}
14771549

14781550
this.emit(ThreadEvent.New, thread, toStartOfTimeline);
1551+
1552+
this.threadsTimelineSets.forEach(timelineSet => {
1553+
if (thread.rootEvent) {
1554+
if (Thread.hasServerSideSupport) {
1555+
timelineSet.addLiveEvent(thread.rootEvent);
1556+
} else {
1557+
timelineSet.addEventToTimeline(
1558+
thread.rootEvent,
1559+
timelineSet.getLiveTimeline(),
1560+
toStartOfTimeline,
1561+
);
1562+
}
1563+
}
1564+
});
1565+
14791566
return thread;
14801567
}
14811568
}

src/models/thread.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,8 @@ export const THREAD_RELATION_TYPE = new ServerControlledNamespacedValue(
364364
"m.thread",
365365
"io.element.thread",
366366
);
367+
368+
export enum ThreadFilterType {
369+
"My",
370+
"All"
371+
}

0 commit comments

Comments
 (0)