diff --git a/src/SecurityManager.ts b/src/SecurityManager.ts index 09c8d30614..1ba0d6439b 100644 --- a/src/SecurityManager.ts +++ b/src/SecurityManager.ts @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import { ICryptoCallbacks, IDeviceTrustLevel, ISecretStorageKeyInfo } from 'matrix-js-sdk/src/matrix'; +import { ICryptoCallbacks, ISecretStorageKeyInfo } from 'matrix-js-sdk/src/matrix'; import { MatrixClient } from 'matrix-js-sdk/src/client'; import Modal from './Modal'; import * as sdk from './index'; @@ -28,6 +28,7 @@ import AccessSecretStorageDialog from './components/views/dialogs/security/Acces import RestoreKeyBackupDialog from './components/views/dialogs/security/RestoreKeyBackupDialog'; import SettingsStore from "./settings/SettingsStore"; import SecurityCustomisations from "./customisations/Security"; +import { DeviceTrustLevel } from 'matrix-js-sdk/src/crypto/CrossSigning'; // This stores the secret storage private keys in memory for the JS SDK. This is // only meant to act as a cache to avoid prompting the user multiple times @@ -244,7 +245,7 @@ async function onSecretRequested( deviceId: string, requestId: string, name: string, - deviceTrust: IDeviceTrustLevel, + deviceTrust: DeviceTrustLevel, ): Promise { console.log("onSecretRequested", userId, deviceId, requestId, name, deviceTrust); const client = MatrixClientPeg.get(); diff --git a/src/TextForEvent.ts b/src/TextForEvent.ts index ad3417fd8c..85d53ee50a 100644 --- a/src/TextForEvent.ts +++ b/src/TextForEvent.ts @@ -32,76 +32,89 @@ function textForMemberEvent(ev): () => string | null { const targetName = ev.target ? ev.target.name : ev.getStateKey(); const prevContent = ev.getPrevContent(); const content = ev.getContent(); + const reason = content.reason; - const getReason = () => content.reason ? (_t('Reason') + ': ' + content.reason) : ''; switch (content.membership) { case 'invite': { const threePidContent = content.third_party_invite; if (threePidContent) { if (threePidContent.display_name) { - return () => _t('%(targetName)s accepted the invitation for %(displayName)s.', { + return () => _t('%(targetName)s accepted the invitation for %(displayName)s', { targetName, displayName: threePidContent.display_name, }); } else { - return () => _t('%(targetName)s accepted an invitation.', {targetName}); + return () => _t('%(targetName)s accepted an invitation', { targetName }); } } else { - return () => _t('%(senderName)s invited %(targetName)s.', {senderName, targetName}); + return () => _t('%(senderName)s invited %(targetName)s', { senderName, targetName }); } } case 'ban': - return () => _t('%(senderName)s banned %(targetName)s.', {senderName, targetName}) + ' ' + getReason(); + return () => reason + ? _t('%(senderName)s banned %(targetName)s: %(reason)s', { senderName, targetName, reason }) + : _t('%(senderName)s banned %(targetName)s', { senderName, targetName }); case 'join': if (prevContent && prevContent.membership === 'join') { if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) { - return () => _t('%(oldDisplayName)s changed their display name to %(displayName)s.', { + return () => _t('%(oldDisplayName)s changed their display name to %(displayName)s', { oldDisplayName: prevContent.displayname, displayName: content.displayname, }); } else if (!prevContent.displayname && content.displayname) { - return () => _t('%(senderName)s set their display name to %(displayName)s.', { + return () => _t('%(senderName)s set their display name to %(displayName)s', { senderName: ev.getSender(), displayName: content.displayname, }); } else if (prevContent.displayname && !content.displayname) { - return () => _t('%(senderName)s removed their display name (%(oldDisplayName)s).', { + return () => _t('%(senderName)s removed their display name (%(oldDisplayName)s)', { senderName, oldDisplayName: prevContent.displayname, }); } else if (prevContent.avatar_url && !content.avatar_url) { - return () => _t('%(senderName)s removed their profile picture.', {senderName}); + return () => _t('%(senderName)s removed their profile picture', { senderName }); } else if (prevContent.avatar_url && content.avatar_url && prevContent.avatar_url !== content.avatar_url) { - return () => _t('%(senderName)s changed their profile picture.', {senderName}); + return () => _t('%(senderName)s changed their profile picture', { senderName }); } else if (!prevContent.avatar_url && content.avatar_url) { - return () => _t('%(senderName)s set a profile picture.', {senderName}); + return () => _t('%(senderName)s set a profile picture', { senderName }); } else if (SettingsStore.getValue("showHiddenEventsInTimeline")) { - // This is a null rejoin, it will only be visible if the Labs option is enabled - return () => _t("%(senderName)s made no change.", {senderName}); + // This is a null rejoin, it will only be visible if using 'show hidden events' (labs) + return () => _t("%(senderName)s made no change", { senderName }); } else { return null; } } else { if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key); - return () => _t('%(targetName)s joined the room.', {targetName}); + return () => _t('%(targetName)s joined the room', { targetName }); } case 'leave': if (ev.getSender() === ev.getStateKey()) { if (prevContent.membership === "invite") { - return () => _t('%(targetName)s rejected the invitation.', {targetName}); + return () => _t('%(targetName)s rejected the invitation', { targetName }); } else { - return () => _t('%(targetName)s left the room.', {targetName}); + return () => reason + ? _t('%(targetName)s left the room: %(reason)s', { targetName, reason }) + : _t('%(targetName)s left the room', { targetName }); } } else if (prevContent.membership === "ban") { - return () => _t('%(senderName)s unbanned %(targetName)s.', {senderName, targetName}); + return () => _t('%(senderName)s unbanned %(targetName)s', { senderName, targetName }); } else if (prevContent.membership === "invite") { - return () => _t('%(senderName)s withdrew %(targetName)s\'s invitation.', { - senderName, - targetName, - }) + ' ' + getReason(); + return () => reason + ? _t('%(senderName)s withdrew %(targetName)s\'s invitation: %(reason)s', { + senderName, + targetName, + reason, + }) + : _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName }) } else if (prevContent.membership === "join") { - return () => _t('%(senderName)s kicked %(targetName)s.', {senderName, targetName}) + ' ' + getReason(); + return () => reason + ? _t('%(senderName)s kicked %(targetName)s: %(reason)s', { + senderName, + targetName, + reason, + }) + : _t('%(senderName)s kicked %(targetName)s', { senderName, targetName }); } else { return null; } diff --git a/src/components/views/dialogs/DevtoolsDialog.tsx b/src/components/views/dialogs/DevtoolsDialog.tsx index 2690eb67d7..b1749b370a 100644 --- a/src/components/views/dialogs/DevtoolsDialog.tsx +++ b/src/components/views/dialogs/DevtoolsDialog.tsx @@ -766,7 +766,7 @@ class VerificationExplorer extends React.PureComponent { render() { const cli = this.context; const room = this.props.room; - const inRoomChannel = cli.crypto._inRoomVerificationRequests; + const inRoomChannel = cli.crypto.inRoomVerificationRequests; const inRoomRequests = (inRoomChannel._requestsByRoomId || new Map()).get(room.roomId) || new Map(); return (
diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index e22b2d5ff4..111e9dbf38 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -503,7 +503,7 @@ const isMuted = (member: RoomMember, powerLevelContent: IPowerLevelsContent) => return member.powerLevel < levelToSend; }; -const getPowerLevels = room => room.currentState.getStateEvents(EventType.RoomPowerLevels, "")?.getContent() || {}; +const getPowerLevels = room => room?.currentState?.getStateEvents(EventType.RoomPowerLevels, "")?.getContent() || {}; export const useRoomPowerLevels = (cli: MatrixClient, room: Room) => { const [powerLevels, setPowerLevels] = useState(getPowerLevels(room)); diff --git a/src/components/views/rooms/EntityTile.js b/src/components/views/rooms/EntityTile.tsx similarity index 74% rename from src/components/views/rooms/EntityTile.js rename to src/components/views/rooms/EntityTile.tsx index a92d87643c..2032856500 100644 --- a/src/components/views/rooms/EntityTile.js +++ b/src/components/views/rooms/EntityTile.tsx @@ -17,13 +17,23 @@ limitations under the License. */ import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; import AccessibleButton from '../elements/AccessibleButton'; -import { _t } from '../../../languageHandler'; +import { _td } from '../../../languageHandler'; import classNames from "classnames"; import E2EIcon from './E2EIcon'; -import {replaceableComponent} from "../../../utils/replaceableComponent"; +import { replaceableComponent } from "../../../utils/replaceableComponent"; +import BaseAvatar from '../avatars/BaseAvatar'; +import PresenceLabel from "./PresenceLabel"; + +export enum PowerStatus { + Admin = "admin", + Moderator = "moderator", +} + +const PowerLabel: Record = { + [PowerStatus.Admin]: _td("Admin"), + [PowerStatus.Moderator]: _td("Mod"), +} const PRESENCE_CLASS = { "offline": "mx_EntityTile_offline", @@ -31,14 +41,14 @@ const PRESENCE_CLASS = { "unavailable": "mx_EntityTile_unavailable", }; -function presenceClassForMember(presenceState, lastActiveAgo, showPresence) { +function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean): string { if (showPresence === false) { return 'mx_EntityTile_online_beenactive'; } // offline is split into two categories depending on whether we have // a last_active_ago for them. - if (presenceState == 'offline') { + if (presenceState === 'offline') { if (lastActiveAgo) { return PRESENCE_CLASS['offline'] + '_beenactive'; } else { @@ -51,29 +61,32 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) { } } -@replaceableComponent("views.rooms.EntityTile") -class EntityTile extends React.Component { - static propTypes = { - name: PropTypes.string, - title: PropTypes.string, - avatarJsx: PropTypes.any, // - className: PropTypes.string, - presenceState: PropTypes.string, - presenceLastActiveAgo: PropTypes.number, - presenceLastTs: PropTypes.number, - presenceCurrentlyActive: PropTypes.bool, - showInviteButton: PropTypes.bool, - shouldComponentUpdate: PropTypes.func, - onClick: PropTypes.func, - suppressOnHover: PropTypes.bool, - showPresence: PropTypes.bool, - subtextLabel: PropTypes.string, - e2eStatus: PropTypes.string, - }; +interface IProps { + name?: string; + title?: string; + avatarJsx?: JSX.Element; // + className?: string; + presenceState?: string; + presenceLastActiveAgo?: number; + presenceLastTs?: number; + presenceCurrentlyActive?: boolean; + showInviteButton?: boolean; + onClick?(): void; + suppressOnHover?: boolean; + showPresence?: boolean; + subtextLabel?: string; + e2eStatus?: string; + powerStatus?: PowerStatus; +} +interface IState { + hover: boolean; +} + +@replaceableComponent("views.rooms.EntityTile") +export default class EntityTile extends React.PureComponent { static defaultProps = { - shouldComponentUpdate: function(nextProps, nextState) { return true; }, - onClick: function() {}, + onClick: () => {}, presenceState: "offline", presenceLastActiveAgo: 0, presenceLastTs: 0, @@ -82,13 +95,12 @@ class EntityTile extends React.Component { showPresence: true, }; - state = { - hover: false, - }; + constructor(props: IProps) { + super(props); - shouldComponentUpdate(nextProps, nextState) { - if (this.state.hover !== nextState.hover) return true; - return this.props.shouldComponentUpdate(nextProps, nextState); + this.state = { + hover: false, + }; } render() { @@ -110,7 +122,6 @@ class EntityTile extends React.Component { const activeAgo = this.props.presenceLastActiveAgo ? (Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1; - const PresenceLabel = sdk.getComponent("rooms.PresenceLabel"); let presenceLabel = null; if (this.props.showPresence) { presenceLabel = {powerText}
; } @@ -168,14 +176,12 @@ class EntityTile extends React.Component { e2eIcon = ; } - const BaseAvatar = sdk.getComponent('avatars.BaseAvatar'); - const av = this.props.avatarJsx ||