Merge pull request #5413 from matrix-org/t3chguy/fix/11415

Change how we expose Role in User Info and hide in DMs
pull/21833/head
Michael Telatynski 2020-11-11 18:15:46 +00:00 committed by GitHub
commit bf62960e1a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 48 additions and 192 deletions

View File

@ -110,7 +110,6 @@
@import "./views/elements/_EventListSummary.scss";
@import "./views/elements/_Field.scss";
@import "./views/elements/_FormButton.scss";
@import "./views/elements/_IconButton.scss";
@import "./views/elements/_ImageView.scss";
@import "./views/elements/_InfoTooltip.scss";
@import "./views/elements/_InlineSpinner.scss";

View File

@ -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');
}
}

View File

@ -173,26 +173,12 @@ limitations under the License.
margin: 6px 0;
.mx_IconButton, .mx_Spinner {
margin-left: 20px;
width: 16px;
height: 16px;
&::before {
mask-size: 80%;
}
}
.mx_UserInfo_roleDescription {
display: flex;
justify-content: center;
align-items: center;
// try to make it the same height as the dropdown
margin: 11px 0 12px 0;
.mx_IconButton {
margin-left: 6px;
}
}
.mx_Field {

View File

@ -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);

View File

@ -51,7 +51,6 @@ import BaseCard from "./BaseCard";
import {E2EStatus} from "../../../utils/ShieldUtils";
import ImageView from "../elements/ImageView";
import Spinner from "../elements/Spinner";
import IconButton from "../elements/IconButton";
import PowerSelector from "../elements/PowerSelector";
import MemberAvatar from "../avatars/MemberAvatar";
import PresenceLabel from "../rooms/PresenceLabel";
@ -1028,24 +1027,15 @@ const PowerLevelSection: React.FC<{
roomPermissions: IRoomPermissions;
powerLevels: IPowerLevelsContent;
}> = ({user, room, roomPermissions, powerLevels}) => {
const [isEditing, setEditing] = useState(false);
if (isEditing) {
return (<PowerLevelEditor
user={user} room={room} roomPermissions={roomPermissions}
onFinished={() => setEditing(false)} />);
if (roomPermissions.canEdit) {
return (<PowerLevelEditor user={user} room={room} roomPermissions={roomPermissions} />);
} else {
const powerLevelUsersDefault = powerLevels.users_default || 0;
const powerLevel = parseInt(user.powerLevel, 10);
const modifyButton = roomPermissions.canEdit ?
(<IconButton icon="edit" onClick={() => setEditing(true)} />) : null;
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 (
<div className="mx_UserInfo_profileField">
<div className="mx_UserInfo_roleDescription">{label}{modifyButton}</div>
<div className="mx_UserInfo_roleDescription">{role}</div>
</div>
);
}
@ -1055,20 +1045,15 @@ const PowerLevelEditor: React.FC<{
user: User;
room: Room;
roomPermissions: IRoomPermissions;
onFinished(): void;
}> = ({user, room, roomPermissions, onFinished}) => {
}> = ({user, room, roomPermissions}) => {
const cli = useContext(MatrixClientContext);
const [isUpdating, setIsUpdating] = useState(false);
const [selectedPowerLevel, setSelectedPowerLevel] = useState(parseInt(user.powerLevel, 10));
const [isDirty, setIsDirty] = useState(false);
const onPowerChange = useCallback((powerLevel) => {
setIsDirty(true);
setSelectedPowerLevel(parseInt(powerLevel, 10));
}, [setSelectedPowerLevel, setIsDirty]);
const onPowerChange = useCallback(async (powerLevelStr: string) => {
const powerLevel = parseInt(powerLevelStr, 10);
setSelectedPowerLevel(powerLevel);
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(
function() {
// NO-OP; rely on the m.room.member event coming down else we could
@ -1084,64 +1069,42 @@ const PowerLevelEditor: React.FC<{
);
};
try {
if (!isDirty) {
return;
}
const roomId = user.roomId;
const target = user.userId;
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 target = user.userId;
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();
const [confirmed] = await finished;
if (!confirmed) return;
} else if (myUserId === target) {
// If we are changing our own PL it can only ever be decreasing, which we cannot reverse.
if (myUserId === target) {
try {
if (!(await warnSelfDemote())) return;
} catch (e) {
console.error("Failed to warn about self demotion: ", e);
}
await _applyPowerChange(roomId, target, powerLevel, powerLevelEvent);
return;
try {
if (!(await warnSelfDemote())) return;
} catch (e) {
console.error("Failed to warn about self demotion: ", e);
}
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 powerLevelUsersDefault = powerLevelEvent ? powerLevelEvent.getContent().users_default : 0;
const buttonOrSpinner = isUpdating ? <Spinner w={16} h={16} /> :
<IconButton icon="check" onClick={changePowerLevel} />;
return (
<div className="mx_UserInfo_profileField">
@ -1151,9 +1114,7 @@ const PowerLevelEditor: React.FC<{
maxValue={roomPermissions.modifyLevelMax}
usersDefault={powerLevelUsersDefault}
onChange={onPowerChange}
disabled={isUpdating}
/>
{buttonOrSpinner}
</div>
);
};
@ -1343,13 +1304,17 @@ const BasicUserInfo: React.FC<{
}
let memberDetails;
if (room && member.roomId) {
memberDetails = <PowerLevelSection
powerLevels={powerLevels}
user={member}
room={room}
roomPermissions={roomPermissions}
/>;
// hide the Roles section for DMs as it doesn't make sense there
if (room && member.roomId && !DMRoomMap.shared().getUserIdForRoomId(member.roomId)) {
memberDetails = <div className="mx_UserInfo_container">
<h3>{ _t("Role") }</h3>
<PowerLevelSection
powerLevels={powerLevels}
user={member}
room={room}
roomPermissions={roomPermissions}
/>
</div>;
}
// only display the devices list if our client supports E2E
@ -1419,12 +1384,7 @@ const BasicUserInfo: React.FC<{
);
return <React.Fragment>
{ memberDetails &&
<div className="mx_UserInfo_container mx_UserInfo_separator mx_UserInfo_memberDetailsContainer">
<div className="mx_UserInfo_memberDetails">
{ memberDetails }
</div>
</div> }
{ memberDetails }
{ securitySection }
<UserOptionsSection

View File

@ -1598,7 +1598,6 @@
"Remove this user from community?": "Remove this user from community?",
"Failed to withdraw invitation": "Failed to withdraw invitation",
"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",
"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?",
@ -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?",
"Deactivate user": "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.",
"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.",