Compare commits

...

7 Commits

Author SHA1 Message Date
Will Hunt
2b8e8b32f2 Merge branch 'develop' into hs/empty-topics 2025-02-03 10:04:19 +00:00
Will Hunt
c781e1db73 Merge branch 'develop' into hs/empty-topics 2025-01-31 17:41:12 +00:00
Half-Shot
3014ee4ad4 Add tests for topic rendering 2025-01-31 17:39:52 +00:00
Half-Shot
a94125b791 Use the correct import pattern 2025-01-31 17:39:47 +00:00
Half-Shot
0d33d2be14 Revert changes i18n for the moment 2025-01-31 17:06:46 +00:00
Half-Shot
ee7ff697cb Use topic parser for topic events. 2025-01-31 12:24:23 +00:00
Half-Shot
718dccd589 Improve display of empty topic events in the timeline. 2025-01-31 12:22:15 +00:00
4 changed files with 62 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ import {
MsgType,
M_POLL_START,
M_POLL_END,
ContentHelpers,
} from "matrix-js-sdk/src/matrix";
import { KnownMembership } from "matrix-js-sdk/src/types";
import { logger } from "matrix-js-sdk/src/logger";
@@ -227,11 +228,16 @@ function textForMemberEvent(
function textForTopicEvent(ev: MatrixEvent): (() => string) | null {
const senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();
const topic = ContentHelpers.parseTopicContent(ev.getContent()).text;
return () =>
_t("timeline|m.room.topic", {
senderDisplayName,
topic: ev.getContent().topic,
});
topic
? _t("timeline|m.room.topic|changed", {
senderDisplayName,
topic,
})
: _t("timeline|m.room.topic|removed", {
senderDisplayName,
});
}
function textForRoomAvatarEvent(ev: MatrixEvent): (() => string) | null {

View File

@@ -7,7 +7,7 @@ Please see LICENSE files in the repository root for full details.
import React, { createRef } from "react";
import classNames from "classnames";
import { EventType } from "matrix-js-sdk/src/matrix";
import { ContentHelpers, EventType } from "matrix-js-sdk/src/matrix";
import { _t } from "../../../languageHandler";
import { MatrixClientPeg } from "../../../MatrixClientPeg";
@@ -51,7 +51,7 @@ export default class RoomProfileSettings extends React.Component<IProps, IState>
const avatarUrl = avatarEvent?.getContent()["url"] ?? null;
const topicEvent = room.currentState.getStateEvents(EventType.RoomTopic, "");
const topic = topicEvent && topicEvent.getContent() ? topicEvent.getContent()["topic"] : "";
const topic = (topicEvent && ContentHelpers.parseTopicContent(topicEvent.getContent()).text) || "";
const nameEvent = room.currentState.getStateEvents(EventType.RoomName, "");
const name = nameEvent && nameEvent.getContent() ? nameEvent.getContent()["name"] : "";
@@ -145,6 +145,8 @@ export default class RoomProfileSettings extends React.Component<IProps, IState>
if (this.state.originalTopic !== this.state.topic) {
const html = htmlSerializeFromMdIfNeeded(this.state.topic, { forceHTML: false });
// XXX: Note that we deliberately send an empty string on an empty topic rather
// than a clearer `undefined` value. Synapse still requires a string in a topic.
await client.setRoomTopic(this.props.roomId, this.state.topic, html);
newState.originalTopic = this.state.topic;
}

View File

@@ -3493,7 +3493,10 @@
"sent": "%(senderName)s sent an invitation to %(targetDisplayName)s to join the room."
},
"m.room.tombstone": "%(senderDisplayName)s upgraded this room.",
"m.room.topic": "%(senderDisplayName)s changed the topic to \"%(topic)s\".",
"m.room.topic": {
"changed": "%(senderDisplayName)s changed the topic to \"%(topic)s\".",
"removed": "%(senderDisplayName)s removed the topic."
},
"m.sticker": "%(senderDisplayName)s sent a sticker.",
"m.video": {
"error_decrypting": "Error decrypting video"

View File

@@ -12,6 +12,7 @@ import {
JoinRule,
MatrixClient,
MatrixEvent,
MRoomTopicEventContent,
Room,
RoomMember,
} from "matrix-js-sdk/src/matrix";
@@ -613,4 +614,47 @@ describe("TextForEvent", () => {
},
);
});
describe("textForTopicEvent()", () => {
type TestCase = [string, MRoomTopicEventContent, { result: string }];
const testCases: TestCase[] = [
["the legacy key", { topic: "My topic" }, { result: '@a changed the topic to "My topic".' }],
[
"the legacy key with an empty m.topic key",
{ "topic": "My topic", "m.topic": [] },
{ result: '@a changed the topic to "My topic".' },
],
[
"the m.topic key",
{ "topic": "Ignore this", "m.topic": [{ mimetype: "text/plain", body: "My topic" }] },
{ result: '@a changed the topic to "My topic".' },
],
[
"the m.topic key and the legacy key undefined",
{ "topic": undefined, "m.topic": [{ mimetype: "text/plain", body: "My topic" }] },
{ result: '@a changed the topic to "My topic".' },
],
["the legacy key undefined", { topic: undefined }, { result: "@a removed the topic." }],
["the legacy key empty string", { topic: "" }, { result: "@a removed the topic." }],
[
"both the legacy and new keys removed",
{ "topic": undefined, "m.topic": [] },
{ result: "@a removed the topic." },
],
];
it.each(testCases)("returns correct message for topic event with %s", (_caseName, content, { result }) => {
expect(
textForEvent(
new MatrixEvent({
type: "m.room.topic",
sender: "@a",
content: content,
state_key: "",
}),
mockClient,
),
).toEqual(result);
});
});
});