From eb9f4c609a22c8493c9021d20958ccdf4286529c Mon Sep 17 00:00:00 2001 From: Michael Telatynski <7t3chguy@gmail.com> Date: Tue, 6 Jul 2021 10:10:47 +0100 Subject: [PATCH] Make CreateRoomDialog capable of creating restricted rooms in spaces --- res/css/views/dialogs/_CreateRoomDialog.scss | 18 ++- .../views/dialogs/CreateRoomDialog.tsx | 117 ++++++++++++++---- src/createRoom.ts | 6 +- src/i18n/strings/en_EN.json | 8 +- 4 files changed, 111 insertions(+), 38 deletions(-) diff --git a/res/css/views/dialogs/_CreateRoomDialog.scss b/res/css/views/dialogs/_CreateRoomDialog.scss index 2678f7b4ad..adba58cbb9 100644 --- a/res/css/views/dialogs/_CreateRoomDialog.scss +++ b/res/css/views/dialogs/_CreateRoomDialog.scss @@ -65,7 +65,7 @@ limitations under the License. .mx_CreateRoomDialog_aliasContainer { display: flex; // put margin on container so it can collapse with siblings - margin: 10px 0; + margin: 24px 0 10px; .mx_RoomAliasField { margin: 0; @@ -101,10 +101,6 @@ limitations under the License. margin-left: 30px; } - .mx_CreateRoomDialog_topic { - margin-bottom: 36px; - } - .mx_Dialog_content > .mx_SettingsFlag { margin-top: 24px; } @@ -113,5 +109,17 @@ limitations under the License. margin: 0 85px 0 0; font-size: $font-12px; } + + .mx_Dropdown { + margin-bottom: 8px; + font-weight: normal; + font-family: $font-family; + font-size: $font-14px; + color: $primary-fg-color; + + .mx_Dropdown_input { + border: 1px solid $input-border-color; + } + } } diff --git a/src/components/views/dialogs/CreateRoomDialog.tsx b/src/components/views/dialogs/CreateRoomDialog.tsx index b5c0096771..eecddf7f31 100644 --- a/src/components/views/dialogs/CreateRoomDialog.tsx +++ b/src/components/views/dialogs/CreateRoomDialog.tsx @@ -17,6 +17,7 @@ limitations under the License. import React, { ChangeEvent, createRef, KeyboardEvent, SyntheticEvent } from "react"; import { Room } from "matrix-js-sdk/src/models/room"; +import { JoinRule, Preset, Visibility } from "matrix-js-sdk/src/@types/partials"; import SdkConfig from '../../../SdkConfig'; import withValidation, { IFieldState } from '../elements/Validation'; @@ -31,7 +32,8 @@ import RoomAliasField from "../elements/RoomAliasField"; import LabelledToggleSwitch from "../elements/LabelledToggleSwitch"; import DialogButtons from "../elements/DialogButtons"; import BaseDialog from "../dialogs/BaseDialog"; -import { Preset, Visibility } from "matrix-js-sdk/src/@types/partials"; +import Dropdown from "../elements/Dropdown"; +import SpaceStore from "../../../stores/SpaceStore"; interface IProps { defaultPublic?: boolean; @@ -41,7 +43,7 @@ interface IProps { } interface IState { - isPublic: boolean; + joinRule: JoinRule; isEncrypted: boolean; name: string; topic: string; @@ -54,15 +56,25 @@ interface IState { @replaceableComponent("views.dialogs.CreateRoomDialog") export default class CreateRoomDialog extends React.Component { + private readonly supportsRestricted: boolean; private nameField = createRef(); private aliasField = createRef(); constructor(props) { super(props); + this.supportsRestricted = this.props.parentSpace && !!SpaceStore.instance.restrictedJoinRuleSupport?.preferred; + + let joinRule = JoinRule.Invite; + if (this.props.defaultPublic) { + joinRule = JoinRule.Public; + } else if (this.supportsRestricted) { + joinRule = JoinRule.Restricted; + } + const config = SdkConfig.get(); this.state = { - isPublic: this.props.defaultPublic || false, + joinRule, isEncrypted: privateShouldBeEncrypted(), name: this.props.defaultName || "", topic: "", @@ -81,7 +93,7 @@ export default class CreateRoomDialog extends React.Component { const opts: IOpts = {}; const createOpts: IOpts["createOpts"] = opts.createOpts = {}; createOpts.name = this.state.name; - if (this.state.isPublic) { + if (this.state.joinRule === JoinRule.Public) { createOpts.visibility = Visibility.Public; createOpts.preset = Preset.PublicChat; opts.guestAccess = false; @@ -95,7 +107,7 @@ export default class CreateRoomDialog extends React.Component { createOpts.creation_content = { 'm.federate': false }; } - if (!this.state.isPublic) { + if (this.state.joinRule !== JoinRule.Public) { if (this.state.canChangeEncryption) { opts.encryption = this.state.isEncrypted; } else { @@ -109,8 +121,9 @@ export default class CreateRoomDialog extends React.Component { opts.associatedWithCommunity = CommunityPrototypeStore.instance.getSelectedCommunityId(); } - if (this.props.parentSpace) { + if (this.props.parentSpace && this.state.joinRule === JoinRule.Restricted) { opts.parentSpace = this.props.parentSpace; + opts.joinRule = JoinRule.Restricted; } return opts; @@ -172,8 +185,8 @@ export default class CreateRoomDialog extends React.Component { this.setState({ topic: ev.target.value }); }; - private onPublicChange = (isPublic: boolean) => { - this.setState({ isPublic }); + private onJoinRuleChange = (joinRule: JoinRule) => { + this.setState({ joinRule }); }; private onEncryptedChange = (isEncrypted: boolean) => { @@ -210,7 +223,7 @@ export default class CreateRoomDialog extends React.Component { render() { let aliasField; - if (this.state.isPublic) { + if (this.state.joinRule === JoinRule.Public) { const domain = MatrixClientPeg.get().getDomain(); aliasField = (
@@ -224,19 +237,46 @@ export default class CreateRoomDialog extends React.Component { ); } - let publicPrivateLabel =

{_t( - "Private rooms can be found and joined by invitation only. Public rooms can be " + - "found and joined by anyone.", - )}

; + let publicPrivateLabel: JSX.Element; if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { - publicPrivateLabel =

{_t( - "Private rooms can be found and joined by invitation only. Public rooms can be " + - "found and joined by anyone in this community.", - )}

; + publicPrivateLabel =

+ { _t( + "Private rooms can be found and joined by invitation only. Public rooms can be " + + "found and joined by anyone in this community.", + ) } +

; + } else if (this.state.joinRule === JoinRule.Restricted) { + publicPrivateLabel =

+ { _t( + "Everyone in will be able to find and join this room.", {}, { + SpaceName: () => this.props.parentSpace.name, + }, + ) } +   + { _t("You can change this at any time from room settings.") } +

; + } else if (this.state.joinRule === JoinRule.Public) { + publicPrivateLabel =

+ { _t( + "Anyone will be able to find and join this room, not just members of .", {}, { + SpaceName: () => this.props.parentSpace.name, + }, + ) } +   + { _t("You can change this at any time from room settings.") } +

; + } else if (this.state.joinRule === JoinRule.Invite) { + publicPrivateLabel =

+ { _t( + "Only people invited will be able to find and join this room.", + ) } +   + { _t("You can change this at any time from room settings.") } +

; } let e2eeSection; - if (!this.state.isPublic) { + if (this.state.joinRule !== JoinRule.Public) { let microcopy; if (privateShouldBeEncrypted()) { if (this.state.canChangeEncryption) { @@ -273,15 +313,31 @@ export default class CreateRoomDialog extends React.Component { ); } - let title = this.state.isPublic ? _t('Create a public room') : _t('Create a private room'); + let title = _t("Create a room"); if (CommunityPrototypeStore.instance.getSelectedCommunityId()) { const name = CommunityPrototypeStore.instance.getSelectedCommunityName(); title = _t("Create a room in %(communityName)s", { communityName: name }); + } else if (!this.props.parentSpace) { + title = this.state.joinRule === JoinRule.Public ? _t('Create a public room') : _t('Create a private room'); } + + const options = [ +
+ { _t("Private room (invite only)") } +
, +
+ { _t("Public room") } +
, + ]; + + if (this.supportsRestricted) { + options.unshift(
+ { _t("Visible to space members") } +
); + } + return ( - +
{ value={this.state.topic} className="mx_CreateRoomDialog_topic" /> - + + + { options } + + { publicPrivateLabel } { e2eeSection } { aliasField } diff --git a/src/createRoom.ts b/src/createRoom.ts index 0a88e2cef7..e809f5ff0a 100644 --- a/src/createRoom.ts +++ b/src/createRoom.ts @@ -153,10 +153,8 @@ export default async function createRoom(opts: IOpts): Promise { }); if (opts.joinRule === JoinRule.Restricted) { - const serverCapabilities = await client.getCapabilities(); - const roomCapabilities = serverCapabilities?.["m.room_versions"]?.["org.matrix.msc3244.room_capabilities"]; - if (roomCapabilities?.["restricted"]?.preferred) { - opts.createOpts.room_version = roomCapabilities?.["restricted"].preferred; + if (SpaceStore.instance.restrictedJoinRuleSupport?.preferred) { + opts.createOpts.room_version = SpaceStore.instance.restrictedJoinRuleSupport.preferred; opts.createOpts.initial_state.push({ type: EventType.RoomJoinRules, diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 12b0c40d75..c7992d93c3 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -2200,11 +2200,15 @@ "Enable end-to-end encryption": "Enable end-to-end encryption", "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.": "You might enable this if the room will only be used for collaborating with internal teams on your homeserver. This cannot be changed later.", "You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.": "You might disable this if the room will be used for collaborating with external teams who have their own homeserver. This cannot be changed later.", + "Create a room": "Create a room", + "Create a room in %(communityName)s": "Create a room in %(communityName)s", "Create a public room": "Create a public room", "Create a private room": "Create a private room", - "Create a room in %(communityName)s": "Create a room in %(communityName)s", + "Private room (invite only)": "Private room (invite only)", + "Public room": "Public room", + "Visible to space members": "Visible to space members", "Topic (optional)": "Topic (optional)", - "Make this room public": "Make this room public", + "Room visibility": "Room visibility", "Block anyone not part of %(serverName)s from ever joining this room.": "Block anyone not part of %(serverName)s from ever joining this room.", "Create Room": "Create Room", "Sign out": "Sign out",