diff --git a/src/components/views/elements/Reply.js b/src/components/views/elements/Reply.js index 3ab7af6ced..ff2a6fc36a 100644 --- a/src/components/views/elements/Reply.js +++ b/src/components/views/elements/Reply.js @@ -23,6 +23,9 @@ import {MatrixEvent} from 'matrix-js-sdk'; import {makeUserPermalink} from "../../../matrix-to"; import SettingsStore from "../../../settings/SettingsStore"; +// This component does no cycle detection, simply because the only way to make such a cycle +// would be to craft event_id's, using a custom homeserver; even then the impact would be low +// as each event being loaded (after the first) is triggered by an explicit user action. export default class Reply extends React.Component { static propTypes = { // The parent event @@ -34,17 +37,6 @@ export default class Reply extends React.Component { constructor(props, context) { super(props, context); - /* - this.state = { - // The event related to this quote and their nested rich quotes - events: [], - // Whether the top (oldest) event should be shown or spoilered - show: true, - // Whether an error was encountered fetching nested older event, show node if it does - err: false, - loading: true, - };*/ - this.state = { // The loaded events to be rendered as linear-replies events: [], @@ -55,7 +47,7 @@ export default class Reply extends React.Component { loading: true, // Whether as error was encountered fetching a replied to event. - err: null, + err: false, }; this.onQuoteClick = this.onQuoteClick.bind(this); @@ -71,9 +63,13 @@ export default class Reply extends React.Component { const inReplyTo = Reply.getInReplyTo(parentEv); const ev = await this.getEvent(this.room, inReplyTo['event_id']); - this.setState({ - events: [ev], - }, this.loadNextEvent); + if (ev) { + this.setState({ + events: [ev], + }, this.loadNextEvent); + } else { + this.setState({err: true}); + } } async loadNextEvent() { @@ -89,7 +85,11 @@ export default class Reply extends React.Component { } const loadedEv = await this.getEvent(this.room, inReplyTo['event_id']); - this.setState({loadedEv}); + if (loadedEv) { + this.setState({loadedEv}); + } else { + this.setState({err: true}); + } } getRoom(id) { @@ -105,7 +105,11 @@ export default class Reply extends React.Component { const event = room.findEventById(eventId); if (event) return event; - await MatrixClientPeg.get().getEventTimeline(room.getUnfilteredTimelineSet(), eventId); + try { + await MatrixClientPeg.get().getEventTimeline(room.getUnfilteredTimelineSet(), eventId); + } catch (e) { + return; + } return room.findEventById(eventId); } @@ -145,7 +149,15 @@ export default class Reply extends React.Component { render() { let header = null; - if (this.state.loadedEv) { + + if (this.state.err) { + header =
+ { + _t('Unable to load event that was replied to, ' + + 'it either does not exist or you do not have permission to view it.') + } +
; + } else if (this.state.loadedEv) { const ev = this.state.loadedEv; const Pill = sdk.getComponent('elements.Pill'); const room = MatrixClientPeg.get().getRoom(ev.getRoomId()); @@ -159,7 +171,8 @@ export default class Reply extends React.Component { } ; } else if (this.state.loading) { - header =
LOADING...
; + const Spinner = sdk.getComponent("elements.Spinner"); + header = ; } const EventTile = sdk.getComponent('views.rooms.EventTile'); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 6139ac2a91..5bde93f46c 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -359,8 +359,8 @@ "Idle": "Idle", "Offline": "Offline", "Unknown": "Unknown", - "Replying": "Replying", "Seen by %(userName)s at %(dateTime)s": "Seen by %(userName)s at %(dateTime)s", + "Replying": "Replying", "No rooms to show": "No rooms to show", "Unnamed room": "Unnamed room", "World readable": "World readable", @@ -500,8 +500,8 @@ "Download %(text)s": "Download %(text)s", "Invalid file%(extra)s": "Invalid file%(extra)s", "Error decrypting image": "Error decrypting image", - "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "This image cannot be displayed.": "This image cannot be displayed.", + "Image '%(Body)s' cannot be displayed.": "Image '%(Body)s' cannot be displayed.", "Error decrypting video": "Error decrypting video", "%(senderDisplayName)s changed the avatar for %(roomName)s": "%(senderDisplayName)s changed the avatar for %(roomName)s", "%(senderDisplayName)s removed the room avatar.": "%(senderDisplayName)s removed the room avatar.", @@ -648,6 +648,7 @@ "expand": "expand", "Custom of %(powerLevel)s": "Custom of %(powerLevel)s", "Custom level": "Custom level", + "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.": "Unable to load event that was replied to, it either does not exist or you do not have permission to view it.", "In reply to ": "In reply to ", "Room directory": "Room directory", "Start chat": "Start chat",