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:
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/_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";

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; 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 {

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 {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

View file

@ -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.",