diff --git a/apps/web/src/components/structures/TimelinePanel.tsx b/apps/web/src/components/structures/TimelinePanel.tsx index 392622745b..f05107d1ac 100644 --- a/apps/web/src/components/structures/TimelinePanel.tsx +++ b/apps/web/src/components/structures/TimelinePanel.tsx @@ -341,8 +341,12 @@ class TimelinePanel extends React.Component { const differentEventId = prevProps.eventId != this.props.eventId; const differentHighlightedEventId = prevProps.highlightedEventId != this.props.highlightedEventId; - const differentAvoidJump = prevProps.eventScrollIntoView && !this.props.eventScrollIntoView; - if (differentEventId || differentHighlightedEventId || differentAvoidJump) { + // Both directions matter. The flag is cleared once a jump has landed, so clicking the same + // permalink again flips it back to true and has to jump afresh. An unset prop means true, + // matching the default in loadTimeline. + const differentScrollIntoView = + (prevProps.eventScrollIntoView ?? true) !== (this.props.eventScrollIntoView ?? true); + if (differentEventId || differentHighlightedEventId || differentScrollIntoView) { logger.log( `TimelinePanel switching to eventId ${this.props.eventId} (was ${prevProps.eventId}), ` + `scrollIntoView: ${this.props.eventScrollIntoView} (was ${prevProps.eventScrollIntoView})`, diff --git a/apps/web/test/unit-tests/components/structures/TimelinePanel-test.tsx b/apps/web/test/unit-tests/components/structures/TimelinePanel-test.tsx index eeb1740c45..351c0669b3 100644 --- a/apps/web/test/unit-tests/components/structures/TimelinePanel-test.tsx +++ b/apps/web/test/unit-tests/components/structures/TimelinePanel-test.tsx @@ -439,6 +439,32 @@ describe("TimelinePanel", () => { expect(props.onEventScrolledIntoView).toHaveBeenCalledWith(events[1].getId()); }); + it("should scroll the event into view again when the same event is re-requested", () => { + const client = MatrixClientPeg.safeGet(); + const room = mkRoom(client, "roomId"); + const events = mockEvents(room); + + const props = { + ...getProps(room, events), + eventId: events[1].getId(), + eventScrollIntoView: true, + onEventScrolledIntoView: jest.fn(), + }; + + const { rerender } = render(); + expect(props.onEventScrolledIntoView).toHaveBeenCalledTimes(1); + + // RoomView clears the flag once the jump has landed, so the event stays put on re-render. + props.eventScrollIntoView = false; + rerender(); + expect(props.onEventScrolledIntoView).toHaveBeenCalledTimes(1); + + // Clicking the same permalink a second time asks for the very same event again. + props.eventScrollIntoView = true; + rerender(); + expect(props.onEventScrolledIntoView).toHaveBeenCalledTimes(2); + }); + it("paginates", async () => { const [client, room, events] = setupTestData(); const eventsPage1 = events.slice(0, 1);