Merge pull request #5413 from matrix-org/t3chguy/fix/11415
Change how we expose Role in User Info and hide in DMs
This commit is contained in:
commit
bf62960e1a
6 changed files with 48 additions and 192 deletions
|
@ -110,7 +110,6 @@
|
||||||
@import "./views/elements/_EventListSummary.scss";
|
@import "./views/elements/_EventListSummary.scss";
|
||||||
@import "./views/elements/_Field.scss";
|
@import "./views/elements/_Field.scss";
|
||||||
@import "./views/elements/_FormButton.scss";
|
@import "./views/elements/_FormButton.scss";
|
||||||
@import "./views/elements/_IconButton.scss";
|
|
||||||
@import "./views/elements/_ImageView.scss";
|
@import "./views/elements/_ImageView.scss";
|
||||||
@import "./views/elements/_InfoTooltip.scss";
|
@import "./views/elements/_InfoTooltip.scss";
|
||||||
@import "./views/elements/_InlineSpinner.scss";
|
@import "./views/elements/_InlineSpinner.scss";
|
||||||
|
|
|
@ -1,55 +0,0 @@
|
||||||
/*
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
.mx_IconButton {
|
|
||||||
width: 32px;
|
|
||||||
height: 32px;
|
|
||||||
border-radius: 100%;
|
|
||||||
background-color: $accent-bg-color;
|
|
||||||
// don't shrink or grow if in a flex container
|
|
||||||
flex: 0 0 auto;
|
|
||||||
|
|
||||||
&.mx_AccessibleButton_disabled {
|
|
||||||
background-color: none;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
background-color: lightgrey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
opacity: 90%;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
content: "";
|
|
||||||
display: block;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
mask-repeat: no-repeat;
|
|
||||||
mask-position: center;
|
|
||||||
mask-size: 55%;
|
|
||||||
background-color: $accent-color;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mx_IconButton_icon_check::before {
|
|
||||||
mask-image: url('$(res)/img/feather-customised/check.svg');
|
|
||||||
}
|
|
||||||
|
|
||||||
&.mx_IconButton_icon_edit::before {
|
|
||||||
mask-image: url('$(res)/img/feather-customised/edit.svg');
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -173,26 +173,12 @@ limitations under the License.
|
||||||
|
|
||||||
margin: 6px 0;
|
margin: 6px 0;
|
||||||
|
|
||||||
.mx_IconButton, .mx_Spinner {
|
|
||||||
margin-left: 20px;
|
|
||||||
width: 16px;
|
|
||||||
height: 16px;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
mask-size: 80%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.mx_UserInfo_roleDescription {
|
.mx_UserInfo_roleDescription {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
// try to make it the same height as the dropdown
|
// try to make it the same height as the dropdown
|
||||||
margin: 11px 0 12px 0;
|
margin: 11px 0 12px 0;
|
||||||
|
|
||||||
.mx_IconButton {
|
|
||||||
margin-left: 6px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.mx_Field {
|
.mx_Field {
|
||||||
|
|
|
@ -1,34 +0,0 @@
|
||||||
/*
|
|
||||||
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 AccessibleButton from "./AccessibleButton";
|
|
||||||
|
|
||||||
export default function IconButton(props) {
|
|
||||||
const {icon, className, ...restProps} = props;
|
|
||||||
|
|
||||||
let newClassName = (className || "") + " mx_IconButton";
|
|
||||||
newClassName = newClassName + " mx_IconButton_icon_" + icon;
|
|
||||||
|
|
||||||
const allProps = Object.assign({}, restProps, {className: newClassName});
|
|
||||||
|
|
||||||
return React.createElement(AccessibleButton, allProps);
|
|
||||||
}
|
|
||||||
|
|
||||||
IconButton.propTypes = Object.assign({
|
|
||||||
icon: PropTypes.string,
|
|
||||||
}, AccessibleButton.propTypes);
|
|
|
@ -51,7 +51,6 @@ import BaseCard from "./BaseCard";
|
||||||
import {E2EStatus} from "../../../utils/ShieldUtils";
|
import {E2EStatus} from "../../../utils/ShieldUtils";
|
||||||
import ImageView from "../elements/ImageView";
|
import ImageView from "../elements/ImageView";
|
||||||
import Spinner from "../elements/Spinner";
|
import Spinner from "../elements/Spinner";
|
||||||
import IconButton from "../elements/IconButton";
|
|
||||||
import PowerSelector from "../elements/PowerSelector";
|
import PowerSelector from "../elements/PowerSelector";
|
||||||
import MemberAvatar from "../avatars/MemberAvatar";
|
import MemberAvatar from "../avatars/MemberAvatar";
|
||||||
import PresenceLabel from "../rooms/PresenceLabel";
|
import PresenceLabel from "../rooms/PresenceLabel";
|
||||||
|
@ -1028,24 +1027,15 @@ const PowerLevelSection: React.FC<{
|
||||||
roomPermissions: IRoomPermissions;
|
roomPermissions: IRoomPermissions;
|
||||||
powerLevels: IPowerLevelsContent;
|
powerLevels: IPowerLevelsContent;
|
||||||
}> = ({user, room, roomPermissions, powerLevels}) => {
|
}> = ({user, room, roomPermissions, powerLevels}) => {
|
||||||
const [isEditing, setEditing] = useState(false);
|
if (roomPermissions.canEdit) {
|
||||||
if (isEditing) {
|
return (<PowerLevelEditor user={user} room={room} roomPermissions={roomPermissions} />);
|
||||||
return (<PowerLevelEditor
|
|
||||||
user={user} room={room} roomPermissions={roomPermissions}
|
|
||||||
onFinished={() => setEditing(false)} />);
|
|
||||||
} else {
|
} else {
|
||||||
const powerLevelUsersDefault = powerLevels.users_default || 0;
|
const powerLevelUsersDefault = powerLevels.users_default || 0;
|
||||||
const powerLevel = parseInt(user.powerLevel, 10);
|
const powerLevel = parseInt(user.powerLevel, 10);
|
||||||
const modifyButton = roomPermissions.canEdit ?
|
|
||||||
(<IconButton icon="edit" onClick={() => setEditing(true)} />) : null;
|
|
||||||
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
|
const role = textualPowerLevel(powerLevel, powerLevelUsersDefault);
|
||||||
const label = _t("<strong>%(role)s</strong> in %(roomName)s",
|
|
||||||
{role, roomName: room.name},
|
|
||||||
{strong: label => <strong>{label}</strong>},
|
|
||||||
);
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_UserInfo_profileField">
|
<div className="mx_UserInfo_profileField">
|
||||||
<div className="mx_UserInfo_roleDescription">{label}{modifyButton}</div>
|
<div className="mx_UserInfo_roleDescription">{role}</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1055,20 +1045,15 @@ const PowerLevelEditor: React.FC<{
|
||||||
user: User;
|
user: User;
|
||||||
room: Room;
|
room: Room;
|
||||||
roomPermissions: IRoomPermissions;
|
roomPermissions: IRoomPermissions;
|
||||||
onFinished(): void;
|
}> = ({user, room, roomPermissions}) => {
|
||||||
}> = ({user, room, roomPermissions, onFinished}) => {
|
|
||||||
const cli = useContext(MatrixClientContext);
|
const cli = useContext(MatrixClientContext);
|
||||||
|
|
||||||
const [isUpdating, setIsUpdating] = useState(false);
|
|
||||||
const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10));
|
const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10));
|
||||||
const [isDirty, setIsDirty] = useState(false);
|
const onPowerChange = useCallback(async (powerLevelStr: string) => {
|
||||||
const onPowerChange = useCallback((powerLevel) => {
|
const powerLevel = parseInt(powerLevelStr, 10);
|
||||||
setIsDirty(true);
|
setSelectedPowerLevel(powerLevel);
|
||||||
setSelectedPowerLevel(parseInt(powerLevel, 10));
|
|
||||||
}, [setSelectedPowerLevel, setIsDirty]);
|
|
||||||
|
|
||||||
const changePowerLevel = useCallback(async () => {
|
const applyPowerChange = (roomId, target, powerLevel, powerLevelEvent) => {
|
||||||
const _applyPowerChange = (roomId, target, powerLevel, powerLevelEvent) => {
|
|
||||||
return cli.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then(
|
return cli.setPowerLevel(roomId, target, parseInt(powerLevel), powerLevelEvent).then(
|
||||||
function() {
|
function() {
|
||||||
// NO-OP; rely on the m.room.member event coming down else we could
|
// NO-OP; rely on the m.room.member event coming down else we could
|
||||||
|
@ -1084,64 +1069,42 @@ const PowerLevelEditor: React.FC<{
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
try {
|
const roomId = user.roomId;
|
||||||
if (!isDirty) {
|
const target = user.userId;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
setIsUpdating(true);
|
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
||||||
|
if (!powerLevelEvent) return;
|
||||||
|
|
||||||
const powerLevel = selectedPowerLevel;
|
const myUserId = cli.getUserId();
|
||||||
|
const myPower = powerLevelEvent.getContent().users[myUserId];
|
||||||
|
if (myPower && parseInt(myPower) === powerLevel) {
|
||||||
|
const {finished} = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
|
||||||
|
title: _t("Warning!"),
|
||||||
|
description:
|
||||||
|
<div>
|
||||||
|
{ _t("You will not be able to undo this change as you are promoting the user " +
|
||||||
|
"to have the same power level as yourself.") }<br />
|
||||||
|
{ _t("Are you sure?") }
|
||||||
|
</div>,
|
||||||
|
button: _t("Continue"),
|
||||||
|
});
|
||||||
|
|
||||||
const roomId = user.roomId;
|
const [confirmed] = await finished;
|
||||||
const target = user.userId;
|
if (!confirmed) return;
|
||||||
|
} else if (myUserId === target) {
|
||||||
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
|
||||||
if (!powerLevelEvent) return;
|
|
||||||
|
|
||||||
if (!powerLevelEvent.getContent().users) {
|
|
||||||
_applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const myUserId = cli.getUserId();
|
|
||||||
// If we are changing our own PL it can only ever be decreasing, which we cannot reverse.
|
// If we are changing our own PL it can only ever be decreasing, which we cannot reverse.
|
||||||
if (myUserId === target) {
|
try {
|
||||||
try {
|
if (!(await warnSelfDemote())) return;
|
||||||
if (!(await warnSelfDemote())) return;
|
} catch (e) {
|
||||||
} catch (e) {
|
console.error("Failed to warn about self demotion: ", e);
|
||||||
console.error("Failed to warn about self demotion: ", e);
|
|
||||||
}
|
|
||||||
await _applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const myPower = powerLevelEvent.getContent().users[myUserId];
|
|
||||||
if (parseInt(myPower) === powerLevel) {
|
|
||||||
const {finished} = Modal.createTrackedDialog('Promote to PL100 Warning', '', QuestionDialog, {
|
|
||||||
title: _t("Warning!"),
|
|
||||||
description:
|
|
||||||
<div>
|
|
||||||
{ _t("You will not be able to undo this change as you are promoting the user " +
|
|
||||||
"to have the same power level as yourself.") }<br />
|
|
||||||
{ _t("Are you sure?") }
|
|
||||||
</div>,
|
|
||||||
button: _t("Continue"),
|
|
||||||
});
|
|
||||||
|
|
||||||
const [confirmed] = await finished;
|
|
||||||
if (!confirmed) return;
|
|
||||||
}
|
|
||||||
await _applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
|
|
||||||
} finally {
|
|
||||||
onFinished();
|
|
||||||
}
|
}
|
||||||
}, [user.roomId, user.userId, cli, selectedPowerLevel, isDirty, setIsUpdating, onFinished, room]);
|
|
||||||
|
await applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
|
||||||
|
}, [user.roomId, user.userId, cli, room]);
|
||||||
|
|
||||||
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
const powerLevelEvent = room.currentState.getStateEvents("m.room.power_levels", "");
|
||||||
const powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0;
|
const powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0;
|
||||||
const buttonOrSpinner = isUpdating ? <Spinner w={16} h={16} /> :
|
|
||||||
<IconButton icon="check" onClick={changePowerLevel} />;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mx_UserInfo_profileField">
|
<div className="mx_UserInfo_profileField">
|
||||||
|
@ -1151,9 +1114,7 @@ const PowerLevelEditor: React.FC<{
|
||||||
maxValue={roomPermissions.modifyLevelMax}
|
maxValue={roomPermissions.modifyLevelMax}
|
||||||
usersDefault={powerLevelUsersDefault}
|
usersDefault={powerLevelUsersDefault}
|
||||||
onChange={onPowerChange}
|
onChange={onPowerChange}
|
||||||
disabled={isUpdating}
|
|
||||||
/>
|
/>
|
||||||
{buttonOrSpinner}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1343,13 +1304,17 @@ const BasicUserInfo: React.FC<{
|
||||||
}
|
}
|
||||||
|
|
||||||
let memberDetails;
|
let memberDetails;
|
||||||
if (room && member.roomId) {
|
// hide the Roles section for DMs as it doesn't make sense there
|
||||||
memberDetails = <PowerLevelSection
|
if (room && member.roomId && !DMRoomMap.shared().getUserIdForRoomId(member.roomId)) {
|
||||||
powerLevels={powerLevels}
|
memberDetails = <div className="mx_UserInfo_container">
|
||||||
user={member}
|
<h3>{ _t("Role") }</h3>
|
||||||
room={room}
|
<PowerLevelSection
|
||||||
roomPermissions={roomPermissions}
|
powerLevels={powerLevels}
|
||||||
/>;
|
user={member}
|
||||||
|
room={room}
|
||||||
|
roomPermissions={roomPermissions}
|
||||||
|
/>
|
||||||
|
</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
// only display the devices list if our client supports E2E
|
// only display the devices list if our client supports E2E
|
||||||
|
@ -1419,12 +1384,7 @@ const BasicUserInfo: React.FC<{
|
||||||
);
|
);
|
||||||
|
|
||||||
return <React.Fragment>
|
return <React.Fragment>
|
||||||
{ memberDetails &&
|
{ memberDetails }
|
||||||
<div className="mx_UserInfo_container mx_UserInfo_separator mx_UserInfo_memberDetailsContainer">
|
|
||||||
<div className="mx_UserInfo_memberDetails">
|
|
||||||
{ memberDetails }
|
|
||||||
</div>
|
|
||||||
</div> }
|
|
||||||
|
|
||||||
{ securitySection }
|
{ securitySection }
|
||||||
<UserOptionsSection
|
<UserOptionsSection
|
||||||
|
|
|
@ -1598,7 +1598,6 @@
|
||||||
"Remove this user from community?": "Remove this user from community?",
|
"Remove this user from community?": "Remove this user from community?",
|
||||||
"Failed to withdraw invitation": "Failed to withdraw invitation",
|
"Failed to withdraw invitation": "Failed to withdraw invitation",
|
||||||
"Failed to remove user from community": "Failed to remove user from community",
|
"Failed to remove user from community": "Failed to remove user from community",
|
||||||
"<strong>%(role)s</strong> in %(roomName)s": "<strong>%(role)s</strong> in %(roomName)s",
|
|
||||||
"Failed to change power level": "Failed to change power level",
|
"Failed to change power level": "Failed to change power level",
|
||||||
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.",
|
"You will not be able to undo this change as you are promoting the user to have the same power level as yourself.": "You will not be able to undo this change as you are promoting the user to have the same power level as yourself.",
|
||||||
"Are you sure?": "Are you sure?",
|
"Are you sure?": "Are you sure?",
|
||||||
|
@ -1606,6 +1605,7 @@
|
||||||
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
|
"Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?": "Deactivating this user will log them out and prevent them from logging back in. Additionally, they will leave all the rooms they are in. This action cannot be reversed. Are you sure you want to deactivate this user?",
|
||||||
"Deactivate user": "Deactivate user",
|
"Deactivate user": "Deactivate user",
|
||||||
"Failed to deactivate user": "Failed to deactivate user",
|
"Failed to deactivate user": "Failed to deactivate user",
|
||||||
|
"Role": "Role",
|
||||||
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
|
"This client does not support end-to-end encryption.": "This client does not support end-to-end encryption.",
|
||||||
"Security": "Security",
|
"Security": "Security",
|
||||||
"The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.",
|
"The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.": "The session you are trying to verify doesn't support scanning a QR code or emoji verification, which is what %(brand)s supports. Try with a different client.",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue