You've already forked matrix-react-sdk
mirror of
https://github.com/matrix-org/matrix-react-sdk.git
synced 2025-11-22 04:02:40 +03:00
Merge branch 'experimental' into bwindels/redesign-smallfixes
This commit is contained in:
@@ -1054,6 +1054,7 @@ export default React.createClass({
|
||||
modal.close();
|
||||
if (this.state.currentRoomId === roomId) {
|
||||
dis.dispatch({action: 'view_next_room'});
|
||||
dis.dispatch({action: 'close_room_settings'});
|
||||
}
|
||||
}, (err) => {
|
||||
modal.close();
|
||||
|
||||
@@ -20,6 +20,7 @@ import {Tab, TabbedView} from "../../structures/TabbedView";
|
||||
import {_t, _td} from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import dis from '../../../dispatcher';
|
||||
import GeneralRoomSettingsTab from "../settings/tabs/GeneralRoomSettingsTab";
|
||||
|
||||
// TODO: Ditch this whole component
|
||||
export class TempTab extends React.Component {
|
||||
@@ -37,18 +38,32 @@ export class TempTab extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default class UserSettingsDialog extends React.Component {
|
||||
export default class RoomSettingsDialog extends React.Component {
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
onFinished: PropTypes.func.isRequired,
|
||||
};
|
||||
|
||||
componentWillMount(): void {
|
||||
this.dispatcherRef = dis.register(this._onAction);
|
||||
}
|
||||
|
||||
componentWillUnmount(): void {
|
||||
dis.unregister(this.dispatcherRef);
|
||||
}
|
||||
|
||||
_onAction = (payload) => {
|
||||
if (payload.action !== 'close_room_settings') return;
|
||||
this.props.onFinished();
|
||||
};
|
||||
|
||||
_getTabs() {
|
||||
const tabs = [];
|
||||
|
||||
tabs.push(new Tab(
|
||||
_td("General"),
|
||||
"mx_RoomSettingsDialog_settingsIcon",
|
||||
<div>General Test</div>,
|
||||
<GeneralRoomSettingsTab roomId={this.props.roomId} />,
|
||||
));
|
||||
tabs.push(new Tab(
|
||||
_td("Security & Privacy"),
|
||||
|
||||
@@ -19,7 +19,7 @@ import PropTypes from 'prop-types';
|
||||
import {Tab, TabbedView} from "../../structures/TabbedView";
|
||||
import {_t, _td} from "../../../languageHandler";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import GeneralSettingsTab from "../settings/tabs/GeneralSettingsTab";
|
||||
import GeneralUserSettingsTab from "../settings/tabs/GeneralUserSettingsTab";
|
||||
import dis from '../../../dispatcher';
|
||||
import SettingsStore from "../../../settings/SettingsStore";
|
||||
import LabsSettingsTab from "../settings/tabs/LabsSettingsTab";
|
||||
@@ -57,7 +57,7 @@ export default class UserSettingsDialog extends React.Component {
|
||||
tabs.push(new Tab(
|
||||
_td("General"),
|
||||
"mx_UserSettingsDialog_settingsIcon",
|
||||
<GeneralSettingsTab />,
|
||||
<GeneralUserSettingsTab />,
|
||||
));
|
||||
tabs.push(new Tab(
|
||||
_td("Flair"),
|
||||
|
||||
@@ -76,6 +76,7 @@ const EditableItem = React.createClass({
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Make this use the new Field element
|
||||
module.exports = React.createClass({
|
||||
displayName: 'EditableItemList',
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ const ObjectUtils = require("../../../ObjectUtils");
|
||||
const MatrixClientPeg = require('../../../MatrixClientPeg');
|
||||
const sdk = require("../../../index");
|
||||
import { _t } from '../../../languageHandler';
|
||||
import Field from "../elements/Field";
|
||||
const Modal = require("../../../Modal");
|
||||
|
||||
module.exports = React.createClass({
|
||||
@@ -222,7 +223,8 @@ module.exports = React.createClass({
|
||||
let found = false;
|
||||
const canonicalValue = this.state.canonicalAlias || "";
|
||||
canonical_alias_section = (
|
||||
<select onChange={this.onCanonicalAliasChange} value={canonicalValue}>
|
||||
<Field onChange={this.onCanonicalAliasChange} value={canonicalValue}
|
||||
element='select' id='canonicalAlias' label={_t('Main address')}>
|
||||
<option value="" key="unset">{ _t('not specified') }</option>
|
||||
{
|
||||
Object.keys(self.state.domainToAliases).map((domain, i) => {
|
||||
@@ -242,7 +244,7 @@ module.exports = React.createClass({
|
||||
{ this.state.canonicalAlias }
|
||||
</option>
|
||||
}
|
||||
</select>
|
||||
</Field>
|
||||
);
|
||||
} else {
|
||||
canonical_alias_section = (
|
||||
@@ -277,11 +279,8 @@ module.exports = React.createClass({
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
<h3>{ _t('Addresses') }</h3>
|
||||
<div className="mx_RoomSettings_aliasLabel">
|
||||
{ _t('The main address for this room is') }: { canonical_alias_section }
|
||||
</div>
|
||||
<div className='mx_AliasSettings'>
|
||||
{canonical_alias_section}
|
||||
<EditableItemList
|
||||
className={"mx_RoomSettings_localAliases"}
|
||||
items={this.state.domainToAliases[localDomain] || []}
|
||||
|
||||
@@ -119,7 +119,6 @@ module.exports = React.createClass({
|
||||
const localDomain = this.context.matrixClient.getDomain();
|
||||
const EditableItemList = sdk.getComponent('elements.EditableItemList');
|
||||
return <div>
|
||||
<h3>{ _t('Flair') }</h3>
|
||||
<EditableItemList
|
||||
items={this.state.newGroupsList}
|
||||
className={"mx_RelatedGroupSettings"}
|
||||
|
||||
199
src/components/views/room_settings/RoomProfileSettings.js
Normal file
199
src/components/views/room_settings/RoomProfileSettings.js
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
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 Field from "../elements/Field";
|
||||
import AccessibleButton from "../elements/AccessibleButton";
|
||||
import classNames from 'classnames';
|
||||
|
||||
// TODO: Merge with ProfileSettings?
|
||||
export default class RoomProfileSettings extends React.Component {
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(props.roomId);
|
||||
if (!room) throw new Error("Expected a room for ID: ", props.roomId);
|
||||
const avatarEvent = room.currentState.getStateEvents("m.room.avatar", "");
|
||||
let avatarUrl = avatarEvent && avatarEvent.getContent() ? avatarEvent.getContent()["url"] : null;
|
||||
if (avatarUrl) avatarUrl = client.mxcUrlToHttp(avatarUrl, 96, 96, 'crop', false);
|
||||
const topicEvent = room.currentState.getStateEvents("m.room.topic", "");
|
||||
const topic = topicEvent && topicEvent.getContent() ? topicEvent.getContent()['topic'] : '';
|
||||
this.state = {
|
||||
originalDisplayName: room.name,
|
||||
displayName: room.name,
|
||||
originalAvatarUrl: avatarUrl,
|
||||
avatarUrl: avatarUrl,
|
||||
avatarFile: null,
|
||||
originalTopic: topic,
|
||||
topic: topic,
|
||||
enableProfileSave: false,
|
||||
canSetName: room.currentState.maySendStateEvent('m.room.name', client.getUserId()),
|
||||
canSetTopic: room.currentState.maySendStateEvent('m.room.topic', client.getUserId()),
|
||||
canSetAvatar: room.currentState.maySendStateEvent('m.room.avatar', client.getUserId()),
|
||||
};
|
||||
}
|
||||
|
||||
_uploadAvatar = (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
this.refs.avatarUpload.click();
|
||||
};
|
||||
|
||||
_saveProfile = async (e) => {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
if (!this.state.enableProfileSave) return;
|
||||
this.setState({enableProfileSave: false});
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
const newState = {};
|
||||
|
||||
// TODO: What do we do about errors?
|
||||
|
||||
if (this.state.originalDisplayName !== this.state.displayName) {
|
||||
await client.setRoomName(this.props.roomId, this.state.displayName);
|
||||
newState.originalDisplayName = this.state.displayName;
|
||||
}
|
||||
|
||||
if (this.state.avatarFile) {
|
||||
const uri = await client.uploadContent(this.state.avatarFile);
|
||||
await client.sendStateEvent(this.props.roomId, 'm.room.avatar', {url: uri}, '');
|
||||
newState.avatarUrl = client.mxcUrlToHttp(uri, 96, 96, 'crop', false);
|
||||
newState.originalAvatarUrl = newState.avatarUrl;
|
||||
newState.avatarFile = null;
|
||||
}
|
||||
|
||||
if (this.state.originalTopic !== this.state.topic) {
|
||||
await client.setRoomTopic(this.props.roomId, this.state.topic);
|
||||
newState.originalTopic = this.state.topic;
|
||||
}
|
||||
|
||||
newState.enableProfileSave = true;
|
||||
this.setState(newState);
|
||||
};
|
||||
|
||||
_onDisplayNameChanged = (e) => {
|
||||
this.setState({
|
||||
displayName: e.target.value,
|
||||
enableProfileSave: true,
|
||||
});
|
||||
};
|
||||
|
||||
_onTopicChanged = (e) => {
|
||||
this.setState({
|
||||
topic: e.target.value,
|
||||
enableProfileSave: true,
|
||||
});
|
||||
};
|
||||
|
||||
_onAvatarChanged = (e) => {
|
||||
if (!e.target.files || !e.target.files.length) {
|
||||
this.setState({
|
||||
avatarUrl: this.state.originalAvatarUrl,
|
||||
avatarFile: null,
|
||||
enableProfileSave: false,
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const file = e.target.files[0];
|
||||
const reader = new FileReader();
|
||||
reader.onload = (ev) => {
|
||||
this.setState({
|
||||
avatarUrl: ev.target.result,
|
||||
avatarFile: file,
|
||||
enableProfileSave: true,
|
||||
});
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
|
||||
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("Room avatar")} />;
|
||||
}
|
||||
|
||||
const avatarOverlayClasses = classNames({
|
||||
"mx_ProfileSettings_avatarOverlay": true,
|
||||
"mx_ProfileSettings_avatarOverlay_show": showOverlayAnyways,
|
||||
});
|
||||
let avatarHoverElement = (
|
||||
<div className={avatarOverlayClasses} onClick={this._uploadAvatar}>
|
||||
<span className="mx_ProfileSettings_avatarOverlayText">{_t("Upload room avatar")}</span>
|
||||
<div className="mx_ProfileSettings_avatarOverlayImgContainer">
|
||||
<div className="mx_ProfileSettings_avatarOverlayImg" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
if (!this.state.canSetAvatar) {
|
||||
if (!showOverlayAnyways) {
|
||||
avatarHoverElement = null;
|
||||
} else {
|
||||
const disabledOverlayClasses = classNames({
|
||||
"mx_ProfileSettings_avatarOverlay": true,
|
||||
"mx_ProfileSettings_avatarOverlay_show": true,
|
||||
"mx_ProfileSettings_avatarOverlay_disabled": true,
|
||||
});
|
||||
avatarHoverElement = (
|
||||
<div className={disabledOverlayClasses}>
|
||||
<span className="mx_ProfileSettings_noAvatarText">{_t("No room avatar")}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<form onSubmit={this._saveProfile} autoComplete={false} noValidate={true}>
|
||||
<input type="file" ref="avatarUpload" className="mx_ProfileSettings_avatarUpload"
|
||||
onChange={this._onAvatarChanged} accept="image/*" />
|
||||
<div className="mx_ProfileSettings_profile">
|
||||
<div className="mx_ProfileSettings_controls">
|
||||
<Field id="profileDisplayName" label={_t("Room Name")}
|
||||
type="text" value={this.state.displayName} autoComplete="off"
|
||||
onChange={this._onDisplayNameChanged} disabled={!this.state.canSetName} />
|
||||
<Field id="profileTopic" label={_t("Room Topic")} disabled={!this.state.canSetTopic}
|
||||
type="text" value={this.state.topic} autoComplete="off"
|
||||
onChange={this._onTopicChanged} element="textarea" />
|
||||
</div>
|
||||
<div className="mx_ProfileSettings_avatar">
|
||||
{avatarElement}
|
||||
{avatarHoverElement}
|
||||
</div>
|
||||
</div>
|
||||
<AccessibleButton onClick={this._saveProfile} kind="primary"
|
||||
disabled={!this.state.enableProfileSave}>
|
||||
{_t("Save")}
|
||||
</AccessibleButton>
|
||||
</form>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
/*
|
||||
Copyright 2016 OpenMarket Ltd
|
||||
Copyright 2017 Travis Ralston
|
||||
Copyright 2018 New Vector Ltd
|
||||
Copyright 2018-2019 New Vector Ltd
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@@ -16,12 +16,13 @@ See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import {MatrixClient} from "matrix-js-sdk";
|
||||
const React = require('react');
|
||||
import PropTypes from 'prop-types';
|
||||
const sdk = require("../../../index");
|
||||
import { _t, _td } from '../../../languageHandler';
|
||||
import SettingsStore, {SettingLevel} from "../../../settings/SettingsStore";
|
||||
import dis from "../../../dispatcher";
|
||||
import MatrixClientPeg from "../../../MatrixClientPeg";
|
||||
|
||||
|
||||
module.exports = React.createClass({
|
||||
@@ -31,21 +32,16 @@ module.exports = React.createClass({
|
||||
room: PropTypes.object,
|
||||
},
|
||||
|
||||
contextTypes: {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient).isRequired,
|
||||
},
|
||||
|
||||
saveSettings: function() {
|
||||
const promises = [];
|
||||
if (this.refs.urlPreviewsRoom) promises.push(this.refs.urlPreviewsRoom.save());
|
||||
if (this.refs.urlPreviewsSelf) promises.push(this.refs.urlPreviewsSelf.save());
|
||||
return promises;
|
||||
_onClickUserSettings: (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
dis.dispatch({action: 'view_user_settings'});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
const SettingsFlag = sdk.getComponent("elements.SettingsFlag");
|
||||
const roomId = this.props.room.roomId;
|
||||
const isEncrypted = this.context.matrixClient.isRoomEncrypted(roomId);
|
||||
const isEncrypted = MatrixClientPeg.get().isRoomEncrypted(roomId);
|
||||
|
||||
let previewsForAccount = null;
|
||||
let previewsForRoom = null;
|
||||
@@ -56,13 +52,13 @@ module.exports = React.createClass({
|
||||
if (accountEnabled) {
|
||||
previewsForAccount = (
|
||||
_t("You have <a>enabled</a> URL previews by default.", {}, {
|
||||
'a': (sub)=><a href="#/settings">{ sub }</a>,
|
||||
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>,
|
||||
})
|
||||
);
|
||||
} else if (accountEnabled) {
|
||||
previewsForAccount = (
|
||||
_t("You have <a>disabled</a> URL previews by default.", {}, {
|
||||
'a': (sub)=><a href="#/settings">{ sub }</a>,
|
||||
'a': (sub)=><a onClick={this._onClickUserSettings} href=''>{ sub }</a>,
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -73,9 +69,7 @@ module.exports = React.createClass({
|
||||
<SettingsFlag name="urlPreviewsEnabled"
|
||||
level={SettingLevel.ROOM}
|
||||
roomId={roomId}
|
||||
isExplicit={true}
|
||||
manualSave={true}
|
||||
ref="urlPreviewsRoom" />
|
||||
isExplicit={true} />
|
||||
</label>
|
||||
);
|
||||
} else {
|
||||
@@ -96,20 +90,16 @@ module.exports = React.createClass({
|
||||
const previewsForRoomAccount = ( // in an e2ee room we use a special key to enforce per-room opt-in
|
||||
<SettingsFlag name={isEncrypted ? 'urlPreviewsEnabled_e2ee' : 'urlPreviewsEnabled'}
|
||||
level={SettingLevel.ROOM_ACCOUNT}
|
||||
roomId={roomId}
|
||||
manualSave={true}
|
||||
ref="urlPreviewsSelf"
|
||||
/>
|
||||
roomId={roomId} />
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx_RoomSettings_toggles">
|
||||
<h3>{ _t("URL Previews") }</h3>
|
||||
<div>
|
||||
<div>
|
||||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{ _t('When someone puts a URL in their message, a URL preview can be shown to give more ' +
|
||||
'information about that link such as the title, description, and an image from the website.') }
|
||||
</div>
|
||||
<div>
|
||||
<div className='mx_SettingsTab_subsectionText'>
|
||||
{ previewsForAccount }
|
||||
</div>
|
||||
{ previewsForRoom }
|
||||
|
||||
118
src/components/views/settings/tabs/GeneralRoomSettingsTab.js
Normal file
118
src/components/views/settings/tabs/GeneralRoomSettingsTab.js
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright 2019 New Vector Ltd
|
||||
|
||||
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 RoomProfileSettings from "../../room_settings/RoomProfileSettings";
|
||||
import MatrixClientPeg from "../../../../MatrixClientPeg";
|
||||
import sdk from "../../../../index";
|
||||
import AccessibleButton from "../../elements/AccessibleButton";
|
||||
import {MatrixClient} from "matrix-js-sdk";
|
||||
import dis from "../../../../dispatcher";
|
||||
|
||||
export default class GeneralRoomSettingsTab extends React.Component {
|
||||
static childContextTypes = {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||
};
|
||||
|
||||
static propTypes = {
|
||||
roomId: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
};
|
||||
}
|
||||
|
||||
_saveAliases = (e) => {
|
||||
// TODO: Live modification?
|
||||
if (!this.refs.aliasSettings) return;
|
||||
this.refs.aliasSettings.saveSettings();
|
||||
};
|
||||
|
||||
_saveGroups = (e) => {
|
||||
// TODO: Live modification?
|
||||
if (!this.refs.flairSettings) return;
|
||||
this.refs.flairSettings.saveSettings();
|
||||
};
|
||||
|
||||
_onLeaveClick = () => {
|
||||
dis.dispatch({
|
||||
action: 'leave_room',
|
||||
room_id: this.props.roomId,
|
||||
});
|
||||
};
|
||||
|
||||
render() {
|
||||
const AliasSettings = sdk.getComponent("room_settings.AliasSettings");
|
||||
const RelatedGroupSettings = sdk.getComponent("room_settings.RelatedGroupSettings");
|
||||
const UrlPreviewSettings = sdk.getComponent("room_settings.UrlPreviewSettings");
|
||||
|
||||
const client = MatrixClientPeg.get();
|
||||
const room = client.getRoom(this.props.roomId);
|
||||
|
||||
const canSetAliases = true; // Previously, we arbitrarily only allowed admins to do this
|
||||
const canSetCanonical = room.currentState.mayClientSendStateEvent("m.room.canonical_alias", client);
|
||||
const canonicalAliasEv = room.currentState.getStateEvents("m.room.canonical_alias", '');
|
||||
const aliasEvents = room.currentState.getStateEvents("m.room.aliases");
|
||||
|
||||
const canChangeGroups = room.currentState.mayClientSendStateEvent("m.room.related_groups", client);
|
||||
const groupsEvent = room.currentState.getStateEvents("m.room.related_groups", "");
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab mx_GeneralRoomSettingsTab">
|
||||
<div className="mx_SettingsTab_heading">{_t("General")}</div>
|
||||
<div className='mx_SettingsTab_section mx_GeneralRoomSettingsTab_profileSection'>
|
||||
<RoomProfileSettings roomId={this.props.roomId} />
|
||||
</div>
|
||||
|
||||
<span className='mx_SettingsTab_subheading'>{_t("Room Addresses")}</span>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
<AliasSettings ref="aliasSettings" roomId={this.props.roomId}
|
||||
canSetCanonicalAlias={canSetCanonical} canSetAliases={canSetAliases}
|
||||
canonicalAliasEvent={canonicalAliasEv} aliasEvents={aliasEvents} />
|
||||
<AccessibleButton onClick={this._saveAliases} kind='primary'>
|
||||
{_t("Save")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
||||
<span className='mx_SettingsTab_subheading'>{_t("Flair")}</span>
|
||||
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
||||
<RelatedGroupSettings ref="flairSettings" roomId={room.roomId}
|
||||
canSetRelatedGroups={canChangeGroups}
|
||||
relatedGroupsEvent={groupsEvent} />
|
||||
<AccessibleButton onClick={this._saveGroups} kind='primary'>
|
||||
{_t("Save")}
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
|
||||
<span className='mx_SettingsTab_subheading'>{_t("URL Previews")}</span>
|
||||
<div className='mx_SettingsTab_section'>
|
||||
<UrlPreviewSettings room={room} />
|
||||
</div>
|
||||
|
||||
<span className='mx_SettingsTab_subheading'>{_t("Leave room")}</span>
|
||||
<div className='mx_SettingsTab_section'>
|
||||
<AccessibleButton kind='danger' onClick={this._onLeaveClick}>
|
||||
{ _t('Leave room') }
|
||||
</AccessibleButton>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,11 @@ limitations under the License.
|
||||
|
||||
import React from 'react';
|
||||
import {_t} from "../../../../languageHandler";
|
||||
import MatrixClientPeg from "../../../../MatrixClientPeg";
|
||||
import GroupUserSettings from "../../groups/GroupUserSettings";
|
||||
import PropTypes from "prop-types";
|
||||
import {MatrixClient} from "matrix-js-sdk";
|
||||
import { DragDropContext } from 'react-beautiful-dnd';
|
||||
import ProfileSettings from "../ProfileSettings";
|
||||
import EmailAddresses from "../EmailAddresses";
|
||||
import PhoneNumbers from "../PhoneNumbers";
|
||||
@@ -31,7 +36,11 @@ const sdk = require('../../../../index');
|
||||
const Modal = require("../../../../Modal");
|
||||
const dis = require("../../../../dispatcher");
|
||||
|
||||
export default class GeneralSettingsTab extends React.Component {
|
||||
export default class GeneralUserSettingsTab extends React.Component {
|
||||
static childContextTypes = {
|
||||
matrixClient: PropTypes.instanceOf(MatrixClient),
|
||||
};
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
@@ -41,6 +50,12 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
};
|
||||
}
|
||||
|
||||
getChildContext() {
|
||||
return {
|
||||
matrixClient: MatrixClientPeg.get(),
|
||||
};
|
||||
}
|
||||
|
||||
_onLanguageChange = (newLanguage) => {
|
||||
if (this.state.language === newLanguage) return;
|
||||
|
||||
@@ -95,6 +110,11 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Profile")}</span>
|
||||
<ProfileSettings />
|
||||
|
||||
<span className="mx_SettingsTab_subheading">{_t("Flair")}</span>
|
||||
<DragDropContext>
|
||||
<GroupUserSettings />
|
||||
</DragDropContext>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -103,7 +123,7 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
const ChangePassword = sdk.getComponent("views.settings.ChangePassword");
|
||||
const passwordChangeForm = (
|
||||
<ChangePassword
|
||||
className="mx_GeneralSettingsTab_changePassword"
|
||||
className="mx_GeneralUserSettingsTab_changePassword"
|
||||
rowClassName=""
|
||||
buttonKind="primary"
|
||||
onError={this._onPasswordChangeError}
|
||||
@@ -111,7 +131,7 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className="mx_SettingsTab_section mx_GeneralSettingsTab_accountSection">
|
||||
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_accountSection">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Account")}</span>
|
||||
<p className="mx_SettingsTab_subsectionText">
|
||||
{_t("Set a new account password...")}
|
||||
@@ -132,7 +152,7 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
return (
|
||||
<div className="mx_SettingsTab_section">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Language and region")}</span>
|
||||
<LanguageDropdown className="mx_GeneralSettingsTab_languageInput"
|
||||
<LanguageDropdown className="mx_GeneralUserSettingsTab_languageInput"
|
||||
onOptionChange={this._onLanguageChange} value={this.state.language} />
|
||||
</div>
|
||||
);
|
||||
@@ -142,7 +162,7 @@ export default class GeneralSettingsTab extends React.Component {
|
||||
// TODO: Re-enable theme selection once the themes actually work
|
||||
const SettingsFlag = sdk.getComponent("views.elements.SettingsFlag");
|
||||
return (
|
||||
<div className="mx_SettingsTab_section mx_GeneralSettingsTab_themeSection">
|
||||
<div className="mx_SettingsTab_section mx_GeneralUserSettingsTab_themeSection">
|
||||
<span className="mx_SettingsTab_subheading">{_t("Theme")}</span>
|
||||
<Field id="theme" label={_t("Theme")} element="select" disabled={true}
|
||||
value={this.state.theme} onChange={this._onThemeChange}>
|
||||
Reference in New Issue
Block a user