[CONFLICT CHUNKS] Merge branch 'develop' into travis/sourcemaps-develop
This commit is contained in:
78
src/components/views/settings/AvatarSetting.js
Normal file
78
src/components/views/settings/AvatarSetting.js
Normal file
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React, {useCallback} from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import sdk from "../../../index";
|
||||
import {_t} from "../../../languageHandler";
|
||||
import Modal from "../../../Modal";
|
||||
|
||||
const AvatarSetting = ({avatarUrl, avatarAltText, avatarName, uploadAvatar, removeAvatar}) => {
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
|
||||
const openImageView = useCallback(() => {
|
||||
const ImageView = sdk.getComponent("elements.ImageView");
|
||||
Modal.createDialog(ImageView, {
|
||||
src: avatarUrl,
|
||||
name: avatarName,
|
||||
}, "mx_Dialog_lightbox");
|
||||
}, [avatarUrl, avatarName]);
|
||||
|
||||
let avatarElement = <div className="mx_AvatarSetting_avatarPlaceholder" />;
|
||||
if (avatarUrl) {
|
||||
avatarElement = (
|
||||
<AccessibleButton
|
||||
element="img"
|
||||
src={avatarUrl}
|
||||
alt={avatarAltText}
|
||||
aria-label={avatarAltText}
|
||||
onClick={openImageView} />
|
||||
);
|
||||
}
|
||||
|
||||
let uploadAvatarBtn;
|
||||
if (uploadAvatar) {
|
||||
// insert an empty div to be the host for a css mask containing the upload.svg
|
||||
uploadAvatarBtn = <AccessibleButton onClick={uploadAvatar} kind="primary">
|
||||
<div> </div>
|
||||
{_t("Upload")}
|
||||
</AccessibleButton>;
|
||||
}
|
||||
|
||||
let removeAvatarBtn;
|
||||
if (avatarUrl && removeAvatar) {
|
||||
removeAvatarBtn = <AccessibleButton onClick={removeAvatar} kind="link_sm">
|
||||
{_t("Remove")}
|
||||
</AccessibleButton>;
|
||||
}
|
||||
|
||||
return <div className="mx_AvatarSetting_avatar">
|
||||
{ avatarElement }
|
||||
{ uploadAvatarBtn }
|
||||
{ removeAvatarBtn }
|
||||
</div>;
|
||||
};
|
||||
|
||||
AvatarSetting.propTypes = {
|
||||
avatarUrl: PropTypes.string,
|
||||
avatarName: PropTypes.string.isRequired, // name of user/room the avatar belongs to
|
||||
uploadAvatar: PropTypes.func,
|
||||
removeAvatar: PropTypes.func,
|
||||
avatarAltText: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default AvatarSetting;
|
||||
@@ -25,8 +25,8 @@ import { _t } from '../../../languageHandler';
|
||||
import Modal from '../../../Modal';
|
||||
|
||||
export default class DevicesPanel extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this.state = {
|
||||
devices: undefined,
|
||||
|
||||
@@ -23,8 +23,8 @@ import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||
import {formatDate} from '../../../DateUtils';
|
||||
|
||||
export default class DevicesPanelEntry extends React.Component {
|
||||
constructor(props, context) {
|
||||
super(props, context);
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
this._unmounted = false;
|
||||
this.onDeviceToggled = this.onDeviceToggled.bind(this);
|
||||
|
||||
@@ -20,6 +20,7 @@ import PropTypes from 'prop-types';
|
||||
import * as sdk from '../../../index';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import dis from '../../../dispatcher';
|
||||
import {Key} from "../../../Keyboard";
|
||||
|
||||
export default class IntegrationManager extends React.Component {
|
||||
static propTypes = {
|
||||
@@ -52,7 +53,7 @@ export default class IntegrationManager extends React.Component {
|
||||
}
|
||||
|
||||
onKeyDown = (ev) => {
|
||||
if (ev.keyCode === 27) { // escape
|
||||
if (ev.key === Key.ESCAPE) {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
this.props.onFinished();
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/*
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019, 2020 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -21,8 +21,12 @@ import * as sdk from '../../../index';
|
||||
import {MatrixClientPeg} from '../../../MatrixClientPeg';
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Modal from '../../../Modal';
|
||||
<<<<<<< HEAD
|
||||
import SettingsStore from '../../../../src/settings/SettingsStore';
|
||||
import { accessSecretStorage } from '../../../CrossSigningManager';
|
||||
=======
|
||||
import SettingsStore from '../../../settings/SettingsStore';
|
||||
>>>>>>> develop
|
||||
|
||||
export default class KeyBackupPanel extends React.PureComponent {
|
||||
constructor(props) {
|
||||
@@ -128,36 +132,24 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||
Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
|
||||
import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'),
|
||||
{
|
||||
secureSecretStorage: false,
|
||||
onFinished: () => {
|
||||
this._loadBackupStatus();
|
||||
},
|
||||
},
|
||||
}, null, /* priority = */ false, /* static = */ true,
|
||||
);
|
||||
}
|
||||
|
||||
_startNewBackupWithSecureSecretStorage = async () => {
|
||||
const cli = MatrixClientPeg.get();
|
||||
let info;
|
||||
try {
|
||||
await accessSecretStorage(async () => {
|
||||
info = await cli.prepareKeyBackupVersion(
|
||||
null /* random key */,
|
||||
{ secureSecretStorage: true },
|
||||
);
|
||||
info = await cli.createKeyBackupVersion(info);
|
||||
});
|
||||
await MatrixClientPeg.get().scheduleAllGroupSessionsForBackup();
|
||||
this._loadBackupStatus();
|
||||
} catch (e) {
|
||||
console.error("Error creating key backup", e);
|
||||
// TODO: If creating a version succeeds, but backup fails, should we
|
||||
// delete the version, disable backup, or do nothing? If we just
|
||||
// disable without deleting, we'll enable on next app reload since
|
||||
// it is trusted.
|
||||
if (info && info.version) {
|
||||
MatrixClientPeg.get().deleteKeyBackupVersion(info.version);
|
||||
}
|
||||
}
|
||||
Modal.createTrackedDialogAsync('Key Backup', 'Key Backup',
|
||||
import('../../../async-components/views/dialogs/keybackup/CreateKeyBackupDialog'),
|
||||
{
|
||||
secureSecretStorage: true,
|
||||
onFinished: () => {
|
||||
this._loadBackupStatus();
|
||||
},
|
||||
}, null, /* priority = */ false, /* static = */ true,
|
||||
);
|
||||
}
|
||||
|
||||
_deleteBackup = () => {
|
||||
@@ -181,22 +173,11 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||
}
|
||||
|
||||
_restoreBackup = async () => {
|
||||
// Use legacy path if backup key not stored in secret storage
|
||||
if (!this.state.backupKeyStored) {
|
||||
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
||||
Modal.createTrackedDialog('Restore Backup', '', RestoreKeyBackupDialog);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await accessSecretStorage(async () => {
|
||||
await MatrixClientPeg.get().restoreKeyBackupWithSecretStorage(
|
||||
this.state.backupInfo,
|
||||
);
|
||||
});
|
||||
} catch (e) {
|
||||
console.log("Error restoring backup", e);
|
||||
}
|
||||
const RestoreKeyBackupDialog = sdk.getComponent('dialogs.keybackup.RestoreKeyBackupDialog');
|
||||
Modal.createTrackedDialog(
|
||||
'Restore Backup', '', RestoreKeyBackupDialog, null, null,
|
||||
/* priority = */ false, /* static = */ true,
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
@@ -270,7 +251,7 @@ export default class KeyBackupPanel extends React.PureComponent {
|
||||
{sub}
|
||||
</span>;
|
||||
const verify = sub =>
|
||||
<span className={sig.device && sig.device.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
|
||||
<span className={sig.device && sig.deviceTrust.isVerified() ? 'mx_KeyBackupPanel_deviceVerified' : 'mx_KeyBackupPanel_deviceNotVerified'}>
|
||||
{sub}
|
||||
</span>;
|
||||
const device = sub => <span className="mx_KeyBackupPanel_deviceName">{deviceName}</span>;
|
||||
|
||||
@@ -18,10 +18,9 @@ import React, {createRef} from 'react';
|
||||
import {_t} from "../../../languageHandler";
|
||||
import {MatrixClientPeg} from "../../../MatrixClientPeg";
|
||||
import Field from "../elements/Field";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import classNames from 'classnames';
|
||||
import {User} from "matrix-js-sdk";
|
||||
import { getHostingLink } from '../../../utils/HostingLink';
|
||||
import sdk from "../../../index";
|
||||
|
||||
export default class ProfileSettings extends React.Component {
|
||||
constructor() {
|
||||
@@ -52,13 +51,20 @@ export default class ProfileSettings extends React.Component {
|
||||
this._avatarUpload = createRef();
|
||||
}
|
||||
|
||||
_uploadAvatar = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
_uploadAvatar = () => {
|
||||
this._avatarUpload.current.click();
|
||||
};
|
||||
|
||||
_removeAvatar = () => {
|
||||
// clear file upload field so same file can be selected
|
||||
this._avatarUpload.current.value = "";
|
||||
this.setState({
|
||||
avatarUrl: undefined,
|
||||
avatarFile: undefined,
|
||||
enableProfileSave: true,
|
||||
});
|
||||
};
|
||||
|
||||
_saveProfile = async (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
@@ -82,6 +88,8 @@ export default class ProfileSettings extends React.Component {
|
||||
newState.avatarUrl = client.mxcUrlToHttp(uri, 96, 96, 'crop', false);
|
||||
newState.originalAvatarUrl = newState.avatarUrl;
|
||||
newState.avatarFile = null;
|
||||
} else if (this.state.originalAvatarUrl !== this.state.avatarUrl) {
|
||||
await client.setAvatarUrl(""); // use empty string as Synapse 500s on undefined
|
||||
}
|
||||
|
||||
this.setState(newState);
|
||||
@@ -117,29 +125,6 @@ export default class ProfileSettings extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
// TODO: Why is rendering a box with an overlay so complicated? Can the DOM be reduced?
|
||||
|
||||
let showOverlayAnyways = true;
|
||||
let avatarElement = <div className="mx_ProfileSettings_avatarPlaceholder" />;
|
||||
if (this.state.avatarUrl) {
|
||||
showOverlayAnyways = false;
|
||||
avatarElement = <img src={this.state.avatarUrl}
|
||||
alt={_t("Profile picture")} />;
|
||||
}
|
||||
|
||||
const avatarOverlayClasses = classNames({
|
||||
"mx_ProfileSettings_avatarOverlay": true,
|
||||
"mx_ProfileSettings_avatarOverlay_show": showOverlayAnyways,
|
||||
});
|
||||
const avatarHoverElement = (
|
||||
<div className={avatarOverlayClasses} onClick={this._uploadAvatar}>
|
||||
<span className="mx_ProfileSettings_avatarOverlayText">{_t("Upload profile picture")}</span>
|
||||
<div className="mx_ProfileSettings_avatarOverlayImgContainer">
|
||||
<div className="mx_ProfileSettings_avatarOverlayImg" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
const hostingSignupLink = getHostingLink('user-settings');
|
||||
let hostingSignup = null;
|
||||
if (hostingSignupLink) {
|
||||
@@ -156,6 +141,8 @@ export default class ProfileSettings extends React.Component {
|
||||
</span>;
|
||||
}
|
||||
|
||||
const AccessibleButton = sdk.getComponent('elements.AccessibleButton');
|
||||
const AvatarSetting = sdk.getComponent('settings.AvatarSetting');
|
||||
return (
|
||||
<form onSubmit={this._saveProfile} autoComplete="off" noValidate={true}>
|
||||
<input type="file" ref={this._avatarUpload} className="mx_ProfileSettings_avatarUpload"
|
||||
@@ -170,10 +157,12 @@ export default class ProfileSettings extends React.Component {
|
||||
type="text" value={this.state.displayName} autoComplete="off"
|
||||
onChange={this._onDisplayNameChanged} />
|
||||
</div>
|
||||
<div className="mx_ProfileSettings_avatar">
|
||||
{avatarElement}
|
||||
{avatarHoverElement}
|
||||
</div>
|
||||
<AvatarSetting
|
||||
avatarUrl={this.state.avatarUrl}
|
||||
avatarName={this.state.displayName || this.state.userId}
|
||||
avatarAltText={_t("Profile picture")}
|
||||
uploadAvatar={this._uploadAvatar}
|
||||
removeAvatar={this._removeAvatar} />
|
||||
</div>
|
||||
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
||||
disabled={!this.state.enableProfileSave}>
|
||||
|
||||
166
src/components/views/settings/tabs/room/BridgeSettingsTab.js
Normal file
166
src/components/views/settings/tabs/room/BridgeSettingsTab.js
Normal file
@@ -0,0 +1,166 @@
|
||||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {_t} from "../../../../../languageHandler";
|
||||
import MatrixClientPeg from "../../../../../MatrixClientPeg";
|
||||
import Pill from "../../../elements/Pill";
|
||||
import {makeUserPermalink} from "../../../../../utils/permalinks/Permalinks";
|
||||
import BaseAvatar from "../../../avatars/BaseAvatar";
|
||||
import { ContentRepo } from "matrix-js-sdk";
|
||||
|
||||
const BRIDGE_EVENT_TYPES = [
|
||||
"uk.half-shot.bridge",
|
||||
// m.bridge
|
||||
];
|
||||
|
||||
export default class BridgeSettingsTab extends React.Component {
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
_renderBridgeCard(event, room) {
|
||||
const content = event.getContent();
|
||||
if (!content || !content.channel || !content.protocol) {
|
||||
return null;
|
||||
}
|
||||
const { channel, network } = content;
|
||||
const protocolName = content.protocol.displayname || content.protocol.id;
|
||||
const channelName = channel.displayname || channel.id;
|
||||
const networkName = network ? network.displayname || network.id : protocolName;
|
||||
|
||||
let creator = null;
|
||||
if (content.creator) {
|
||||
creator = <p> { _t("This bridge was provisioned by <user />", {}, {
|
||||
user: <Pill
|
||||
type={Pill.TYPE_USER_MENTION}
|
||||
room={room}
|
||||
url={makeUserPermalink(content.creator)}
|
||||
shouldShowPillAvatar={true}
|
||||
/>,
|
||||
})}</p>;
|
||||
}
|
||||
|
||||
const bot = (<p> {_t("This bridge is managed by <user />.", {}, {
|
||||
user: <Pill
|
||||
type={Pill.TYPE_USER_MENTION}
|
||||
room={room}
|
||||
url={makeUserPermalink(event.getSender())}
|
||||
shouldShowPillAvatar={true}
|
||||
/>,
|
||||
})} </p>);
|
||||
let channelLink = channelName;
|
||||
if (channel.external_url) {
|
||||
channelLink = <a target="_blank" href={channel.external_url} rel="noopener">{channelName}</a>;
|
||||
}
|
||||
|
||||
let networkLink = networkName;
|
||||
if (network && network.external_url) {
|
||||
networkLink = <a target="_blank" href={network.external_url} rel="noopener">{networkName}</a>;
|
||||
}
|
||||
|
||||
const chanAndNetworkInfo = (
|
||||
_t("Bridged into <channelLink /> <networkLink />, on <protocolName />", {}, {
|
||||
channelLink,
|
||||
networkLink,
|
||||
protocolName,
|
||||
})
|
||||
);
|
||||
|
||||
let networkIcon = null;
|
||||
if (networkName && network.avatar) {
|
||||
const avatarUrl = ContentRepo.getHttpUriForMxc(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
network.avatar, 32, 32, "crop",
|
||||
);
|
||||
networkIcon = <BaseAvatar
|
||||
width={32}
|
||||
height={32}
|
||||
resizeMethod='crop'
|
||||
name={ networkName }
|
||||
idName={ networkName }
|
||||
url={ avatarUrl }
|
||||
/>;
|
||||
}
|
||||
|
||||
let channelIcon = null;
|
||||
if (channel.avatar) {
|
||||
const avatarUrl = ContentRepo.getHttpUriForMxc(
|
||||
MatrixClientPeg.get().getHomeserverUrl(),
|
||||
channel.avatar, 32, 32, "crop",
|
||||
);
|
||||
channelIcon = <BaseAvatar
|
||||
width={32}
|
||||
height={32}
|
||||
resizeMethod='crop'
|
||||
name={ networkName }
|
||||
idName={ networkName }
|
||||
url={ avatarUrl }
|
||||
/>;
|
||||
}
|
||||
|
||||
const heading = _t("Connected to <channelIcon /> <channelName /> on <networkIcon /> <networkName />", { }, {
|
||||
channelIcon,
|
||||
channelName,
|
||||
networkName,
|
||||
networkIcon,
|
||||
});
|
||||
|
||||
return (<li key={event.stateKey}>
|
||||
<div>
|
||||
<h3>{heading}</h3>
|
||||
<p>{_t("Connected via %(protocolName)s", { protocolName })}</p>
|
||||
<details>
|
||||
{creator}
|
||||
{bot}
|
||||
<p>{chanAndNetworkInfo}</p>
|
||||
</details>
|
||||
</div>
|
||||
</li>);
|
||||
}
|
||||
|
||||
static getBridgeStateEvents(roomId) {
|
||||
const client = MatrixClientPeg.get();
|
||||
const roomState = (client.getRoom(roomId)).currentState;
|
||||
|
||||
const bridgeEvents = Array.concat(...BRIDGE_EVENT_TYPES.map((typeName) =>
|
||||
Object.values(roomState.events[typeName] || {}),
|
||||
));
|
||||
|
||||
return bridgeEvents;
|
||||
}
|
||||
|
||||
render() {
|
||||
// This settings tab will only be invoked if the following function returns more
|
||||
// than 0 events, so no validation is needed at this stage.
|
||||
const bridgeEvents = BridgeSettingsTab.getBridgeStateEvents(this.props.roomId);
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{_t("Bridge Info")}</div>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
<p>{ _t("Below is a list of bridges connected to this room.") }</p>
|
||||
<ul className="mx_RoomSettingsDialog_BridgeList">
|
||||
{ bridgeEvents.map((event) => this._renderBridgeCard(event, room)) }
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -18,22 +18,24 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import {_t} from "../../../../../languageHandler";
|
||||
import RoomProfileSettings from "../../../room_settings/RoomProfileSettings";
|
||||
<<<<<<< HEAD
|
||||
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
||||
import * as sdk from "../../../../..";
|
||||
=======
|
||||
import sdk from "../../../../..";
|
||||
>>>>>>> develop
|
||||
import AccessibleButton from "../../../elements/AccessibleButton";
|
||||
import {MatrixClient} from "matrix-js-sdk";
|
||||
import dis from "../../../../../dispatcher";
|
||||
import LabelledToggleSwitch from "../../../elements/LabelledToggleSwitch";
|
||||
import MatrixClientContext from "../../../../../contexts/MatrixClientContext";
|
||||
|
||||
export default class GeneralRoomSettingsTab extends React.Component {
|
||||
static childContextTypes = {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
static contextType = MatrixClientContext;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -42,14 +44,8 @@ export default class GeneralRoomSettingsTab extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
};
|
||||
}
|
||||
|
||||
componentWillMount() {
|
||||
MatrixClientPeg.get().getRoomDirectoryVisibility(this.props.roomId).then((result => {
|
||||
this.context.getRoomDirectoryVisibility(this.props.roomId).then((result => {
|
||||
this.setState({isRoomPublished: result.visibility === 'public'});
|
||||
}));
|
||||
}
|
||||
@@ -59,7 +55,7 @@ export default class GeneralRoomSettingsTab extends React.Component {
|
||||
const newValue = !valueBefore;
|
||||
this.setState({isRoomPublished: newValue});
|
||||
|
||||
MatrixClientPeg.get().setRoomDirectoryVisibility(
|
||||
this.context.setRoomDirectoryVisibility(
|
||||
this.props.roomId,
|
||||
newValue ? 'public' : 'private',
|
||||
).catch(() => {
|
||||
@@ -80,7 +76,7 @@ export default class GeneralRoomSettingsTab extends React.Component {
|
||||
const RelatedGroupSettings = sdk.getComponent("room_settings.RelatedGroupSettings");
|
||||
const UrlPreviewSettings = sdk.getComponent("room_settings.UrlPreviewSettings");
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
const client = this.context;
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
|
||||
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
|
||||
|
||||
@@ -17,25 +17,14 @@ limitations under the License.
|
||||
import React from 'react';
|
||||
import {_t} from "../../../../../languageHandler";
|
||||
import GroupUserSettings from "../../../groups/GroupUserSettings";
|
||||
<<<<<<< HEAD
|
||||
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
||||
import PropTypes from "prop-types";
|
||||
import {MatrixClient} from "matrix-js-sdk";
|
||||
=======
|
||||
>>>>>>> develop
|
||||
|
||||
export default class FlairUserSettingsTab extends React.Component {
|
||||
static childContextTypes = {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="mx_SettingsTab">
|
||||
|
||||
@@ -26,7 +26,6 @@ import PlatformPeg from "../../../../../PlatformPeg";
|
||||
|
||||
export default class PreferencesUserSettingsTab extends React.Component {
|
||||
static COMPOSER_SETTINGS = [
|
||||
'useCiderComposer',
|
||||
'MessageComposerInput.autoReplaceEmoji',
|
||||
'MessageComposerInput.suggestEmoji',
|
||||
'sendTypingNotifications',
|
||||
|
||||
@@ -37,12 +37,13 @@ export class IgnoredUser extends React.Component {
|
||||
};
|
||||
|
||||
render() {
|
||||
const id = `mx_SecurityUserSettingsTab_ignoredUser_${this.props.userId}`;
|
||||
return (
|
||||
<div className='mx_SecurityUserSettingsTab_ignoredUser'>
|
||||
<AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm'>
|
||||
{_t('Unignore')}
|
||||
<AccessibleButton onClick={this._onUnignoreClicked} kind='primary_sm' aria-describedby={id}>
|
||||
{ _t('Unignore') }
|
||||
</AccessibleButton>
|
||||
<span>{this.props.userId}</span>
|
||||
<span id={id}>{ this.props.userId }</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user