Merge branch 'develop' of github.com:matrix-org/matrix-react-sdk into export-conversations
This commit is contained in:
commit
91b8b2ac5a
13 changed files with 229 additions and 203 deletions
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
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 { MatrixClient } from 'matrix-js-sdk/src/client';
|
||||||
import Modal from './Modal';
|
import Modal from './Modal';
|
||||||
import * as sdk from './index';
|
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 RestoreKeyBackupDialog from './components/views/dialogs/security/RestoreKeyBackupDialog';
|
||||||
import SettingsStore from "./settings/SettingsStore";
|
import SettingsStore from "./settings/SettingsStore";
|
||||||
import SecurityCustomisations from "./customisations/Security";
|
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
|
// 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
|
// only meant to act as a cache to avoid prompting the user multiple times
|
||||||
|
@ -244,7 +245,7 @@ async function onSecretRequested(
|
||||||
deviceId: string,
|
deviceId: string,
|
||||||
requestId: string,
|
requestId: string,
|
||||||
name: string,
|
name: string,
|
||||||
deviceTrust: IDeviceTrustLevel,
|
deviceTrust: DeviceTrustLevel,
|
||||||
): Promise<string> {
|
): Promise<string> {
|
||||||
console.log("onSecretRequested", userId, deviceId, requestId, name, deviceTrust);
|
console.log("onSecretRequested", userId, deviceId, requestId, name, deviceTrust);
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
|
|
|
@ -32,76 +32,89 @@ function textForMemberEvent(ev): () => string | null {
|
||||||
const targetName = ev.target ? ev.target.name : ev.getStateKey();
|
const targetName = ev.target ? ev.target.name : ev.getStateKey();
|
||||||
const prevContent = ev.getPrevContent();
|
const prevContent = ev.getPrevContent();
|
||||||
const content = ev.getContent();
|
const content = ev.getContent();
|
||||||
|
const reason = content.reason;
|
||||||
|
|
||||||
const getReason = () => content.reason ? (_t('Reason') + ': ' + content.reason) : '';
|
|
||||||
switch (content.membership) {
|
switch (content.membership) {
|
||||||
case 'invite': {
|
case 'invite': {
|
||||||
const threePidContent = content.third_party_invite;
|
const threePidContent = content.third_party_invite;
|
||||||
if (threePidContent) {
|
if (threePidContent) {
|
||||||
if (threePidContent.display_name) {
|
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,
|
targetName,
|
||||||
displayName: threePidContent.display_name,
|
displayName: threePidContent.display_name,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return () => _t('%(targetName)s accepted an invitation.', {targetName});
|
return () => _t('%(targetName)s accepted an invitation', { targetName });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return () => _t('%(senderName)s invited %(targetName)s.', {senderName, targetName});
|
return () => _t('%(senderName)s invited %(targetName)s', { senderName, targetName });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
case 'ban':
|
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':
|
case 'join':
|
||||||
if (prevContent && prevContent.membership === 'join') {
|
if (prevContent && prevContent.membership === 'join') {
|
||||||
if (prevContent.displayname && content.displayname && prevContent.displayname !== content.displayname) {
|
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,
|
oldDisplayName: prevContent.displayname,
|
||||||
displayName: content.displayname,
|
displayName: content.displayname,
|
||||||
});
|
});
|
||||||
} else if (!prevContent.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(),
|
senderName: ev.getSender(),
|
||||||
displayName: content.displayname,
|
displayName: content.displayname,
|
||||||
});
|
});
|
||||||
} else if (prevContent.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,
|
senderName,
|
||||||
oldDisplayName: prevContent.displayname,
|
oldDisplayName: prevContent.displayname,
|
||||||
});
|
});
|
||||||
} else if (prevContent.avatar_url && !content.avatar_url) {
|
} 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 &&
|
} else if (prevContent.avatar_url && content.avatar_url &&
|
||||||
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) {
|
} 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")) {
|
} else if (SettingsStore.getValue("showHiddenEventsInTimeline")) {
|
||||||
// This is a null rejoin, it will only be visible if the Labs option is enabled
|
// This is a null rejoin, it will only be visible if using 'show hidden events' (labs)
|
||||||
return () => _t("%(senderName)s made no change.", {senderName});
|
return () => _t("%(senderName)s made no change", { senderName });
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
|
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':
|
case 'leave':
|
||||||
if (ev.getSender() === ev.getStateKey()) {
|
if (ev.getSender() === ev.getStateKey()) {
|
||||||
if (prevContent.membership === "invite") {
|
if (prevContent.membership === "invite") {
|
||||||
return () => _t('%(targetName)s rejected the invitation.', {targetName});
|
return () => _t('%(targetName)s rejected the invitation', { targetName });
|
||||||
} else {
|
} 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") {
|
} 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") {
|
} else if (prevContent.membership === "invite") {
|
||||||
return () => _t('%(senderName)s withdrew %(targetName)s\'s invitation.', {
|
return () => reason
|
||||||
senderName,
|
? _t('%(senderName)s withdrew %(targetName)s\'s invitation: %(reason)s', {
|
||||||
targetName,
|
senderName,
|
||||||
}) + ' ' + getReason();
|
targetName,
|
||||||
|
reason,
|
||||||
|
})
|
||||||
|
: _t('%(senderName)s withdrew %(targetName)s\'s invitation', { senderName, targetName })
|
||||||
} else if (prevContent.membership === "join") {
|
} 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 {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -766,7 +766,7 @@ class VerificationExplorer extends React.PureComponent<IExplorerProps> {
|
||||||
render() {
|
render() {
|
||||||
const cli = this.context;
|
const cli = this.context;
|
||||||
const room = this.props.room;
|
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();
|
const inRoomRequests = (inRoomChannel._requestsByRoomId || new Map()).get(room.roomId) || new Map();
|
||||||
|
|
||||||
return (<div>
|
return (<div>
|
||||||
|
|
|
@ -503,7 +503,7 @@ const isMuted = (member: RoomMember, powerLevelContent: IPowerLevelsContent) =>
|
||||||
return member.powerLevel < levelToSend;
|
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) => {
|
export const useRoomPowerLevels = (cli: MatrixClient, room: Room) => {
|
||||||
const [powerLevels, setPowerLevels] = useState<IPowerLevelsContent>(getPowerLevels(room));
|
const [powerLevels, setPowerLevels] = useState<IPowerLevelsContent>(getPowerLevels(room));
|
||||||
|
|
|
@ -17,13 +17,23 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import * as sdk from '../../../index';
|
|
||||||
import AccessibleButton from '../elements/AccessibleButton';
|
import AccessibleButton from '../elements/AccessibleButton';
|
||||||
import { _t } from '../../../languageHandler';
|
import { _td } from '../../../languageHandler';
|
||||||
import classNames from "classnames";
|
import classNames from "classnames";
|
||||||
import E2EIcon from './E2EIcon';
|
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, string> = {
|
||||||
|
[PowerStatus.Admin]: _td("Admin"),
|
||||||
|
[PowerStatus.Moderator]: _td("Mod"),
|
||||||
|
}
|
||||||
|
|
||||||
const PRESENCE_CLASS = {
|
const PRESENCE_CLASS = {
|
||||||
"offline": "mx_EntityTile_offline",
|
"offline": "mx_EntityTile_offline",
|
||||||
|
@ -31,14 +41,14 @@ const PRESENCE_CLASS = {
|
||||||
"unavailable": "mx_EntityTile_unavailable",
|
"unavailable": "mx_EntityTile_unavailable",
|
||||||
};
|
};
|
||||||
|
|
||||||
function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
|
function presenceClassForMember(presenceState: string, lastActiveAgo: number, showPresence: boolean): string {
|
||||||
if (showPresence === false) {
|
if (showPresence === false) {
|
||||||
return 'mx_EntityTile_online_beenactive';
|
return 'mx_EntityTile_online_beenactive';
|
||||||
}
|
}
|
||||||
|
|
||||||
// offline is split into two categories depending on whether we have
|
// offline is split into two categories depending on whether we have
|
||||||
// a last_active_ago for them.
|
// a last_active_ago for them.
|
||||||
if (presenceState == 'offline') {
|
if (presenceState === 'offline') {
|
||||||
if (lastActiveAgo) {
|
if (lastActiveAgo) {
|
||||||
return PRESENCE_CLASS['offline'] + '_beenactive';
|
return PRESENCE_CLASS['offline'] + '_beenactive';
|
||||||
} else {
|
} else {
|
||||||
|
@ -51,29 +61,32 @@ function presenceClassForMember(presenceState, lastActiveAgo, showPresence) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.rooms.EntityTile")
|
interface IProps {
|
||||||
class EntityTile extends React.Component {
|
name?: string;
|
||||||
static propTypes = {
|
title?: string;
|
||||||
name: PropTypes.string,
|
avatarJsx?: JSX.Element; // <BaseAvatar />
|
||||||
title: PropTypes.string,
|
className?: string;
|
||||||
avatarJsx: PropTypes.any, // <BaseAvatar />
|
presenceState?: string;
|
||||||
className: PropTypes.string,
|
presenceLastActiveAgo?: number;
|
||||||
presenceState: PropTypes.string,
|
presenceLastTs?: number;
|
||||||
presenceLastActiveAgo: PropTypes.number,
|
presenceCurrentlyActive?: boolean;
|
||||||
presenceLastTs: PropTypes.number,
|
showInviteButton?: boolean;
|
||||||
presenceCurrentlyActive: PropTypes.bool,
|
onClick?(): void;
|
||||||
showInviteButton: PropTypes.bool,
|
suppressOnHover?: boolean;
|
||||||
shouldComponentUpdate: PropTypes.func,
|
showPresence?: boolean;
|
||||||
onClick: PropTypes.func,
|
subtextLabel?: string;
|
||||||
suppressOnHover: PropTypes.bool,
|
e2eStatus?: string;
|
||||||
showPresence: PropTypes.bool,
|
powerStatus?: PowerStatus;
|
||||||
subtextLabel: PropTypes.string,
|
}
|
||||||
e2eStatus: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
hover: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
@replaceableComponent("views.rooms.EntityTile")
|
||||||
|
export default class EntityTile extends React.PureComponent<IProps, IState> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
shouldComponentUpdate: function(nextProps, nextState) { return true; },
|
onClick: () => {},
|
||||||
onClick: function() {},
|
|
||||||
presenceState: "offline",
|
presenceState: "offline",
|
||||||
presenceLastActiveAgo: 0,
|
presenceLastActiveAgo: 0,
|
||||||
presenceLastTs: 0,
|
presenceLastTs: 0,
|
||||||
|
@ -82,13 +95,12 @@ class EntityTile extends React.Component {
|
||||||
showPresence: true,
|
showPresence: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
state = {
|
constructor(props: IProps) {
|
||||||
hover: false,
|
super(props);
|
||||||
};
|
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
this.state = {
|
||||||
if (this.state.hover !== nextState.hover) return true;
|
hover: false,
|
||||||
return this.props.shouldComponentUpdate(nextProps, nextState);
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
|
@ -110,7 +122,6 @@ class EntityTile extends React.Component {
|
||||||
const activeAgo = this.props.presenceLastActiveAgo ?
|
const activeAgo = this.props.presenceLastActiveAgo ?
|
||||||
(Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1;
|
(Date.now() - (this.props.presenceLastTs - this.props.presenceLastActiveAgo)) : -1;
|
||||||
|
|
||||||
const PresenceLabel = sdk.getComponent("rooms.PresenceLabel");
|
|
||||||
let presenceLabel = null;
|
let presenceLabel = null;
|
||||||
if (this.props.showPresence) {
|
if (this.props.showPresence) {
|
||||||
presenceLabel = <PresenceLabel activeAgo={activeAgo}
|
presenceLabel = <PresenceLabel activeAgo={activeAgo}
|
||||||
|
@ -155,10 +166,7 @@ class EntityTile extends React.Component {
|
||||||
let powerLabel;
|
let powerLabel;
|
||||||
const powerStatus = this.props.powerStatus;
|
const powerStatus = this.props.powerStatus;
|
||||||
if (powerStatus) {
|
if (powerStatus) {
|
||||||
const powerText = {
|
const powerText = PowerLabel[powerStatus];
|
||||||
[EntityTile.POWER_STATUS_MODERATOR]: _t("Mod"),
|
|
||||||
[EntityTile.POWER_STATUS_ADMIN]: _t("Admin"),
|
|
||||||
}[powerStatus];
|
|
||||||
powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
|
powerLabel = <div className="mx_EntityTile_power">{powerText}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -168,14 +176,12 @@ class EntityTile extends React.Component {
|
||||||
e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
|
e2eIcon = <E2EIcon status={e2eStatus} isUser={true} bordered={true} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BaseAvatar = sdk.getComponent('avatars.BaseAvatar');
|
|
||||||
|
|
||||||
const av = this.props.avatarJsx ||
|
const av = this.props.avatarJsx ||
|
||||||
<BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />;
|
<BaseAvatar name={this.props.name} width={36} height={36} aria-hidden="true" />;
|
||||||
|
|
||||||
// The wrapping div is required to make the magic mouse listener work, for some reason.
|
// The wrapping div is required to make the magic mouse listener work, for some reason.
|
||||||
return (
|
return (
|
||||||
<div ref={(c) => this.container = c} >
|
<div>
|
||||||
<AccessibleButton
|
<AccessibleButton
|
||||||
className={classNames(mainClassNames)}
|
className={classNames(mainClassNames)}
|
||||||
title={this.props.title}
|
title={this.props.title}
|
||||||
|
@ -193,8 +199,3 @@ class EntityTile extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
EntityTile.POWER_STATUS_MODERATOR = "moderator";
|
|
||||||
EntityTile.POWER_STATUS_ADMIN = "admin";
|
|
||||||
|
|
||||||
export default EntityTile;
|
|
|
@ -17,20 +17,33 @@ limitations under the License.
|
||||||
|
|
||||||
import SettingsStore from "../../../settings/SettingsStore";
|
import SettingsStore from "../../../settings/SettingsStore";
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import * as sdk from "../../../index";
|
|
||||||
import dis from "../../../dispatcher/dispatcher";
|
import dis from "../../../dispatcher/dispatcher";
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
import { MatrixClientPeg } from "../../../MatrixClientPeg";
|
||||||
import {Action} from "../../../dispatcher/actions";
|
import {Action} from "../../../dispatcher/actions";
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
||||||
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
||||||
|
import { EventType } from "matrix-js-sdk/src/@types/event";
|
||||||
|
import { DeviceInfo } from "matrix-js-sdk/src/crypto/deviceinfo";
|
||||||
|
import EntityTile, { PowerStatus } from "./EntityTile";
|
||||||
|
import MemberAvatar from "./../avatars/MemberAvatar";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
member: RoomMember;
|
||||||
|
showPresence?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IState {
|
||||||
|
statusMessage: string;
|
||||||
|
isRoomEncrypted: boolean;
|
||||||
|
e2eStatus: string;
|
||||||
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.rooms.MemberTile")
|
@replaceableComponent("views.rooms.MemberTile")
|
||||||
export default class MemberTile extends React.Component {
|
export default class MemberTile extends React.Component<IProps, IState> {
|
||||||
static propTypes = {
|
private userLastModifiedTime: number;
|
||||||
member: PropTypes.any.isRequired, // RoomMember
|
private memberLastModifiedTime: number;
|
||||||
showPresence: PropTypes.bool,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
showPresence: true,
|
showPresence: true,
|
||||||
|
@ -52,7 +65,7 @@ export default class MemberTile extends React.Component {
|
||||||
if (SettingsStore.getValue("feature_custom_status")) {
|
if (SettingsStore.getValue("feature_custom_status")) {
|
||||||
const { user } = this.props.member;
|
const { user } = this.props.member;
|
||||||
if (user) {
|
if (user) {
|
||||||
user.on("User._unstable_statusMessage", this._onStatusMessageCommitted);
|
user.on("User._unstable_statusMessage", this.onStatusMessageCommitted);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +93,7 @@ export default class MemberTile extends React.Component {
|
||||||
if (user) {
|
if (user) {
|
||||||
user.removeListener(
|
user.removeListener(
|
||||||
"User._unstable_statusMessage",
|
"User._unstable_statusMessage",
|
||||||
this._onStatusMessageCommitted,
|
this.onStatusMessageCommitted,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,8 +104,8 @@ export default class MemberTile extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onRoomStateEvents = ev => {
|
private onRoomStateEvents = (ev: MatrixEvent): void => {
|
||||||
if (ev.getType() !== "m.room.encryption") return;
|
if (ev.getType() !== EventType.RoomEncryption) return;
|
||||||
const { roomId } = this.props.member;
|
const { roomId } = this.props.member;
|
||||||
if (ev.getRoomId() !== roomId) return;
|
if (ev.getRoomId() !== roomId) return;
|
||||||
|
|
||||||
|
@ -105,17 +118,17 @@ export default class MemberTile extends React.Component {
|
||||||
this.updateE2EStatus();
|
this.updateE2EStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
onUserTrustStatusChanged = (userId, trustStatus) => {
|
private onUserTrustStatusChanged = (userId: string, trustStatus: string): void => {
|
||||||
if (userId !== this.props.member.userId) return;
|
if (userId !== this.props.member.userId) return;
|
||||||
this.updateE2EStatus();
|
this.updateE2EStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
onDeviceVerificationChanged = (userId, deviceId, deviceInfo) => {
|
private onDeviceVerificationChanged = (userId: string, deviceId: string, deviceInfo: DeviceInfo): void => {
|
||||||
if (userId !== this.props.member.userId) return;
|
if (userId !== this.props.member.userId) return;
|
||||||
this.updateE2EStatus();
|
this.updateE2EStatus();
|
||||||
};
|
};
|
||||||
|
|
||||||
async updateE2EStatus() {
|
private async updateE2EStatus(): Promise<void> {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const { userId } = this.props.member;
|
const { userId } = this.props.member;
|
||||||
const isMe = userId === cli.getUserId();
|
const isMe = userId === cli.getUserId();
|
||||||
|
@ -143,32 +156,32 @@ export default class MemberTile extends React.Component {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
getStatusMessage() {
|
private getStatusMessage(): string {
|
||||||
const { user } = this.props.member;
|
const { user } = this.props.member;
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return user._unstable_statusMessage;
|
return user.unstable_statusMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
_onStatusMessageCommitted = () => {
|
private onStatusMessageCommitted = (): void => {
|
||||||
// The `User` object has observed a status message change.
|
// The `User` object has observed a status message change.
|
||||||
this.setState({
|
this.setState({
|
||||||
statusMessage: this.getStatusMessage(),
|
statusMessage: this.getStatusMessage(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
shouldComponentUpdate(nextProps, nextState) {
|
shouldComponentUpdate(nextProps: IProps, nextState: IState): boolean {
|
||||||
if (
|
if (
|
||||||
this.member_last_modified_time === undefined ||
|
this.memberLastModifiedTime === undefined ||
|
||||||
this.member_last_modified_time < nextProps.member.getLastModifiedTime()
|
this.memberLastModifiedTime < nextProps.member.getLastModifiedTime()
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
nextProps.member.user &&
|
nextProps.member.user &&
|
||||||
(this.user_last_modified_time === undefined ||
|
(this.userLastModifiedTime === undefined ||
|
||||||
this.user_last_modified_time < nextProps.member.user.getLastModifiedTime())
|
this.userLastModifiedTime < nextProps.member.user.getLastModifiedTime())
|
||||||
) {
|
) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -181,18 +194,18 @@ export default class MemberTile extends React.Component {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
onClick = e => {
|
private onClick = (): void => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: Action.ViewUser,
|
action: Action.ViewUser,
|
||||||
member: this.props.member,
|
member: this.props.member,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_getDisplayName() {
|
private getDisplayName(): string {
|
||||||
return this.props.member.name;
|
return this.props.member.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
getPowerLabel() {
|
private getPowerLabel(): string {
|
||||||
return _t("%(userName)s (power %(powerLevelNumber)s)", {
|
return _t("%(userName)s (power %(powerLevelNumber)s)", {
|
||||||
userName: this.props.member.userId,
|
userName: this.props.member.userId,
|
||||||
powerLevelNumber: this.props.member.powerLevel,
|
powerLevelNumber: this.props.member.powerLevel,
|
||||||
|
@ -200,11 +213,8 @@ export default class MemberTile extends React.Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const MemberAvatar = sdk.getComponent('avatars.MemberAvatar');
|
|
||||||
const EntityTile = sdk.getComponent('rooms.EntityTile');
|
|
||||||
|
|
||||||
const member = this.props.member;
|
const member = this.props.member;
|
||||||
const name = this._getDisplayName();
|
const name = this.getDisplayName();
|
||||||
const presenceState = member.user ? member.user.presence : null;
|
const presenceState = member.user ? member.user.presence : null;
|
||||||
|
|
||||||
let statusMessage = null;
|
let statusMessage = null;
|
||||||
|
@ -217,13 +227,13 @@ export default class MemberTile extends React.Component {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (member.user) {
|
if (member.user) {
|
||||||
this.user_last_modified_time = member.user.getLastModifiedTime();
|
this.userLastModifiedTime = member.user.getLastModifiedTime();
|
||||||
}
|
}
|
||||||
this.member_last_modified_time = member.getLastModifiedTime();
|
this.memberLastModifiedTime = member.getLastModifiedTime();
|
||||||
|
|
||||||
const powerStatusMap = new Map([
|
const powerStatusMap = new Map([
|
||||||
[100, EntityTile.POWER_STATUS_ADMIN],
|
[100, PowerStatus.Admin],
|
||||||
[50, EntityTile.POWER_STATUS_MODERATOR],
|
[50, PowerStatus.Moderator],
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Find the nearest power level with a badge
|
// Find the nearest power level with a badge
|
|
@ -15,26 +15,23 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
|
|
||||||
import { _t } from '../../../languageHandler';
|
import { _t } from '../../../languageHandler';
|
||||||
import {replaceableComponent} from "../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../utils/replaceableComponent";
|
||||||
|
|
||||||
|
interface IProps {
|
||||||
|
// number of milliseconds ago this user was last active.
|
||||||
|
// zero = unknown
|
||||||
|
activeAgo?: number;
|
||||||
|
// if true, activeAgo is an approximation and "Now" should
|
||||||
|
// be shown instead
|
||||||
|
currentlyActive?: boolean;
|
||||||
|
// offline, online, etc
|
||||||
|
presenceState?: string;
|
||||||
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.rooms.PresenceLabel")
|
@replaceableComponent("views.rooms.PresenceLabel")
|
||||||
export default class PresenceLabel extends React.Component {
|
export default class PresenceLabel extends React.Component<IProps> {
|
||||||
static propTypes = {
|
|
||||||
// number of milliseconds ago this user was last active.
|
|
||||||
// zero = unknown
|
|
||||||
activeAgo: PropTypes.number,
|
|
||||||
|
|
||||||
// if true, activeAgo is an approximation and "Now" should
|
|
||||||
// be shown instead
|
|
||||||
currentlyActive: PropTypes.bool,
|
|
||||||
|
|
||||||
// offline, online, etc
|
|
||||||
presenceState: PropTypes.string,
|
|
||||||
};
|
|
||||||
|
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
activeAgo: -1,
|
activeAgo: -1,
|
||||||
presenceState: null,
|
presenceState: null,
|
||||||
|
@ -42,29 +39,29 @@ export default class PresenceLabel extends React.Component {
|
||||||
|
|
||||||
// Return duration as a string using appropriate time units
|
// Return duration as a string using appropriate time units
|
||||||
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
|
// XXX: This would be better handled using a culture-aware library, but we don't use one yet.
|
||||||
getDuration(time) {
|
private getDuration(time: number): string {
|
||||||
if (!time) return;
|
if (!time) return;
|
||||||
const t = parseInt(time / 1000);
|
const t = time / 1000;
|
||||||
const s = t % 60;
|
const s = t % 60;
|
||||||
const m = parseInt(t / 60) % 60;
|
const m = t / 60 % 60;
|
||||||
const h = parseInt(t / (60 * 60)) % 24;
|
const h = t / (60 * 60) % 24;
|
||||||
const d = parseInt(t / (60 * 60 * 24));
|
const d = t / (60 * 60 * 24);
|
||||||
if (t < 60) {
|
if (t < 60) {
|
||||||
if (t < 0) {
|
if (t < 0) {
|
||||||
return _t("%(duration)ss", {duration: 0});
|
return _t("%(duration)ss", { duration: 0 });
|
||||||
}
|
}
|
||||||
return _t("%(duration)ss", {duration: s});
|
return _t("%(duration)ss", { duration: s });
|
||||||
}
|
}
|
||||||
if (t < 60 * 60) {
|
if (t < 60 * 60) {
|
||||||
return _t("%(duration)sm", {duration: m});
|
return _t("%(duration)sm", { duration: m });
|
||||||
}
|
}
|
||||||
if (t < 24 * 60 * 60) {
|
if (t < 24 * 60 * 60) {
|
||||||
return _t("%(duration)sh", {duration: h});
|
return _t("%(duration)sh", { duration: h });
|
||||||
}
|
}
|
||||||
return _t("%(duration)sd", {duration: d});
|
return _t("%(duration)sd", { duration: d });
|
||||||
}
|
}
|
||||||
|
|
||||||
getPrettyPresence(presence, activeAgo, currentlyActive) {
|
private getPrettyPresence(presence: string, activeAgo: number, currentlyActive: boolean): string {
|
||||||
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
|
if (!currentlyActive && activeAgo !== undefined && activeAgo > 0) {
|
||||||
const duration = this.getDuration(activeAgo);
|
const duration = this.getDuration(activeAgo);
|
||||||
if (presence === "online") return _t("Online for %(duration)s", { duration: duration });
|
if (presence === "online") return _t("Online for %(duration)s", { duration: duration });
|
|
@ -79,8 +79,8 @@ export default class CrossSigningPanel extends React.PureComponent {
|
||||||
async _getUpdatedStatus() {
|
async _getUpdatedStatus() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const pkCache = cli.getCrossSigningCacheCallbacks();
|
const pkCache = cli.getCrossSigningCacheCallbacks();
|
||||||
const crossSigning = cli.crypto._crossSigningInfo;
|
const crossSigning = cli.crypto.crossSigningInfo;
|
||||||
const secretStorage = cli.crypto._secretStorage;
|
const secretStorage = cli.crypto.secretStorage;
|
||||||
const crossSigningPublicKeysOnDevice = crossSigning.getId();
|
const crossSigningPublicKeysOnDevice = crossSigning.getId();
|
||||||
const crossSigningPrivateKeysInStorage = await crossSigning.isStoredInSecretStorage(secretStorage);
|
const crossSigningPrivateKeysInStorage = await crossSigning.isStoredInSecretStorage(secretStorage);
|
||||||
const masterPrivateKeyCached = !!(pkCache && await pkCache.getCrossSigningKeyCache("master"));
|
const masterPrivateKeyCached = !!(pkCache && await pkCache.getCrossSigningKeyCache("master"));
|
||||||
|
|
|
@ -131,7 +131,7 @@ export default class SecureBackupPanel extends React.PureComponent {
|
||||||
|
|
||||||
async _getUpdatedDiagnostics() {
|
async _getUpdatedDiagnostics() {
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const secretStorage = cli.crypto._secretStorage;
|
const secretStorage = cli.crypto.secretStorage;
|
||||||
|
|
||||||
const backupKeyStored = !!(await cli.isKeyBackupKeyStored());
|
const backupKeyStored = !!(await cli.isKeyBackupKeyStored());
|
||||||
const backupKeyFromCache = await cli.crypto.getSessionBackupPrivateKey();
|
const backupKeyFromCache = await cli.crypto.getSessionBackupPrivateKey();
|
||||||
|
|
|
@ -491,24 +491,27 @@
|
||||||
"Converts the room to a DM": "Converts the room to a DM",
|
"Converts the room to a DM": "Converts the room to a DM",
|
||||||
"Converts the DM to a room": "Converts the DM to a room",
|
"Converts the DM to a room": "Converts the DM to a room",
|
||||||
"Displays action": "Displays action",
|
"Displays action": "Displays action",
|
||||||
"Reason": "Reason",
|
"%(targetName)s accepted the invitation for %(displayName)s": "%(targetName)s accepted the invitation for %(displayName)s",
|
||||||
"%(targetName)s accepted the invitation for %(displayName)s.": "%(targetName)s accepted the invitation for %(displayName)s.",
|
"%(targetName)s accepted an invitation": "%(targetName)s accepted an invitation",
|
||||||
"%(targetName)s accepted an invitation.": "%(targetName)s accepted an invitation.",
|
"%(senderName)s invited %(targetName)s": "%(senderName)s invited %(targetName)s",
|
||||||
"%(senderName)s invited %(targetName)s.": "%(senderName)s invited %(targetName)s.",
|
"%(senderName)s banned %(targetName)s: %(reason)s": "%(senderName)s banned %(targetName)s: %(reason)s",
|
||||||
"%(senderName)s banned %(targetName)s.": "%(senderName)s banned %(targetName)s.",
|
"%(senderName)s banned %(targetName)s": "%(senderName)s banned %(targetName)s",
|
||||||
"%(oldDisplayName)s changed their display name to %(displayName)s.": "%(oldDisplayName)s changed their display name to %(displayName)s.",
|
"%(oldDisplayName)s changed their display name to %(displayName)s": "%(oldDisplayName)s changed their display name to %(displayName)s",
|
||||||
"%(senderName)s set their display name to %(displayName)s.": "%(senderName)s set their display name to %(displayName)s.",
|
"%(senderName)s set their display name to %(displayName)s": "%(senderName)s set their display name to %(displayName)s",
|
||||||
"%(senderName)s removed their display name (%(oldDisplayName)s).": "%(senderName)s removed their display name (%(oldDisplayName)s).",
|
"%(senderName)s removed their display name (%(oldDisplayName)s)": "%(senderName)s removed their display name (%(oldDisplayName)s)",
|
||||||
"%(senderName)s removed their profile picture.": "%(senderName)s removed their profile picture.",
|
"%(senderName)s removed their profile picture": "%(senderName)s removed their profile picture",
|
||||||
"%(senderName)s changed their profile picture.": "%(senderName)s changed their profile picture.",
|
"%(senderName)s changed their profile picture": "%(senderName)s changed their profile picture",
|
||||||
"%(senderName)s set a profile picture.": "%(senderName)s set a profile picture.",
|
"%(senderName)s set a profile picture": "%(senderName)s set a profile picture",
|
||||||
"%(senderName)s made no change.": "%(senderName)s made no change.",
|
"%(senderName)s made no change": "%(senderName)s made no change",
|
||||||
"%(targetName)s joined the room.": "%(targetName)s joined the room.",
|
"%(targetName)s joined the room": "%(targetName)s joined the room",
|
||||||
"%(targetName)s rejected the invitation.": "%(targetName)s rejected the invitation.",
|
"%(targetName)s rejected the invitation": "%(targetName)s rejected the invitation",
|
||||||
"%(targetName)s left the room.": "%(targetName)s left the room.",
|
"%(targetName)s left the room: %(reason)s": "%(targetName)s left the room: %(reason)s",
|
||||||
"%(senderName)s unbanned %(targetName)s.": "%(senderName)s unbanned %(targetName)s.",
|
"%(targetName)s left the room": "%(targetName)s left the room",
|
||||||
"%(senderName)s withdrew %(targetName)s's invitation.": "%(senderName)s withdrew %(targetName)s's invitation.",
|
"%(senderName)s unbanned %(targetName)s": "%(senderName)s unbanned %(targetName)s",
|
||||||
"%(senderName)s kicked %(targetName)s.": "%(senderName)s kicked %(targetName)s.",
|
"%(senderName)s withdrew %(targetName)s's invitation: %(reason)s": "%(senderName)s withdrew %(targetName)s's invitation: %(reason)s",
|
||||||
|
"%(senderName)s withdrew %(targetName)s's invitation": "%(senderName)s withdrew %(targetName)s's invitation",
|
||||||
|
"%(senderName)s kicked %(targetName)s: %(reason)s": "%(senderName)s kicked %(targetName)s: %(reason)s",
|
||||||
|
"%(senderName)s kicked %(targetName)s": "%(senderName)s kicked %(targetName)s",
|
||||||
"%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s changed the topic to \"%(topic)s\".",
|
"%(senderDisplayName)s changed the topic to \"%(topic)s\".": "%(senderDisplayName)s changed the topic to \"%(topic)s\".",
|
||||||
"%(senderDisplayName)s changed the room avatar.": "%(senderDisplayName)s changed the room avatar.",
|
"%(senderDisplayName)s changed the room avatar.": "%(senderDisplayName)s changed the room avatar.",
|
||||||
"%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s removed the room name.",
|
"%(senderDisplayName)s removed the room name.": "%(senderDisplayName)s removed the room name.",
|
||||||
|
@ -1422,6 +1425,7 @@
|
||||||
"Failed to unban": "Failed to unban",
|
"Failed to unban": "Failed to unban",
|
||||||
"Unban": "Unban",
|
"Unban": "Unban",
|
||||||
"Banned by %(displayName)s": "Banned by %(displayName)s",
|
"Banned by %(displayName)s": "Banned by %(displayName)s",
|
||||||
|
"Reason": "Reason",
|
||||||
"Error changing power level requirement": "Error changing power level requirement",
|
"Error changing power level requirement": "Error changing power level requirement",
|
||||||
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.",
|
"An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.": "An error occurred changing the room's power level requirements. Ensure you have sufficient permissions and try again.",
|
||||||
"Error changing power level": "Error changing power level",
|
"Error changing power level": "Error changing power level",
|
||||||
|
|
|
@ -17,7 +17,7 @@ limitations under the License.
|
||||||
// The following interfaces take their names and member names from seshat and the spec
|
// The following interfaces take their names and member names from seshat and the spec
|
||||||
/* eslint-disable camelcase */
|
/* eslint-disable camelcase */
|
||||||
|
|
||||||
export interface MatrixEvent {
|
export interface IMatrixEvent {
|
||||||
type: string;
|
type: string;
|
||||||
sender: string;
|
sender: string;
|
||||||
content: {};
|
content: {};
|
||||||
|
@ -27,37 +27,37 @@ export interface MatrixEvent {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MatrixProfile {
|
export interface IMatrixProfile {
|
||||||
avatar_url: string;
|
avatar_url: string;
|
||||||
displayname: string;
|
displayname: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface CrawlerCheckpoint {
|
export interface ICrawlerCheckpoint {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
token: string;
|
token: string;
|
||||||
fullCrawl?: boolean;
|
fullCrawl?: boolean;
|
||||||
direction: string;
|
direction: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResultContext {
|
export interface IResultContext {
|
||||||
events_before: [MatrixEvent];
|
events_before: [IMatrixEvent];
|
||||||
events_after: [MatrixEvent];
|
events_after: [IMatrixEvent];
|
||||||
profile_info: Map<string, MatrixProfile>;
|
profile_info: Map<string, IMatrixProfile>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ResultsElement {
|
export interface IResultsElement {
|
||||||
rank: number;
|
rank: number;
|
||||||
result: MatrixEvent;
|
result: IMatrixEvent;
|
||||||
context: ResultContext;
|
context: IResultContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchResult {
|
export interface ISearchResult {
|
||||||
count: number;
|
count: number;
|
||||||
results: [ResultsElement];
|
results: [IResultsElement];
|
||||||
highlights: [string];
|
highlights: [string];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SearchArgs {
|
export interface ISearchArgs {
|
||||||
search_term: string;
|
search_term: string;
|
||||||
before_limit: number;
|
before_limit: number;
|
||||||
after_limit: number;
|
after_limit: number;
|
||||||
|
@ -65,19 +65,19 @@ export interface SearchArgs {
|
||||||
room_id?: string;
|
room_id?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventAndProfile {
|
export interface IEventAndProfile {
|
||||||
event: MatrixEvent;
|
event: IMatrixEvent;
|
||||||
profile: MatrixProfile;
|
profile: IMatrixProfile;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface LoadArgs {
|
export interface ILoadArgs {
|
||||||
roomId: string;
|
roomId: string;
|
||||||
limit: number;
|
limit: number;
|
||||||
fromEvent?: string;
|
fromEvent?: string;
|
||||||
direction?: string;
|
direction?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IndexStats {
|
export interface IIndexStats {
|
||||||
size: number;
|
size: number;
|
||||||
eventCount: number;
|
eventCount: number;
|
||||||
roomCount: number;
|
roomCount: number;
|
||||||
|
@ -119,13 +119,13 @@ export default abstract class BaseEventIndexManager {
|
||||||
* Queue up an event to be added to the index.
|
* Queue up an event to be added to the index.
|
||||||
*
|
*
|
||||||
* @param {MatrixEvent} ev The event that should be added to the index.
|
* @param {MatrixEvent} ev The event that should be added to the index.
|
||||||
* @param {MatrixProfile} profile The profile of the event sender at the
|
* @param {IMatrixProfile} profile The profile of the event sender at the
|
||||||
* time of the event receival.
|
* time of the event receival.
|
||||||
*
|
*
|
||||||
* @return {Promise} A promise that will resolve when the was queued up for
|
* @return {Promise} A promise that will resolve when the was queued up for
|
||||||
* addition.
|
* addition.
|
||||||
*/
|
*/
|
||||||
async addEventToIndex(ev: MatrixEvent, profile: MatrixProfile): Promise<void> {
|
async addEventToIndex(ev: IMatrixEvent, profile: IMatrixProfile): Promise<void> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -160,10 +160,10 @@ export default abstract class BaseEventIndexManager {
|
||||||
/**
|
/**
|
||||||
* Get statistical information of the index.
|
* Get statistical information of the index.
|
||||||
*
|
*
|
||||||
* @return {Promise<IndexStats>} A promise that will resolve to the index
|
* @return {Promise<IIndexStats>} A promise that will resolve to the index
|
||||||
* statistics.
|
* statistics.
|
||||||
*/
|
*/
|
||||||
async getStats(): Promise<IndexStats> {
|
async getStats(): Promise<IIndexStats> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,13 +203,13 @@ export default abstract class BaseEventIndexManager {
|
||||||
/**
|
/**
|
||||||
* Search the event index using the given term for matching events.
|
* Search the event index using the given term for matching events.
|
||||||
*
|
*
|
||||||
* @param {SearchArgs} searchArgs The search configuration for the search,
|
* @param {ISearchArgs} searchArgs The search configuration for the search,
|
||||||
* sets the search term and determines the search result contents.
|
* sets the search term and determines the search result contents.
|
||||||
*
|
*
|
||||||
* @return {Promise<[SearchResult]>} A promise that will resolve to an array
|
* @return {Promise<[ISearchResult]>} A promise that will resolve to an array
|
||||||
* of search results once the search is done.
|
* of search results once the search is done.
|
||||||
*/
|
*/
|
||||||
async searchEventIndex(searchArgs: SearchArgs): Promise<SearchResult> {
|
async searchEventIndex(searchArgs: ISearchArgs): Promise<ISearchResult> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -218,12 +218,12 @@ export default abstract class BaseEventIndexManager {
|
||||||
*
|
*
|
||||||
* This is used to add a batch of events to the index.
|
* This is used to add a batch of events to the index.
|
||||||
*
|
*
|
||||||
* @param {[EventAndProfile]} events The list of events and profiles that
|
* @param {[IEventAndProfile]} events The list of events and profiles that
|
||||||
* should be added to the event index.
|
* should be added to the event index.
|
||||||
* @param {[CrawlerCheckpoint]} checkpoint A new crawler checkpoint that
|
* @param {[ICrawlerCheckpoint]} checkpoint A new crawler checkpoint that
|
||||||
* should be stored in the index which should be used to continue crawling
|
* should be stored in the index which should be used to continue crawling
|
||||||
* the room.
|
* the room.
|
||||||
* @param {[CrawlerCheckpoint]} oldCheckpoint The checkpoint that was used
|
* @param {[ICrawlerCheckpoint]} oldCheckpoint The checkpoint that was used
|
||||||
* to fetch the current batch of events. This checkpoint will be removed
|
* to fetch the current batch of events. This checkpoint will be removed
|
||||||
* from the index.
|
* from the index.
|
||||||
*
|
*
|
||||||
|
@ -231,9 +231,9 @@ export default abstract class BaseEventIndexManager {
|
||||||
* were already added to the index, false otherwise.
|
* were already added to the index, false otherwise.
|
||||||
*/
|
*/
|
||||||
async addHistoricEvents(
|
async addHistoricEvents(
|
||||||
events: [EventAndProfile],
|
events: IEventAndProfile[],
|
||||||
checkpoint: CrawlerCheckpoint | null,
|
checkpoint: ICrawlerCheckpoint | null,
|
||||||
oldCheckpoint: CrawlerCheckpoint | null,
|
oldCheckpoint: ICrawlerCheckpoint | null,
|
||||||
): Promise<boolean> {
|
): Promise<boolean> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
@ -241,36 +241,36 @@ export default abstract class BaseEventIndexManager {
|
||||||
/**
|
/**
|
||||||
* Add a new crawler checkpoint to the index.
|
* Add a new crawler checkpoint to the index.
|
||||||
*
|
*
|
||||||
* @param {CrawlerCheckpoint} checkpoint The checkpoint that should be added
|
* @param {ICrawlerCheckpoint} checkpoint The checkpoint that should be added
|
||||||
* to the index.
|
* to the index.
|
||||||
*
|
*
|
||||||
* @return {Promise} A promise that will resolve once the checkpoint has
|
* @return {Promise} A promise that will resolve once the checkpoint has
|
||||||
* been stored.
|
* been stored.
|
||||||
*/
|
*/
|
||||||
async addCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
|
async addCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise<void> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new crawler checkpoint to the index.
|
* Add a new crawler checkpoint to the index.
|
||||||
*
|
*
|
||||||
* @param {CrawlerCheckpoint} checkpoint The checkpoint that should be
|
* @param {ICrawlerCheckpoint} checkpoint The checkpoint that should be
|
||||||
* removed from the index.
|
* removed from the index.
|
||||||
*
|
*
|
||||||
* @return {Promise} A promise that will resolve once the checkpoint has
|
* @return {Promise} A promise that will resolve once the checkpoint has
|
||||||
* been removed.
|
* been removed.
|
||||||
*/
|
*/
|
||||||
async removeCrawlerCheckpoint(checkpoint: CrawlerCheckpoint): Promise<void> {
|
async removeCrawlerCheckpoint(checkpoint: ICrawlerCheckpoint): Promise<void> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load the stored checkpoints from the index.
|
* Load the stored checkpoints from the index.
|
||||||
*
|
*
|
||||||
* @return {Promise<[CrawlerCheckpoint]>} A promise that will resolve to an
|
* @return {Promise<[ICrawlerCheckpoint]>} A promise that will resolve to an
|
||||||
* array of crawler checkpoints once they have been loaded from the index.
|
* array of crawler checkpoints once they have been loaded from the index.
|
||||||
*/
|
*/
|
||||||
async loadCheckpoints(): Promise<[CrawlerCheckpoint]> {
|
async loadCheckpoints(): Promise<ICrawlerCheckpoint[]> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,11 +286,11 @@ export default abstract class BaseEventIndexManager {
|
||||||
* @param {string} args.direction The direction to which we should continue
|
* @param {string} args.direction The direction to which we should continue
|
||||||
* loading events from. This is used only if fromEvent is used as well.
|
* loading events from. This is used only if fromEvent is used as well.
|
||||||
*
|
*
|
||||||
* @return {Promise<[EventAndProfile]>} A promise that will resolve to an
|
* @return {Promise<[IEventAndProfile]>} A promise that will resolve to an
|
||||||
* array of Matrix events that contain mxc URLs accompanied with the
|
* array of Matrix events that contain mxc URLs accompanied with the
|
||||||
* historic profile of the sender.
|
* historic profile of the sender.
|
||||||
*/
|
*/
|
||||||
async loadFileEvents(args: LoadArgs): Promise<[EventAndProfile]> {
|
async loadFileEvents(args: ILoadArgs): Promise<IEventAndProfile[]> {
|
||||||
throw new Error("Unimplemented");
|
throw new Error("Unimplemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ import { MatrixClientPeg } from "../MatrixClientPeg";
|
||||||
import { sleep } from "../utils/promise";
|
import { sleep } from "../utils/promise";
|
||||||
import SettingsStore from "../settings/SettingsStore";
|
import SettingsStore from "../settings/SettingsStore";
|
||||||
import { SettingLevel } from "../settings/SettingLevel";
|
import { SettingLevel } from "../settings/SettingLevel";
|
||||||
import {CrawlerCheckpoint, LoadArgs, SearchArgs} from "./BaseEventIndexManager";
|
import { ICrawlerCheckpoint, ILoadArgs, ISearchArgs } from "./BaseEventIndexManager";
|
||||||
|
|
||||||
// The time in ms that the crawler will wait loop iterations if there
|
// The time in ms that the crawler will wait loop iterations if there
|
||||||
// have not been any checkpoints to consume in the last iteration.
|
// have not been any checkpoints to consume in the last iteration.
|
||||||
|
@ -45,9 +45,9 @@ interface ICrawler {
|
||||||
* Event indexing class that wraps the platform specific event indexing.
|
* Event indexing class that wraps the platform specific event indexing.
|
||||||
*/
|
*/
|
||||||
export default class EventIndex extends EventEmitter {
|
export default class EventIndex extends EventEmitter {
|
||||||
private crawlerCheckpoints: CrawlerCheckpoint[] = [];
|
private crawlerCheckpoints: ICrawlerCheckpoint[] = [];
|
||||||
private crawler: ICrawler = null;
|
private crawler: ICrawler = null;
|
||||||
private currentCheckpoint: CrawlerCheckpoint = null;
|
private currentCheckpoint: ICrawlerCheckpoint = null;
|
||||||
|
|
||||||
public async init() {
|
public async init() {
|
||||||
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
||||||
|
@ -111,14 +111,14 @@ export default class EventIndex extends EventEmitter {
|
||||||
const timeline = room.getLiveTimeline();
|
const timeline = room.getLiveTimeline();
|
||||||
const token = timeline.getPaginationToken("b");
|
const token = timeline.getPaginationToken("b");
|
||||||
|
|
||||||
const backCheckpoint: CrawlerCheckpoint = {
|
const backCheckpoint: ICrawlerCheckpoint = {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
token: token,
|
token: token,
|
||||||
direction: "b",
|
direction: "b",
|
||||||
fullCrawl: true,
|
fullCrawl: true,
|
||||||
};
|
};
|
||||||
|
|
||||||
const forwardCheckpoint: CrawlerCheckpoint = {
|
const forwardCheckpoint: ICrawlerCheckpoint = {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
token: token,
|
token: token,
|
||||||
direction: "f",
|
direction: "f",
|
||||||
|
@ -668,13 +668,13 @@ export default class EventIndex extends EventEmitter {
|
||||||
/**
|
/**
|
||||||
* Search the event index using the given term for matching events.
|
* Search the event index using the given term for matching events.
|
||||||
*
|
*
|
||||||
* @param {SearchArgs} searchArgs The search configuration for the search,
|
* @param {ISearchArgs} searchArgs The search configuration for the search,
|
||||||
* sets the search term and determines the search result contents.
|
* sets the search term and determines the search result contents.
|
||||||
*
|
*
|
||||||
* @return {Promise<[SearchResult]>} A promise that will resolve to an array
|
* @return {Promise<[SearchResult]>} A promise that will resolve to an array
|
||||||
* of search results once the search is done.
|
* of search results once the search is done.
|
||||||
*/
|
*/
|
||||||
public async search(searchArgs: SearchArgs) {
|
public async search(searchArgs: ISearchArgs) {
|
||||||
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
||||||
return indexManager.searchEventIndex(searchArgs);
|
return indexManager.searchEventIndex(searchArgs);
|
||||||
}
|
}
|
||||||
|
@ -709,7 +709,7 @@ export default class EventIndex extends EventEmitter {
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
const indexManager = PlatformPeg.get().getEventIndexingManager();
|
||||||
|
|
||||||
const loadArgs: LoadArgs = {
|
const loadArgs: ILoadArgs = {
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
limit: limit,
|
limit: limit,
|
||||||
};
|
};
|
||||||
|
|
|
@ -86,8 +86,8 @@ async function collectBugReport(opts: IOpts = {}, gzipLogs = true) {
|
||||||
body.append('cross_signing_key', client.getCrossSigningId());
|
body.append('cross_signing_key', client.getCrossSigningId());
|
||||||
|
|
||||||
// add cross-signing status information
|
// add cross-signing status information
|
||||||
const crossSigning = client.crypto._crossSigningInfo;
|
const crossSigning = client.crypto.crossSigningInfo;
|
||||||
const secretStorage = client.crypto._secretStorage;
|
const secretStorage = client.crypto.secretStorage;
|
||||||
|
|
||||||
body.append("cross_signing_ready", String(await client.isCrossSigningReady()));
|
body.append("cross_signing_ready", String(await client.isCrossSigningReady()));
|
||||||
body.append("cross_signing_supported_by_hs",
|
body.append("cross_signing_supported_by_hs",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue