Hook thread panel to homeserver API (#7352)
This commit is contained in:
parent
b4755f38b9
commit
cd04799cb4
1 changed files with 103 additions and 72 deletions
|
@ -14,10 +14,17 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { Thread, ThreadEvent } from 'matrix-js-sdk/src/models/thread';
|
||||
import React, { useContext, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { EventTimelineSet } from 'matrix-js-sdk/src/models/event-timeline-set';
|
||||
import { Room } from 'matrix-js-sdk/src/models/room';
|
||||
import { RelationType } from 'matrix-js-sdk/src/@types/event';
|
||||
import { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||
import {
|
||||
Filter,
|
||||
IFilterDefinition,
|
||||
UNSTABLE_FILTER_RELATION_SENDERS,
|
||||
UNSTABLE_FILTER_RELATION_TYPES,
|
||||
} from 'matrix-js-sdk/src/filter';
|
||||
|
||||
import BaseCard from "../views/right_panel/BaseCard";
|
||||
import ResizeNotifier from '../../utils/ResizeNotifier';
|
||||
|
@ -28,10 +35,65 @@ import ContextMenu, { ChevronFace, MenuItemRadio, useContextMenu } from './Conte
|
|||
import RoomContext, { TimelineRenderingType } from '../../contexts/RoomContext';
|
||||
import TimelinePanel from './TimelinePanel';
|
||||
import { Layout } from '../../settings/enums/Layout';
|
||||
import { useEventEmitter } from '../../hooks/useEventEmitter';
|
||||
import { TileShape } from '../views/rooms/EventTile';
|
||||
import { RoomPermalinkCreator } from '../../utils/permalinks/Permalinks';
|
||||
|
||||
async function getThreadTimelineSet(
|
||||
client: MatrixClient,
|
||||
room: Room,
|
||||
filterType = ThreadFilterType.All,
|
||||
): Promise<EventTimelineSet> {
|
||||
const myUserId = client.getUserId();
|
||||
const filter = new Filter(myUserId);
|
||||
|
||||
const definition: IFilterDefinition = {
|
||||
"room": {
|
||||
"timeline": {
|
||||
[UNSTABLE_FILTER_RELATION_TYPES.name]: [RelationType.Thread],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
if (filterType === ThreadFilterType.My) {
|
||||
definition.room.timeline[UNSTABLE_FILTER_RELATION_SENDERS.name] = [myUserId];
|
||||
}
|
||||
|
||||
filter.setDefinition(definition);
|
||||
|
||||
let timelineSet;
|
||||
|
||||
try {
|
||||
const filterId = await client.getOrCreateFilter(
|
||||
`THREAD_PANEL_${room.roomId}_${filterType}`,
|
||||
filter,
|
||||
);
|
||||
filter.filterId = filterId;
|
||||
timelineSet = room.getOrCreateFilteredTimelineSet(
|
||||
filter,
|
||||
{ prepopulateTimeline: false },
|
||||
);
|
||||
|
||||
timelineSet.resetLiveTimeline();
|
||||
await client.paginateEventTimeline(
|
||||
timelineSet.getLiveTimeline(),
|
||||
{ backwards: true, limit: 20 },
|
||||
);
|
||||
} catch (e) {
|
||||
// Filter creation fails if HomeServer does not support the new relation
|
||||
// filter fields. We fallback to the threads that have been discovered in
|
||||
// the main timeline
|
||||
timelineSet = new EventTimelineSet(room, {});
|
||||
for (const [, thread] of room.threads) {
|
||||
const isOwnEvent = thread.rootEvent.getSender() === client.getUserId();
|
||||
if (filterType !== ThreadFilterType.My || isOwnEvent) {
|
||||
timelineSet.getLiveTimeline().addEvent(thread.rootEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return timelineSet;
|
||||
}
|
||||
|
||||
interface IProps {
|
||||
roomId: string;
|
||||
onClose: () => void;
|
||||
|
@ -50,44 +112,6 @@ type ThreadPanelHeaderOption = {
|
|||
key: ThreadFilterType;
|
||||
};
|
||||
|
||||
const useFilteredThreadsTimelinePanel = ({
|
||||
threads,
|
||||
room,
|
||||
filterOption,
|
||||
userId,
|
||||
updateTimeline,
|
||||
}: {
|
||||
threads: Map<string, Thread>;
|
||||
room: Room;
|
||||
userId: string;
|
||||
filterOption: ThreadFilterType;
|
||||
updateTimeline: () => void;
|
||||
}) => {
|
||||
const timelineSet = useMemo(() => new EventTimelineSet(null, {
|
||||
timelineSupport: true,
|
||||
unstableClientRelationAggregation: true,
|
||||
pendingEvents: false,
|
||||
}), []);
|
||||
|
||||
const buildThreadList = useCallback(function(timelineSet: EventTimelineSet) {
|
||||
timelineSet.resetLiveTimeline("");
|
||||
Array.from(threads)
|
||||
.forEach(([, thread]) => {
|
||||
if (filterOption !== ThreadFilterType.My || thread.hasCurrentUserParticipated) {
|
||||
timelineSet.addLiveEvent(thread.rootEvent);
|
||||
}
|
||||
});
|
||||
updateTimeline();
|
||||
}, [filterOption, threads, updateTimeline]);
|
||||
|
||||
useEffect(() => { buildThreadList(timelineSet); }, [timelineSet, buildThreadList]);
|
||||
|
||||
useEventEmitter(room, ThreadEvent.Update, () => { buildThreadList(timelineSet); });
|
||||
useEventEmitter(room, ThreadEvent.New, () => { buildThreadList(timelineSet); });
|
||||
|
||||
return timelineSet;
|
||||
};
|
||||
|
||||
export const ThreadPanelHeaderFilterOptionItem = ({
|
||||
label,
|
||||
description,
|
||||
|
@ -185,19 +209,24 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
|
|||
const [filterOption, setFilterOption] = useState<ThreadFilterType>(ThreadFilterType.All);
|
||||
const ref = useRef<TimelinePanel>();
|
||||
|
||||
const filteredTimelineSet = useFilteredThreadsTimelinePanel({
|
||||
threads: room.threads,
|
||||
room,
|
||||
filterOption,
|
||||
userId: mxClient.getUserId(),
|
||||
updateTimeline: () => ref.current?.refreshTimeline(),
|
||||
});
|
||||
const [timelineSet, setTimelineSet] = useState<EventTimelineSet | null>(null);
|
||||
const timelineSetPromise = useMemo(
|
||||
async () => {
|
||||
const timelineSet = getThreadTimelineSet(mxClient, room, filterOption);
|
||||
return timelineSet;
|
||||
},
|
||||
[mxClient, room, filterOption],
|
||||
);
|
||||
useEffect(() => {
|
||||
timelineSetPromise
|
||||
.then(timelineSet => { setTimelineSet(timelineSet); })
|
||||
.catch(() => setTimelineSet(null));
|
||||
}, [timelineSetPromise]);
|
||||
|
||||
return (
|
||||
<RoomContext.Provider value={{
|
||||
...roomContext,
|
||||
timelineRenderingType: TimelineRenderingType.ThreadsList,
|
||||
liveTimeline: filteredTimelineSet.getLiveTimeline(),
|
||||
showHiddenEventsInTimeline: true,
|
||||
}}>
|
||||
<BaseCard
|
||||
|
@ -206,29 +235,31 @@ const ThreadPanel: React.FC<IProps> = ({ roomId, onClose, permalinkCreator }) =>
|
|||
onClose={onClose}
|
||||
withoutScrollContainer={true}
|
||||
>
|
||||
<TimelinePanel
|
||||
ref={ref}
|
||||
showReadReceipts={false} // No RR support in thread's MVP
|
||||
manageReadReceipts={false} // No RR support in thread's MVP
|
||||
manageReadMarkers={false} // No RM support in thread's MVP
|
||||
sendReadReceiptOnLoad={false} // No RR support in thread's MVP
|
||||
timelineSet={filteredTimelineSet}
|
||||
showUrlPreview={true}
|
||||
empty={<EmptyThread
|
||||
filterOption={filterOption}
|
||||
showAllThreadsCallback={() => setFilterOption(ThreadFilterType.All)}
|
||||
/>}
|
||||
alwaysShowTimestamps={true}
|
||||
layout={Layout.Group}
|
||||
hideThreadedMessages={false}
|
||||
hidden={false}
|
||||
showReactions={true}
|
||||
className="mx_RoomView_messagePanel mx_GroupLayout"
|
||||
membersLoaded={true}
|
||||
permalinkCreator={permalinkCreator}
|
||||
tileShape={TileShape.ThreadPanel}
|
||||
disableGrouping={true}
|
||||
/>
|
||||
{ timelineSet && (
|
||||
<TimelinePanel
|
||||
ref={ref}
|
||||
showReadReceipts={false} // No RR support in thread's MVP
|
||||
manageReadReceipts={false} // No RR support in thread's MVP
|
||||
manageReadMarkers={false} // No RM support in thread's MVP
|
||||
sendReadReceiptOnLoad={false} // No RR support in thread's MVP
|
||||
timelineSet={timelineSet}
|
||||
showUrlPreview={true}
|
||||
empty={<EmptyThread
|
||||
filterOption={filterOption}
|
||||
showAllThreadsCallback={() => setFilterOption(ThreadFilterType.All)}
|
||||
/>}
|
||||
alwaysShowTimestamps={true}
|
||||
layout={Layout.Group}
|
||||
hideThreadedMessages={false}
|
||||
hidden={false}
|
||||
showReactions={false}
|
||||
className="mx_RoomView_messagePanel mx_GroupLayout"
|
||||
membersLoaded={true}
|
||||
permalinkCreator={permalinkCreator}
|
||||
tileShape={TileShape.ThreadPanel}
|
||||
disableGrouping={true}
|
||||
/>
|
||||
) }
|
||||
</BaseCard>
|
||||
</RoomContext.Provider>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue