From 1858c63c4af98c9f976a818bd3cf20b7a184e3b3 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 17 Sep 2021 15:34:49 +0100 Subject: [PATCH 1/7] Allow options to cascade kicks/bans throughout spaces --- res/css/_components.scss | 5 +- .../_ConfirmSpaceUserActionDialog.scss | 66 ++++++++ .../dialogs/_ConfirmUserActionDialog.scss | 2 +- res/css/views/dialogs/_LeaveSpaceDialog.scss | 22 +-- .../views/spaces/_SpaceChildrenPicker.scss | 35 ++++ .../dialogs/ConfirmSpaceUserActionDialog.tsx | 86 ++++++++++ .../views/dialogs/ConfirmUserActionDialog.tsx | 26 +-- .../views/dialogs/LeaveSpaceDialog.tsx | 123 ++------------ src/components/views/right_panel/UserInfo.tsx | 100 +++++++++--- .../views/spaces/SpaceChildrenPicker.tsx | 150 ++++++++++++++++++ src/i18n/strings/en_EN.json | 17 +- src/utils/space.tsx | 26 +-- 12 files changed, 481 insertions(+), 177 deletions(-) create mode 100644 res/css/views/dialogs/_ConfirmSpaceUserActionDialog.scss create mode 100644 res/css/views/spaces/_SpaceChildrenPicker.scss create mode 100644 src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx create mode 100644 src/components/views/spaces/SpaceChildrenPicker.tsx diff --git a/res/css/_components.scss b/res/css/_components.scss index ffaec43b68..adbe67b20e 100644 --- a/res/css/_components.scss +++ b/res/css/_components.scss @@ -1,8 +1,10 @@ // autogenerated by rethemendex.sh +@import "./_animations.scss"; @import "./_common.scss"; @import "./_font-sizes.scss"; @import "./_font-weights.scss"; @import "./structures/_AutoHideScrollbar.scss"; +@import "./structures/_BackdropPanel.scss"; @import "./structures/_CompatibilityPage.scss"; @import "./structures/_ContextualMenu.scss"; @import "./structures/_CreateRoom.scss"; @@ -17,7 +19,6 @@ @import "./structures/_LeftPanelWidget.scss"; @import "./structures/_MainSplit.scss"; @import "./structures/_MatrixChat.scss"; -@import "./structures/_BackdropPanel.scss"; @import "./structures/_MyGroups.scss"; @import "./structures/_NonUrgentToastContainer.scss"; @import "./structures/_NotificationPanel.scss"; @@ -72,6 +73,7 @@ @import "./views/dialogs/_ChangelogDialog.scss"; @import "./views/dialogs/_ChatCreateOrReuseChatDialog.scss"; @import "./views/dialogs/_CommunityPrototypeInviteDialog.scss"; +@import "./views/dialogs/_ConfirmSpaceUserActionDialog.scss"; @import "./views/dialogs/_ConfirmUserActionDialog.scss"; @import "./views/dialogs/_CreateCommunityPrototypeDialog.scss"; @import "./views/dialogs/_CreateGroupDialog.scss"; @@ -266,6 +268,7 @@ @import "./views/settings/tabs/user/_SecurityUserSettingsTab.scss"; @import "./views/settings/tabs/user/_VoiceUserSettingsTab.scss"; @import "./views/spaces/_SpaceBasicSettings.scss"; +@import "./views/spaces/_SpaceChildrenPicker.scss"; @import "./views/spaces/_SpaceCreateMenu.scss"; @import "./views/spaces/_SpacePublicShare.scss"; @import "./views/terms/_InlineTermsAgreement.scss"; diff --git a/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.scss b/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.scss new file mode 100644 index 0000000000..3b21ea74de --- /dev/null +++ b/res/css/views/dialogs/_ConfirmSpaceUserActionDialog.scss @@ -0,0 +1,66 @@ +/* +Copyright 2021 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_ConfirmSpaceUserActionDialog_wrapper { + .mx_Dialog { + display: flex; + flex-direction: column; + padding: 24px 32px; + } +} + +.mx_ConfirmSpaceUserActionDialog { + width: 440px; + display: flex; + flex-direction: column; + flex-wrap: nowrap; + height: 520px; + + .mx_Dialog_content { + margin: 12px 0; + flex-grow: 1; + overflow-y: auto; + } + + .mx_ConfirmUserActionDialog_reasonField { + margin-bottom: 12px; + } + + .mx_ConfirmSpaceUserActionDialog_warning { + position: relative; + border-radius: 8px; + padding: 12px 8px 12px 42px; + background-color: $header-panel-bg-color; + + font-size: $font-12px; + line-height: $font-15px; + color: $secondary-content; + + &::before { + content: ''; + position: absolute; + left: 10px; + top: calc(50% - 8px); // vertical centering + height: 16px; + width: 16px; + background-color: $secondary-content; + mask-repeat: no-repeat; + mask-size: contain; + mask-image: url('$(res)/img/element-icons/room/room-summary.svg'); + mask-position: center; + } + } +} diff --git a/res/css/views/dialogs/_ConfirmUserActionDialog.scss b/res/css/views/dialogs/_ConfirmUserActionDialog.scss index 5ac0f07b14..777c9fdfd9 100644 --- a/res/css/views/dialogs/_ConfirmUserActionDialog.scss +++ b/res/css/views/dialogs/_ConfirmUserActionDialog.scss @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -.mx_ConfirmUserActionDialog .mx_Dialog_content { +.mx_ConfirmUserActionDialog .mx_Dialog_content .mx_ConfirmUserActionDialog_user { min-height: 48px; margin-bottom: 24px; } diff --git a/res/css/views/dialogs/_LeaveSpaceDialog.scss b/res/css/views/dialogs/_LeaveSpaceDialog.scss index 0d85a87faf..c0f24871c6 100644 --- a/res/css/views/dialogs/_LeaveSpaceDialog.scss +++ b/res/css/views/dialogs/_LeaveSpaceDialog.scss @@ -27,33 +27,13 @@ limitations under the License. display: flex; flex-direction: column; flex-wrap: nowrap; - max-height: 520px; + height: 520px; .mx_Dialog_content { flex-grow: 1; margin: 0; overflow-y: auto; - .mx_RadioButton + .mx_RadioButton { - margin-top: 16px; - } - - .mx_SearchBox { - // To match the space around the title - margin: 0 0 15px 0; - flex-grow: 0; - border-radius: 8px; - } - - .mx_LeaveSpaceDialog_noResults { - display: block; - margin-top: 24px; - } - - .mx_LeaveSpaceDialog_section { - margin: 16px 0; - } - .mx_LeaveSpaceDialog_section_warning { position: relative; border-radius: 8px; diff --git a/res/css/views/spaces/_SpaceChildrenPicker.scss b/res/css/views/spaces/_SpaceChildrenPicker.scss new file mode 100644 index 0000000000..e0fa6ef26d --- /dev/null +++ b/res/css/views/spaces/_SpaceChildrenPicker.scss @@ -0,0 +1,35 @@ +/* +Copyright 2021 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_SpaceChildrenPicker { + margin: 16px 0; + + .mx_RadioButton + .mx_RadioButton { + margin-top: 16px; + } + + .mx_SearchBox { + // To match the space around the title + margin: 0 0 15px 0; + flex-grow: 0; + border-radius: 8px; + } + + .mx_SpaceChildrenPicker_noResults { + display: block; + margin-top: 24px; + } +} diff --git a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx new file mode 100644 index 0000000000..4059682ade --- /dev/null +++ b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx @@ -0,0 +1,86 @@ +/* +Copyright 2021 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, { ComponentProps, useMemo, useState } from 'react'; +import ConfirmUserActionDialog from "./ConfirmUserActionDialog"; +import SpaceStore from "../../../stores/SpaceStore"; +import { Room } from "matrix-js-sdk/src/models/room"; +import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker"; +import { _t } from '../../../languageHandler'; + +type BaseProps = ComponentProps; +interface IProps extends Omit { + space: Room; + allLabel: string; + specificLabel: string; + noneLabel?: string; + onFinished(success: boolean, reason?: string, rooms?: Room[]): void; + spaceChildFilter?(child: Room): boolean; +} + +const ConfirmSpaceUserActionDialog: React.FC = ({ + space, + spaceChildFilter, + allLabel, + specificLabel, + noneLabel, + onFinished, + ...props +}) => { + const spaceChildren = useMemo(() => { + const children = SpaceStore.instance.getChildren(space.roomId); + if (spaceChildFilter) { + return children.filter(spaceChildFilter); + } + return children; + }, [space.roomId, spaceChildFilter]); + + const [roomsToLeave, setRoomsToLeave] = useState([]); + const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); + + let warning: JSX.Element; + if (!spaceChildren.length) { + warning =
+ { _t("You’re not an admin of anything they’re a member of in , " + + "so banning won’t remove them from any rooms or spaces in .", {}, { + SpaceName: () => { space.name }, + }) } +
; + } + + return ( + { + onFinished(success, reason, roomsToLeave); + }} + className="mx_ConfirmSpaceUserActionDialog" + > + { warning } + + + ); +}; + +export default ConfirmSpaceUserActionDialog; diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx index 7099556ac6..7468f400c6 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -14,9 +14,11 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; +import React, { ReactNode } from 'react'; import { MatrixClient } from 'matrix-js-sdk/src/client'; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; +import classNames from "classnames"; + import { _t } from '../../../languageHandler'; import { GroupMemberType } from '../../../groups'; import { replaceableComponent } from "../../../utils/replaceableComponent"; @@ -28,9 +30,9 @@ import DialogButtons from "../elements/DialogButtons"; interface IProps { // matrix-js-sdk (room) member object. Supply either this or 'groupMember' - member: RoomMember; + member?: RoomMember; // group member object. Supply either this or 'member' - groupMember: GroupMemberType; + groupMember?: GroupMemberType; // needed if a group member is specified matrixClient?: MatrixClient; action: string; // eg. 'Ban' @@ -41,6 +43,8 @@ interface IProps { // be the string entered. askReason?: boolean; danger?: boolean; + children?: ReactNode; + className?: string; onFinished: (success: boolean, reason?: string) => void; } @@ -105,19 +109,23 @@ export default class ConfirmUserActionDialog extends React.Component { return (
-
- { avatar } +
+
+ { avatar } +
+
{ name }
+
{ userId }
-
{ name }
-
{ userId }
+ + { reasonBox } + { this.props.children }
- { reasonBox } { - const [query, setQuery] = useState(""); - const lcQuery = query.toLowerCase().trim(); - - const filteredRooms = useMemo(() => { - if (!lcQuery) { - return rooms; - } - - const matcher = new QueryMatcher(rooms, { - keys: ["name"], - funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)], - shouldMatchWordsOnly: false, - }); - - return matcher.match(lcQuery); - }, [rooms, lcQuery]); - - return
- - - { filteredRooms.map(room => { - return { - onChange(checked, room); - }} - />; - }) } - { filteredRooms.length < 1 ? - { _t("No results") } - : undefined } - -
; -}; - -const LeaveRoomsPicker = ({ space, spaceChildren, roomsToLeave, setRoomsToLeave }) => { - const selected = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); - const [state, setState] = useState(RoomsToLeave.None); - - useEffect(() => { - if (state === RoomsToLeave.All) { - setRoomsToLeave(spaceChildren); - } else { - setRoomsToLeave([]); - } - }, [setRoomsToLeave, state, spaceChildren]); - - return
- - - { state === RoomsToLeave.Specific && ( - { - if (selected) { - setRoomsToLeave([room, ...roomsToLeave]); - } else { - setRoomsToLeave(roomsToLeave.filter(r => r !== room)); - } - }} - /> - ) } -
; -}; +import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker"; interface IProps { space: Room; @@ -139,6 +38,7 @@ const isOnlyAdmin = (room: Room): boolean => { const LeaveSpaceDialog: React.FC = ({ space, onFinished }) => { const spaceChildren = useMemo(() => SpaceStore.instance.getChildren(space.roomId), [space.roomId]); const [roomsToLeave, setRoomsToLeave] = useState([]); + const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); let rejoinWarning; if (space.getJoinRule() !== JoinRule.Public) { @@ -173,12 +73,17 @@ const LeaveSpaceDialog: React.FC = ({ space, onFinished }) => { { rejoinWarning }

- { spaceChildren.length > 0 && } + { spaceChildren.length > 0 && ( + + ) } { onlyAdminWarning &&
{ onlyAdminWarning } diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index f1807985ae..3a12c6478f 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -70,6 +70,8 @@ import { mediaFromMxc } from "../../../customisations/Media"; import UIStore from "../../../stores/UIStore"; import { ComposerInsertPayload } from "../../../dispatcher/payloads/ComposerInsertPayload"; import SpaceStore from "../../../stores/SpaceStore"; +import ConfirmSpaceUserActionDialog from "../dialogs/ConfirmSpaceUserActionDialog"; +import { bulkSpaceBehaviour } from "../../../utils/space"; export interface IDevice { deviceId: string; @@ -530,7 +532,7 @@ interface IBaseProps { stopUpdating(): void; } -const RoomKickButton: React.FC = ({ member, startUpdating, stopUpdating }) => { +const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit) => { const cli = useContext(MatrixClientContext); // check if user can be kicked/disinvited @@ -540,21 +542,35 @@ const RoomKickButton: React.FC = ({ member, startUpdating, stopUpdat const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onKick', - ConfirmUserActionDialog, + room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog, { member, action: member.membership === "invite" ? _t("Disinvite") : _t("Kick"), title: member.membership === "invite" ? _t("Disinvite this user?") : _t("Kick this user?"), askReason: member.membership === "join", danger: true, + // space-specific props + space: room, + spaceChildFilter: (child: Room) => { + // Return true if the target member is not banned and we have sufficient PL to ban them + const myMember = child.getMember(cli.credentials.userId); + const theirMember = child.getMember(member.userId); + return myMember && theirMember && theirMember.membership === member.membership && + myMember.powerLevel > theirMember.powerLevel && + child.currentState.hasSufficientPowerLevelFor("kick", myMember.powerLevel); + }, + allLabel: _t("Kick them from everything I'm able to"), + specificLabel: _t("Kick them from specific things I'm able to"), }, + room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); - const [proceed, reason] = await finished; + const [proceed, reason, rooms = []] = await finished; if (!proceed) return; startUpdating(); - cli.kick(member.roomId, member.userId, reason || undefined).then(() => { + + bulkSpaceBehaviour(room, rooms, room => cli.kick(room.roomId, member.userId, reason || undefined)).then(() => { // NO-OP; rely on the m.room.member event coming down else we could // get out of sync if we force setState here! console.log("Kick success"); @@ -654,34 +670,64 @@ const RedactMessagesButton: React.FC = ({ member }) => { ; }; -const BanToggleButton: React.FC = ({ member, startUpdating, stopUpdating }) => { +const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit) => { const cli = useContext(MatrixClientContext); + const isBanned = member.membership === "ban"; const onBanOrUnban = async () => { const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onBanOrUnban', - ConfirmUserActionDialog, + room.isSpaceRoom() ? ConfirmSpaceUserActionDialog : ConfirmUserActionDialog, { member, - action: member.membership === 'ban' ? _t("Unban") : _t("Ban"), - title: member.membership === 'ban' ? _t("Unban this user?") : _t("Ban this user?"), - askReason: member.membership !== 'ban', - danger: member.membership !== 'ban', + action: isBanned ? _t("Unban") : _t("Ban"), + title: isBanned ? _t("Unban this user?") : _t("Ban this user?"), + askReason: !isBanned, + danger: !isBanned, + // space-specific props + space: room, + spaceChildFilter: isBanned + ? (child: Room) => { + // Return true if the target member is banned and we have sufficient PL to unban + const myMember = child.getMember(cli.credentials.userId); + const theirMember = child.getMember(member.userId); + return myMember && theirMember && theirMember.membership === "ban" && + myMember.powerLevel > theirMember.powerLevel && + child.currentState.hasSufficientPowerLevelFor("ban", myMember.powerLevel); + } + : (child: Room) => { + // Return true if the target member isn't banned and we have sufficient PL to ban + const myMember = child.getMember(cli.credentials.userId); + const theirMember = child.getMember(member.userId); + return myMember && theirMember && theirMember.membership !== "ban" && + myMember.powerLevel > theirMember.powerLevel && + child.currentState.hasSufficientPowerLevelFor("ban", myMember.powerLevel); + }, + allLabel: isBanned + ? _t("Unban them from everything I'm able to") + : _t("Ban them from everything I'm able to"), + specificLabel: isBanned + ? _t("Unban them from specific things I'm able to") + : _t("Ban them from specific things I'm able to"), }, + room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); - const [proceed, reason] = await finished; + const [proceed, reason, rooms = []] = await finished; if (!proceed) return; startUpdating(); - let promise; - if (member.membership === 'ban') { - promise = cli.unban(member.roomId, member.userId); - } else { - promise = cli.ban(member.roomId, member.userId, reason || undefined); - } - promise.then(() => { + + const fn = (roomId: string) => { + if (isBanned) { + return cli.unban(roomId, member.userId); + } else { + return cli.ban(roomId, member.userId, reason || undefined); + } + }; + + bulkSpaceBehaviour(room, rooms, room => fn(room.roomId)).then(() => { // NO-OP; rely on the m.room.member event coming down else we could // get out of sync if we force setState here! console.log("Ban success"); @@ -697,12 +743,12 @@ const BanToggleButton: React.FC = ({ member, startUpdating, stopUpda }; let label = _t("Ban"); - if (member.membership === 'ban') { + if (isBanned) { label = _t("Unban"); } const classes = classNames("mx_UserInfo_field", { - mx_UserInfo_destructive: member.membership !== 'ban', + mx_UserInfo_destructive: !isBanned, }); return @@ -816,7 +862,12 @@ const RoomAdminToolsContainer: React.FC = ({ const canAffectUser = member.powerLevel < me.powerLevel || isMe; if (canAffectUser && me.powerLevel >= kickPowerLevel) { - kickButton = ; + kickButton = ; } if (me.powerLevel >= redactPowerLevel && (!SpaceStore.spacesEnabled || !room.isSpaceRoom())) { redactButton = ( @@ -824,7 +875,12 @@ const RoomAdminToolsContainer: React.FC = ({ ); } if (canAffectUser && me.powerLevel >= banPowerLevel) { - banButton = ; + banButton = ; } if (canAffectUser && me.powerLevel >= editPowerLevel && !room.isSpaceRoom()) { muteButton = ( diff --git a/src/components/views/spaces/SpaceChildrenPicker.tsx b/src/components/views/spaces/SpaceChildrenPicker.tsx new file mode 100644 index 0000000000..7b9e5534ca --- /dev/null +++ b/src/components/views/spaces/SpaceChildrenPicker.tsx @@ -0,0 +1,150 @@ +/* +Copyright 2021 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, { useEffect, useMemo, useState } from "react"; +import { Room } from "matrix-js-sdk/src/models/room"; + +import { _t } from "../../../languageHandler"; +import StyledRadioGroup from "../elements/StyledRadioGroup"; +import QueryMatcher from "../../../autocomplete/QueryMatcher"; +import SearchBox from "../../structures/SearchBox"; +import AutoHideScrollbar from "../../structures/AutoHideScrollbar"; +import { Entry } from "../dialogs/AddExistingToSpaceDialog"; + +enum Target { + All = "All", + Specific = "Specific", + None = "None", +} + +interface ISpecificChildrenPickerProps { + filterPlaceholder: string; + rooms: Room[]; + selected: Set; + onChange(selected: boolean, room: Room): void; +} + +const SpecificChildrenPicker = ({ filterPlaceholder, rooms, selected, onChange }: ISpecificChildrenPickerProps) => { + const [query, setQuery] = useState(""); + const lcQuery = query.toLowerCase().trim(); + + const filteredRooms = useMemo(() => { + if (!lcQuery) { + return rooms; + } + + const matcher = new QueryMatcher(rooms, { + keys: ["name"], + funcs: [r => [r.getCanonicalAlias(), ...r.getAltAliases()].filter(Boolean)], + shouldMatchWordsOnly: false, + }); + + return matcher.match(lcQuery); + }, [rooms, lcQuery]); + + return
+ + + { filteredRooms.map(room => { + return { + onChange(checked, room); + }} + />; + }) } + { filteredRooms.length < 1 ? + { _t("No results") } + : undefined } + +
; +}; + +interface IProps { + space: Room; + spaceChildren: Room[]; + selected: Set; + noneLabel?: string; + allLabel: string; + specificLabel: string; + onChange(rooms: Room[]): void; +} + +const SpaceChildrenPicker = ({ + space, + spaceChildren, + selected, + onChange, + noneLabel, + allLabel, + specificLabel, +}: IProps) => { + const [state, setState] = useState(noneLabel ? Target.None : Target.All); + + useEffect(() => { + if (state === Target.All) { + onChange(spaceChildren); + } else { + onChange([]); + } + }, [onChange, state, spaceChildren]); + + return <> +
+ d.label)} + /> +
+ + { state === Target.Specific && ( + { + if (isSelected) { + onChange([room, ...selected]); + } else { + onChange([...selected].filter(r => r !== room)); + } + }} + /> + ) } + ; +}; + +export default SpaceChildrenPicker; diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 28d0b2914b..5195b08f56 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1018,6 +1018,8 @@ "Upload": "Upload", "Name": "Name", "Description": "Description", + "No results": "No results", + "Search %(spaceName)s": "Search %(spaceName)s", "Please enter a name for the space": "Please enter a name for the space", "Spaces are a new feature.": "Spaces are a new feature.", "Spaces feedback": "Spaces feedback", @@ -1847,6 +1849,8 @@ "Kick": "Kick", "Disinvite this user?": "Disinvite this user?", "Kick this user?": "Kick this user?", + "Kick them from everything I'm able to": "Kick them from everything I'm able to", + "Kick them from specific things I'm able to": "Kick them from specific things I'm able to", "Failed to kick": "Failed to kick", "No recent messages by %(user)s found": "No recent messages by %(user)s found", "Try scrolling up in the timeline to see if there are any earlier ones.": "Try scrolling up in the timeline to see if there are any earlier ones.", @@ -1860,6 +1864,10 @@ "Ban": "Ban", "Unban this user?": "Unban this user?", "Ban this user?": "Ban this user?", + "Unban them from everything I'm able to": "Unban them from everything I'm able to", + "Ban them from everything I'm able to": "Ban them from everything I'm able to", + "Unban them from specific things I'm able to": "Unban them from specific things I'm able to", + "Ban them from specific things I'm able to": "Ban them from specific things I'm able to", "Failed to ban user": "Failed to ban user", "Failed to mute user": "Failed to mute user", "Unmute": "Unmute", @@ -2050,7 +2058,6 @@ "Application window": "Application window", "Share content": "Share content", "Join": "Join", - "No results": "No results", "Please create a new issue on GitHub so that we can investigate this bug.": "Please create a new issue on GitHub so that we can investigate this bug.", "collapse": "collapse", "expand": "expand", @@ -2217,6 +2224,7 @@ "Confirm Removal": "Confirm Removal", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.", "Reason (optional)": "Reason (optional)", + "You’re not an admin of anything they’re a member of in , so banning won’t remove them from any rooms or spaces in .": "You’re not an admin of anything they’re a member of in , so banning won’t remove them from any rooms or spaces in .", "Clear all data in this session?": "Clear all data in this session?", "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.", "Clear all data": "Clear all data", @@ -2430,15 +2438,14 @@ "Clear cache and resync": "Clear cache and resync", "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!": "%(brand)s now uses 3-5x less memory, by only loading information about other users when needed. Please wait whilst we resynchronise with the server!", "Updating %(brand)s": "Updating %(brand)s", - "Don't leave any": "Don't leave any", - "Leave all rooms and spaces": "Leave all rooms and spaces", - "Leave specific rooms and spaces": "Leave specific rooms and spaces", - "Search %(spaceName)s": "Search %(spaceName)s", "You won't be able to rejoin unless you are re-invited.": "You won't be able to rejoin unless you are re-invited.", "You're the only admin of this space. Leaving it will mean no one has control over it.": "You're the only admin of this space. Leaving it will mean no one has control over it.", "You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.": "You're the only admin of some of the rooms or spaces you wish to leave. Leaving them will leave them without any admins.", "Leave %(spaceName)s": "Leave %(spaceName)s", "Are you sure you want to leave ?": "Are you sure you want to leave ?", + "Don't leave any": "Don't leave any", + "Leave all rooms and spaces": "Leave all rooms and spaces", + "Leave specific rooms and spaces": "Leave specific rooms and spaces", "Leave space": "Leave space", "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.": "Encrypted messages are secured with end-to-end encryption. Only you and the recipient(s) have the keys to read these messages.", "Start using Key Backup": "Start using Key Backup", diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 5bbae369e7..aba9883ae7 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -155,20 +155,28 @@ export const showCreateNewSubspace = (space: Room): void => { ); }; +export const bulkSpaceBehaviour = async ( + space: Room, + children: Room[], + fn: (room: Room) => Promise, +): Promise => { + const modal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner"); + try { + for (const room of children) { + await fn(room); + } + await fn(space); + } finally { + modal.close(); + } +}; + export const leaveSpace = (space: Room) => { Modal.createTrackedDialog("Leave Space", "", LeaveSpaceDialog, { space, onFinished: async (leave: boolean, rooms: Room[]) => { if (!leave) return; - const modal = Modal.createDialog(Spinner, null, "mx_Dialog_spinner"); - try { - for (const room of rooms) { - await leaveRoomBehaviour(room.roomId); - } - await leaveRoomBehaviour(space.roomId); - } finally { - modal.close(); - } + await bulkSpaceBehaviour(space, rooms, room => leaveRoomBehaviour(room.roomId)); dis.dispatch({ action: "after_leave_room", From d6159523373b4073cf77412d0dd85cae9c85bd64 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Fri, 17 Sep 2021 16:02:12 +0100 Subject: [PATCH 2/7] Add fallback warning --- .../views/dialogs/ConfirmSpaceUserActionDialog.tsx | 6 ++++++ src/components/views/right_panel/UserInfo.tsx | 13 +++++++++++++ src/i18n/strings/en_EN.json | 3 +++ 3 files changed, 22 insertions(+) diff --git a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx index 4059682ade..9e014b86fd 100644 --- a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx @@ -27,6 +27,7 @@ interface IProps extends Omit = ({ allLabel, specificLabel, noneLabel, + warningMessage, onFinished, ...props }) => { @@ -59,6 +61,10 @@ const ConfirmSpaceUserActionDialog: React.FC = ({ SpaceName: () => { space.name }, }) }
; + } else if (warningMessage) { + warning =
+ { warningMessage } +
; } return ( diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 3a12c6478f..9b394fea39 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -561,6 +561,10 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + + "they'll still be able to access it after you kick them.", {}, { + SpaceName: () => { room.name }, + }), }, room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); @@ -710,6 +714,15 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + + "they won’t be unbanned from it.", {}, { + SpaceName: () => { room.name }, + }) + : _t("If you're not an admin of a room or space in , " + + "they'll still be able to access it after you ban them.", {}, { + SpaceName: () => { room.name }, + }), }, room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 5195b08f56..d0bb4366fd 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1851,6 +1851,7 @@ "Kick this user?": "Kick this user?", "Kick them from everything I'm able to": "Kick them from everything I'm able to", "Kick them from specific things I'm able to": "Kick them from specific things I'm able to", + "If you're not an admin of a room or space in , they'll still be able to access it after you kick them.": "If you're not an admin of a room or space in , they'll still be able to access it after you kick them.", "Failed to kick": "Failed to kick", "No recent messages by %(user)s found": "No recent messages by %(user)s found", "Try scrolling up in the timeline to see if there are any earlier ones.": "Try scrolling up in the timeline to see if there are any earlier ones.", @@ -1868,6 +1869,8 @@ "Ban them from everything I'm able to": "Ban them from everything I'm able to", "Unban them from specific things I'm able to": "Unban them from specific things I'm able to", "Ban them from specific things I'm able to": "Ban them from specific things I'm able to", + "If you’re not an admin of a room or space in , they won’t be unbanned from it.": "If you’re not an admin of a room or space in , they won’t be unbanned from it.", + "If you're not an admin of a room or space in , they'll still be able to access it after you ban them.": "If you're not an admin of a room or space in , they'll still be able to access it after you ban them.", "Failed to ban user": "Failed to ban user", "Failed to mute user": "Failed to mute user", "Unmute": "Unmute", From 2ac2358d9354ce9c1825431d92cb0fddb5e3961f Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 28 Sep 2021 16:22:05 +0100 Subject: [PATCH 3/7] Fix avatar getting chopped off --- res/css/views/dialogs/_ConfirmUserActionDialog.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/res/css/views/dialogs/_ConfirmUserActionDialog.scss b/res/css/views/dialogs/_ConfirmUserActionDialog.scss index 777c9fdfd9..fd286720c4 100644 --- a/res/css/views/dialogs/_ConfirmUserActionDialog.scss +++ b/res/css/views/dialogs/_ConfirmUserActionDialog.scss @@ -22,10 +22,10 @@ limitations under the License. .mx_ConfirmUserActionDialog_avatar { float: left; margin-right: 20px; - margin-top: -2px; } .mx_ConfirmUserActionDialog_name { + padding-top: 2px; font-size: $font-18px; } From 0f8069ac35521e90b3c412606a68a1452e4d5ce4 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 28 Sep 2021 16:22:27 +0100 Subject: [PATCH 4/7] Switch ConfirmUserActionDialog over to using a Field --- .../dialogs/_ConfirmUserActionDialog.scss | 12 ----- .../views/dialogs/ConfirmUserActionDialog.tsx | 50 +++++++++++++------ 2 files changed, 34 insertions(+), 28 deletions(-) diff --git a/res/css/views/dialogs/_ConfirmUserActionDialog.scss b/res/css/views/dialogs/_ConfirmUserActionDialog.scss index fd286720c4..cdcb2b4587 100644 --- a/res/css/views/dialogs/_ConfirmUserActionDialog.scss +++ b/res/css/views/dialogs/_ConfirmUserActionDialog.scss @@ -37,16 +37,4 @@ limitations under the License. font-size: $font-14px; color: $primary-content; background-color: $background; - - border-radius: 3px; - border: solid 1px $input-border-color; - line-height: $font-36px; - padding-left: 16px; - padding-right: 16px; - padding-top: 1px; - padding-bottom: 1px; - - margin-bottom: 24px; - - width: 90%; } diff --git a/src/components/views/dialogs/ConfirmUserActionDialog.tsx b/src/components/views/dialogs/ConfirmUserActionDialog.tsx index 7468f400c6..2f4e511675 100644 --- a/src/components/views/dialogs/ConfirmUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmUserActionDialog.tsx @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React, { ReactNode } from 'react'; +import React, { ChangeEvent, ReactNode } from 'react'; import { MatrixClient } from 'matrix-js-sdk/src/client'; import { RoomMember } from "matrix-js-sdk/src/models/room-member"; import classNames from "classnames"; @@ -27,6 +27,7 @@ import MemberAvatar from '../avatars/MemberAvatar'; import BaseAvatar from '../avatars/BaseAvatar'; import BaseDialog from "./BaseDialog"; import DialogButtons from "../elements/DialogButtons"; +import Field from '../elements/Field'; interface IProps { // matrix-js-sdk (room) member object. Supply either this or 'groupMember' @@ -48,6 +49,10 @@ interface IProps { onFinished: (success: boolean, reason?: string) => void; } +interface IState { + reason: string; +} + /* * A dialog for confirming an operation on another user. * Takes a user ID and a verb, displays the target user prominently @@ -57,37 +62,50 @@ interface IProps { * Also tweaks the style for 'dangerous' actions (albeit only with colour) */ @replaceableComponent("views.dialogs.ConfirmUserActionDialog") -export default class ConfirmUserActionDialog extends React.Component { - private reasonField: React.RefObject = React.createRef(); - +export default class ConfirmUserActionDialog extends React.Component { static defaultProps = { danger: false, askReason: false, }; - public onOk = (): void => { - this.props.onFinished(true, this.reasonField.current?.value); + constructor(props: IProps) { + super(props); + + this.state = { + reason: "", + }; + } + + private onOk = (): void => { + this.props.onFinished(true, this.state.reason); }; - public onCancel = (): void => { + private onCancel = (): void => { this.props.onFinished(false); }; + private onReasonChange = (ev: ChangeEvent) => { + this.setState({ + reason: ev.target.value, + }); + }; + public render() { const confirmButtonClass = this.props.danger ? 'danger' : ''; let reasonBox; if (this.props.askReason) { reasonBox = ( -
-
- -
-
+
+ + ); } From 886f8d31fb523a9b42db07fcaae03a7795c071c6 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 28 Sep 2021 16:23:42 +0100 Subject: [PATCH 5/7] Iterate title on confirm space action dialog --- src/components/views/right_panel/UserInfo.tsx | 34 +++++++++++++++++-- src/i18n/strings/en_EN.json | 10 ++++-- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 091581a6f8..605b47f027 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -541,6 +541,21 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit { + let title: string; + if (room.isSpaceRoom()) { + if (member.membership === "invite") { + title = _t("Disinvite this user from %(spaceName)s?", { spaceName: room.name }); + } else { + title = _t("Kick this user from %(spaceName)s?", { spaceName: room.name }); + } + } else { + if (member.membership === "invite") { + title = _t("Disinvite this user?"); + } else { + title = _t("Kick this user?"); + } + } + const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onKick', @@ -548,7 +563,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit { + let title: string; + if (room.isSpaceRoom()) { + if (isBanned) { + title = _t("Unban this user from %(spaceName)s?", { spaceName: room.name }); + } else { + title = _t("Ban this user from %(spaceName)s?", { spaceName: room.name }); + } + } else { + if (isBanned) { + title = _t("Unban this user?"); + } else { + title = _t("Ban this user?"); + } + } + const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onBanOrUnban', @@ -688,7 +718,7 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit, they'll still be able to access it after you kick them.": "If you're not an admin of a room or space in , they'll still be able to access it after you kick them.", @@ -1862,9 +1864,11 @@ "Remove %(count)s messages|other": "Remove %(count)s messages", "Remove %(count)s messages|one": "Remove 1 message", "Remove recent messages": "Remove recent messages", - "Ban": "Ban", + "Unban this user from %(spaceName)s?": "Unban this user from %(spaceName)s?", + "Ban this user from %(spaceName)s?": "Ban this user from %(spaceName)s?", "Unban this user?": "Unban this user?", "Ban this user?": "Ban this user?", + "Ban": "Ban", "Unban them from everything I'm able to": "Unban them from everything I'm able to", "Ban them from everything I'm able to": "Ban them from everything I'm able to", "Unban them from specific things I'm able to": "Unban them from specific things I'm able to", From 0697470cc8141b9784d9738cae54800c691a35e1 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Wed, 29 Sep 2021 16:05:03 +0100 Subject: [PATCH 6/7] Update copy --- .../dialogs/ConfirmSpaceUserActionDialog.tsx | 11 +---- src/components/views/right_panel/UserInfo.tsx | 44 ++++--------------- src/i18n/strings/en_EN.json | 18 +++----- 3 files changed, 17 insertions(+), 56 deletions(-) diff --git a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx index 9e014b86fd..1c5dd3fafa 100644 --- a/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx +++ b/src/components/views/dialogs/ConfirmSpaceUserActionDialog.tsx @@ -15,11 +15,11 @@ limitations under the License. */ import React, { ComponentProps, useMemo, useState } from 'react'; + import ConfirmUserActionDialog from "./ConfirmUserActionDialog"; import SpaceStore from "../../../stores/SpaceStore"; import { Room } from "matrix-js-sdk/src/models/room"; import SpaceChildrenPicker from "../spaces/SpaceChildrenPicker"; -import { _t } from '../../../languageHandler'; type BaseProps = ComponentProps; interface IProps extends Omit { @@ -54,14 +54,7 @@ const ConfirmSpaceUserActionDialog: React.FC = ({ const selectedRooms = useMemo(() => new Set(roomsToLeave), [roomsToLeave]); let warning: JSX.Element; - if (!spaceChildren.length) { - warning =
- { _t("You’re not an admin of anything they’re a member of in , " + - "so banning won’t remove them from any rooms or spaces in .", {}, { - SpaceName: () => { space.name }, - }) } -
; - } else if (warningMessage) { + if (warningMessage) { warning =
{ warningMessage }
; diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index 605b47f027..edb78fc167 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -541,21 +541,6 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit { - let title: string; - if (room.isSpaceRoom()) { - if (member.membership === "invite") { - title = _t("Disinvite this user from %(spaceName)s?", { spaceName: room.name }); - } else { - title = _t("Kick this user from %(spaceName)s?", { spaceName: room.name }); - } - } else { - if (member.membership === "invite") { - title = _t("Disinvite this user?"); - } else { - title = _t("Kick this user?"); - } - } - const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onKick', @@ -563,7 +548,9 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + - "they'll still be able to access it after you kick them.", {}, { + "they'll still be able to access whatever you're not an admin of.", {}, { SpaceName: () => { room.name }, }), }, @@ -696,21 +683,6 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit { - let title: string; - if (room.isSpaceRoom()) { - if (isBanned) { - title = _t("Unban this user from %(spaceName)s?", { spaceName: room.name }); - } else { - title = _t("Ban this user from %(spaceName)s?", { spaceName: room.name }); - } - } else { - if (isBanned) { - title = _t("Unban this user?"); - } else { - title = _t("Ban this user?"); - } - } - const { finished } = Modal.createTrackedDialog( 'Confirm User Action Dialog', 'onBanOrUnban', @@ -718,7 +690,9 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + - "they won’t be unbanned from it.", {}, { + "they still won't be able to access whatever you're not an admin of.", {}, { SpaceName: () => { room.name }, }) : _t("If you're not an admin of a room or space in , " + - "they'll still be able to access it after you ban them.", {}, { + "they'll still be able to access whatever you're not an admin of.", {}, { SpaceName: () => { room.name }, }), }, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index e986139eb8..07757b9c8b 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1845,15 +1845,13 @@ "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the space it will be impossible to regain privileges.": "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the space it will be impossible to regain privileges.", "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.": "You will not be able to undo this change as you are demoting yourself, if you are the last privileged user in the room it will be impossible to regain privileges.", "Demote": "Demote", - "Disinvite this user from %(spaceName)s?": "Disinvite this user from %(spaceName)s?", - "Kick this user from %(spaceName)s?": "Kick this user from %(spaceName)s?", - "Disinvite this user?": "Disinvite this user?", - "Kick this user?": "Kick this user?", "Disinvite": "Disinvite", "Kick": "Kick", + "Disinvite from %(roomName)s": "Disinvite from %(roomName)s", + "Kick from %(roomName)s": "Kick from %(roomName)s", "Kick them from everything I'm able to": "Kick them from everything I'm able to", "Kick them from specific things I'm able to": "Kick them from specific things I'm able to", - "If you're not an admin of a room or space in , they'll still be able to access it after you kick them.": "If you're not an admin of a room or space in , they'll still be able to access it after you kick them.", + "If you're not an admin of a room or space in , they'll still be able to access whatever you're not an admin of.": "If you're not an admin of a room or space in , they'll still be able to access whatever you're not an admin of.", "Failed to kick": "Failed to kick", "No recent messages by %(user)s found": "No recent messages by %(user)s found", "Try scrolling up in the timeline to see if there are any earlier ones.": "Try scrolling up in the timeline to see if there are any earlier ones.", @@ -1864,17 +1862,14 @@ "Remove %(count)s messages|other": "Remove %(count)s messages", "Remove %(count)s messages|one": "Remove 1 message", "Remove recent messages": "Remove recent messages", - "Unban this user from %(spaceName)s?": "Unban this user from %(spaceName)s?", - "Ban this user from %(spaceName)s?": "Ban this user from %(spaceName)s?", - "Unban this user?": "Unban this user?", - "Ban this user?": "Ban this user?", "Ban": "Ban", + "Unban from %(roomName)s": "Unban from %(roomName)s", + "Ban from %(roomName)s": "Ban from %(roomName)s", "Unban them from everything I'm able to": "Unban them from everything I'm able to", "Ban them from everything I'm able to": "Ban them from everything I'm able to", "Unban them from specific things I'm able to": "Unban them from specific things I'm able to", "Ban them from specific things I'm able to": "Ban them from specific things I'm able to", - "If you’re not an admin of a room or space in , they won’t be unbanned from it.": "If you’re not an admin of a room or space in , they won’t be unbanned from it.", - "If you're not an admin of a room or space in , they'll still be able to access it after you ban them.": "If you're not an admin of a room or space in , they'll still be able to access it after you ban them.", + "If you’re not an admin of a room or space in , they still won't be able to access whatever you're not an admin of.": "If you’re not an admin of a room or space in , they still won't be able to access whatever you're not an admin of.", "Failed to ban user": "Failed to ban user", "Failed to mute user": "Failed to mute user", "Unmute": "Unmute", @@ -2233,7 +2228,6 @@ "Confirm Removal": "Confirm Removal", "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.", "Reason (optional)": "Reason (optional)", - "You’re not an admin of anything they’re a member of in , so banning won’t remove them from any rooms or spaces in .": "You’re not an admin of anything they’re a member of in , so banning won’t remove them from any rooms or spaces in .", "Clear all data in this session?": "Clear all data in this session?", "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.": "Clearing all data from this session is permanent. Encrypted messages will be lost unless their keys have been backed up.", "Clear all data": "Clear all data", From 6454aa7a95ec4d387b3bd84aa6d3ac98ca80b073 Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Thu, 30 Sep 2021 11:46:05 +0100 Subject: [PATCH 7/7] Update copy --- src/components/views/right_panel/UserInfo.tsx | 15 +++------------ src/i18n/strings/en_EN.json | 4 ++-- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/src/components/views/right_panel/UserInfo.tsx b/src/components/views/right_panel/UserInfo.tsx index edb78fc167..ee81664a47 100644 --- a/src/components/views/right_panel/UserInfo.tsx +++ b/src/components/views/right_panel/UserInfo.tsx @@ -565,10 +565,7 @@ const RoomKickButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + - "they'll still be able to access whatever you're not an admin of.", {}, { - SpaceName: () => { room.name }, - }), + warningMessage: _t("They'll still be able to access whatever you're not an admin of."), }, room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); @@ -721,14 +718,8 @@ const BanToggleButton = ({ room, member, startUpdating, stopUpdating }: Omit, " + - "they still won't be able to access whatever you're not an admin of.", {}, { - SpaceName: () => { room.name }, - }) - : _t("If you're not an admin of a room or space in , " + - "they'll still be able to access whatever you're not an admin of.", {}, { - SpaceName: () => { room.name }, - }), + ? _t("They won't be able to access whatever you're not an admin of.") + : _t("They'll still be able to access whatever you're not an admin of."), }, room.isSpaceRoom() ? "mx_ConfirmSpaceUserActionDialog_wrapper" : undefined, ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 07757b9c8b..01189adbe1 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -1851,7 +1851,7 @@ "Kick from %(roomName)s": "Kick from %(roomName)s", "Kick them from everything I'm able to": "Kick them from everything I'm able to", "Kick them from specific things I'm able to": "Kick them from specific things I'm able to", - "If you're not an admin of a room or space in , they'll still be able to access whatever you're not an admin of.": "If you're not an admin of a room or space in , they'll still be able to access whatever you're not an admin of.", + "They'll still be able to access whatever you're not an admin of.": "They'll still be able to access whatever you're not an admin of.", "Failed to kick": "Failed to kick", "No recent messages by %(user)s found": "No recent messages by %(user)s found", "Try scrolling up in the timeline to see if there are any earlier ones.": "Try scrolling up in the timeline to see if there are any earlier ones.", @@ -1869,7 +1869,7 @@ "Ban them from everything I'm able to": "Ban them from everything I'm able to", "Unban them from specific things I'm able to": "Unban them from specific things I'm able to", "Ban them from specific things I'm able to": "Ban them from specific things I'm able to", - "If you’re not an admin of a room or space in , they still won't be able to access whatever you're not an admin of.": "If you’re not an admin of a room or space in , they still won't be able to access whatever you're not an admin of.", + "They won't be able to access whatever you're not an admin of.": "They won't be able to access whatever you're not an admin of.", "Failed to ban user": "Failed to ban user", "Failed to mute user": "Failed to mute user", "Unmute": "Unmute",