diff --git a/README.md b/README.md index 67e5e12f59..4588a0586e 100644 --- a/README.md +++ b/README.md @@ -48,7 +48,7 @@ Code should be committed as follows: * CSS: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/css * Theme specific CSS & resources: https://github.com/matrix-org/matrix-react-sdk/tree/master/res/themes -React components in matrix-react-sdk are come in two different flavours: +React components in matrix-react-sdk come in two different flavours: 'structures' and 'views'. Structures are stateful components which handle the more complicated business logic of the app, delegating their actual presentation rendering to stateless 'view' components. For instance, the RoomView component diff --git a/res/css/_components.scss b/res/css/_components.scss index ffaec43b68..4ef95e8cd8 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"; @@ -243,6 +244,7 @@ @import "./views/settings/_E2eAdvancedPanel.scss"; @import "./views/settings/_EmailAddresses.scss"; @import "./views/settings/_IntegrationManager.scss"; +@import "./views/settings/_JoinRuleSettings.scss"; @import "./views/settings/_LayoutSwitcher.scss"; @import "./views/settings/_Notifications.scss"; @import "./views/settings/_PhoneNumbers.scss"; diff --git a/res/css/views/settings/_JoinRuleSettings.scss b/res/css/views/settings/_JoinRuleSettings.scss new file mode 100644 index 0000000000..8b520b2ab1 --- /dev/null +++ b/res/css/views/settings/_JoinRuleSettings.scss @@ -0,0 +1,88 @@ +/* +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_JoinRuleSettings_upgradeRequired { + margin-left: 16px; + padding: 4px 16px; + border: 1px solid $accent-color; + border-radius: 8px; + color: $accent-color; + font-size: $font-12px; + line-height: $font-15px; +} + +.mx_JoinRuleSettings_spacesWithAccess { + > h4 { + color: $secondary-content; + font-weight: $font-semi-bold; + font-size: $font-12px; + line-height: $font-15px; + text-transform: uppercase; + } + + > span { + font-weight: 500; + font-size: $font-14px; + line-height: 32px; // matches height of avatar for v-align + color: $secondary-content; + display: inline-block; + + img.mx_RoomAvatar_isSpaceRoom, + .mx_RoomAvatar_isSpaceRoom img { + border-radius: 8px; + } + + .mx_BaseAvatar { + margin-right: 8px; + } + + & + span { + margin-left: 16px; + } + } +} + +.mx_JoinRuleSettings_radioButton { + padding-top: 16px; + margin-bottom: 8px; + + .mx_RadioButton_content { + margin-left: 14px; + font-weight: $font-semi-bold; + font-size: $font-15px; + line-height: $font-24px; + color: $primary-content; + display: block; + } + + & + span { + display: inline-block; + margin-left: 34px; + margin-bottom: 16px; + font-size: $font-15px; + line-height: $font-24px; + color: $secondary-content; + + & + .mx_RadioButton { + border-top: 1px solid $menu-border-color; + } + } +} + +.mx_JoinRuleSettings_linkButton { + padding: 0; + font-size: inherit; +} diff --git a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss index 8fd0f14418..a3b3b17899 100644 --- a/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss +++ b/res/css/views/settings/tabs/room/_SecurityRoomSettingsTab.scss @@ -19,37 +19,6 @@ limitations under the License. padding: 0; margin-bottom: 16px; } - - .mx_SecurityRoomSettingsTab_spacesWithAccess { - > h4 { - color: $secondary-content; - font-weight: $font-semi-bold; - font-size: $font-12px; - line-height: $font-15px; - text-transform: uppercase; - } - - > span { - font-weight: 500; - font-size: $font-14px; - line-height: 32px; // matches height of avatar for v-align - color: $secondary-content; - display: inline-block; - - img.mx_RoomAvatar_isSpaceRoom, - .mx_RoomAvatar_isSpaceRoom img { - border-radius: 8px; - } - - .mx_BaseAvatar { - margin-right: 8px; - } - - & + span { - margin-left: 16px; - } - } - } } .mx_SecurityRoomSettingsTab_warning { @@ -68,47 +37,3 @@ limitations under the License. border-bottom: 1px solid $menu-border-color; margin-bottom: 32px; } - -.mx_SecurityRoomSettingsTab_upgradeRequired { - margin-left: 16px; - padding: 4px 16px; - border: 1px solid $accent-color; - border-radius: 8px; - color: $accent-color; - font-size: $font-12px; - line-height: $font-15px; -} - -.mx_SecurityRoomSettingsTab_joinRule { - .mx_RadioButton { - padding-top: 16px; - margin-bottom: 8px; - - .mx_RadioButton_content { - margin-left: 14px; - font-weight: $font-semi-bold; - font-size: $font-15px; - line-height: $font-24px; - color: $primary-content; - display: block; - } - } - - > span { - display: inline-block; - margin-left: 34px; - margin-bottom: 16px; - font-size: $font-15px; - line-height: $font-24px; - color: $secondary-content; - - & + .mx_RadioButton { - border-top: 1px solid $menu-border-color; - } - } - - .mx_AccessibleButton_kind_link { - padding: 0; - font-size: inherit; - } -} diff --git a/res/img/element-icons/message/view-in-timeline.svg b/res/img/element-icons/message/view-in-timeline.svg new file mode 100644 index 0000000000..9f05950ce0 --- /dev/null +++ b/res/img/element-icons/message/view-in-timeline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/components/structures/ScrollPanel.tsx b/src/components/structures/ScrollPanel.tsx index 2eae585f4f..0ea070627a 100644 --- a/src/components/structures/ScrollPanel.tsx +++ b/src/components/structures/ScrollPanel.tsx @@ -277,8 +277,15 @@ export default class ScrollPanel extends React.Component { // fractional values (both too big and too small) // for scrollTop happen on certain browsers/platforms // when scrolled all the way down. E.g. Chrome 72 on debian. - // so check difference <= 1; - return Math.abs(sn.scrollHeight - (sn.scrollTop + sn.clientHeight)) <= 1; + // + // We therefore leave a bit of wiggle-room and assume we're at the + // bottom if the unscrolled area is less than one pixel high. + // + // non-standard DPI settings also seem to have effect here and can + // actually lead to scrollTop+clientHeight being *larger* than + // scrollHeight. (observed in element-desktop on Ubuntu 20.04) + // + return sn.scrollHeight - (sn.scrollTop + sn.clientHeight) <= 1; }; // returns the vertical height in the given direction that can be removed from diff --git a/src/components/structures/ThreadView.tsx b/src/components/structures/ThreadView.tsx index bb31c32877..180a870cd5 100644 --- a/src/components/structures/ThreadView.tsx +++ b/src/components/structures/ThreadView.tsx @@ -139,7 +139,7 @@ export default class ThreadView extends React.Component { sendReadReceiptOnLoad={false} // No RR support in thread's MVP timelineSet={this.state?.thread?.timelineSet} showUrlPreview={true} - tileShape={TileShape.Notif} + tileShape={TileShape.Thread} empty={
empty
} alwaysShowTimestamps={true} layout={Layout.Group} diff --git a/src/components/views/context_menus/MessageContextMenu.tsx b/src/components/views/context_menus/MessageContextMenu.tsx index c7fcf32260..22dd3ac438 100644 --- a/src/components/views/context_menus/MessageContextMenu.tsx +++ b/src/components/views/context_menus/MessageContextMenu.tsx @@ -34,8 +34,7 @@ import ForwardDialog from "../dialogs/ForwardDialog"; import { Action } from "../../../dispatcher/actions"; import ReportEventDialog from '../dialogs/ReportEventDialog'; import ViewSource from '../../structures/ViewSource'; -import ConfirmRedactDialog from '../dialogs/ConfirmRedactDialog'; -import ErrorDialog from '../dialogs/ErrorDialog'; +import { createRedactEventDialog } from '../dialogs/ConfirmRedactDialog'; import ShareDialog from '../dialogs/ShareDialog'; import { RoomPermalinkCreator } from "../../../utils/permalinks/Permalinks"; import { IPosition, ChevronFace } from '../../structures/ContextMenu'; @@ -140,34 +139,11 @@ export default class MessageContextMenu extends React.Component }; private onRedactClick = (): void => { - Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, { - onFinished: async (proceed: boolean, reason?: string) => { - if (!proceed) return; - - const cli = MatrixClientPeg.get(); - try { - this.props.onCloseDialog?.(); - await cli.redactEvent( - this.props.mxEvent.getRoomId(), - this.props.mxEvent.getId(), - undefined, - reason ? { reason } : {}, - ); - } catch (e) { - const code = e.errcode || e.statusCode; - // only show the dialog if failing for something other than a network error - // (e.g. no errcode or statusCode) as in that case the redactions end up in the - // detached queue and we show the room status bar to allow retry - if (typeof code !== "undefined") { - // display error message stating you couldn't delete this. - Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, { - title: _t('Error'), - description: _t('You cannot delete this message. (%(code)s)', { code }), - }); - } - } - }, - }, 'mx_Dialog_confirmredact'); + const { mxEvent, onCloseDialog } = this.props; + createRedactEventDialog({ + mxEvent, + onCloseDialog, + }); this.closeMenu(); }; diff --git a/src/components/views/dialogs/ConfirmRedactDialog.tsx b/src/components/views/dialogs/ConfirmRedactDialog.tsx index b346d2d44c..74b3320fdf 100644 --- a/src/components/views/dialogs/ConfirmRedactDialog.tsx +++ b/src/components/views/dialogs/ConfirmRedactDialog.tsx @@ -14,9 +14,13 @@ See the License for the specific language governing permissions and limitations under the License. */ +import { MatrixEvent } from 'matrix-js-sdk/src/models/event'; import React from 'react'; import { _t } from '../../../languageHandler'; +import { MatrixClientPeg } from '../../../MatrixClientPeg'; +import Modal from '../../../Modal'; import { replaceableComponent } from "../../../utils/replaceableComponent"; +import ErrorDialog from './ErrorDialog'; import TextInputDialog from "./TextInputDialog"; interface IProps { @@ -42,3 +46,40 @@ export default class ConfirmRedactDialog extends React.Component { ); } } + +export function createRedactEventDialog({ + mxEvent, + onCloseDialog = () => {}, +}: { + mxEvent: MatrixEvent; + onCloseDialog?: () => void; +}) { + Modal.createTrackedDialog('Confirm Redact Dialog', '', ConfirmRedactDialog, { + onFinished: async (proceed: boolean, reason?: string) => { + if (!proceed) return; + + const cli = MatrixClientPeg.get(); + try { + onCloseDialog?.(); + await cli.redactEvent( + mxEvent.getRoomId(), + mxEvent.getId(), + undefined, + reason ? { reason } : {}, + ); + } catch (e) { + const code = e.errcode || e.statusCode; + // only show the dialog if failing for something other than a network error + // (e.g. no errcode or statusCode) as in that case the redactions end up in the + // detached queue and we show the room status bar to allow retry + if (typeof code !== "undefined") { + // display error message stating you couldn't delete this. + Modal.createTrackedDialog('You cannot delete this message', '', ErrorDialog, { + title: _t('Error'), + description: _t('You cannot delete this message. (%(code)s)', { code }), + }); + } + } + }, + }, 'mx_Dialog_confirmredact'); +} diff --git a/src/components/views/messages/MessageActionBar.tsx b/src/components/views/messages/MessageActionBar.tsx index e835584387..06817b910a 100644 --- a/src/components/views/messages/MessageActionBar.tsx +++ b/src/components/views/messages/MessageActionBar.tsx @@ -128,6 +128,11 @@ const ReactButton: React.FC = ({ mxEvent, reactions, onFocusC ; }; +export enum ActionBarRenderingContext { + Room, + Thread +} + interface IMessageActionBarProps { mxEvent: MatrixEvent; reactions?: Relations; @@ -135,15 +140,20 @@ interface IMessageActionBarProps { getTile: () => any | null; getReplyThread: () => ReplyThread | undefined; permalinkCreator?: RoomPermalinkCreator; - onFocusChange: (menuDisplayed: boolean) => void; - isQuoteExpanded?: boolean; + onFocusChange?: (menuDisplayed: boolean) => void; toggleThreadExpanded: () => void; + renderingContext?: ActionBarRenderingContext; + isQuoteExpanded?: boolean; } @replaceableComponent("views.messages.MessageActionBar") export default class MessageActionBar extends React.PureComponent { public static contextType = RoomContext; + public static defaultProps = { + renderingContext: ActionBarRenderingContext.Room, + }; + public componentDidMount(): void { if (this.props.mxEvent.status && this.props.mxEvent.status !== EventStatus.SENT) { this.props.mxEvent.on("Event.status", this.onSent); @@ -288,7 +298,7 @@ export default class MessageActionBar extends React.PureComponent let shouldSend = true; + if (newContent?.body === '') { + this.cancelPreviousPendingEdit(); + createRedactEventDialog({ + mxEvent: editedEvent, + }); + return; + } + // If content is modified then send an updated event into the room if (this.isContentModified(newContent)) { const roomId = editedEvent.getRoomId(); diff --git a/src/components/views/rooms/EventTile.tsx b/src/components/views/rooms/EventTile.tsx index 592827eaf5..27cf7d761f 100644 --- a/src/components/views/rooms/EventTile.tsx +++ b/src/components/views/rooms/EventTile.tsx @@ -53,7 +53,7 @@ import SenderProfile from '../messages/SenderProfile'; import MessageTimestamp from '../messages/MessageTimestamp'; import TooltipButton from '../elements/TooltipButton'; import ReadReceiptMarker from "./ReadReceiptMarker"; -import MessageActionBar from "../messages/MessageActionBar"; +import MessageActionBar, { ActionBarRenderingContext } from "../messages/MessageActionBar"; import ReactionsRow from '../messages/ReactionsRow'; import { getEventDisplayInfo } from '../../../utils/EventUtils'; import { RightPanelPhases } from "../../../stores/RightPanelStorePhases"; @@ -192,6 +192,7 @@ export enum TileShape { Notif = "notif", FileGrid = "file_grid", Pinned = "pinned", + Thread = "thread", } interface IProps { @@ -1055,6 +1056,9 @@ export default class EventTile extends React.Component { } } + const renderingContext = this.props.tileShape === TileShape.Thread + ? ActionBarRenderingContext.Thread + : ActionBarRenderingContext.Room; const actionBar = !isEditing ? { getTile={this.getTile} getReplyThread={this.getReplyThread} onFocusChange={this.onActionBarFocusChange} + renderingContext={renderingContext} isQuoteExpanded={isQuoteExpanded} toggleThreadExpanded={() => this.setQuoteExpanded(!isQuoteExpanded)} /> : undefined; @@ -1170,6 +1175,40 @@ export default class EventTile extends React.Component { , ]); } + case TileShape.Thread: { + const room = this.context.getRoom(this.props.mxEvent.getRoomId()); + return React.createElement(this.props.as || "li", { + "className": classes, + "aria-live": ariaLive, + "aria-atomic": true, + "data-scroll-tokens": scrollToken, + }, [ + , + , +
+ + { actionBar } +
, + ]); + } case TileShape.FileGrid: { return React.createElement(this.props.as || "li", { "className": classes, diff --git a/src/components/views/settings/JoinRuleSettings.tsx b/src/components/views/settings/JoinRuleSettings.tsx index a32d147d3a..76596103f5 100644 --- a/src/components/views/settings/JoinRuleSettings.tsx +++ b/src/components/views/settings/JoinRuleSettings.tsx @@ -97,7 +97,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange, closeSet if (roomSupportsRestricted || preferredRestrictionVersion || joinRule === JoinRule.Restricted) { let upgradeRequiredPill; if (preferredRestrictionVersion) { - upgradeRequiredPill = + upgradeRequiredPill = { _t("Upgrade required") } ; } @@ -159,13 +159,14 @@ const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange, closeSet disabled={disabled} onClick={onEditRestrictedClick} kind="link" + className="mx_JoinRuleSettings_linkButton" > { sub } , }) } -
+

{ _t("Spaces with access") }

{ shownSpaces.map(room => { return @@ -286,6 +287,7 @@ const JoinRuleSettings = ({ room, promptUpgrade, onError, beforeChange, closeSet onChange={onChange} definitions={definitions} disabled={disabled} + className="mx_JoinRuleSettings_radioButton" /> ); }; diff --git a/src/editor/serialize.ts b/src/editor/serialize.ts index 38a73cc945..9822046a0d 100644 --- a/src/editor/serialize.ts +++ b/src/editor/serialize.ts @@ -185,7 +185,7 @@ export function startsWith(model: EditorModel, prefix: string, caseSensitive = t const firstPart = model.parts[0]; // part type will be "plain" while editing, // and "command" while composing a message. - let text = firstPart && firstPart.text; + let text = firstPart?.text || ''; if (!caseSensitive) { prefix = prefix.toLowerCase(); text = text.toLowerCase(); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index bc45caedb5..62cd130110 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -773,16 +773,6 @@ "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 makes 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 makes 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", @@ -1056,6 +1046,7 @@ "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", @@ -1465,6 +1456,7 @@ "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 space": "Select the roles required to change various parts of the space", "Select the roles required to change various parts of the room": "Select the roles required to change various parts of the room", @@ -1487,6 +1479,7 @@ "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.": "Changes to who can read history will only apply to future messages in this room. The visibility of existing history will be unchanged.", "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", @@ -2211,6 +2204,7 @@ "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", @@ -2532,6 +2526,7 @@ "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", diff --git a/src/stores/SpaceStore.tsx b/src/stores/SpaceStore.ts similarity index 90% rename from src/stores/SpaceStore.tsx rename to src/stores/SpaceStore.ts index 73feb300a5..6625e2117e 100644 --- a/src/stores/SpaceStore.tsx +++ b/src/stores/SpaceStore.ts @@ -14,13 +14,11 @@ 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"; import { MatrixEvent } from "matrix-js-sdk/src/models/event"; import { IHierarchyRoom } from "matrix-js-sdk/src/@types/spaces"; -import { JoinRule } from "matrix-js-sdk/src/@types/partials"; import { IRoomCapability } from "matrix-js-sdk/src/client"; import { AsyncStoreWithClient } from "./AsyncStoreWithClient"; @@ -41,12 +39,6 @@ import { arrayHasDiff, arrayHasOrderChange } from "../utils/arrays"; import { objectDiff } from "../utils/objects"; import { reorderLexicographically } from "../utils/stringOrderField"; import { TAG_ORDER } from "../components/views/rooms/RoomList"; -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 { SettingUpdatedPayload } from "../dispatcher/payloads/SettingUpdatedPayload"; type SpaceKey = string | symbol; @@ -233,65 +225,6 @@ export class SpaceStoreClass extends AsyncStoreWithClient { window.localStorage.removeItem(ACTIVE_SPACE_LS_KEY); } - // New in Spaces beta toast for Restricted Join Rule - const lsKey = "mx_SpaceBeta_restrictedJoinRuleToastSeen"; - if (contextSwitch && space?.getJoinRule() === JoinRule.Invite && shouldShowSpaceSettings(space) && - space.getJoinedMemberCount() > 1 && !localStorage.getItem(lsKey) - && this.restrictedJoinRuleSupport?.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 makes 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, - }); - } - if (space) { this.loadSuggestedRooms(space); } @@ -595,7 +528,7 @@ export class SpaceStoreClass extends AsyncStoreWithClient { // Update NotificationStates this.getNotificationState(s).setRooms(visibleRooms.filter(room => { - if (!roomIds.has(room.roomId)) return false; + if (!roomIds.has(room.roomId) || room.isSpaceRoom()) return false; if (DMRoomMap.shared().getUserIdForRoomId(room.roomId)) { return s === HOME_SPACE;