mirror of https://github.com/vector-im/riot-web
Add new in the spaces beta toast & explanatory modal
parent
912e192dc6
commit
89949bd884
src
components
structures
views
i18n/strings
stores
utils
|
@ -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 = <AccessibleTooltipButton
|
||||
className="mx_SpaceRoomView_landing_settingsButton"
|
||||
onClick={() => {
|
||||
showSpaceSettings(cli, space);
|
||||
showSpaceSettings(space);
|
||||
}}
|
||||
title={_t("Settings")}
|
||||
/>;
|
||||
|
|
|
@ -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<IAddExistingToSpaceProps> = ({
|
|||
</div>;
|
||||
};
|
||||
|
||||
const AddExistingToSpaceDialog: React.FC<IProps> = ({ matrixClient: cli, space, onCreateRoomClick, onFinished }) => {
|
||||
const AddExistingToSpaceDialog: React.FC<IProps> = ({ space, onCreateRoomClick, onFinished }) => {
|
||||
const [selectedSpace, setSelectedSpace] = useState(space);
|
||||
const existingSubspaces = SpaceStore.instance.getChildSpaces(space.roomId);
|
||||
|
||||
|
@ -344,13 +342,13 @@ const AddExistingToSpaceDialog: React.FC<IProps> = ({ matrixClient: cli, space,
|
|||
onFinished={onFinished}
|
||||
fixedWidth={false}
|
||||
>
|
||||
<MatrixClientContext.Provider value={cli}>
|
||||
<MatrixClientContext.Provider value={space.client}>
|
||||
<AddExistingToSpace
|
||||
space={space}
|
||||
onFinished={onFinished}
|
||||
footerPrompt={<>
|
||||
<div>{ _t("Want to add a new room instead?") }</div>
|
||||
<AccessibleButton onClick={() => onCreateRoomClick(cli, space)} kind="link">
|
||||
<AccessibleButton onClick={() => onCreateRoomClick(space)} kind="link">
|
||||
{ _t("Create a new room") }
|
||||
</AccessibleButton>
|
||||
</>}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
/*
|
||||
Copyright 2015, 2016 OpenMarket Ltd
|
||||
Copyright 2017 New Vector Ltd.
|
||||
Copyright 2019 Bastian Masanek, Noxware IT <matrix@noxware.de>
|
||||
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<IProps> {
|
||||
static defaultProps = {
|
||||
title: '',
|
||||
description: '',
|
||||
hasCloseButton: false,
|
||||
};
|
||||
|
||||
onFinished = () => {
|
||||
private onFinished = () => {
|
||||
this.props.onFinished();
|
||||
};
|
||||
|
|
@ -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
|
||||
|
|
|
@ -203,7 +203,7 @@ export class SpaceItem extends React.PureComponent<IItemProps, IItemState> {
|
|||
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<IItemProps, IItemState> {
|
|||
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<IItemProps, IItemState> {
|
|||
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<IItemProps, IItemState> {
|
|||
|
||||
let settingsOption;
|
||||
let leaveSection;
|
||||
if (shouldShowSpaceSettings(this.context, this.props.space)) {
|
||||
if (shouldShowSpaceSettings(this.props.space)) {
|
||||
settingsOption = (
|
||||
<IconizedContextMenuOption
|
||||
iconClassName="mx_SpacePanel_iconSettings"
|
||||
|
|
|
@ -774,6 +774,16 @@
|
|||
"The person who invited you already left the room.": "The person who invited you already left the room.",
|
||||
"The person who invited you already left the room, or their server is offline.": "The person who invited you already left the room, or their server is offline.",
|
||||
"Failed to join room": "Failed to join room",
|
||||
"New in the Spaces beta": "New in the Spaces beta",
|
||||
"Help people in spaces to find and join private rooms": "Help people in spaces to find and join private rooms",
|
||||
"Learn more": "Learn more",
|
||||
"Help space members find private rooms": "Help space members find private rooms",
|
||||
"To help space members find and join a private room, go to that room's Security & Privacy settings.": "To help space members find and join a private room, go to that room's Security & Privacy settings.",
|
||||
"General": "General",
|
||||
"Security & Privacy": "Security & Privacy",
|
||||
"Roles & Permissions": "Roles & Permissions",
|
||||
"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.": "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.",
|
||||
"Skip": "Skip",
|
||||
"You joined the call": "You joined the call",
|
||||
"%(senderName)s joined the call": "%(senderName)s joined the call",
|
||||
"Call in progress": "Call in progress",
|
||||
|
@ -1040,7 +1050,6 @@
|
|||
"Invite people": "Invite people",
|
||||
"Invite with email or username": "Invite with email or username",
|
||||
"Failed to save space settings.": "Failed to save space settings.",
|
||||
"General": "General",
|
||||
"Edit settings relating to your space.": "Edit settings relating to your space.",
|
||||
"Saving...": "Saving...",
|
||||
"Save Changes": "Save Changes",
|
||||
|
@ -1430,7 +1439,6 @@
|
|||
"Muted Users": "Muted Users",
|
||||
"Banned users": "Banned users",
|
||||
"Send %(eventType)s events": "Send %(eventType)s events",
|
||||
"Roles & Permissions": "Roles & Permissions",
|
||||
"Permissions": "Permissions",
|
||||
"Select the roles required to change various parts of the room": "Select the roles required to change various parts of the room",
|
||||
"Enable encryption?": "Enable encryption?",
|
||||
|
@ -1456,7 +1464,6 @@
|
|||
"Members only (since they joined)": "Members only (since they joined)",
|
||||
"People with supported clients will be able to join the room without having a registered account.": "People with supported clients will be able to join the room without having a registered account.",
|
||||
"Who can read history?": "Who can read history?",
|
||||
"Security & Privacy": "Security & Privacy",
|
||||
"Once enabled, encryption cannot be disabled.": "Once enabled, encryption cannot be disabled.",
|
||||
"Encrypted": "Encrypted",
|
||||
"Access": "Access",
|
||||
|
@ -2147,7 +2154,6 @@
|
|||
"People you know on %(brand)s": "People you know on %(brand)s",
|
||||
"Hide": "Hide",
|
||||
"Show": "Show",
|
||||
"Skip": "Skip",
|
||||
"Send %(count)s invites|other": "Send %(count)s invites",
|
||||
"Send %(count)s invites|one": "Send %(count)s invite",
|
||||
"Invite people to join %(communityName)s": "Invite people to join %(communityName)s",
|
||||
|
@ -2422,7 +2428,6 @@
|
|||
"We call the places where you can host your account ‘homeservers’.": "We call the places where you can host your account ‘homeservers’.",
|
||||
"Other homeserver": "Other homeserver",
|
||||
"Use your preferred Matrix homeserver if you have one, or host your own.": "Use your preferred Matrix homeserver if you have one, or host your own.",
|
||||
"Learn more": "Learn more",
|
||||
"About homeservers": "About homeservers",
|
||||
"Reset event store?": "Reset event store?",
|
||||
"You most likely do not want to reset your event index store": "You most likely do not want to reset your event index store",
|
||||
|
|
|
@ -14,6 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { ListIteratee, Many, sortBy, throttle } from "lodash";
|
||||
import { EventType, RoomType } from "matrix-js-sdk/src/@types/event";
|
||||
import { Room } from "matrix-js-sdk/src/models/room";
|
||||
|
@ -38,6 +39,13 @@ import { arrayHasDiff } from "../utils/arrays";
|
|||
import { objectDiff } from "../utils/objects";
|
||||
import { arrayHasOrderChange } from "../utils/arrays";
|
||||
import { reorderLexicographically } from "../utils/stringOrderField";
|
||||
import { shouldShowSpaceSettings } from "../utils/space";
|
||||
import ToastStore from "./ToastStore";
|
||||
import { _t } from "../languageHandler";
|
||||
import GenericToast from "../components/views/toasts/GenericToast";
|
||||
import Modal from "../Modal";
|
||||
import InfoDialog from "../components/views/dialogs/InfoDialog";
|
||||
import { JoinRule } from "../../../matrix-js-sdk/src/@types/partials";
|
||||
|
||||
type SpaceKey = string | symbol;
|
||||
|
||||
|
@ -173,6 +181,68 @@ export class SpaceStoreClass extends AsyncStoreWithClient<IState> {
|
|||
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: <>
|
||||
<p>{ _t("To help space members find and join a private room, " +
|
||||
"go to that room's Security & Privacy settings.") }</p>
|
||||
|
||||
{ /* Reuses classes from TabbedView for simplicity, non-interactive */ }
|
||||
<div style={{ width: "190px" }}>
|
||||
<div className="mx_TabbedView_tabLabel">
|
||||
<span className="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_settingsIcon" />
|
||||
<span className="mx_TabbedView_tabLabel_text">{ _t("General") }</span>
|
||||
</div>
|
||||
<div className="mx_TabbedView_tabLabel mx_TabbedView_tabLabel_active">
|
||||
<span className="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_securityIcon" />
|
||||
<span className="mx_TabbedView_tabLabel_text">{ _t("Security & Privacy") }</span>
|
||||
</div>
|
||||
<div className="mx_TabbedView_tabLabel">
|
||||
<span className="mx_TabbedView_maskedIcon mx_RoomSettingsDialog_rolesIcon" />
|
||||
<span className="mx_TabbedView_tabLabel_text">{ _t("Roles & Permissions") }</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<p>{ _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.")}</p>
|
||||
</>,
|
||||
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) {
|
||||
|
|
|
@ -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",
|
||||
|
|
Loading…
Reference in New Issue