diff --git a/src/components/structures/SpaceRoomView.tsx b/src/components/structures/SpaceRoomView.tsx index 3880e014aa..cb440ca576 100644 --- a/src/components/structures/SpaceRoomView.tsx +++ b/src/components/structures/SpaceRoomView.tsx @@ -307,7 +307,6 @@ const SpacePreview = ({ space, onJoinButtonClicked, onRejectButtonClicked }) => }; const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { - const cli = useContext(MatrixClientContext); const [menuDisplayed, handle, openMenu, closeMenu] = useContextMenu(); let contextMenu; @@ -330,7 +329,7 @@ const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { e.stopPropagation(); closeMenu(); - if (await showCreateNewRoom(cli, space)) { + if (await showCreateNewRoom(space)) { onNewRoomAdded(); } }} @@ -343,7 +342,7 @@ const SpaceLandingAddButton = ({ space, onNewRoomAdded }) => { e.stopPropagation(); closeMenu(); - const [added] = await showAddExistingRooms(cli, space); + const [added] = await showAddExistingRooms(space); if (added) { onNewRoomAdded(); } @@ -397,11 +396,11 @@ const SpaceLanding = ({ space }) => { } let settingsButton; - if (shouldShowSpaceSettings(cli, space)) { + if (shouldShowSpaceSettings(space)) { settingsButton = { - showSpaceSettings(cli, space); + showSpaceSettings(space); }} title={_t("Settings")} />; diff --git a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx index c09097c4b4..adb36485a7 100644 --- a/src/components/views/dialogs/AddExistingToSpaceDialog.tsx +++ b/src/components/views/dialogs/AddExistingToSpaceDialog.tsx @@ -17,7 +17,6 @@ limitations under the License. import React, { ReactNode, useContext, useMemo, useState } from "react"; import classNames from "classnames"; import { Room } from "matrix-js-sdk/src/models/room"; -import { MatrixClient } from "matrix-js-sdk/src/client"; import { _t } from '../../../languageHandler'; import { IDialogProps } from "./IDialogProps"; @@ -44,9 +43,8 @@ import EntityTile from "../rooms/EntityTile"; import BaseAvatar from "../avatars/BaseAvatar"; interface IProps extends IDialogProps { - matrixClient: MatrixClient; space: Room; - onCreateRoomClick(cli: MatrixClient, space: Room): void; + onCreateRoomClick(space: Room): void; } const Entry = ({ room, checked, onChange }) => { @@ -295,7 +293,7 @@ export const AddExistingToSpace: React.FC = ({ ; }; -const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, onCreateRoomClick, onFinished }) => { +const AddExistingToSpaceDialog: React.FC = ({ space, onCreateRoomClick, onFinished }) => { const [selectedSpace, setSelectedSpace] = useState(space); const existingSubspaces = SpaceStore.instance.getChildSpaces(space.roomId); @@ -344,13 +342,13 @@ const AddExistingToSpaceDialog: React.FC = ({ matrixClient: cli, space, onFinished={onFinished} fixedWidth={false} > - +
{ _t("Want to add a new room instead?") }
- onCreateRoomClick(cli, space)} kind="link"> + onCreateRoomClick(space)} kind="link"> { _t("Create a new room") } } diff --git a/src/components/views/dialogs/InfoDialog.js b/src/components/views/dialogs/InfoDialog.tsx similarity index 77% rename from src/components/views/dialogs/InfoDialog.js rename to src/components/views/dialogs/InfoDialog.tsx index 8207d334d3..8570f46d27 100644 --- a/src/components/views/dialogs/InfoDialog.js +++ b/src/components/views/dialogs/InfoDialog.tsx @@ -1,7 +1,6 @@ /* -Copyright 2015, 2016 OpenMarket Ltd -Copyright 2017 New Vector Ltd. Copyright 2019 Bastian Masanek, Noxware IT +Copyright 2015 - 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. @@ -16,31 +15,31 @@ See the License for the specific language governing permissions and limitations under the License. */ -import React from 'react'; -import PropTypes from 'prop-types'; -import * as sdk from '../../../index'; -import { _t } from '../../../languageHandler'; +import React, { ReactNode, KeyboardEvent } from 'react'; import classNames from "classnames"; -export default class InfoDialog extends React.Component { - static propTypes = { - className: PropTypes.string, - title: PropTypes.string, - description: PropTypes.node, - button: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]), - onFinished: PropTypes.func, - hasCloseButton: PropTypes.bool, - onKeyDown: PropTypes.func, - fixedWidth: PropTypes.bool, - }; +import { _t } from '../../../languageHandler'; +import * as sdk from '../../../index'; +import { IDialogProps } from "./IDialogProps"; +interface IProps extends IDialogProps { + title?: string; + description?: ReactNode; + className?: string; + button?: boolean | string; + hasCloseButton?: boolean; + fixedWidth?: boolean; + onKeyDown?(event: KeyboardEvent): void; +} + +export default class InfoDialog extends React.Component { static defaultProps = { title: '', description: '', hasCloseButton: false, }; - onFinished = () => { + private onFinished = () => { this.props.onFinished(); }; diff --git a/src/components/views/rooms/RoomList.tsx b/src/components/views/rooms/RoomList.tsx index c94256800d..5c683711fc 100644 --- a/src/components/views/rooms/RoomList.tsx +++ b/src/components/views/rooms/RoomList.tsx @@ -140,7 +140,7 @@ const TAG_AESTHETICS: ITagAestheticsMap = { e.preventDefault(); e.stopPropagation(); onFinished(); - showCreateNewRoom(MatrixClientPeg.get(), SpaceStore.instance.activeSpace); + showCreateNewRoom(SpaceStore.instance.activeSpace); }} disabled={!canAddRooms} tooltip={canAddRooms ? undefined @@ -153,7 +153,7 @@ const TAG_AESTHETICS: ITagAestheticsMap = { e.preventDefault(); e.stopPropagation(); onFinished(); - showAddExistingRooms(MatrixClientPeg.get(), SpaceStore.instance.activeSpace); + showAddExistingRooms(SpaceStore.instance.activeSpace); }} disabled={!canAddRooms} tooltip={canAddRooms ? undefined diff --git a/src/components/views/spaces/SpaceTreeLevel.tsx b/src/components/views/spaces/SpaceTreeLevel.tsx index 486a988b93..908506aa3a 100644 --- a/src/components/views/spaces/SpaceTreeLevel.tsx +++ b/src/components/views/spaces/SpaceTreeLevel.tsx @@ -203,7 +203,7 @@ export class SpaceItem extends React.PureComponent { ev.preventDefault(); ev.stopPropagation(); - showSpaceSettings(this.context, this.props.space); + showSpaceSettings(this.props.space); this.setState({ contextMenuPosition: null }); // also close the menu }; @@ -222,7 +222,7 @@ export class SpaceItem extends React.PureComponent { ev.preventDefault(); ev.stopPropagation(); - showCreateNewRoom(this.context, this.props.space); + showCreateNewRoom(this.props.space); this.setState({ contextMenuPosition: null }); // also close the menu }; @@ -230,7 +230,7 @@ export class SpaceItem extends React.PureComponent { ev.preventDefault(); ev.stopPropagation(); - showAddExistingRooms(this.context, this.props.space); + showAddExistingRooms(this.props.space); this.setState({ contextMenuPosition: null }); // also close the menu }; @@ -285,7 +285,7 @@ export class SpaceItem extends React.PureComponent { let settingsOption; let leaveSection; - if (shouldShowSpaceSettings(this.context, this.props.space)) { + if (shouldShowSpaceSettings(this.props.space)) { settingsOption = ( { window.localStorage.removeItem(ACTIVE_SPACE_LS_KEY); } + // New in Spaces beta toast for Restricted Join Rule + (async () => { + const lsKey = "mx_SpaceBeta_restrictedJoinRuleToastSeen"; + if (contextSwitch && space?.getJoinRule() === JoinRule.Invite && shouldShowSpaceSettings(space) && + space.getJoinedMemberCount() > 1 && !localStorage.getItem(lsKey) /*&& + (await this.matrixClient.getCapabilities()) + ?.["m.room_versions"]?.["org.matrix.msc3244.room_capabilities"]?.["restricted"]?.preferred*/ + ) { + const toastKey = "restrictedjoinrule"; + ToastStore.sharedInstance().addOrReplaceToast({ + key: toastKey, + title: _t("New in the Spaces beta"), + props: { + description: _t("Help people in spaces to find and join private rooms"), + acceptLabel: _t("Learn more"), + onAccept: () => { + localStorage.setItem(lsKey, "true"); + ToastStore.sharedInstance().dismissToast(toastKey); + + Modal.createTrackedDialog("New in the Spaces beta", "restricted join rule", InfoDialog, { + title: _t("Help space members find private rooms"), + description: <> +

{ _t("To help space members find and join a private room, " + + "go to that room's Security & Privacy settings.") }

+ + { /* Reuses classes from TabbedView for simplicity, non-interactive */ } +
+
+ + { _t("General") } +
+
+ + { _t("Security & Privacy") } +
+
+ + { _t("Roles & Permissions") } +
+
+ +

{ _t("This make it easy for rooms to stay private to a space, " + + "while letting people in the space find and join them. " + + "All new rooms in a space will have this option available.")}

+ , + button: _t("OK"), + hasCloseButton: false, + fixedWidth: true, + }); + }, + rejectLabel: _t("Skip"), + onReject: () => { + localStorage.setItem(lsKey, "true"); + ToastStore.sharedInstance().dismissToast(toastKey); + }, + }, + component: GenericToast, + priority: 35, + }); + } + })().then(); + if (space) { const suggestedRooms = await this.fetchSuggestedRooms(space); if (this._activeSpace === space) { diff --git a/src/utils/space.tsx b/src/utils/space.tsx index 38f6e348d7..c238a83bc2 100644 --- a/src/utils/space.tsx +++ b/src/utils/space.tsx @@ -16,10 +16,9 @@ limitations under the License. import React from "react"; import { Room } from "matrix-js-sdk/src/models/room"; -import { MatrixClient } from "matrix-js-sdk/src/client"; import { EventType } from "matrix-js-sdk/src/@types/event"; -import { calculateRoomVia } from "../utils/permalinks/Permalinks"; +import { calculateRoomVia } from "./permalinks/Permalinks"; import Modal from "../Modal"; import SpaceSettingsDialog from "../components/views/dialogs/SpaceSettingsDialog"; import AddExistingToSpaceDialog from "../components/views/dialogs/AddExistingToSpaceDialog"; @@ -30,8 +29,8 @@ import SpacePublicShare from "../components/views/spaces/SpacePublicShare"; import InfoDialog from "../components/views/dialogs/InfoDialog"; import { showRoomInviteDialog } from "../RoomInvite"; -export const shouldShowSpaceSettings = (cli: MatrixClient, space: Room) => { - const userId = cli.getUserId(); +export const shouldShowSpaceSettings = (space: Room) => { + const userId = space.client.getUserId(); return space.getMyMembership() === "join" && (space.currentState.maySendStateEvent(EventType.RoomAvatar, userId) || space.currentState.maySendStateEvent(EventType.RoomName, userId) @@ -48,20 +47,20 @@ export const makeSpaceParentEvent = (room: Room, canonical = false) => ({ state_key: room.roomId, }); -export const showSpaceSettings = (cli: MatrixClient, space: Room) => { +export const showSpaceSettings = (space: Room) => { Modal.createTrackedDialog("Space Settings", "", SpaceSettingsDialog, { - matrixClient: cli, + matrixClient: space.client, space, }, /*className=*/null, /*isPriority=*/false, /*isStatic=*/true); }; -export const showAddExistingRooms = async (cli: MatrixClient, space: Room) => { +export const showAddExistingRooms = async (space: Room) => { return Modal.createTrackedDialog( "Space Landing", "Add Existing", AddExistingToSpaceDialog, { - matrixClient: cli, + matrixClient: space.client, onCreateRoomClick: showCreateNewRoom, space, }, @@ -69,7 +68,7 @@ export const showAddExistingRooms = async (cli: MatrixClient, space: Room) => { ).finished; }; -export const showCreateNewRoom = async (cli: MatrixClient, space: Room) => { +export const showCreateNewRoom = async (space: Room) => { const modal = Modal.createTrackedDialog<[boolean, IOpts]>( "Space Landing", "Create Room",