2019-01-30 01:54:51 +03:00
|
|
|
/*
|
2021-04-06 14:26:50 +03:00
|
|
|
Copyright 2019-2021 The Matrix.org Foundation C.I.C.
|
2019-01-30 01:54:51 +03:00
|
|
|
|
|
|
|
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';
|
2019-02-22 20:47:18 +03:00
|
|
|
import {_t, _td} from "../../../../../languageHandler";
|
2019-12-21 00:13:46 +03:00
|
|
|
import {MatrixClientPeg} from "../../../../../MatrixClientPeg";
|
2019-12-20 04:19:56 +03:00
|
|
|
import * as sdk from "../../../../..";
|
2019-02-22 20:47:18 +03:00
|
|
|
import AccessibleButton from "../../../elements/AccessibleButton";
|
|
|
|
import Modal from "../../../../../Modal";
|
2021-03-09 06:20:07 +03:00
|
|
|
import {replaceableComponent} from "../../../../../utils/replaceableComponent";
|
2021-04-09 04:18:30 +03:00
|
|
|
import {EventType} from "matrix-js-sdk/src/@types/event";
|
2021-04-06 14:26:50 +03:00
|
|
|
import { RoomMember } from "matrix-js-sdk/src/models/room-member";
|
2021-04-27 13:42:11 +03:00
|
|
|
import { MatrixEvent } from "matrix-js-sdk/src/models/event";
|
|
|
|
import { RoomState } from "matrix-js-sdk/src/models/room-state";
|
2019-01-30 01:54:51 +03:00
|
|
|
|
|
|
|
const plEventsToLabels = {
|
|
|
|
// These will be translated for us later.
|
2021-04-09 04:18:30 +03:00
|
|
|
[EventType.RoomAvatar]: _td("Change room avatar"),
|
|
|
|
[EventType.RoomName]: _td("Change room name"),
|
|
|
|
[EventType.RoomCanonicalAlias]: _td("Change main address for the room"),
|
|
|
|
[EventType.RoomHistoryVisibility]: _td("Change history visibility"),
|
|
|
|
[EventType.RoomPowerLevels]: _td("Change permissions"),
|
|
|
|
[EventType.RoomTopic]: _td("Change topic"),
|
|
|
|
[EventType.RoomTombstone]: _td("Upgrade the room"),
|
|
|
|
[EventType.RoomEncryption]: _td("Enable room encryption"),
|
2021-04-09 04:20:08 +03:00
|
|
|
[EventType.RoomServerAcl]: _td("Change server ACLs"),
|
2019-02-07 21:31:35 +03:00
|
|
|
|
2020-08-03 18:02:26 +03:00
|
|
|
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
2019-02-07 21:31:35 +03:00
|
|
|
"im.vector.modular.widgets": _td("Modify widgets"),
|
2019-01-30 01:54:51 +03:00
|
|
|
};
|
|
|
|
|
|
|
|
const plEventsToShow = {
|
|
|
|
// If an event is listed here, it will be shown in the PL settings. Defaults will be calculated.
|
2021-04-09 04:18:30 +03:00
|
|
|
[EventType.RoomAvatar]: {isState: true},
|
|
|
|
[EventType.RoomName]: {isState: true},
|
|
|
|
[EventType.RoomCanonicalAlias]: {isState: true},
|
|
|
|
[EventType.RoomHistoryVisibility]: {isState: true},
|
|
|
|
[EventType.RoomPowerLevels]: {isState: true},
|
|
|
|
[EventType.RoomTopic]: {isState: true},
|
|
|
|
[EventType.RoomTombstone]: {isState: true},
|
|
|
|
[EventType.RoomEncryption]: {isState: true},
|
2021-04-09 04:20:08 +03:00
|
|
|
[EventType.RoomServerAcl]: {isState: true},
|
2019-01-30 01:54:51 +03:00
|
|
|
|
2020-08-03 18:02:26 +03:00
|
|
|
// TODO: Enable support for m.widget event type (https://github.com/vector-im/element-web/issues/13111)
|
2019-01-30 01:54:51 +03:00
|
|
|
"im.vector.modular.widgets": {isState: true},
|
|
|
|
};
|
|
|
|
|
|
|
|
// parse a string as an integer; if the input is undefined, or cannot be parsed
|
|
|
|
// as an integer, return a default.
|
|
|
|
function parseIntWithDefault(val, def) {
|
|
|
|
const res = parseInt(val);
|
|
|
|
return isNaN(res) ? def : res;
|
|
|
|
}
|
|
|
|
|
2021-04-06 14:26:50 +03:00
|
|
|
interface IBannedUserProps {
|
2021-04-26 16:56:43 +03:00
|
|
|
canUnban?: boolean;
|
2021-04-06 14:26:50 +03:00
|
|
|
member: RoomMember;
|
|
|
|
by: string;
|
2021-04-26 16:56:43 +03:00
|
|
|
reason?: string;
|
2021-04-06 14:26:50 +03:00
|
|
|
}
|
2019-01-30 01:54:51 +03:00
|
|
|
|
2021-04-06 14:26:50 +03:00
|
|
|
export class BannedUser extends React.Component<IBannedUserProps> {
|
2021-04-26 16:02:53 +03:00
|
|
|
private onUnbanClick = (e) => {
|
2019-10-11 14:56:48 +03:00
|
|
|
MatrixClientPeg.get().unban(this.props.member.roomId, this.props.member.userId).catch((err) => {
|
2019-01-30 01:54:51 +03:00
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
console.error("Failed to unban: " + err);
|
|
|
|
Modal.createTrackedDialog('Failed to unban', '', ErrorDialog, {
|
|
|
|
title: _t('Error'),
|
|
|
|
description: _t('Failed to unban'),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
render() {
|
|
|
|
let unbanButton;
|
|
|
|
|
|
|
|
if (this.props.canUnban) {
|
|
|
|
unbanButton = (
|
2021-04-23 20:11:54 +03:00
|
|
|
<AccessibleButton className='mx_RolesRoomSettingsTab_unbanBtn'
|
|
|
|
kind='danger_sm'
|
2021-04-26 16:02:53 +03:00
|
|
|
onClick={this.onUnbanClick}
|
2021-04-23 20:11:54 +03:00
|
|
|
>
|
2019-01-30 01:54:51 +03:00
|
|
|
{ _t('Unban') }
|
|
|
|
</AccessibleButton>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
const userId = this.props.member.name === this.props.member.userId ? null : this.props.member.userId;
|
|
|
|
return (
|
|
|
|
<li>
|
|
|
|
{unbanButton}
|
|
|
|
<span title={_t("Banned by %(displayName)s", {displayName: this.props.by})}>
|
|
|
|
<strong>{ this.props.member.name }</strong> {userId}
|
|
|
|
{this.props.reason ? " " + _t('Reason') + ": " + this.props.reason : ""}
|
|
|
|
</span>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-06 14:26:50 +03:00
|
|
|
interface IProps {
|
|
|
|
roomId: string;
|
|
|
|
}
|
2019-01-30 01:54:51 +03:00
|
|
|
|
2021-04-06 14:26:50 +03:00
|
|
|
@replaceableComponent("views.settings.tabs.room.RolesRoomSettingsTab")
|
|
|
|
export default class RolesRoomSettingsTab extends React.Component<IProps> {
|
2021-04-27 13:42:11 +03:00
|
|
|
componentDidMount() {
|
2021-04-26 16:02:53 +03:00
|
|
|
MatrixClientPeg.get().on("RoomState.members", this.onRoomMembership);
|
2019-10-11 14:56:48 +03:00
|
|
|
}
|
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
componentWillUnmount() {
|
2019-10-11 14:56:48 +03:00
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
if (client) {
|
2021-04-26 16:02:53 +03:00
|
|
|
client.removeListener("RoomState.members", this.onRoomMembership);
|
2019-10-11 14:56:48 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
private onRoomMembership = (event: MatrixEvent, state: RoomState, member: RoomMember) => {
|
2019-10-11 14:56:48 +03:00
|
|
|
if (state.roomId !== this.props.roomId) return;
|
|
|
|
this.forceUpdate();
|
2020-02-20 05:35:30 +03:00
|
|
|
};
|
2019-10-11 14:56:48 +03:00
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
private populateDefaultPlEvents(eventsSection: Record<string, number>, stateLevel: number, eventsLevel: number) {
|
2019-01-30 01:54:51 +03:00
|
|
|
for (const desiredEvent of Object.keys(plEventsToShow)) {
|
|
|
|
if (!(desiredEvent in eventsSection)) {
|
|
|
|
eventsSection[desiredEvent] = (plEventsToShow[desiredEvent].isState ? stateLevel : eventsLevel);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
private onPowerLevelsChanged = (inputValue: string, powerLevelKey: string) => {
|
2019-02-07 01:06:15 +03:00
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
const room = client.getRoom(this.props.roomId);
|
2019-02-14 21:09:37 +03:00
|
|
|
const plEvent = room.currentState.getStateEvents('m.room.power_levels', '');
|
|
|
|
let plContent = plEvent ? (plEvent.getContent() || {}) : {};
|
2019-02-07 01:06:15 +03:00
|
|
|
|
|
|
|
// Clone the power levels just in case
|
|
|
|
plContent = Object.assign({}, plContent);
|
|
|
|
|
|
|
|
const eventsLevelPrefix = "event_levels_";
|
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
const value = parseInt(inputValue);
|
2019-02-07 01:06:15 +03:00
|
|
|
|
|
|
|
if (powerLevelKey.startsWith(eventsLevelPrefix)) {
|
|
|
|
// deep copy "events" object, Object.assign itself won't deep copy
|
|
|
|
plContent["events"] = Object.assign({}, plContent["events"] || {});
|
|
|
|
plContent["events"][powerLevelKey.slice(eventsLevelPrefix.length)] = value;
|
|
|
|
} else {
|
|
|
|
const keyPath = powerLevelKey.split('.');
|
|
|
|
let parentObj;
|
|
|
|
let currentObj = plContent;
|
|
|
|
for (const key of keyPath) {
|
|
|
|
if (!currentObj[key]) {
|
|
|
|
currentObj[key] = {};
|
|
|
|
}
|
|
|
|
parentObj = currentObj;
|
|
|
|
currentObj = currentObj[key];
|
|
|
|
}
|
|
|
|
parentObj[keyPath[keyPath.length - 1]] = value;
|
|
|
|
}
|
|
|
|
|
2019-09-09 14:50:05 +03:00
|
|
|
client.sendStateEvent(this.props.roomId, "m.room.power_levels", plContent).catch(e => {
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
Modal.createTrackedDialog('Power level requirement change failed', '', ErrorDialog, {
|
|
|
|
title: _t('Error changing power level requirement'),
|
|
|
|
description: _t(
|
|
|
|
"An error occurred changing the room's power level requirements. Ensure you have sufficient " +
|
|
|
|
"permissions and try again.",
|
|
|
|
),
|
|
|
|
});
|
|
|
|
});
|
2019-02-07 01:06:15 +03:00
|
|
|
};
|
|
|
|
|
2021-04-27 13:42:11 +03:00
|
|
|
private onUserPowerLevelChanged = (value: string, powerLevelKey: string) => {
|
2019-09-03 17:36:24 +03:00
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
const room = client.getRoom(this.props.roomId);
|
|
|
|
const plEvent = room.currentState.getStateEvents('m.room.power_levels', '');
|
|
|
|
let plContent = plEvent ? (plEvent.getContent() || {}) : {};
|
|
|
|
|
|
|
|
// Clone the power levels just in case
|
|
|
|
plContent = Object.assign({}, plContent);
|
|
|
|
|
|
|
|
// powerLevelKey should be a user ID
|
|
|
|
if (!plContent['users']) plContent['users'] = {};
|
|
|
|
plContent['users'][powerLevelKey] = value;
|
|
|
|
|
2019-09-04 20:24:31 +03:00
|
|
|
client.sendStateEvent(this.props.roomId, "m.room.power_levels", plContent).catch(e => {
|
|
|
|
console.error(e);
|
|
|
|
|
|
|
|
const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog");
|
|
|
|
Modal.createTrackedDialog('Power level change failed', '', ErrorDialog, {
|
|
|
|
title: _t('Error changing power level'),
|
|
|
|
description: _t(
|
|
|
|
"An error occurred changing the user's power level. Ensure you have sufficient " +
|
|
|
|
"permissions and try again.",
|
|
|
|
),
|
|
|
|
});
|
|
|
|
});
|
2019-09-03 17:36:24 +03:00
|
|
|
};
|
|
|
|
|
2019-01-30 01:54:51 +03:00
|
|
|
render() {
|
|
|
|
const PowerSelector = sdk.getComponent('elements.PowerSelector');
|
|
|
|
|
|
|
|
const client = MatrixClientPeg.get();
|
|
|
|
const room = client.getRoom(this.props.roomId);
|
2019-02-14 21:09:37 +03:00
|
|
|
const plEvent = room.currentState.getStateEvents('m.room.power_levels', '');
|
|
|
|
const plContent = plEvent ? (plEvent.getContent() || {}) : {};
|
2019-01-30 01:54:51 +03:00
|
|
|
const canChangeLevels = room.currentState.mayClientSendStateEvent('m.room.power_levels', client);
|
|
|
|
|
|
|
|
const powerLevelDescriptors = {
|
|
|
|
"users_default": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Default role'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 0,
|
|
|
|
},
|
|
|
|
"events_default": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Send messages'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 0,
|
|
|
|
},
|
|
|
|
"invite": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Invite users'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
"state_default": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Change settings'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
"kick": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Kick users'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
"ban": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Ban users'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
"redact": {
|
2020-10-01 17:51:35 +03:00
|
|
|
desc: _t('Remove messages sent by others'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
"notifications.room": {
|
2019-02-07 21:31:35 +03:00
|
|
|
desc: _t('Notify everyone'),
|
2019-01-30 01:54:51 +03:00
|
|
|
defaultValue: 50,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const eventsLevels = plContent.events || {};
|
|
|
|
const userLevels = plContent.users || {};
|
|
|
|
const banLevel = parseIntWithDefault(plContent.ban, powerLevelDescriptors.ban.defaultValue);
|
|
|
|
const defaultUserLevel = parseIntWithDefault(
|
|
|
|
plContent.users_default,
|
|
|
|
powerLevelDescriptors.users_default.defaultValue,
|
|
|
|
);
|
|
|
|
|
|
|
|
let currentUserLevel = userLevels[client.getUserId()];
|
|
|
|
if (currentUserLevel === undefined) {
|
|
|
|
currentUserLevel = defaultUserLevel;
|
|
|
|
}
|
|
|
|
|
2021-04-26 16:02:53 +03:00
|
|
|
this.populateDefaultPlEvents(
|
2019-01-30 01:54:51 +03:00
|
|
|
eventsLevels,
|
|
|
|
parseIntWithDefault(plContent.state_default, powerLevelDescriptors.state_default.defaultValue),
|
|
|
|
parseIntWithDefault(plContent.events_default, powerLevelDescriptors.events_default.defaultValue),
|
|
|
|
);
|
|
|
|
|
|
|
|
let privilegedUsersSection = <div>{_t('No users have specific privileges in this room')}</div>;
|
|
|
|
let mutedUsersSection;
|
|
|
|
if (Object.keys(userLevels).length) {
|
|
|
|
const privilegedUsers = [];
|
|
|
|
const mutedUsers = [];
|
|
|
|
|
2019-09-03 17:36:24 +03:00
|
|
|
Object.keys(userLevels).forEach((user) => {
|
2019-02-07 21:31:35 +03:00
|
|
|
const canChange = userLevels[user] < currentUserLevel && canChangeLevels;
|
2019-01-30 01:54:51 +03:00
|
|
|
if (userLevels[user] > defaultUserLevel) { // privileged
|
2019-02-07 21:31:35 +03:00
|
|
|
privilegedUsers.push(
|
2019-09-03 17:36:24 +03:00
|
|
|
<PowerSelector
|
|
|
|
value={userLevels[user]}
|
|
|
|
disabled={!canChange}
|
|
|
|
label={user}
|
|
|
|
key={user}
|
|
|
|
powerLevelKey={user} // Will be sent as the second parameter to `onChange`
|
2021-04-26 16:02:53 +03:00
|
|
|
onChange={this.onUserPowerLevelChanged}
|
2019-09-03 17:36:24 +03:00
|
|
|
/>,
|
2019-02-07 21:31:35 +03:00
|
|
|
);
|
2019-01-30 01:54:51 +03:00
|
|
|
} else if (userLevels[user] < defaultUserLevel) { // muted
|
2019-02-07 21:31:35 +03:00
|
|
|
mutedUsers.push(
|
2019-09-03 17:36:24 +03:00
|
|
|
<PowerSelector
|
|
|
|
value={userLevels[user]}
|
|
|
|
disabled={!canChange}
|
|
|
|
label={user}
|
|
|
|
key={user}
|
|
|
|
powerLevelKey={user} // Will be sent as the second parameter to `onChange`
|
2021-04-26 16:02:53 +03:00
|
|
|
onChange={this.onUserPowerLevelChanged}
|
2019-09-03 17:36:24 +03:00
|
|
|
/>,
|
2019-02-07 21:31:35 +03:00
|
|
|
);
|
2019-01-30 01:54:51 +03:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
// comparator for sorting PL users lexicographically on PL descending, MXID ascending. (case-insensitive)
|
|
|
|
const comparator = (a, b) => {
|
|
|
|
const plDiff = userLevels[b.key] - userLevels[a.key];
|
|
|
|
return plDiff !== 0 ? plDiff : a.key.toLocaleLowerCase().localeCompare(b.key.toLocaleLowerCase());
|
|
|
|
};
|
|
|
|
|
|
|
|
privilegedUsers.sort(comparator);
|
|
|
|
mutedUsers.sort(comparator);
|
|
|
|
|
|
|
|
if (privilegedUsers.length) {
|
|
|
|
privilegedUsersSection =
|
|
|
|
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
|
|
|
<div className='mx_SettingsTab_subheading'>{ _t('Privileged Users') }</div>
|
2019-02-07 21:31:35 +03:00
|
|
|
{privilegedUsers}
|
2019-01-30 01:54:51 +03:00
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
if (mutedUsers.length) {
|
|
|
|
mutedUsersSection =
|
|
|
|
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
|
|
|
<div className='mx_SettingsTab_subheading'>{ _t('Muted Users') }</div>
|
2019-02-07 21:31:35 +03:00
|
|
|
{mutedUsers}
|
2019-01-30 01:54:51 +03:00
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const banned = room.getMembersWithMembership("ban");
|
|
|
|
let bannedUsersSection;
|
|
|
|
if (banned.length) {
|
|
|
|
const canBanUsers = currentUserLevel >= banLevel;
|
|
|
|
bannedUsersSection =
|
|
|
|
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
|
|
|
<div className='mx_SettingsTab_subheading'>{ _t('Banned users') }</div>
|
|
|
|
<ul>
|
|
|
|
{banned.map((member) => {
|
|
|
|
const banEvent = member.events.member.getContent();
|
|
|
|
const sender = room.getMember(member.events.member.getSender());
|
|
|
|
let bannedBy = member.events.member.getSender(); // start by falling back to mxid
|
|
|
|
if (sender) bannedBy = sender.name;
|
|
|
|
return (
|
|
|
|
<BannedUser key={member.userId} canUnban={canBanUsers}
|
2021-04-23 20:11:54 +03:00
|
|
|
member={member} reason={banEvent.reason}
|
|
|
|
by={bannedBy}
|
|
|
|
/>
|
2019-01-30 01:54:51 +03:00
|
|
|
);
|
|
|
|
})}
|
|
|
|
</ul>
|
|
|
|
</div>;
|
|
|
|
}
|
|
|
|
|
|
|
|
const powerSelectors = Object.keys(powerLevelDescriptors).map((key, index) => {
|
|
|
|
const descriptor = powerLevelDescriptors[key];
|
|
|
|
|
|
|
|
const keyPath = key.split('.');
|
|
|
|
let currentObj = plContent;
|
|
|
|
for (const prop of keyPath) {
|
|
|
|
if (currentObj === undefined) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
currentObj = currentObj[prop];
|
|
|
|
}
|
|
|
|
|
|
|
|
const value = parseIntWithDefault(currentObj, descriptor.defaultValue);
|
|
|
|
return <div key={index} className="">
|
|
|
|
<PowerSelector
|
2019-02-07 21:31:35 +03:00
|
|
|
label={descriptor.desc}
|
2019-01-30 01:54:51 +03:00
|
|
|
value={value}
|
|
|
|
usersDefault={defaultUserLevel}
|
|
|
|
disabled={!canChangeLevels || currentUserLevel < value}
|
|
|
|
powerLevelKey={key} // Will be sent as the second parameter to `onChange`
|
2021-04-26 16:02:53 +03:00
|
|
|
onChange={this.onPowerLevelsChanged}
|
2019-01-30 01:54:51 +03:00
|
|
|
/>
|
|
|
|
</div>;
|
|
|
|
});
|
|
|
|
|
2019-08-30 12:57:46 +03:00
|
|
|
// hide the power level selector for enabling E2EE if it the room is already encrypted
|
|
|
|
if (client.isRoomEncrypted(this.props.roomId)) {
|
|
|
|
delete eventsLevels["m.room.encryption"];
|
|
|
|
}
|
|
|
|
|
2019-02-07 01:06:15 +03:00
|
|
|
const eventPowerSelectors = Object.keys(eventsLevels).map((eventType, i) => {
|
2019-01-30 01:54:51 +03:00
|
|
|
let label = plEventsToLabels[eventType];
|
|
|
|
if (label) {
|
|
|
|
label = _t(label);
|
|
|
|
} else {
|
2019-02-07 21:31:35 +03:00
|
|
|
label = _t("Send %(eventType)s events", {eventType});
|
2019-01-30 01:54:51 +03:00
|
|
|
}
|
|
|
|
return (
|
|
|
|
<div className="" key={eventType}>
|
|
|
|
<PowerSelector
|
2019-02-07 21:31:35 +03:00
|
|
|
label={label}
|
2019-01-30 01:54:51 +03:00
|
|
|
value={eventsLevels[eventType]}
|
|
|
|
usersDefault={defaultUserLevel}
|
|
|
|
disabled={!canChangeLevels || currentUserLevel < eventsLevels[eventType]}
|
|
|
|
powerLevelKey={"event_levels_" + eventType}
|
2021-04-26 16:02:53 +03:00
|
|
|
onChange={this.onPowerLevelsChanged}
|
2019-01-30 01:54:51 +03:00
|
|
|
/>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
return (
|
|
|
|
<div className="mx_SettingsTab mx_RolesRoomSettingsTab">
|
|
|
|
<div className="mx_SettingsTab_heading">{_t("Roles & Permissions")}</div>
|
|
|
|
{privilegedUsersSection}
|
|
|
|
{mutedUsersSection}
|
|
|
|
{bannedUsersSection}
|
|
|
|
<div className='mx_SettingsTab_section mx_SettingsTab_subsectionText'>
|
|
|
|
<span className='mx_SettingsTab_subheading'>{_t("Permissions")}</span>
|
2019-02-07 21:31:35 +03:00
|
|
|
<p>{_t('Select the roles required to change various parts of the room')}</p>
|
2019-01-30 01:54:51 +03:00
|
|
|
{powerSelectors}
|
|
|
|
{eventPowerSelectors}
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|