Remove old pre-join UTD logic (#12464)
* remove old pre-join UTD logic and add a playwright test for new pre-join UTD * remove variable that isn't used any more * add missing synapse template * remove unused variable (again) and run prettier * add test that we can jump to an event before our latest join membership event * modify default template instead of creating a new template
This commit is contained in:
parent
948435ceb9
commit
4ed6da4eba
5 changed files with 232 additions and 126 deletions
|
@ -39,8 +39,7 @@ import {
|
|||
ThreadEvent,
|
||||
ReceiptType,
|
||||
} from "matrix-js-sdk/src/matrix";
|
||||
import { KnownMembership, Membership } from "matrix-js-sdk/src/types";
|
||||
import { debounce, findLastIndex, throttle } from "lodash";
|
||||
import { debounce, findLastIndex } from "lodash";
|
||||
import { logger } from "matrix-js-sdk/src/logger";
|
||||
|
||||
import SettingsStore from "../../settings/SettingsStore";
|
||||
|
@ -176,9 +175,6 @@ interface IState {
|
|||
// track whether our room timeline is loading
|
||||
timelineLoading: boolean;
|
||||
|
||||
// the index of the first event that is to be shown
|
||||
firstVisibleEventIndex: number;
|
||||
|
||||
// canBackPaginate == false may mean:
|
||||
//
|
||||
// * we haven't (successfully) loaded the timeline yet, or:
|
||||
|
@ -296,7 +292,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
events: [],
|
||||
liveEvents: [],
|
||||
timelineLoading: true,
|
||||
firstVisibleEventIndex: 0,
|
||||
canBackPaginate: false,
|
||||
canForwardPaginate: false,
|
||||
readMarkerVisible: true,
|
||||
|
@ -568,12 +563,11 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
this.overlayTimelineWindow!.unpaginate(overlayCount, backwards);
|
||||
}
|
||||
|
||||
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
|
||||
const { events, liveEvents } = this.getEvents();
|
||||
this.buildLegacyCallEventGroupers(events);
|
||||
this.setState({
|
||||
events,
|
||||
liveEvents,
|
||||
firstVisibleEventIndex,
|
||||
});
|
||||
|
||||
// We can now paginate in the unpaginated direction
|
||||
|
@ -617,11 +611,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
if (backwards && this.state.firstVisibleEventIndex !== 0) {
|
||||
debuglog("won't", dir, "paginate past first visible event");
|
||||
return Promise.resolve(false);
|
||||
}
|
||||
|
||||
debuglog("Initiating paginate; backwards:" + backwards);
|
||||
this.setState({ [paginatingKey]: true } as Pick<IState, PaginatingKey>);
|
||||
|
||||
|
@ -636,15 +625,14 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
|
||||
debuglog("paginate complete backwards:" + backwards + "; success:" + r);
|
||||
|
||||
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
|
||||
const { events, liveEvents } = this.getEvents();
|
||||
this.buildLegacyCallEventGroupers(events);
|
||||
const newState = {
|
||||
[paginatingKey]: false,
|
||||
[canPaginateKey]: r,
|
||||
events,
|
||||
liveEvents,
|
||||
firstVisibleEventIndex,
|
||||
} as Pick<IState, PaginatingKey | CanPaginateKey | "events" | "liveEvents" | "firstVisibleEventIndex">;
|
||||
} as Pick<IState, PaginatingKey | CanPaginateKey | "events" | "liveEvents">;
|
||||
|
||||
// moving the window in this direction may mean that we can now
|
||||
// paginate in the other where we previously could not.
|
||||
|
@ -662,11 +650,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
// itself into the right place
|
||||
return new Promise((resolve) => {
|
||||
this.setState(newState, () => {
|
||||
// we can continue paginating in the given direction if:
|
||||
// - timelineWindow.paginate says we can
|
||||
// - we're paginating forwards, or we won't be trying to
|
||||
// paginate backwards past the first visible event
|
||||
resolve(r && (!backwards || firstVisibleEventIndex === 0));
|
||||
// we can continue paginating in the given direction if
|
||||
// timelineWindow.paginate says we can
|
||||
resolve(r);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -782,14 +768,13 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
return;
|
||||
}
|
||||
|
||||
const { events, liveEvents, firstVisibleEventIndex } = this.getEvents();
|
||||
const { events, liveEvents } = this.getEvents();
|
||||
this.buildLegacyCallEventGroupers(events);
|
||||
const lastLiveEvent = liveEvents[liveEvents.length - 1];
|
||||
|
||||
const updatedState: Partial<IState> = {
|
||||
events,
|
||||
liveEvents,
|
||||
firstVisibleEventIndex,
|
||||
};
|
||||
|
||||
let callRMUpdated = false;
|
||||
|
@ -967,8 +952,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
|
||||
if (!this.state.events.includes(ev)) return;
|
||||
|
||||
this.recheckFirstVisibleEventIndex();
|
||||
|
||||
// Need to update as we don't display event tiles for events that
|
||||
// haven't yet been decrypted. The event will have just been updated
|
||||
// in place so we just need to re-render.
|
||||
|
@ -984,17 +967,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
this.setState({ clientSyncState });
|
||||
};
|
||||
|
||||
private recheckFirstVisibleEventIndex = throttle(
|
||||
(): void => {
|
||||
const firstVisibleEventIndex = this.checkForPreJoinUISI(this.state.events);
|
||||
if (firstVisibleEventIndex !== this.state.firstVisibleEventIndex) {
|
||||
this.setState({ firstVisibleEventIndex });
|
||||
}
|
||||
},
|
||||
500,
|
||||
{ leading: true, trailing: true },
|
||||
);
|
||||
|
||||
private readMarkerTimeout(readMarkerPosition: number | null): number {
|
||||
return readMarkerPosition === 0
|
||||
? this.context?.readMarkerInViewThresholdMs ?? this.state.readMarkerInViewThresholdMs
|
||||
|
@ -1721,7 +1693,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
}
|
||||
|
||||
// get the list of events from the timeline windows and the pending event list
|
||||
private getEvents(): Pick<IState, "events" | "liveEvents" | "firstVisibleEventIndex"> {
|
||||
private getEvents(): Pick<IState, "events" | "liveEvents"> {
|
||||
const mainEvents = this.timelineWindow!.getEvents();
|
||||
let overlayEvents = this.overlayTimelineWindow?.getEvents() ?? [];
|
||||
if (this.props.overlayTimelineSetFilter !== undefined) {
|
||||
|
@ -1759,8 +1731,6 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
client.decryptEventIfNeeded(events[i]);
|
||||
}
|
||||
|
||||
const firstVisibleEventIndex = this.checkForPreJoinUISI(events);
|
||||
|
||||
// Hold onto the live events separately. The read receipt and read marker
|
||||
// should use this list, so that they don't advance into pending events.
|
||||
const liveEvents = [...events];
|
||||
|
@ -1788,87 +1758,9 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
return {
|
||||
events,
|
||||
liveEvents,
|
||||
firstVisibleEventIndex,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for undecryptable messages that were sent while the user was not in
|
||||
* the room.
|
||||
*
|
||||
* @param {Array<MatrixEvent>} events The timeline events to check
|
||||
*
|
||||
* @return {Number} The index within `events` of the event after the most recent
|
||||
* undecryptable event that was sent while the user was not in the room. If no
|
||||
* such events were found, then it returns 0.
|
||||
*/
|
||||
private checkForPreJoinUISI(events: MatrixEvent[]): number {
|
||||
const cli = MatrixClientPeg.safeGet();
|
||||
const room = this.props.timelineSet.room;
|
||||
|
||||
const isThreadTimeline = [TimelineRenderingType.Thread, TimelineRenderingType.ThreadsList].includes(
|
||||
this.context.timelineRenderingType,
|
||||
);
|
||||
if (events.length === 0 || !room || !cli.isRoomEncrypted(room.roomId) || isThreadTimeline) {
|
||||
logger.debug("checkForPreJoinUISI: showing all messages, skipping check");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const userId = cli.getSafeUserId();
|
||||
|
||||
// get the user's membership at the last event by getting the timeline
|
||||
// that the event belongs to, and traversing the timeline looking for
|
||||
// that event, while keeping track of the user's membership
|
||||
let i = events.length - 1;
|
||||
let userMembership: Membership = KnownMembership.Leave;
|
||||
for (; i >= 0; i--) {
|
||||
const timeline = this.props.timelineSet.getTimelineForEvent(events[i].getId()!);
|
||||
if (!timeline) {
|
||||
// Somehow, it seems to be possible for live events to not have
|
||||
// a timeline, even though that should not happen. :(
|
||||
// https://github.com/vector-im/element-web/issues/12120
|
||||
logger.warn(
|
||||
`Event ${events[i].getId()} in room ${room.roomId} is live, ` + `but it does not have a timeline`,
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
userMembership =
|
||||
timeline.getState(EventTimeline.FORWARDS)?.getMember(userId)?.membership ?? KnownMembership.Leave;
|
||||
const timelineEvents = timeline.getEvents();
|
||||
for (let j = timelineEvents.length - 1; j >= 0; j--) {
|
||||
const event = timelineEvents[j];
|
||||
if (event.getId() === events[i].getId()) {
|
||||
break;
|
||||
} else if (event.getStateKey() === userId && event.getType() === EventType.RoomMember) {
|
||||
userMembership = event.getPrevContent().membership || KnownMembership.Leave;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// now go through the rest of the events and find the first undecryptable
|
||||
// one that was sent when the user wasn't in the room
|
||||
for (; i >= 0; i--) {
|
||||
const event = events[i];
|
||||
if (event.getStateKey() === userId && event.getType() === EventType.RoomMember) {
|
||||
userMembership = event.getPrevContent().membership || KnownMembership.Leave;
|
||||
} else if (
|
||||
userMembership === KnownMembership.Leave &&
|
||||
(event.isDecryptionFailure() || event.isBeingDecrypted())
|
||||
) {
|
||||
// reached an undecryptable message when the user wasn't in the room -- don't try to load any more
|
||||
// Note: for now, we assume that events that are being decrypted are
|
||||
// not decryptable - we will be called once more when it is decrypted.
|
||||
logger.debug("checkForPreJoinUISI: reached a pre-join UISI at index ", i);
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
logger.debug("checkForPreJoinUISI: did not find pre-join UISI");
|
||||
return 0;
|
||||
}
|
||||
|
||||
private indexForEventId(evId: string | null): number | null {
|
||||
if (evId === null) {
|
||||
return null;
|
||||
|
@ -2119,9 +2011,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
// the HS and fetch the latest events, so we are effectively forward paginating.
|
||||
const forwardPaginating =
|
||||
this.state.forwardPaginating || ["PREPARED", "CATCHUP"].includes(this.state.clientSyncState!);
|
||||
const events = this.state.firstVisibleEventIndex
|
||||
? this.state.events.slice(this.state.firstVisibleEventIndex)
|
||||
: this.state.events;
|
||||
const events = this.state.events;
|
||||
return (
|
||||
<MessagePanel
|
||||
ref={this.messagePanel}
|
||||
|
@ -2134,7 +2024,7 @@ class TimelinePanel extends React.Component<IProps, IState> {
|
|||
highlightedEventId={this.props.highlightedEventId}
|
||||
readMarkerEventId={this.state.readMarkerEventId}
|
||||
readMarkerVisible={this.state.readMarkerVisible}
|
||||
canBackPaginate={this.state.canBackPaginate && this.state.firstVisibleEventIndex === 0}
|
||||
canBackPaginate={this.state.canBackPaginate}
|
||||
showUrlPreview={this.props.showUrlPreview}
|
||||
showReadReceipts={this.props.showReadReceipts}
|
||||
ourUserId={MatrixClientPeg.safeGet().getSafeUserId()}
|
||||
|
|
|
@ -25,7 +25,6 @@ const HistoryTile: React.FC = () => {
|
|||
const { room } = useContext(RoomContext);
|
||||
|
||||
const oldState = room?.getLiveTimeline().getState(EventTimeline.BACKWARDS);
|
||||
const encryptionState = oldState?.getStateEvents("m.room.encryption")[0];
|
||||
const historyState = oldState?.getStateEvents("m.room.history_visibility")[0]?.getContent().history_visibility;
|
||||
|
||||
let subtitle: string | undefined;
|
||||
|
@ -33,8 +32,6 @@ const HistoryTile: React.FC = () => {
|
|||
subtitle = _t("timeline|no_permission_messages_before_invite");
|
||||
} else if (historyState == "joined") {
|
||||
subtitle = _t("timeline|no_permission_messages_before_join");
|
||||
} else if (encryptionState) {
|
||||
subtitle = _t("timeline|encrypted_historical_messages_unavailable");
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue