Convert SecurityUserSettingsTab to TS
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>pull/21833/head
parent
222427dae8
commit
073eff4c71
|
@ -16,7 +16,6 @@ limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import { sleep } from "matrix-js-sdk/src/utils";
|
import { sleep } from "matrix-js-sdk/src/utils";
|
||||||
|
|
||||||
import { _t } from "../../../../../languageHandler";
|
import { _t } from "../../../../../languageHandler";
|
||||||
|
@ -26,34 +25,40 @@ import * as FormattingUtils from "../../../../../utils/FormattingUtils";
|
||||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||||
import Analytics from "../../../../../Analytics";
|
import Analytics from "../../../../../Analytics";
|
||||||
import Modal from "../../../../../Modal";
|
import Modal from "../../../../../Modal";
|
||||||
import * as sdk from "../../../../..";
|
|
||||||
import dis from "../../../../../dispatcher/dispatcher";
|
import dis from "../../../../../dispatcher/dispatcher";
|
||||||
import { privateShouldBeEncrypted } from "../../../../../createRoom";
|
import { privateShouldBeEncrypted } from "../../../../../createRoom";
|
||||||
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
import { SettingLevel } from "../../../../../settings/SettingLevel";
|
||||||
import SecureBackupPanel from "../../SecureBackupPanel";
|
import SecureBackupPanel from "../../SecureBackupPanel";
|
||||||
import SettingsStore from "../../../../../settings/SettingsStore";
|
import SettingsStore from "../../../../../settings/SettingsStore";
|
||||||
import { UIFeature } from "../../../../../settings/UIFeature";
|
import { UIFeature } from "../../../../../settings/UIFeature";
|
||||||
import { isE2eAdvancedPanelPossible } from "../../E2eAdvancedPanel";
|
import E2eAdvancedPanel, { isE2eAdvancedPanelPossible } from "../../E2eAdvancedPanel";
|
||||||
import CountlyAnalytics from "../../../../../CountlyAnalytics";
|
import CountlyAnalytics from "../../../../../CountlyAnalytics";
|
||||||
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
import { replaceableComponent } from "../../../../../utils/replaceableComponent";
|
||||||
import { PosthogAnalytics } from "../../../../../PosthogAnalytics";
|
import { PosthogAnalytics } from "../../../../../PosthogAnalytics";
|
||||||
|
import { ActionPayload } from "../../../../../dispatcher/payloads";
|
||||||
|
import { Room } from "matrix-js-sdk/src/models/room";
|
||||||
|
import DevicesPanel from "../../DevicesPanel";
|
||||||
|
import SettingsFlag from "../../../elements/SettingsFlag";
|
||||||
|
import CrossSigningPanel from "../../CrossSigningPanel";
|
||||||
|
import EventIndexPanel from "../../EventIndexPanel";
|
||||||
|
import InlineSpinner from "../../../elements/InlineSpinner";
|
||||||
|
|
||||||
export class IgnoredUser extends React.Component {
|
interface IIgnoredUserProps {
|
||||||
static propTypes = {
|
userId: string;
|
||||||
userId: PropTypes.string.isRequired,
|
onUnignored: (userId: string) => void;
|
||||||
onUnignored: PropTypes.func.isRequired,
|
inProgress: boolean;
|
||||||
inProgress: PropTypes.bool.isRequired,
|
}
|
||||||
};
|
|
||||||
|
|
||||||
_onUnignoreClicked = (e) => {
|
export class IgnoredUser extends React.Component<IIgnoredUserProps> {
|
||||||
|
private onUnignoreClicked = (): void => {
|
||||||
this.props.onUnignored(this.props.userId);
|
this.props.onUnignored(this.props.userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
public render(): JSX.Element {
|
||||||
const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
|
const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
|
||||||
return (
|
return (
|
||||||
<div className='mx_SecurityUserSettingsTab_ignoredUser'>
|
<div className='mx_SecurityUserSettingsTab_ignoredUser'>
|
||||||
<AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm' aria-describedby={id} disabled={this.props.inProgress}>
|
<AccessibleButton onClick={this.onUnignoreClicked} kind='primary_sm' aria-describedby={id} disabled={this.props.inProgress}>
|
||||||
{ _t('Unignore') }
|
{ _t('Unignore') }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<span id={id}>{ this.props.userId }</span>
|
<span id={id}>{ this.props.userId }</span>
|
||||||
|
@ -62,17 +67,26 @@ export class IgnoredUser extends React.Component {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@replaceableComponent("views.settings.tabs.user.SecurityUserSettingsTab")
|
interface IProps {
|
||||||
export default class SecurityUserSettingsTab extends React.Component {
|
closeSettingsFn: () => void;
|
||||||
static propTypes = {
|
}
|
||||||
closeSettingsFn: PropTypes.func.isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
constructor() {
|
interface IState {
|
||||||
super();
|
ignoredUserIds: string[];
|
||||||
|
waitingUnignored: string[];
|
||||||
|
managingInvites: boolean;
|
||||||
|
invitedRoomAmt: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
@replaceableComponent("views.settings.tabs.user.SecurityUserSettingsTab")
|
||||||
|
export default class SecurityUserSettingsTab extends React.Component<IProps, IState> {
|
||||||
|
private dispatcherRef: string;
|
||||||
|
|
||||||
|
constructor(props: IProps) {
|
||||||
|
super(props);
|
||||||
|
|
||||||
// Get number of rooms we're invited to
|
// Get number of rooms we're invited to
|
||||||
const invitedRooms = this._getInvitedRooms();
|
const invitedRooms = this.getInvitedRooms();
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
|
ignoredUserIds: MatrixClientPeg.get().getIgnoredUsers(),
|
||||||
|
@ -80,59 +94,57 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
managingInvites: false,
|
managingInvites: false,
|
||||||
invitedRoomAmt: invitedRooms.length,
|
invitedRoomAmt: invitedRooms.length,
|
||||||
};
|
};
|
||||||
|
|
||||||
this._onAction = this._onAction.bind(this);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_onAction({ action }) {
|
private onAction = ({ action }: ActionPayload)=> {
|
||||||
if (action === "ignore_state_changed") {
|
if (action === "ignore_state_changed") {
|
||||||
const ignoredUserIds = MatrixClientPeg.get().getIgnoredUsers();
|
const ignoredUserIds = MatrixClientPeg.get().getIgnoredUsers();
|
||||||
const newWaitingUnignored = this.state.waitingUnignored.filter(e=> ignoredUserIds.includes(e));
|
const newWaitingUnignored = this.state.waitingUnignored.filter(e=> ignoredUserIds.includes(e));
|
||||||
this.setState({ ignoredUserIds, waitingUnignored: newWaitingUnignored });
|
this.setState({ ignoredUserIds, waitingUnignored: newWaitingUnignored });
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public componentDidMount(): void {
|
||||||
|
this.dispatcherRef = dis.register(this.onAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount() {
|
public componentWillUnmount(): void {
|
||||||
this.dispatcherRef = dis.register(this._onAction);
|
|
||||||
}
|
|
||||||
|
|
||||||
componentWillUnmount() {
|
|
||||||
dis.unregister(this.dispatcherRef);
|
dis.unregister(this.dispatcherRef);
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateBlacklistDevicesFlag = (checked) => {
|
private updateBlacklistDevicesFlag = (checked): void => {
|
||||||
MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
|
MatrixClientPeg.get().setGlobalBlacklistUnverifiedDevices(checked);
|
||||||
};
|
};
|
||||||
|
|
||||||
_updateAnalytics = (checked) => {
|
private updateAnalytics = (checked: boolean): void => {
|
||||||
checked ? Analytics.enable() : Analytics.disable();
|
checked ? Analytics.enable() : Analytics.disable();
|
||||||
CountlyAnalytics.instance.enable(/* anonymous = */ !checked);
|
CountlyAnalytics.instance.enable(/* anonymous = */ !checked);
|
||||||
PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId());
|
PosthogAnalytics.instance.updateAnonymityFromSettings(MatrixClientPeg.get().getUserId());
|
||||||
};
|
};
|
||||||
|
|
||||||
_onExportE2eKeysClicked = () => {
|
private onExportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
Modal.createTrackedDialogAsync('Export E2E Keys', '',
|
||||||
import('../../../../../async-components/views/dialogs/security/ExportE2eKeysDialog'),
|
import('../../../../../async-components/views/dialogs/security/ExportE2eKeysDialog'),
|
||||||
{ matrixClient: MatrixClientPeg.get() },
|
{ matrixClient: MatrixClientPeg.get() },
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onImportE2eKeysClicked = () => {
|
private onImportE2eKeysClicked = (): void => {
|
||||||
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
Modal.createTrackedDialogAsync('Import E2E Keys', '',
|
||||||
import('../../../../../async-components/views/dialogs/security/ImportE2eKeysDialog'),
|
import('../../../../../async-components/views/dialogs/security/ImportE2eKeysDialog'),
|
||||||
{ matrixClient: MatrixClientPeg.get() },
|
{ matrixClient: MatrixClientPeg.get() },
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onGoToUserProfileClick = () => {
|
private onGoToUserProfileClick = (): void => {
|
||||||
dis.dispatch({
|
dis.dispatch({
|
||||||
action: 'view_user_info',
|
action: 'view_user_info',
|
||||||
userId: MatrixClientPeg.get().getUserId(),
|
userId: MatrixClientPeg.get().getUserId(),
|
||||||
});
|
});
|
||||||
this.props.closeSettingsFn();
|
this.props.closeSettingsFn();
|
||||||
}
|
};
|
||||||
|
|
||||||
_onUserUnignored = async (userId) => {
|
private onUserUnignored = async (userId: string): Promise<void> => {
|
||||||
const { ignoredUserIds, waitingUnignored } = this.state;
|
const { ignoredUserIds, waitingUnignored } = this.state;
|
||||||
const currentlyIgnoredUserIds = ignoredUserIds.filter(e => !waitingUnignored.includes(e));
|
const currentlyIgnoredUserIds = ignoredUserIds.filter(e => !waitingUnignored.includes(e));
|
||||||
|
|
||||||
|
@ -144,23 +156,24 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
_getInvitedRooms = () => {
|
private getInvitedRooms = (): Room[] => {
|
||||||
return MatrixClientPeg.get().getRooms().filter((r) => {
|
return MatrixClientPeg.get().getRooms().filter((r) => {
|
||||||
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
|
return r.hasMembershipState(MatrixClientPeg.get().getUserId(), "invite");
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_manageInvites = async (accept) => {
|
private manageInvites = async (accept: boolean): Promise<void> => {
|
||||||
this.setState({
|
this.setState({
|
||||||
managingInvites: true,
|
managingInvites: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Compile array of invitation room ids
|
// Compile array of invitation room ids
|
||||||
const invitedRoomIds = this._getInvitedRooms().map((room) => {
|
const invitedRoomIds = this.getInvitedRooms().map((room) => {
|
||||||
return room.roomId;
|
return room.roomId;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Execute all acceptances/rejections sequentially
|
// Execute all acceptances/rejections sequentially
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
const self = this;
|
const self = this;
|
||||||
const cli = MatrixClientPeg.get();
|
const cli = MatrixClientPeg.get();
|
||||||
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
|
const action = accept ? cli.joinRoom.bind(cli) : cli.leave.bind(cli);
|
||||||
|
@ -192,17 +205,15 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
_onAcceptAllInvitesClicked = (ev) => {
|
private onAcceptAllInvitesClicked = (): void => {
|
||||||
this._manageInvites(true);
|
this.manageInvites(true);
|
||||||
};
|
};
|
||||||
|
|
||||||
_onRejectAllInvitesClicked = (ev) => {
|
private onRejectAllInvitesClicked = (): void => {
|
||||||
this._manageInvites(false);
|
this.manageInvites(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
_renderCurrentDeviceInfo() {
|
private renderCurrentDeviceInfo(): JSX.Element {
|
||||||
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
|
|
||||||
|
|
||||||
const client = MatrixClientPeg.get();
|
const client = MatrixClientPeg.get();
|
||||||
const deviceId = client.deviceId;
|
const deviceId = client.deviceId;
|
||||||
let identityKey = client.getDeviceEd25519Key();
|
let identityKey = client.getDeviceEd25519Key();
|
||||||
|
@ -216,10 +227,10 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
if (client.isCryptoEnabled()) {
|
if (client.isCryptoEnabled()) {
|
||||||
importExportButtons = (
|
importExportButtons = (
|
||||||
<div className='mx_SecurityUserSettingsTab_importExportButtons'>
|
<div className='mx_SecurityUserSettingsTab_importExportButtons'>
|
||||||
<AccessibleButton kind='primary' onClick={this._onExportE2eKeysClicked}>
|
<AccessibleButton kind='primary' onClick={this.onExportE2eKeysClicked}>
|
||||||
{ _t("Export E2E room keys") }
|
{ _t("Export E2E room keys") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
<AccessibleButton kind='primary' onClick={this._onImportE2eKeysClicked}>
|
<AccessibleButton kind='primary' onClick={this.onImportE2eKeysClicked}>
|
||||||
{ _t("Import E2E room keys") }
|
{ _t("Import E2E room keys") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
|
@ -231,7 +242,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
noSendUnverifiedSetting = <SettingsFlag
|
noSendUnverifiedSetting = <SettingsFlag
|
||||||
name='blacklistUnverifiedDevices'
|
name='blacklistUnverifiedDevices'
|
||||||
level={SettingLevel.DEVICE}
|
level={SettingLevel.DEVICE}
|
||||||
onChange={this._updateBlacklistDevicesFlag}
|
onChange={this.updateBlacklistDevicesFlag}
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +265,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderIgnoredUsers() {
|
private renderIgnoredUsers(): JSX.Element {
|
||||||
const { waitingUnignored, ignoredUserIds } = this.state;
|
const { waitingUnignored, ignoredUserIds } = this.state;
|
||||||
|
|
||||||
const userIds = !ignoredUserIds?.length
|
const userIds = !ignoredUserIds?.length
|
||||||
|
@ -263,7 +274,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
return (
|
return (
|
||||||
<IgnoredUser
|
<IgnoredUser
|
||||||
userId={u}
|
userId={u}
|
||||||
onUnignored={this._onUserUnignored}
|
onUnignored={this.onUserUnignored}
|
||||||
key={u}
|
key={u}
|
||||||
inProgress={waitingUnignored.includes(u)}
|
inProgress={waitingUnignored.includes(u)}
|
||||||
/>
|
/>
|
||||||
|
@ -280,15 +291,14 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
_renderManageInvites() {
|
private renderManageInvites(): JSX.Element {
|
||||||
if (this.state.invitedRoomAmt === 0) {
|
if (this.state.invitedRoomAmt === 0) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const invitedRooms = this._getInvitedRooms();
|
const invitedRooms = this.getInvitedRooms();
|
||||||
const InlineSpinner = sdk.getComponent('elements.InlineSpinner');
|
const onClickAccept = this.onAcceptAllInvitesClicked.bind(this, invitedRooms);
|
||||||
const onClickAccept = this._onAcceptAllInvitesClicked.bind(this, invitedRooms);
|
const onClickReject = this.onRejectAllInvitesClicked.bind(this, invitedRooms);
|
||||||
const onClickReject = this._onRejectAllInvitesClicked.bind(this, invitedRooms);
|
|
||||||
return (
|
return (
|
||||||
<div className='mx_SettingsTab_section mx_SecurityUserSettingsTab_bulkOptions'>
|
<div className='mx_SettingsTab_section mx_SecurityUserSettingsTab_bulkOptions'>
|
||||||
<span className='mx_SettingsTab_subheading'>{ _t('Bulk options') }</span>
|
<span className='mx_SettingsTab_subheading'>{ _t('Bulk options') }</span>
|
||||||
|
@ -303,11 +313,8 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
public render(): JSX.Element {
|
||||||
const brand = SdkConfig.get().brand;
|
const brand = SdkConfig.get().brand;
|
||||||
const DevicesPanel = sdk.getComponent('views.settings.DevicesPanel');
|
|
||||||
const SettingsFlag = sdk.getComponent('views.elements.SettingsFlag');
|
|
||||||
const EventIndexPanel = sdk.getComponent('views.settings.EventIndexPanel');
|
|
||||||
|
|
||||||
const secureBackup = (
|
const secureBackup = (
|
||||||
<div className='mx_SettingsTab_section'>
|
<div className='mx_SettingsTab_section'>
|
||||||
|
@ -329,7 +336,6 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
// it's useful to have for testing the feature. If there's no interest
|
// it's useful to have for testing the feature. If there's no interest
|
||||||
// in having advanced details here once all flows are implemented, we
|
// in having advanced details here once all flows are implemented, we
|
||||||
// can remove this.
|
// can remove this.
|
||||||
const CrossSigningPanel = sdk.getComponent('views.settings.CrossSigningPanel');
|
|
||||||
const crossSigning = (
|
const crossSigning = (
|
||||||
<div className='mx_SettingsTab_section'>
|
<div className='mx_SettingsTab_section'>
|
||||||
<span className="mx_SettingsTab_subheading">{ _t("Cross-signing") }</span>
|
<span className="mx_SettingsTab_subheading">{ _t("Cross-signing") }</span>
|
||||||
|
@ -365,16 +371,15 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
{ _t("Learn more about how we use analytics.") }
|
{ _t("Learn more about how we use analytics.") }
|
||||||
</AccessibleButton>
|
</AccessibleButton>
|
||||||
</div>
|
</div>
|
||||||
<SettingsFlag name="analyticsOptIn" level={SettingLevel.DEVICE} onChange={this._updateAnalytics} />
|
<SettingsFlag name="analyticsOptIn" level={SettingLevel.DEVICE} onChange={this.updateAnalytics} />
|
||||||
</div>
|
</div>
|
||||||
</React.Fragment>;
|
</React.Fragment>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const E2eAdvancedPanel = sdk.getComponent('views.settings.E2eAdvancedPanel');
|
|
||||||
let advancedSection;
|
let advancedSection;
|
||||||
if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
|
if (SettingsStore.getValue(UIFeature.AdvancedSettings)) {
|
||||||
const ignoreUsersPanel = this._renderIgnoredUsers();
|
const ignoreUsersPanel = this.renderIgnoredUsers();
|
||||||
const invitesPanel = this._renderManageInvites();
|
const invitesPanel = this.renderManageInvites();
|
||||||
const e2ePanel = isE2eAdvancedPanelPossible() ? <E2eAdvancedPanel /> : null;
|
const e2ePanel = isE2eAdvancedPanelPossible() ? <E2eAdvancedPanel /> : null;
|
||||||
// only show the section if there's something to show
|
// only show the section if there's something to show
|
||||||
if (ignoreUsersPanel || invitesPanel || e2ePanel) {
|
if (ignoreUsersPanel || invitesPanel || e2ePanel) {
|
||||||
|
@ -399,7 +404,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
"Manage the names of and sign out of your sessions below or " +
|
"Manage the names of and sign out of your sessions below or " +
|
||||||
"<a>verify them in your User Profile</a>.", {},
|
"<a>verify them in your User Profile</a>.", {},
|
||||||
{
|
{
|
||||||
a: sub => <AccessibleButton kind="link" onClick={this._onGoToUserProfileClick}>
|
a: sub => <AccessibleButton kind="link" onClick={this.onGoToUserProfileClick}>
|
||||||
{ sub }
|
{ sub }
|
||||||
</AccessibleButton>,
|
</AccessibleButton>,
|
||||||
},
|
},
|
||||||
|
@ -415,7 +420,7 @@ export default class SecurityUserSettingsTab extends React.Component {
|
||||||
{ secureBackup }
|
{ secureBackup }
|
||||||
{ eventIndex }
|
{ eventIndex }
|
||||||
{ crossSigning }
|
{ crossSigning }
|
||||||
{ this._renderCurrentDeviceInfo() }
|
{ this.renderCurrentDeviceInfo() }
|
||||||
</div>
|
</div>
|
||||||
{ privacySection }
|
{ privacySection }
|
||||||
{ advancedSection }
|
{ advancedSection }
|
Loading…
Reference in New Issue