From 286148681dd0d39f8d1eb74dbcfd1d559a9cc874 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Wed, 4 May 2022 23:42:27 -0500 Subject: [PATCH 1/9] Log TimelinePanel debuggin info when opening the bug report modal To debug all of the timeline problems: - https://github.com/vector-im/element-web/issues/21613 - https://github.com/vector-im/element-web/issues/21922 - https://github.com/vector-im/element-web/issues/21432 - https://github.com/vector-im/element-web/issues/21533 --- src/components/structures/TimelinePanel.tsx | 78 ++++++++++++++++++- .../views/dialogs/BugReportDialog.tsx | 10 +++ src/components/views/rooms/EventTile.tsx | 4 + 3 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 7201e3c6f2e..68d56e0bc71 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -69,6 +69,32 @@ if (DEBUG) { debuglog = logger.log.bind(console, "TimelinePanel debuglog:"); } +/** + * Iterate across all of the timelineSets and timelines inside to expose all of + * the event IDs contained inside. + * + * @return An event ID list for every timeline in every timelineSet + */ +function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] { + const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => { + const timelineMap = {}; + + const timelines = timelineSet.getTimelines(); + const liveTimeline = timelineSet.getLiveTimeline(); + + timelines.forEach((timeline, index) => { + // Add a special label when it is the live timeline so we can tell + // it apart from the others + const isLiveTimeline = timeline === liveTimeline; + timelineMap[isLiveTimeline ? 'liveTimeline' : `${index}`] = timeline.getEvents().map(ev => ev.getId()); + }); + + return timelineMap; + }); + + return serializedEventIdsInTimelineSet; +} + interface IProps { // The js-sdk EventTimelineSet object for the timeline sequence we are // representing. This may or may not have a room, depending on what it's @@ -294,6 +320,7 @@ class TimelinePanel extends React.Component { cli.on(MatrixEventEvent.Decrypted, this.onEventDecrypted); cli.on(MatrixEventEvent.Replaced, this.onEventReplaced); cli.on(ClientEvent.Sync, this.onSync); + cli.on(ClientEvent.DumpDebugLogs, this.onDumpDebugLogs); } // TODO: [REACT-WARNING] Move into constructor @@ -369,9 +396,55 @@ class TimelinePanel extends React.Component { client.removeListener(MatrixEventEvent.Replaced, this.onEventReplaced); client.removeListener(MatrixEventEvent.VisibilityChange, this.onEventVisibilityChange); client.removeListener(ClientEvent.Sync, this.onSync); + client.removeListener(ClientEvent.Sync, this.onDumpDebugLogs); } } + private onDumpDebugLogs = (): void => { + const roomId = this.props.timelineSet.room.roomId; + // This includes state and hidden events which we don't render + const eventIdList = this.state.events.map((ev) => ev.getId()); + + // Get the list of actually rendered events seen in the DOM. + let renderedEventIds; + const messagePanel = this.messagePanel.current; + if (messagePanel) { + const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as HTMLElement; + if (messagePanelNode) { + const actuallyRenderedEvents = messagePanelNode.querySelectorAll('[data-event-id]'); + renderedEventIds = [...actuallyRenderedEvents].map((renderedEvent) => { + return renderedEvent.getAttribute('data-txn-id') || renderedEvent.getAttribute('data-event-id'); + }); + } + } + + let serializedEventIdsFromTimelineSets; + let serializedEventIdsFromThreadsTimelineSets; + let serializedThreadsMap = {}; + const client = MatrixClientPeg.get(); + if (client) { + const room = client.getRoom(roomId); + const timelineSets = room.getTimelineSets(); + const threadsTimelineSets = room.threadsTimelineSets; + + serializedEventIdsFromTimelineSets = serializeEventIdsFromTimelineSets(timelineSets); + serializedEventIdsFromThreadsTimelineSets = serializeEventIdsFromTimelineSets(threadsTimelineSets); + + room.getThreadsMap().forEach((thread, threadId) => { + serializedThreadsMap[threadId] = thread.events.map(ev => ev.getId()); + }); + } + + logger.debug( + `TimelinePanel(${this.context.timelineRenderingType}): Debugging info for ${roomId}\n` + + `\tevents(${eventIdList.length})=${JSON.stringify(eventIdList)}\n` + + `\trenderedEventIds(${renderedEventIds ? renderedEventIds.length : 0})=${JSON.stringify(renderedEventIds)}\n` + + `\tserializedEventIdsFromTimelineSets=${JSON.stringify(serializedEventIdsFromTimelineSets)}\n` + + `\tserializedEventIdsFromThreadsTimelineSets=${JSON.stringify(serializedEventIdsFromThreadsTimelineSets)}\n` + + `\tserializedThreadsMap=${JSON.stringify(serializedThreadsMap)}`, + ); + } + private onMessageListUnfillRequest = (backwards: boolean, scrollToken: string): void => { // If backwards, unpaginate from the back (i.e. the start of the timeline) const dir = backwards ? EventTimeline.BACKWARDS : EventTimeline.FORWARDS; @@ -1183,7 +1256,10 @@ class TimelinePanel extends React.Component { private loadTimeline(eventId?: string, pixelOffset?: number, offsetBase?: number, scrollIntoView = true): void { this.timelineWindow = new TimelineWindow( MatrixClientPeg.get(), this.props.timelineSet, - { windowLimit: this.props.timelineCap }); + { + windowLimit: this.props.timelineCap, + contextLabel: this.context.timelineRenderingType, + }); const onLoaded = () => { if (this.unmounted) return; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index eae26735214..2e90eeac89b 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -19,6 +19,7 @@ limitations under the License. import React from 'react'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; @@ -65,6 +66,15 @@ export default class BugReportDialog extends React.Component { downloadProgress: null, }; this.unmounted = false; + + const client = MatrixClientPeg.get(); + // Get all of the extra info dumped to the console when someone is about + // to send debug logs. Since this is a fire and forget action, we do + // this when the bug report dialog is opened instead of when we submit + // logs because we have no signal to know when all of the various + // components have finished logging. Someone could potentially send logs + // before we fully dump everything but it's probably unlikely. + client.dumpDebugLogs(); } public componentWillUnmount() { diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index b74556ad5f0..f8604f75b73 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -1290,6 +1290,8 @@ export class UnwrappedEventTile extends React.Component { "data-has-reply": !!replyChain, "data-layout": this.props.layout, "data-self": isOwnEvent, + "data-txn-id": this.props.mxEvent.getTxnId(), + "data-event-id": this.props.mxEvent.getId(), "onMouseEnter": () => this.setState({ hover: true }), "onMouseLeave": () => this.setState({ hover: false }), }, [ @@ -1436,6 +1438,8 @@ export class UnwrappedEventTile extends React.Component { "data-scroll-tokens": scrollToken, "data-layout": this.props.layout, "data-self": isOwnEvent, + "data-txn-id": this.props.mxEvent.getTxnId(), + "data-event-id": this.props.mxEvent.getId(), "data-has-reply": !!replyChain, "onMouseEnter": () => this.setState({ hover: true }), "onMouseLeave": () => this.setState({ hover: false }), From c15cac9c5611b68f593ee305ac3ad5b445da6568 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 02:16:42 -0500 Subject: [PATCH 2/9] Fix up some lints --- src/components/structures/TimelinePanel.tsx | 19 +++++++++---------- .../views/dialogs/BugReportDialog.tsx | 2 +- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 68d56e0bc71..804d796e246 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -420,7 +420,7 @@ class TimelinePanel extends React.Component { let serializedEventIdsFromTimelineSets; let serializedEventIdsFromThreadsTimelineSets; - let serializedThreadsMap = {}; + const serializedThreadsMap = {}; const client = MatrixClientPeg.get(); if (client) { const room = client.getRoom(roomId); @@ -430,20 +430,22 @@ class TimelinePanel extends React.Component { serializedEventIdsFromTimelineSets = serializeEventIdsFromTimelineSets(timelineSets); serializedEventIdsFromThreadsTimelineSets = serializeEventIdsFromTimelineSets(threadsTimelineSets); - room.getThreadsMap().forEach((thread, threadId) => { - serializedThreadsMap[threadId] = thread.events.map(ev => ev.getId()); + room.getThreads().forEach((thread) => { + serializedThreadsMap[thread.id] = thread.events.map(ev => ev.getId()); }); } logger.debug( `TimelinePanel(${this.context.timelineRenderingType}): Debugging info for ${roomId}\n` + `\tevents(${eventIdList.length})=${JSON.stringify(eventIdList)}\n` + - `\trenderedEventIds(${renderedEventIds ? renderedEventIds.length : 0})=${JSON.stringify(renderedEventIds)}\n` + + `\trenderedEventIds(${renderedEventIds ? renderedEventIds.length : 0})=` + + `${JSON.stringify(renderedEventIds)}\n` + `\tserializedEventIdsFromTimelineSets=${JSON.stringify(serializedEventIdsFromTimelineSets)}\n` + - `\tserializedEventIdsFromThreadsTimelineSets=${JSON.stringify(serializedEventIdsFromThreadsTimelineSets)}\n` + + `\tserializedEventIdsFromThreadsTimelineSets=` + + `${JSON.stringify(serializedEventIdsFromThreadsTimelineSets)}\n` + `\tserializedThreadsMap=${JSON.stringify(serializedThreadsMap)}`, ); - } + }; private onMessageListUnfillRequest = (backwards: boolean, scrollToken: string): void => { // If backwards, unpaginate from the back (i.e. the start of the timeline) @@ -1256,10 +1258,7 @@ class TimelinePanel extends React.Component { private loadTimeline(eventId?: string, pixelOffset?: number, offsetBase?: number, scrollIntoView = true): void { this.timelineWindow = new TimelineWindow( MatrixClientPeg.get(), this.props.timelineSet, - { - windowLimit: this.props.timelineCap, - contextLabel: this.context.timelineRenderingType, - }); + { windowLimit: this.props.timelineCap }); const onLoaded = () => { if (this.unmounted) return; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index 2e90eeac89b..57c658173c4 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -67,7 +67,7 @@ export default class BugReportDialog extends React.Component { }; this.unmounted = false; - const client = MatrixClientPeg.get(); + const client = MatrixClientPeg.get(); // Get all of the extra info dumped to the console when someone is about // to send debug logs. Since this is a fire and forget action, we do // this when the bug report dialog is opened instead of when we submit From 144e23b9cfe57713b12e1467a15863925ff4ed03 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 17:43:50 -0500 Subject: [PATCH 3/9] Add some descriptive comments --- src/components/structures/TimelinePanel.tsx | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index a9fe4985978..767ae17f9b3 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -396,16 +396,29 @@ class TimelinePanel extends React.Component { client.removeListener(MatrixEventEvent.Replaced, this.onEventReplaced); client.removeListener(MatrixEventEvent.VisibilityChange, this.onEventVisibilityChange); client.removeListener(ClientEvent.Sync, this.onSync); - client.removeListener(ClientEvent.Sync, this.onDumpDebugLogs); + client.removeListener(ClientEvent.DumpDebugLogs, this.onDumpDebugLogs); } } + /** + * Logs out debug info to describe the state of the TimelinePanel and the + * events in the room according to the matrix-js-sdk. This is useful when + * debugging problems like messages out of order, or messages that should + * not be showing up in a thread, etc. + * + * It's too expensive and cumbersome to do all of these calculations for + * every message change so instead we only log it out when the + * BugReportDialog is opened. + */ private onDumpDebugLogs = (): void => { const roomId = this.props.timelineSet.room.roomId; + // Get a list of the event IDs given to the TimelinePanel. // This includes state and hidden events which we don't render const eventIdList = this.state.events.map((ev) => ev.getId()); // Get the list of actually rendered events seen in the DOM. + // This is useful to know for sure what's being shown on screen. + // And we can suss out any corrupted React `key` problems. let renderedEventIds; const messagePanel = this.messagePanel.current; if (messagePanel) { @@ -418,6 +431,8 @@ class TimelinePanel extends React.Component { } } + // Get the list of events and threads for the room as seen by the + // matrix-js-sdk. let serializedEventIdsFromTimelineSets; let serializedEventIdsFromThreadsTimelineSets; const serializedThreadsMap = {}; @@ -427,9 +442,11 @@ class TimelinePanel extends React.Component { const timelineSets = room.getTimelineSets(); const threadsTimelineSets = room.threadsTimelineSets; + // Serialize all of the timelineSets and timelines in each set to their event IDs serializedEventIdsFromTimelineSets = serializeEventIdsFromTimelineSets(timelineSets); serializedEventIdsFromThreadsTimelineSets = serializeEventIdsFromTimelineSets(threadsTimelineSets); + // Serialize all threads in the room from theadId -> event IDs in the thread room.getThreads().forEach((thread) => { serializedThreadsMap[thread.id] = thread.events.map(ev => ev.getId()); }); From 03ef042037983aa12e16c5d97f328eeecc994648 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 19:09:42 -0500 Subject: [PATCH 4/9] =?UTF-8?q?Better=20comment,=20only=20speak=20when=20s?= =?UTF-8?q?poken=20to=20=F0=9F=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Travis Ralston --- src/components/structures/TimelinePanel.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 767ae17f9b3..9d7ca56a850 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -407,8 +407,7 @@ class TimelinePanel extends React.Component { * not be showing up in a thread, etc. * * It's too expensive and cumbersome to do all of these calculations for - * every message change so instead we only log it out when the - * BugReportDialog is opened. + * every message change so instead we only log it out when asked. */ private onDumpDebugLogs = (): void => { const roomId = this.props.timelineSet.room.roomId; From 3307c4ec7d04a687c7693a79325255cb40966e31 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 19:31:33 -0500 Subject: [PATCH 5/9] Address review --- src/components/structures/TimelinePanel.tsx | 75 +++++++++++---------- 1 file changed, 39 insertions(+), 36 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 9d7ca56a850..1882811fa90 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -69,32 +69,6 @@ if (DEBUG) { debuglog = logger.log.bind(console, "TimelinePanel debuglog:"); } -/** - * Iterate across all of the timelineSets and timelines inside to expose all of - * the event IDs contained inside. - * - * @return An event ID list for every timeline in every timelineSet - */ -function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] { - const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => { - const timelineMap = {}; - - const timelines = timelineSet.getTimelines(); - const liveTimeline = timelineSet.getLiveTimeline(); - - timelines.forEach((timeline, index) => { - // Add a special label when it is the live timeline so we can tell - // it apart from the others - const isLiveTimeline = timeline === liveTimeline; - timelineMap[isLiveTimeline ? 'liveTimeline' : `${index}`] = timeline.getEvents().map(ev => ev.getId()); - }); - - return timelineMap; - }); - - return serializedEventIdsInTimelineSet; -} - interface IProps { // The js-sdk EventTimelineSet object for the timeline sequence we are // representing. This may or may not have a room, depending on what it's @@ -410,21 +384,24 @@ class TimelinePanel extends React.Component { * every message change so instead we only log it out when asked. */ private onDumpDebugLogs = (): void => { - const roomId = this.props.timelineSet.room.roomId; - // Get a list of the event IDs given to the TimelinePanel. + const roomId = this.props.timelineSet.room?.roomId; + // Get a list of the event IDs used in this TimelinePanel. // This includes state and hidden events which we don't render const eventIdList = this.state.events.map((ev) => ev.getId()); // Get the list of actually rendered events seen in the DOM. // This is useful to know for sure what's being shown on screen. // And we can suss out any corrupted React `key` problems. - let renderedEventIds; + let renderedEventIds: string[]; const messagePanel = this.messagePanel.current; if (messagePanel) { - const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as HTMLElement; + const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as Element; if (messagePanelNode) { const actuallyRenderedEvents = messagePanelNode.querySelectorAll('[data-event-id]'); renderedEventIds = [...actuallyRenderedEvents].map((renderedEvent) => { + // Get the txn ID for local echo events that haven't + // persisted yet or the event ID. This mimics the `key` + // logic when showing EventTile's in a MessagePanel return renderedEvent.getAttribute('data-txn-id') || renderedEvent.getAttribute('data-event-id'); }); } @@ -432,12 +409,12 @@ class TimelinePanel extends React.Component { // Get the list of events and threads for the room as seen by the // matrix-js-sdk. - let serializedEventIdsFromTimelineSets; - let serializedEventIdsFromThreadsTimelineSets; - const serializedThreadsMap = {}; + let serializedEventIdsFromTimelineSets: { [key: string]: string[] }[]; + let serializedEventIdsFromThreadsTimelineSets: { [key: string]: string[] }[]; + const serializedThreadsMap: { [key: string]: string[] } = {}; const client = MatrixClientPeg.get(); - if (client) { - const room = client.getRoom(roomId); + const room = client?.getRoom(roomId); + if (room) { const timelineSets = room.getTimelineSets(); const threadsTimelineSets = room.threadsTimelineSets; @@ -1556,7 +1533,7 @@ class TimelinePanel extends React.Component { const messagePanel = this.messagePanel.current; if (!messagePanel) return null; - const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as HTMLElement; + const messagePanelNode = ReactDOM.findDOMNode(messagePanel) as Element; if (!messagePanelNode) return null; // sometimes this happens for fresh rooms/post-sync const wrapperRect = messagePanelNode.getBoundingClientRect(); const myUserId = MatrixClientPeg.get().credentials.userId; @@ -1778,4 +1755,30 @@ class TimelinePanel extends React.Component { } } +/** + * Iterate across all of the timelineSets and timelines inside to expose all of + * the event IDs contained inside. + * + * @return An event ID list for every timeline in every timelineSet + */ + function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] { + const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => { + const timelineMap = {}; + + const timelines = timelineSet.getTimelines(); + const liveTimeline = timelineSet.getLiveTimeline(); + + timelines.forEach((timeline, index) => { + // Add a special label when it is the live timeline so we can tell + // it apart from the others + const isLiveTimeline = timeline === liveTimeline; + timelineMap[isLiveTimeline ? 'liveTimeline' : `${index}`] = timeline.getEvents().map(ev => ev.getId()); + }); + + return timelineMap; + }); + + return serializedEventIdsInTimelineSet; +} + export default TimelinePanel; From 18c99702a68e03cbee319f70aeaabdf04547ab5d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 19:41:17 -0500 Subject: [PATCH 6/9] Use built in dispatcher See https://github.com/matrix-org/matrix-react-sdk/pull/8502#discussion_r865555576 --- src/components/structures/TimelinePanel.tsx | 5 +++-- src/components/views/dialogs/BugReportDialog.tsx | 8 +++++--- src/dispatcher/actions.ts | 7 +++++++ 3 files changed, 15 insertions(+), 5 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 1882811fa90..2fa88d76fb7 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -294,7 +294,6 @@ class TimelinePanel extends React.Component { cli.on(MatrixEventEvent.Decrypted, this.onEventDecrypted); cli.on(MatrixEventEvent.Replaced, this.onEventReplaced); cli.on(ClientEvent.Sync, this.onSync); - cli.on(ClientEvent.DumpDebugLogs, this.onDumpDebugLogs); } // TODO: [REACT-WARNING] Move into constructor @@ -370,7 +369,6 @@ class TimelinePanel extends React.Component { client.removeListener(MatrixEventEvent.Replaced, this.onEventReplaced); client.removeListener(MatrixEventEvent.VisibilityChange, this.onEventVisibilityChange); client.removeListener(ClientEvent.Sync, this.onSync); - client.removeListener(ClientEvent.DumpDebugLogs, this.onDumpDebugLogs); } } @@ -597,6 +595,9 @@ class TimelinePanel extends React.Component { case "ignore_state_changed": this.forceUpdate(); break; + case Action.DumpDebugLogs: + this.onDumpDebugLogs(); + break; } }; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index 57c658173c4..ae2d6fa110b 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -19,7 +19,6 @@ limitations under the License. import React from 'react'; -import { MatrixClientPeg } from '../../../MatrixClientPeg'; import SdkConfig from '../../../SdkConfig'; import Modal from '../../../Modal'; import { _t } from '../../../languageHandler'; @@ -31,6 +30,8 @@ import Field from '../elements/Field'; import Spinner from "../elements/Spinner"; import DialogButtons from "../elements/DialogButtons"; import { sendSentryReport } from "../../../sentry"; +import defaultDispatcher from '../../../dispatcher/dispatcher'; +import { Action } from '../../../dispatcher/actions'; interface IProps { onFinished: (success: boolean) => void; @@ -67,14 +68,15 @@ export default class BugReportDialog extends React.Component { }; this.unmounted = false; - const client = MatrixClientPeg.get(); // Get all of the extra info dumped to the console when someone is about // to send debug logs. Since this is a fire and forget action, we do // this when the bug report dialog is opened instead of when we submit // logs because we have no signal to know when all of the various // components have finished logging. Someone could potentially send logs // before we fully dump everything but it's probably unlikely. - client.dumpDebugLogs(); + defaultDispatcher.dispatch({ + action: Action.DumpDebugLogs + }); } public componentWillUnmount() { diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index 3fdbccb71b9..d89395e3a1d 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -312,4 +312,11 @@ export enum Action { * Opens a dialog to add an existing object to a space. Used with a OpenAddExistingToSpaceDialogPayload. */ OpenAddToExistingSpaceDialog = "open_add_to_existing_space_dialog", + + /** + * Let components know that they should log any useful debugging information + * because we're probably about to send bug report which includes all of the + * logs. + */ + DumpDebugLogs = "dump_debug_logs", } From c597c964b51005a5facb62d23ae48a1c0bb49262 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 19:45:20 -0500 Subject: [PATCH 7/9] Fix lints --- src/components/structures/TimelinePanel.tsx | 2 +- src/components/views/dialogs/BugReportDialog.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 2fa88d76fb7..4a6c99bb9f6 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -1762,7 +1762,7 @@ class TimelinePanel extends React.Component { * * @return An event ID list for every timeline in every timelineSet */ - function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] { +function serializeEventIdsFromTimelineSets(timelineSets): { [key: string]: string[] }[] { const serializedEventIdsInTimelineSet = timelineSets.map((timelineSet) => { const timelineMap = {}; diff --git a/src/components/views/dialogs/BugReportDialog.tsx b/src/components/views/dialogs/BugReportDialog.tsx index ae2d6fa110b..b6ff9440471 100644 --- a/src/components/views/dialogs/BugReportDialog.tsx +++ b/src/components/views/dialogs/BugReportDialog.tsx @@ -75,7 +75,7 @@ export default class BugReportDialog extends React.Component { // components have finished logging. Someone could potentially send logs // before we fully dump everything but it's probably unlikely. defaultDispatcher.dispatch({ - action: Action.DumpDebugLogs + action: Action.DumpDebugLogs, }); } From cfa475717580cf48e4a455857b623c1c4e1c6d9d Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Thu, 5 May 2022 20:05:35 -0500 Subject: [PATCH 8/9] No need to grab the txn-id since local echo events have event.getId() which we can derive from See - https://github.com/matrix-org/matrix-react-sdk/pull/8502#discussion_r866404427 --- src/components/structures/TimelinePanel.tsx | 5 +---- src/components/views/rooms/EventTile.tsx | 2 -- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/components/structures/TimelinePanel.tsx b/src/components/structures/TimelinePanel.tsx index 4a6c99bb9f6..2502cdb4af9 100644 --- a/src/components/structures/TimelinePanel.tsx +++ b/src/components/structures/TimelinePanel.tsx @@ -397,10 +397,7 @@ class TimelinePanel extends React.Component { if (messagePanelNode) { const actuallyRenderedEvents = messagePanelNode.querySelectorAll('[data-event-id]'); renderedEventIds = [...actuallyRenderedEvents].map((renderedEvent) => { - // Get the txn ID for local echo events that haven't - // persisted yet or the event ID. This mimics the `key` - // logic when showing EventTile's in a MessagePanel - return renderedEvent.getAttribute('data-txn-id') || renderedEvent.getAttribute('data-event-id'); + return renderedEvent.getAttribute('data-event-id'); }); } } diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 1c3d3cdbaa7..631593b6a8d 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -1291,7 +1291,6 @@ export class UnwrappedEventTile extends React.Component { "data-has-reply": !!replyChain, "data-layout": this.props.layout, "data-self": isOwnEvent, - "data-txn-id": this.props.mxEvent.getTxnId(), "data-event-id": this.props.mxEvent.getId(), "onMouseEnter": () => this.setState({ hover: true }), "onMouseLeave": () => this.setState({ hover: false }), @@ -1439,7 +1438,6 @@ export class UnwrappedEventTile extends React.Component { "data-scroll-tokens": scrollToken, "data-layout": this.props.layout, "data-self": isOwnEvent, - "data-txn-id": this.props.mxEvent.getTxnId(), "data-event-id": this.props.mxEvent.getId(), "data-has-reply": !!replyChain, "onMouseEnter": () => this.setState({ hover: true }), From 0dc63a6e3b4cd347a9be825769fb949915a71c00 Mon Sep 17 00:00:00 2001 From: Eric Eastwood Date: Mon, 9 May 2022 20:46:43 -0500 Subject: [PATCH 9/9] Verbally type payload Co-authored-by: Travis Ralston --- src/dispatcher/actions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dispatcher/actions.ts b/src/dispatcher/actions.ts index d89395e3a1d..910aabab526 100644 --- a/src/dispatcher/actions.ts +++ b/src/dispatcher/actions.ts @@ -316,7 +316,7 @@ export enum Action { /** * Let components know that they should log any useful debugging information * because we're probably about to send bug report which includes all of the - * logs. + * logs. Fires with no payload. */ DumpDebugLogs = "dump_debug_logs", }