diff --git a/res/css/views/right_panel/_RoomSummaryCard.scss b/res/css/views/right_panel/_RoomSummaryCard.scss index 36882f4e8b..dc7804d072 100644 --- a/res/css/views/right_panel/_RoomSummaryCard.scss +++ b/res/css/views/right_panel/_RoomSummaryCard.scss @@ -36,6 +36,7 @@ limitations under the License. -webkit-box-orient: vertical; overflow: hidden; text-overflow: ellipsis; + white-space: pre-wrap; } .mx_RoomSummaryCard_avatar { diff --git a/src/components/structures/SpaceRoomDirectory.tsx b/src/components/structures/SpaceRoomDirectory.tsx index c1e9027b1d..2881b6c3ea 100644 --- a/src/components/structures/SpaceRoomDirectory.tsx +++ b/src/components/structures/SpaceRoomDirectory.tsx @@ -152,7 +152,7 @@ const Tile: React.FC = ({ } let description = _t("%(count)s members", { count: room.num_joined_members }); - if (numChildRooms) { + if (numChildRooms !== undefined) { description += " ยท " + _t("%(count)s rooms", { count: numChildRooms }); } if (room.topic) { diff --git a/src/components/views/right_panel/RoomSummaryCard.tsx b/src/components/views/right_panel/RoomSummaryCard.tsx index bbe61807ae..88928290f4 100644 --- a/src/components/views/right_panel/RoomSummaryCard.tsx +++ b/src/components/views/right_panel/RoomSummaryCard.tsx @@ -45,6 +45,7 @@ import {ChevronFace, ContextMenuTooltipButton, useContextMenu} from "../../struc import WidgetContextMenu from "../context_menus/WidgetContextMenu"; import {useRoomMemberCount} from "../../../hooks/useRoomMembers"; import { Container, MAX_PINNED, WidgetLayoutStore } from "../../../stores/widgets/WidgetLayoutStore"; +import RoomName from "../elements/RoomName"; interface IProps { room: Room; @@ -249,7 +250,13 @@ const RoomSummaryCard: React.FC = ({ room, onClose }) => { /> -

{ room.name }

+ + { name => ( +

+ { name } +

+ )} +
{ alias }
diff --git a/src/components/views/rooms/MemberList.js b/src/components/views/rooms/MemberList.js index fbc0e477a1..55fe650b7b 100644 --- a/src/components/views/rooms/MemberList.js +++ b/src/components/views/rooms/MemberList.js @@ -133,6 +133,12 @@ export default class MemberList extends React.Component { } } + get canInvite() { + const cli = MatrixClientPeg.get(); + const room = cli.getRoom(this.props.roomId); + return room && room.canInvite(cli.getUserId()); + } + _getMembersState(members) { // set the state after determining _showPresence to make sure it's // taken into account while rerendering @@ -141,6 +147,7 @@ export default class MemberList extends React.Component { members: members, filteredJoinedMembers: this._filterMembers(members, 'join'), filteredInvitedMembers: this._filterMembers(members, 'invite'), + canInvite: this.canInvite, // ideally we'd size this to the page height, but // in practice I find that a little constraining @@ -196,6 +203,8 @@ export default class MemberList extends React.Component { event.getType() === "m.room.third_party_invite") { this._updateList(); } + + if (this.canInvite !== this.state.canInvite) this.setState({ canInvite: this.canInvite }); }; _updateList = rate_limited_func(() => { @@ -455,8 +464,6 @@ export default class MemberList extends React.Component { let inviteButton; if (room && room.getMyMembership() === 'join') { - const canInvite = room.canInvite(cli.getUserId()); - let inviteButtonText = _t("Invite to this room"); const chat = CommunityPrototypeStore.instance.getSelectedCommunityGeneralChat(); if (chat && chat.roomId === this.props.roomId) { @@ -467,7 +474,7 @@ export default class MemberList extends React.Component { const AccessibleButton = sdk.getComponent("elements.AccessibleButton"); inviteButton = - + { inviteButtonText } ; } diff --git a/src/components/views/rooms/RoomSublist.tsx b/src/components/views/rooms/RoomSublist.tsx index dd80e9d40a..f9881d33ae 100644 --- a/src/components/views/rooms/RoomSublist.tsx +++ b/src/components/views/rooms/RoomSublist.tsx @@ -18,6 +18,7 @@ limitations under the License. import * as React from "react"; import { createRef, ReactComponentElement } from "react"; +import { normalize } from "matrix-js-sdk/src/utils"; import { Room } from "matrix-js-sdk/src/models/room"; import classNames from 'classnames'; import { RovingAccessibleButton, RovingTabIndexWrapper } from "../../../accessibility/RovingTabIndex"; @@ -259,7 +260,7 @@ export default class RoomSublist extends React.Component { const nameCondition = RoomListStore.instance.getFirstNameFilterCondition(); if (nameCondition) { stateUpdates.filteredExtraTiles = this.props.extraTiles - .filter(t => nameCondition.matches(t.props.displayName || "")); + .filter(t => nameCondition.matches(normalize(t.props.displayName || ""))); } else if (this.state.filteredExtraTiles) { stateUpdates.filteredExtraTiles = null; } diff --git a/src/languageHandler.tsx b/src/languageHandler.tsx index 4a3fb30886..26c89afec6 100644 --- a/src/languageHandler.tsx +++ b/src/languageHandler.tsx @@ -344,7 +344,10 @@ export function setLanguage(preferredLangs: string | string[]) { counterpart.registerTranslations(langToUse, langData); counterpart.setLocale(langToUse); SettingsStore.setValue("language", null, SettingLevel.DEVICE, langToUse); - console.log("set language to " + langToUse); + // Adds a lot of noise to test runs, so disable logging there. + if (process.env.NODE_ENV !== "test") { + console.log("set language to " + langToUse); + } // Set 'en' as fallback language: if (langToUse !== "en") { diff --git a/src/stores/room-list/filters/NameFilterCondition.ts b/src/stores/room-list/filters/NameFilterCondition.ts index 8e63c23131..7ec91a3249 100644 --- a/src/stores/room-list/filters/NameFilterCondition.ts +++ b/src/stores/room-list/filters/NameFilterCondition.ts @@ -17,7 +17,7 @@ limitations under the License. import { Room } from "matrix-js-sdk/src/models/room"; import { FILTER_CHANGED, FilterKind, IFilterCondition } from "./IFilterCondition"; import { EventEmitter } from "events"; -import { removeHiddenChars } from "matrix-js-sdk/src/utils"; +import { normalize } from "matrix-js-sdk/src/utils"; import { throttle } from "lodash"; /** @@ -62,20 +62,10 @@ export class NameFilterCondition extends EventEmitter implements IFilterConditio if (!room.name) return false; // should realistically not happen: the js-sdk always calculates a name - return this.matches(room.name); + return this.matches(room.normalizedName); } - private normalize(val: string): string { - // Note: we have to match the filter with the removeHiddenChars() room name because the - // function strips spaces and other characters (M becomes RN for example, in lowercase). - return removeHiddenChars(val.toLowerCase()) - // Strip all punctuation - .replace(/[\\'!"#$%&()*+,\-./:;<=>?@[\]^_`{|}~\u2000-\u206f\u2e00-\u2e7f]/g, "") - // We also doubly convert to lowercase to work around oddities of the library. - .toLowerCase(); - } - - public matches(val: string): boolean { - return this.normalize(val).includes(this.normalize(this.search)); + public matches(normalizedName: string): boolean { + return normalizedName.includes(normalize(this.search)); } } diff --git a/test/components/views/rooms/MemberList-test.js b/test/components/views/rooms/MemberList-test.js index 093e5588d0..50b40dea20 100644 --- a/test/components/views/rooms/MemberList-test.js +++ b/test/components/views/rooms/MemberList-test.js @@ -88,6 +88,7 @@ describe('MemberList', () => { }; memberListRoom.currentState = { members: {}, + getMember: jest.fn(), getStateEvents: (eventType, stateKey) => stateKey === undefined ? [] : null, // ignore 3pid invites }; for (const member of [...adminUsers, ...moderatorUsers, ...defaultUsers]) { diff --git a/test/test-utils.js b/test/test-utils.js index bad3547133..4faf948178 100644 --- a/test/test-utils.js +++ b/test/test-utils.js @@ -246,6 +246,7 @@ export function mkStubRoom(roomId = null) { maySendMessage: jest.fn().mockReturnValue(true), currentState: { getStateEvents: jest.fn(), + getMember: jest.fn(), mayClientSendStateEvent: jest.fn().mockReturnValue(true), maySendStateEvent: jest.fn().mockReturnValue(true), maySendEvent: jest.fn().mockReturnValue(true),